基于javaweb+mysql的springbootcrm客户关系管理系统(java+springboot+echarts+freemarker+layui+maven+mysql)
私信源码获取及调试交流
运行环境
Java≥8、MySQL≥5.7
开发工具
eclipse/idea/myeclipse/sts等均可配置运行
适用
课程设计,大作业,毕业设计,项目练习,学习演示等
功能说明
基于javaweb+mysql的SpringBootcrm客户关系管理系统(java+springboot+echarts+freemarker+layui+maven+mysql)
CRM智能办公
项目介绍
本应用是一个客户关系管理系统,主要包括五大模块,分别是营销管理,客户管理,服务管理,统计报表和系统管理,为客户关系管理提供简单的数据管理与分析
技术选型方面,该项目是一个SpringBoot
的单体应用,项目使用SpringBoot2
框架快速开发,数据访问层使用Mybatis
框架,页面渲染引擎使用Freemarker
,页面样式使用Layui
,日志方面选用的是logback
,统计报表部分使用的是ECharts
,数据库使用的Mysql 8.0版本;
安装教程
-
在mysql(默认为mysql8)中创建名为
crm
的数据库,并执行源码根目录的crm.sql
脚本生成数据库表以及数据 2. 将项目源码导入idea中,指定项目的jdk版本为jdk8或以上,并标记为maven项目,下载所需依赖 3. 修改application.yml
中针对于数据库的配置(主要是数据库名和数据库密码) 4. 修改logback.xml中,第4行,日志文件的存储地址,改为自己的路径; -
启动项目测试是否正常,默认启动地址首页为
http://localhost:1212/crm
,默认数据库中的管理员为admin
,密码为123456
,可在登录系统之后自行修改用户密码
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@Autowired
private ResultInfo resultInfo;
/**
* 全局异常处理
* @param request
* @param response
* @param handler
* @param ex
* @return
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 设置默认视图
ModelAndView view = new ModelAndView("error");
view.addObject("code", "500");
view.addObject("msg", "系统资源繁忙");
// 处理未登录异常
if (ex instanceof NoLoginException) {
// 清除view设置
view.clear();
// 返回到登录页面
view.setViewName("redirect:/index");
logger.error("未登录异常");
return view;
}
// 判断handler
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Annotation responseBody = handlerMethod.getMethod().getDeclaredAnnotation(ResponseBody.class);
// 返回视图
if (responseBody == null) {
// 自定义异常
if (ex instanceof ParamsException) {
ParamsException paramsException = (ParamsException) ex;
view.addObject("code", paramsException.getCode());
view.addObject("msg", paramsException.getMsg());
}else if (ex instanceof AuthException) {
AuthException authException = (AuthException) ex;
view.addObject("code", authException.getCode());
view.addObject("msg", authException.getMsg());
}
logger.error("返回视图异常:viewName={}",view.getViewName());
} else { // 返回json数据
// 设置默认值
resultInfo.setAll(500, ex.getMessage(), null);
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取session
Object user = request.getSession().getAttribute("user");
// 获取cookie
int userId = LoginUserUtil.releaseUserIdFromCookie(request);
// session为空
if (user != null) {
return true;
}else if (userId != -1 && userMapper.selectByPrimaryKey(userId) != null) {
return true;
}else {
throw new NoLoginException();
}
}
}
/**
* 资源管理控制器
*
* @version 1.0
*/
@Controller
@RequestMapping("/permission")
public class PermissionController {
@Autowired
private PermissionService permissionService;
@Autowired
private ResultInfo resultInfo;
/**
* 客户开发计划控制器
*
* @version 1.0
*/
@RequestMapping("/cusDevPlan")
@Controller
public class CusDevPlanController extends BaseController {
@Autowired
private SaleChanceService saleChanceService;
@Autowired
private CusDevPlanService cusDevPlanService;
@Autowired
private ResultInfo resultInfo;
/**
* 跳转到客户开发计划首页
* @return
*/
@GetMapping("/index")
public String index() {
return "cusDevPlan/cusDevPlan";
}
/**
* 多条件查询客户开发计划数据
*
* @param saleChanceQuery
* @return
*/
@GetMapping("/cusDevPlanList")
@ResponseBody
return "customerServe/customerServeBackForEdit";
}
/**
* 客户管理模块的视图有此方法执行跳转
*
* @return
*/
@GetMapping("/index/{index}")
public String index(@PathVariable("index") Integer index) {
// 校验参数
AssertUtil.isTrue(index == null, "非法页面跳转");
if (index == 1) {
// 服务创建
return "customerServe/customerServe";
} else if (index == 2) {
// 服务分配
return "customerServe/customerServeAssigner";
} else if (index == 3) {
// 服务处理
return "customerServe/customerServeHandle";
} else if (index == 4) {
// 服务反馈
return "customerServe/customerServeBack";
} else if (index == 5) {
// 服务反馈
return "customerServe/customerServeArchive";
} else {
AssertUtil.isTrue(true, "非法页面跳转");
}
return null;
}
}
}
/**
* 销售机会控制层
*
* @version 1.0
*/
@Controller
@RequestMapping("/saleChance")
public class SaleChanceController extends BaseController {
private Logger logger = LoggerFactory.getLogger(SaleChanceController.class);
@Autowired
private SaleChanceService saleChanceService;
// 存放到session中
request.getSession().setAttribute("permissions", permissions);
}
request.getSession().setAttribute("user", user);
return "main";
}
}
public class CookieUtil {
/**
* 设置Cookie
* @param key Cookie名称
* @param value Cookie Value
* @param domain
* @param response
*/
public static void setCookie(String key, String value, String domain,
HttpServletResponse response) {
try {
value = URLEncoder.encode(value, "UTF-8");
if (StringUtils.isNotBlank(value)) {
value = value.replaceAll("\\+", "%20");
}
Cookie cookie = new Cookie(key, value);
cookie.setMaxAge(-1);
cookie.setPath("/");
cookie.setDomain(domain);
response.addCookie(cookie);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* 设置Cookie
* @param key Cookie名称
* @param value Cookie Value
@GetMapping("/toOrderDetailPage")
public String toOrderDetailPage(@RequestParam("id") Integer id, Model model) {
// 查询订单信息
model.addAttribute("customer", customerOrderService.findCustomerOrderById(id));
model.addAttribute("sum", orderDetailService.findSum(id));
return "customerOrder/orderDetail";
}
}
/**
* 权限拦截处理器
*
* @version 1.0
*/
@Component
@Aspect
public class PermissionHandler {
@Autowired
HttpSession session;
/**
* 权限控制
*/
@Around("@annotation(com.wuhunyu.annotation.RequestCode)")
public void permissionHandler(ProceedingJoinPoint joinPoint) throws Throwable {
List<String> permissions = (List<String>) session.getAttribute("permissions");
System.out.println("permissions:"+permissions);
if (permissions == null || permissions.size() == 0) {
// 抛出没有权限的异常
throw new AuthException();
} else {
// 获取注解上的授权码
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
RequestCode requestCode = signature.getMethod().getDeclaredAnnotation(RequestCode.class);
* 新增客户信息
* @param customer
* @return
*/
@PostMapping("/addCustomer")
@ResponseBody
public ResultInfo addCustomer(Customer customer) {
customerService.addCustomer(customer);
resultInfo.setAll(200, "添加客户信息成功", null);
return resultInfo;
}
/**
* 修改客户信息
* @param customer
* @return
*/
@PostMapping("/updateCustomer")
@ResponseBody
public ResultInfo updateCustomer(Customer customer) {
customerService.updateCustomer(customer);
resultInfo.setAll(200, "更新客户信息成功", null);
return resultInfo;
}
/**
* 批量删除客户信息
* @param ids
* @return
*/
@PostMapping("/deleteCustomer")
@ResponseBody
public ResultInfo deleteCustomer(@RequestParam("ids") Integer[] ids) {
customerService.deleteCustomerByIds(ids);
resultInfo.setAll(200, "删除客户信息成功", null);
return resultInfo;
}
/**
* 查询所有客户级别
* @return
*/
@GetMapping("/getLevels")
@ResponseBody
public List<String> findLevels() {
return customerService.findLevels();
}
/**
/**
* 新增/修改公用页面
* @param roleId
* @return
*/
@GetMapping("/toAddAndUpdatePage")
public String toAddAndUpdatePage(@Nullable Integer roleId, Model model) {
// 修改
if (roleId != null) {
Role role = roleService.selectByPrimaryKey(roleId);
AssertUtil.isTrue(role == null, "角色不存在");
model.addAttribute("role", role);
}
return "role/addAndUpdateRole";
}
/**
* 新增角色
* @param role
* @return
*/
@RequestCode("601001")
@PostMapping("/addRole")
@ResponseBody
public ResultInfo addRole(Role role) {
roleService.addRole(role);
resultInfo.setAll(200, "新增角色成功", null);
return resultInfo;
}
/**
* 修改角色信息
* @param role
* @return
*/
@RequestCode("601003")
@PostMapping("/updateRole")
@ResponseBody
public ResultInfo updateRole(Role role) {
roleService.updateRole(role);
resultInfo.setAll(200, "修改角色成功", null);
return resultInfo;
}
/**
* 批量删除角色
* @param ids
* @return
*/
@RequestCode("601004")
@PostMapping("/deleteRole")
@ResponseBody
public ResultInfo updateRole(@RequestParam("ids") Integer[] ids) {
dataDicService.updateDic(dataDic);
resultInfo.setAll(200, "字典数据修改成功", null);
return resultInfo;
}
@PostMapping("/deleteDicById")
@ResponseBody
public ResultInfo deleteDicById(@RequestParam("id") Integer id) {
dataDicService.deleteDicById(id);
resultInfo.setAll(200, "字典数据删除成功", null);
return resultInfo;
}
@GetMapping("/toAddAndUpdatePage")
public String toAddAndUpdate(@Nullable Integer id, Model model) {
// 修改
if (id != null) {
model.addAttribute("dic", dataDicService.selectDataDicById(id));
}
// 新增
return "dic/addAndUpdate";
}
}
private ResultInfo resultInfo;
/**
* 根据流失客户id查询流失客户详情信息
* @param lossId
* @return
*/
@GetMapping("/customerReprieveList")
@ResponseBody
public Map<String, Object> findCustomerReprieveByLossId(@RequestParam("lossId") Integer lossId) {
return customerReprieveService.findCustomerReprieveByLossId(lossId);
}
/**
* 添加客户流失信息
* @param customerReprieve
* @return
*/
@PostMapping("addCustomerReprieve")
@ResponseBody
public ResultInfo addCustomerReprieve(CustomerReprieve customerReprieve) {
customerReprieveService.addCustomerReprieve(customerReprieve);
resultInfo.setAll(200, "添加客户流失信息成功", null);
return resultInfo;
}
/**
* 更新客户流失信息
* @param customerReprieve
* @return
*/
@PostMapping("updateCustomerReprieve")
@ResponseBody
public ResultInfo updateCustomerReprieve(CustomerReprieve customerReprieve) {
customerReprieveService.updateCustomerReprieve(customerReprieve);
resultInfo.setAll(200, "更新客户流失信息成功", null);
return resultInfo;
}
/**
* 删除客户流失信息
* @param ids
* @return
*/
@PostMapping("deleteCustomerReprieve")
@ResponseBody
public ResultInfo deleteCustomerReprieve(@RequestParam("ids") Integer[] ids) {
customerReprieveService.deleteCustomerReprieveByIds(ids);
}
@GetMapping("/toCountCustomerMakePage")
public String toCountCustomerMakePage() {
return "customerCount/countCustomerMake";
}
@GetMapping("/countCustomerMake")
@ResponseBody
public ResultInfo countCustomerMake() {
resultInfo.setAll(200, "查询客户组成信息成功", customerCountService.countCustomerMake());
return resultInfo;
}
@GetMapping("/toCountCustomerLossPage")
public String toCountCustomerLossPage() {
return "customerCount/customerCountLoss";
}
@GetMapping("/countCustomerLoss")
@ResponseBody
public ResultInfo countCustomerLoss(CustomerLossQuery customerLossQuery) {
resultInfo.setAll(200, "查询客户流失信息成功", customerCountService.countCustomerLoss(customerLossQuery));
return resultInfo;
}
}
* @version 1.0
*/
@Controller
@RequestMapping("/customerCount")
public class CustomerCountController extends BaseController {
@Autowired
private ResultInfo resultInfo;
@Autowired
private CustomerCountService customerCountService;
@GetMapping("/toCustomerContributionPage")
public String toCustomerContributionPage() {
return "customerCount/customerCount";
}
@GetMapping("/countCustomerContribution")
@ResponseBody
public Map<String, Object> countCustomerContribution(CustomerContributionQuery customerContributionQuery) {
return customerCountService.countCustomerContribution(customerContributionQuery);
}
@GetMapping("/toCountCustomerMakePage")
public String toCountCustomerMakePage() {
return "customerCount/countCustomerMake";
}
@GetMapping("/countCustomerMake")
@ResponseBody
public ResultInfo countCustomerMake() {
resultInfo.setAll(200, "查询客户组成信息成功", customerCountService.countCustomerMake());
return resultInfo;
}
@GetMapping("/toCountCustomerLossPage")
public String toCountCustomerLossPage() {
return "customerCount/customerCountLoss";
}
@GetMapping("/countCustomerLoss")
@ResponseBody
public ResultInfo countCustomerLoss(CustomerLossQuery customerLossQuery) {
resultInfo.setAll(200, "查询客户流失信息成功", customerCountService.countCustomerLoss(customerLossQuery));
return resultInfo;
}
}
@GetMapping("/toAddAndUpdatePage")
public String toAddAndUpdatePage(@RequestParam("saleChanceId") Integer saleChanceId,@Nullable Integer id , Model model) {
// 封装销售机会id
model.addAttribute("saleChanceId", saleChanceId);
// 如果id不为空,则表示需要跳转到计划向修改页面
if (id != null) {
CusDevPlan cusDevPlan = cusDevPlanService.selectByPrimaryKey(id);
AssertUtil.isTrue(cusDevPlan == null, "查询的计划项数据不存在");
model.addAttribute("cusDevPlan", cusDevPlan);
}
return "cusDevPlan/addAndUpdate";
}
}
/**
* 全局异常处理类
*
* @version 1.0
*/
@Component
public class GlobalExceptionHandler implements HandlerExceptionResolver {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@Autowired
private ResultInfo resultInfo;
private CustomerReprieveService customerReprieveService;
@Autowired
private ResultInfo resultInfo;
/**
* 根据流失客户id查询流失客户详情信息
* @param lossId
* @return
*/
@GetMapping("/customerReprieveList")
@ResponseBody
public Map<String, Object> findCustomerReprieveByLossId(@RequestParam("lossId") Integer lossId) {
return customerReprieveService.findCustomerReprieveByLossId(lossId);
}
/**
* 添加客户流失信息
* @param customerReprieve
* @return
*/
@PostMapping("addCustomerReprieve")
@ResponseBody
public ResultInfo addCustomerReprieve(CustomerReprieve customerReprieve) {
customerReprieveService.addCustomerReprieve(customerReprieve);
resultInfo.setAll(200, "添加客户流失信息成功", null);
return resultInfo;
}
/**
* 更新客户流失信息
* @param customerReprieve
* @return
*/
@PostMapping("updateCustomerReprieve")
@ResponseBody
public ResultInfo updateCustomerReprieve(CustomerReprieve customerReprieve) {
customerReprieveService.updateCustomerReprieve(customerReprieve);
resultInfo.setAll(200, "更新客户流失信息成功", null);
return resultInfo;
}
/**
* 删除客户流失信息
* @param ids
* @return
*/
@PostMapping("deleteCustomerReprieve")
@ResponseBody
public ResultInfo deleteCustomerReprieve(@RequestParam("ids") Integer[] ids) {
customerReprieveService.deleteCustomerReprieveByIds(ids);
resultInfo.setAll(200, "删除客户流失信息成功", null);
return resultInfo;
}
@ResponseBody
public ResultInfo getAssignMan() {
List<Map<String, Object>> assignMans = saleChanceService.getAssignMan();
logger.info("assignMans={}",assignMans);
AssertUtil.isTrue(assignMans == null, "获取指派人信息失败");
AssertUtil.isTrue(assignMans.size() == 0, "没有可获取的指派人信息");
resultInfo.setAll(200, "获取指派人成功", assignMans);
return resultInfo;
}
/**
* 批量删除销售机会记录
* @return
*/
@PostMapping("/deleteSaleChance")
@ResponseBody
public ResultInfo deleteSaleChance(@RequestParam("ids") Integer[] ids) {
System.out.println("ids="+ids);
saleChanceService.deleteSaleChance(ids);
resultInfo.setAll(200, "删除成功", null);
return resultInfo;
}
}
/**
* 菜单资源管理控制器
*
* @version 1.0
*/
@Controller
@RequestMapping("/module")
// 若存在cookie,则自动填充登录用户名
String userName = CookieUtil.getCookieValue(request, "userName");
String password = CookieUtil.getCookieValue(request, "password");
if (!StringUtils.isBlank(userName)) {
model.addAttribute("userName", userName);
}
if (!StringUtils.isBlank(password)) {
model.addAttribute("password", password);
}
return "index";
}
/**
* 系统欢迎页
* @return
*/
@GetMapping("/welcome")
public String welcome() {
return "welcome";
}
/**
* 后端管理主页面
* @return
*/
@GetMapping({"/","/main"})
public String main(HttpServletRequest request) {
// 获取cookie中的userId
int userId = LoginUserUtil.releaseUserIdFromCookie(request);
User user = new User();
if (userId == -1) {
user.setUserName("游客");
} else {
// 根据userId查询userName
user = userService.selectByPrimaryKey(userId);
// 获取权限码
List<String> permissions = permissionService.findAclValueByUserId(userId);
// 存放到session中
request.getSession().setAttribute("permissions", permissions);
}
request.getSession().setAttribute("user", user);
return "main";
}
}