# CRM **Repository Path**: li_jinsong/CRM ## Basic Information - **Project Name**: CRM - **Description**: SSM 框架搭建的CRM客户管理系统 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2019-12-02 - **Last Updated**: 2021-06-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 【CRM客户管理系统】 ## 调研 ## 产品 ## 需求 参考《01_CRM需求概要文档V1.0》 ## UI ## 开发 * 技术选型: SSM、MYSQL57、tomcat7、jdk1.7、boostrap、anglur.js、quartz、ehcache、富文本编辑器(百度编辑器) * 框架搭建: * 数据库设计: 数据库名称=工程名称CRM_16 表设计: 表字符:utf-8、utf8 表字段: 主键、bigint(20) 自增、(32) UUID、不能为空 索引: 外键、关联字段、查询比较频繁的字段 单表:500M、索引个数16个 临时表、存储过程、视图、触发器、监听器 * 数据库优化原则: * CRM数据库表设计说明: 参考脚本文件《crm.sql》 hj_user 用户表 userid 用户主键 roleid 角色主键 deptid 部门主键 hj_role 角色表 roleid 角色ID deptid 部门ID hj_dept 部门表 deptid 部门ID deptparaid 上一级部门ID hj_menu 菜单表 menuid 菜单主键ID menuparaid 上一级菜单ID hj_role_menu 角色-菜单关系表 roleid 角色ID menuid 菜单ID * SQL需求: * 需求1:查询用户ID=2的信息: 用户ID,用户名,角色ID,角色名称,部门ID,部门名称 select u.userid,u.username,u.roleid,r.rolename,u.deptid,d.deptname from hj_user u left join hj_role r on r.roleid = u.roleid left join hj_dept d on d.deptid = u.deptid where u.userid = 2; * 需求2:查询角色ID=2所属的菜单信息:角色ID,角色名称,菜单ID,菜单名称 select rm.roleid,r.rolename,rm.menuid,m.menuname from hj_role_menu rm left join hj_role r on r.roleid = rm.roleid left join hj_menu m on m.menuid = rm.menuid where rm.roleid = 2; select rm.roleid,r.rolename,rm.menuid, -- group_concat() group_concat(m.menuname separator ',') menuname from hj_role_menu rm left join hj_role r on r.roleid = rm.roleid left join hj_menu m on m.menuid = rm.menuid group by r.rolename; * 需求3:查询系统管理(菜单ID=1)所有下级菜单 select * from hj_menu m where m.menuparaid = 1; * 需求4:查询所有的上级菜单信息 select * from hj_menu m where m.menuparaid is null; * 项目工程搭建步骤: * 1:新建一个web project工程CRM_16 * 2:解压FTP中CRM压缩包到本地文件夹 * 3:工程名右键,选择build path,选中最后一个选项,将tomcat的jar包导入工程 * 4:复制压缩文件中的webroot文件夹“内”的文件,到工程的WebROOT文件夹下 * 5:复制lib文件夹下的jar包复制到工程中 * 6:取消前端文件验证表达式错误,操作步骤,参考下图 ![](https://i.imgur.com/7rGu5JI.png) * 框架代码: * web.xml: 通用性设置如下: CRM_16 contextConfigLocation classpath:applicationContext.xml org.springframework.web.context.ContextLoaderListener crm_16 org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:context-dispatcher.xml 1 crm_16 *.do encodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding UTF-8 forceEncoding true encodingFilter * log4jConfigLocation classpath:/log4j.xml org.springframework.web.util.Log4jConfigListener 120 404 /404.do 500 /500.do /index.do * 连接池: * c3p0: * 阿里: 问题: 1:游标越界 2:事务连接次数过多 too many connect 解决方式: 参考代码 ### 登录页面跳转 * 开发步骤: 1:获取跳转页面的接口地址(前端获取) 2:增加controller类进行页面跳转 * 代码示例: * UserLoginController.java: /** * 登录首页 * @author likang * @date 2018-4-19 下午5:33:34 */ @Controller public class UserLoginController { /** * 跳转登录页面 * @param model * @return */ @RequestMapping(value = "/login.do",method = RequestMethod.GET) public String index(Model model){ return JumpViewConstants.SYSTEM_LOGIN; } } * 页面展示: ![](https://i.imgur.com/nS0sDEd.png) ### 登录 * 开发步骤: * 1:通过点击【登录】按钮,获取登录的接口地址 * 2:在UserLoginController类中,增加登录接口 * 3:首先判断用户名是否存在,其次判断匹配是否匹配 * 4:处理session问题 * 代码如下: * UserLoginController.java: /** * 登录首页 * @author likang * @date 2018-4-19 下午5:33:34 */ @Controller public class UserLoginController { @Autowired private IUserService userService; /** * 跳转登录页面 * @param model * @return */ @RequestMapping(value = "/login.do",method = RequestMethod.GET) public String index(Model model){ return JumpViewConstants.SYSTEM_LOGIN; } /** * 登录功能 * @param request * @param email 用户名 * @param password 密码 * @param sign * @return */ @RequestMapping(value = "/login.do",method = RequestMethod.POST) public String login(HttpServletRequest request,String email,String password,String sign,Model model){ // if (email != null && !"".equals(email)) { // // } //isnotblank:判断参数是否为空和“” //isNotEmpty:只会判断参数是否为null if (StringUtils.isNotBlank(email) && StringUtils.isNotBlank(password)) { //利用spring容器获取map中的属性值 email = email + ContextUtil.getInitConfig("email_suffix"); //验证用户名是否存在 User user = userService.queryUserByEmail(email); if (user == null) {//用户不存在 // model.addAttribute(ReturnConstants.USER_NOT_EXIST); model.addAttribute("msg", ReturnConstants.USER_NOT_EXIST); return JumpViewConstants.SYSTEM_LOGIN; } //验证密码是否匹配 boolean isExis = userService.isExisPassword(String.valueOf(user.getUserid()), password); if (!isExis) { // model.addAttribute(ReturnConstants.PASSWORD_ERROR); model.addAttribute("msg", ReturnConstants.PASSWORD_ERROR); return JumpViewConstants.SYSTEM_LOGIN; } //cookie //TODO...... //处理session UserContext.setLoginUser(user); request.getSession(true).setAttribute("loginName", user.getUsername()); request.getSession(true).setAttribute("ischange", user.getIschange()); //跳转成功首页 return JumpViewConstants.SYSTEM_INDEX; } return ReturnConstants.PARAM_NULL;//接收参数为空 } } * IUserService.java: /** * 用户信息接口 * @author likang * @date 2018-4-23 上午9:36:12 */ public interface IUserService { /** * 根据邮箱查询用户信息 * @param email 邮箱 * @return */ public User queryUserByEmail(String email); /** * 验证密码是否匹配 * @param userid 用户主键ID * @param password 密码 * @return */ public boolean isExisPassword(String userid,String password); } * UserServiceImpl.java: @Service @Transactional(rollbackFor=Exception.class) public class UserServiceImpl implements IUserService{ // @Resource//首先按照名称匹配,其次按照类型匹配 @Autowired//只会按照类型匹配(推荐使用) IDataAccess userDao; public User queryUserByEmail(String email) { Map param = new HashMap(); param.put("email", email); List list = userDao.queryByStatment("queryUserByEmail", param, null); if (list != null && list.size() > 0) { return list.get(0); } return null; } public boolean isExisPassword(String userid, String password) { Map param = new HashMap(); param.put("userid", userid); param.put("password", MD5Tools.encode(password)); List list = userDao.queryByStatment("isExisPassword", param, null); if (list != null && list.size() > 0) { return true; } return false; } } * UserMapper.xml:

mybatis-config.xml:


                
                
            

### 登录功能-首页访问--完善功能
* 代码如下:
    * UserLoginController.java:

            /**
             * 登录首页
             * @author likang
             * @date   2018-4-19 下午5:33:34
             */
            @Controller
            public class UserLoginController {
            
            
                @Autowired
                private IUserService userService;
            
                /**
                 * 跳转登录页面
                 * @param model
                 * @return
                 */
                @RequestMapping(value = "/login.do",method = RequestMethod.GET)
                public String index(Model model){
                    if (UserContext.getLoginUser() != null) {
                        return "redirect:/main.do";
                    }
                    return JumpViewConstants.SYSTEM_LOGIN;
                }
            
                /**
                 * 主页面
                 * @param model
                 * @return
                 */
                @RequestMapping(value = "/main.do",method = RequestMethod.GET)
                public String main(Model model){
                    if (UserContext.getLoginUser() != null) {
                        return JumpViewConstants.SYSTEM_INDEX;
                    }
                    return JumpViewConstants.SYSTEM_LOGIN;
                }
            
                /**
                 * 登录功能
                 * @param request
                 * @param email  用户名
                 * @param password 密码
                 * @param sign
                 * @return
                 */
                @RequestMapping(value = "/login.do",method = RequestMethod.POST)
                public String login(HttpServletRequest request,String email,String password,String sign,Model model){
            //      if (email != null && !"".equals(email)) {
            //          
            //      }
                    //isnotblank:判断参数是否为空和“”
                    //isNotEmpty:只会判断参数是否为null
                    if (StringUtils.isNotBlank(email) && StringUtils.isNotBlank(password)) {
                        //利用spring容器获取map中的属性值
                        email = email + ContextUtil.getInitConfig("email_suffix");
            
                        //验证用户名是否存在
                        User user = userService.queryUserByEmail(email);
                        if (user == null) {//用户不存在
            //              model.addAttribute(ReturnConstants.USER_NOT_EXIST);
                            model.addAttribute("msg", ReturnConstants.USER_NOT_EXIST);
                            return JumpViewConstants.SYSTEM_LOGIN;
                        }
                        //验证密码是否匹配
                        boolean isExis = userService.isExisPassword(String.valueOf(user.getUserid()), password);
                        if (!isExis) {
            //              model.addAttribute(ReturnConstants.PASSWORD_ERROR);
                            model.addAttribute("msg", ReturnConstants.PASSWORD_ERROR);
                            return JumpViewConstants.SYSTEM_LOGIN;
                        }
                        //cookie
                        //TODO......
            
                        //处理session
                        UserContext.setLoginUser(user);
                        request.getSession(true).setAttribute("loginName", user.getUsername());
                        request.getSession(true).setAttribute("ischange", user.getIschange());
                        //跳转成功首页
            //          return JumpViewConstants.SYSTEM_INDEX;
                        return "redirect:/main.do";
                    }
                    return ReturnConstants.PARAM_NULL;//接收参数为空
                }
            }

### 登录功能-cookie问题
* 开发步骤:
    * 1:为了解决用户端禁用浏览器cookie第三方数据的问题
    * 2:只需要在服务器中保存一份cookie即可,同步到浏览器客户端

* 示例代码:
    * UserLoginController.java:

            private static final String COOKIE_KEY = "_auth_";
            private static final String COOKIE_SPI = "_#_";
            
                /**
                 * 登录功能
                 * @param request
                 * @param email  用户名
                 * @param password 密码
                 * @param sign
                 * @return
                 */
                @RequestMapping(value = "/login.do",method = RequestMethod.POST)
                public String login(HttpServletRequest request,HttpServletResponse response,String email,String password,String sign,Model model){
            //      if (email != null && !"".equals(email)) {
            //          
            //      }
                    //isnotblank:判断参数是否为空和“”
                    //isNotEmpty:只会判断参数是否为null
                    if (StringUtils.isNotBlank(email) && StringUtils.isNotBlank(password)) {
                        //利用spring容器获取map中的属性值
                        email = email + ContextUtil.getInitConfig("email_suffix");
            
                        //验证用户名是否存在
                        User user = userService.queryUserByEmail(email);
                        if (user == null) {//用户不存在
            //              model.addAttribute(ReturnConstants.USER_NOT_EXIST);
                            model.addAttribute("msg", ReturnConstants.USER_NOT_EXIST);
                            return JumpViewConstants.SYSTEM_LOGIN;
                        }
                        //验证密码是否匹配
                        boolean isExis = userService.isExisPassword(String.valueOf(user.getUserid()), password);
                        if (!isExis) {
            //              model.addAttribute(ReturnConstants.PASSWORD_ERROR);
                            model.addAttribute("msg", ReturnConstants.PASSWORD_ERROR);
                            return JumpViewConstants.SYSTEM_LOGIN;
                        }
                        //cookie
                        Cookie cok = new Cookie(COOKIE_KEY, URLEncoder.encode(user.getUsername())+COOKIE_SPI+MD5Tools.encode(user.getEmail()));
                        cok.setPath("/");
                        cok.setMaxAge(-1);//-1:立即创建,并且在登录成功之后,就生效
                                           //0:在客户端关闭浏览器之后,即失效
                        response.addCookie(cok);
                        //处理session
                        UserContext.setLoginUser(user);
                        request.getSession(true).setAttribute("loginName", user.getUsername());
                        request.getSession(true).setAttribute("ischange", user.getIschange());
                        //跳转成功首页
            //          return JumpViewConstants.SYSTEM_INDEX;
                        return "redirect:/main.do";
                    }
                    return ReturnConstants.PARAM_NULL;//接收参数为空
                }

## 退出功能
* 开发步骤:
    * 1:清除session信息
    * 2:清除存放于服务器中的cookie数据
    * 3:清除客户端中的cookie数据
    * 4:跳转登录页面即可

* 示例代码:
    * UserLoginController.java:
    
            /**
            * 退出
            * @param request
            * @return
            */
            @RequestMapping(value = "/logout.do",method = RequestMethod.GET)
            public String logout(HttpServletRequest request,HttpServletResponse response){
                //清除session
                UserContext.clearLoginUser();
                //清除服务器中的cookie数据
                Cookie cok = new Cookie(COOKIE_KEY,null);
                cok.setMaxAge(0);
                cok.setPath("/");
                response.addCookie(cok);
                //清除客户端中的cookie数据
                Cookie coksessionID = new Cookie("JSESSIONID",null);
                coksessionID.setMaxAge(0);
                coksessionID.setPath(request.getContextPath());
                response.addCookie(coksessionID);
        
                //跳转登录页面
                return "redirect:/main.do";
            }

## 登录成功-权限管理-左侧菜单展示功能
* 开发步骤:
    * 1:根据登录成功用户的角色ID,查询对应的菜单信息,参考第一天的sql语句
    * 2:首先查询一级菜单信息
    * 3:循环遍历一级菜单信息,查询当前一级菜单对应的二级菜单信息

* 示例代码:
    * UserLoginController.java:
    
            /**
            * 主页面
            * @param model
            * @return
            */
            @RequestMapping(value = "/main.do",method = RequestMethod.GET)
            public String main(Model model){
                if (UserContext.getLoginUser() != null) {
                    //根据当前登录用户的角色,查询当前角色对应的菜单信息
                    List list = userService.queryMenusByRoleId(UserContext.getLoginUser().getRoleid().toString());
                    model.addAttribute("menus", list);
                    return JumpViewConstants.SYSTEM_INDEX;
                }
                return JumpViewConstants.SYSTEM_LOGIN;
            }


    * IUserService.java:
    
            /**
            * 根据角色主键ID,查询当前角色对应的菜单信息
            * @param roleId 角色主键ID
            * @return
            */
            public List queryMenusByRoleId(String roleId);

    * UserServiceImpl.java:

            @Autowired
            IDataAccess menuDao;
            public List queryMenusByRoleId(String roleId) {
            
                Map param = new HashMap();
                param.put("roleId", roleId);
                param.put("isparid", "true");//判断sql语句的标识,不封装到sql执行语句当中
                //只查询一级菜单信息
                List list = menuDao.queryByStatment("queryMenusByRoleId", param, null);
                if (list != null && list.size() > 0) {
                    for (int i = 0; i < list.size(); i++) {
                        Long menuid = list.get(i).getMenuid();//一级菜单主键ID
                        param.clear();
                        param.put("roleId", roleId);
                        param.put("menuparaid", menuid);//将一级菜单ID,当做二级菜单的父ID
                        param.put("isparid", null);
                        List listch = menuDao.queryByStatment("queryMenusByRoleId", param, null);
                        list.get(i).setChildren(listch);
                    }
                }
                return list;
            }

    * UserMapper.xml:

            
            


#### 页面展示:
![](https://i.imgur.com/tIbdpL5.png)
## 用户管理
### 页面跳转
* 开发步骤:
    * 1:通过前端找到接口地址
    * 2:为菜单的查询添加url的字段

* 示例代码:
    * UserController.java:

            /**
            * 跳转用户管理页面
            * @param model
            * @return
            */
            @RequestMapping(value = "/system/userMang.do",method = RequestMethod.GET)
            public String userManger(Model model){
                if (UserContext.getLoginUser() != null) {
                    return JumpViewConstants.SYSTEM_USER_MANAGE;
                }
                return JumpViewConstants.SYSTEM_LOGIN;
            }

### 列表查询
* 开发步骤:
    * 1:通过浏览器debug,获取接口地址(红色的404接口)
    * 2:支持分页查询

* 示例代码:
    * UserController.java:

            /**
            * 用户管理模块
            * @author likang
            * @date   2018-4-23 下午4:55:12
            */
            @Controller
            public class UserController extends BaseController{
            
            
                @Autowired
                private IUserService userService;
            
                /**
                 * 跳转用户管理页面
                 * @param model
                 * @return
                 */
                @RequestMapping(value = "/system/userMang.do",method = RequestMethod.GET)
                public String userManger(Model model){
                    if (UserContext.getLoginUser() != null) {
                        return JumpViewConstants.SYSTEM_USER_MANAGE;
                    }
                    return JumpViewConstants.SYSTEM_LOGIN;
                }
            
                /**
                 * 查询用户信息列表
                 * @param request
                 * @param currentPage
                 * @param pageSize
                 * @return
                 */
                @RequestMapping(value = "/system/userlist.do",method = RequestMethod.GET)
                public @ResponseBody String queryUserList(HttpServletRequest request,Integer currentPage,Integer pageSize){
                    List list = userService.queryAllUser(processPageBean(pageSize, currentPage));
                    return jsonToPage(list);
                }
            }

    * IUserService.java:

            /**
            * 查询用户信息列表
            * @param pageBean
            * @return
            */
            public List queryAllUser(PageBean pageBean);

    * UserServiceImpl.java:

            public List queryAllUser(PageBean pageBean) {
                List list = userDao.queryByStatment("queryAllUser", null, pageBean);
                return list;
            }

    * UserMapper.xml:

            
            

### 增加、修改
* 开发步骤:
    * 1:通过前端获取增加、修改的接口地址
    * 2:添加查询所有部门信息接口
    * 3:添加根据部门ID查询当前部门下所有角色信息的接口
    * 4:添加保存、修改的方法controller
    * 5:根据是否存在用户主键ID,来区分到底是修改还是增加
    * 6:增加和修改无需写sql语句

* 示例代码:
    * DeptController.java:

            /**
            * 部门管理模块
            * @author likang
            * @date   2018-4-24 上午9:06:29
            */
            @Controller
            public class DeptController extends BaseController{
            
                @Autowired
                private IDeptService deptService;
            
                /**
                 * 查询所有部门信息
                 * @param request
                 * @return
                 */
                @RequestMapping(value = "/dept/queryDept.do",method = RequestMethod.GET)
                public @ResponseBody String queryAllDepts(HttpServletRequest request){
                    List list = deptService.queryAllDepts();
                    return jsonToPage(list);
                }
            
                /**
                 * 根据部门ID,查询当前部门下的角色信息列表
                 * @param request
                 * @param deptid 部门ID
                 * @return
                 */
                @RequestMapping(value = "/role/queryRoleByDeptid.do",method =RequestMethod.GET)
                public @ResponseBody String queryRolesByDeptId(HttpServletRequest request,String deptid){
                    List list = deptService.queryRolesByDeptId(deptid);
                    return jsonToPage(list);
                }
            }

    * IDeptService.java:

            /**
            * 部门信息接口
            * @author likang
            * @date   2018-4-24 上午9:08:04
            */
            public interface IDeptService {
            
                /**
                 * 查询所有的部门信息
                 * @return
                 */
                public List queryAllDepts();
            
                /**
                 * 根据部门ID,查询角色信息
                 * @param deptid 部门ID
                 * @return
                 */
                public List queryRolesByDeptId(String deptid);
            }

    * DeptServiceImpl.java:

            @Service
            @Transactional(rollbackFor = Exception.class)
            public class DeptServiceImpl implements IDeptService{
            
                @Autowired
                IDataAccess deptDao;
                @Autowired
                IDataAccess roleDao;
            
                public List queryAllDepts() {
                    List list = deptDao.queryByStatment("queryAllDepts", null, null);
                    return list;
                }
            
                public List queryRolesByDeptId(String deptid) {
                    Map param = new HashMap();
                    param.put("deptid", deptid);
                    List list = roleDao.queryByStatment("queryRolesByDeptId", param, null);
                    return list;
                }
            }

    * DeptMapper.xml:

            
            
                
                
            
                
                
            

    * mybatis-config.xml:

            
                
                
                
            

    * UserController.java:

            /**
            * 增加\修改用户信息
            * @param request
            * @param user
            * @return
            */
            @RequestMapping(value = "/system/saveOrUpdate.do",method = RequestMethod.POST)
            public @ResponseBody String saveOrUpdateUser(HttpServletRequest request,User user){
                if (user != null) {
                    userService.saveOrUpdateUser(user);
                    return ReturnConstants.SUCCESS;
                }
                return ReturnConstants.PARAM_NULL;
            }

    * IUserService.java:

            /**
            * 增加、修改用户信息
            * @param user
            */
            public void saveOrUpdateUser(User user);
            

UserServiceImpl.java:

public void saveOrUpdateUser(User user) {
                if (user != null) {
                    if (user.getUserid() != null) {//修改
                        user.setUpdate_id(UserContext.getLoginUser().getUserid());
                        user.setUpdate_time(new Timestamp(System.currentTimeMillis()));
                        userDao.update(user);
                    }else{//增加
                        user.setCreate_id(UserContext.getLoginUser().getUserid());
                        user.setCreate_time(new Timestamp(System.currentTimeMillis()));
                        userDao.insert(user);
                    }
                }
            }

### 删除
* 开发步骤:
    * 1:通过前端找到删除的接口地址(支持批量删除,真正企业做的时候,接口是后台来定义)
    * 2:增加删除的接口和方法

* 示例代码:
    * UserController.java:

            /**
            * 删除用户信息,支持批量删除
            * @param request
            * @param ids 用户主键ID,多个用逗号隔开
            * @return
            */
            @RequestMapping(value = "/system/deleteUser.do",method = RequestMethod.POST)
            public @ResponseBody String deleteUsers(HttpServletRequest request,String ids){
                if (StringUtils.isNotBlank(ids)) {
                    userService.deleteUserByIds(ids);
                    return ReturnConstants.SUCCESS;
                }
                return ReturnConstants.PARAM_NULL;
            }

    * IUserService.java:

            /**
            * 删除用户信息,批量删除
            * @param ids 用户主键ID,多个用逗号隔开
            */
            public void deleteUserByIds(String ids);


    * UserServiceImpl.java:
    
            public void deleteUserByIds(String ids) {
                if (StringUtils.isNotBlank(ids)) {
                    userDao.deleteByIds(User.class, ids);
                }
            }

* 提示:
    * 1:回顾mysql的删除别名问题
    * 2:练习mybatis中的for标签

### 页面展示
![](https://i.imgur.com/rUyy9qq.png)

## 测试环境项目部署过程
* 系统环境:
    * linux-CentOS7

* 使用工具:
    * CRT\SCP

* 部署步骤:
    * 1:首先确认本地访问运行没有任何问题
    * 2:导出本地的数据库脚本,将脚本文件在虚拟机服务器的数据库中执行
    * 3:使用scp工具连接服务器,将本地tomcat的webapps目录下的项目,拖到虚拟机服务器tomcat的webapps目录下(可选:修改项目访问名称,ROOT在访问时,不需要输入)
    * 4:修改虚拟机服务器中项目的jdbc配置文件,修改为虚拟机数据库的连接信息
    * 5:使用crt工具,启动tomcat
    * 6:本地访问服务器项目信息

* 注意事项:
    * 1:本地连接服务器的数据库,需要开启3306端口号(防火墙允许3306端口允许)
    
            命令:/sbin/iptables -I INPUT -p tcp --dport 3306 -j ACCEPT

    * 2:需要开启tomcat访问的端口号,命令如下:
    
            /sbin/iptables -I INPUT -p tcp --dport 8080 -j ACCEPT

    * 3:如果新增增量补丁,如下地方是需要重启tomcat服务的
    
            - 接口代码
            - 配置文件、属性文件
            - xml对应的sql语句
            
    * 4:查看服务器mysql是否开启的命令
    
                ps -ef|grep mysql

## 菜单管理

### 跳转页面

	略,参考工程文件

### 查询

	略,参考工程文件

### 增加、修改

	略,参考工程文件

### 删除

* 需求:

	1:如果菜单存在下一级菜单,则不允许删除
	2:如果菜单已经被分配,则不允许删除

* 开发步骤:

	1://查询菜单ID,是否存在下一级菜单
	2://查询菜单ID,是否存在权限分配
	3://如果当前菜单ID,既不存在下一级菜单,又不存在权限分配,则可以直接删除成功
	4://如果满足其中一条信息,则都不允许删除,返回错误信息
	5://如果都不满足,删除成功



* 示例代码:

    * MenuController.java:

        	/**
        	 * 菜单删除功能
        	 * 
        	 * 	1:如果菜单存在下一级菜单,则不允许删除
        	 *	2:如果菜单已经被分配,则不允许删除
        	 *
        	 *  error1 = [菜单:用户管理,菜单管理]  存在下一级菜单信息,不允许删除
        	 *  error2 = [菜单:角色管理,部门管理]  存在权限分配,不允许删除
        	 *
        	 * @param request
        	 * @param ids 菜单主键ID,多个用逗号隔开
        	 * @return
        	 */
        	@RequestMapping(value = "/menu/delete.do",method = RequestMethod.POST)
        	public @ResponseBody String deleteMenus(HttpServletRequest request,String ids){
        		if (StringUtils.isNotBlank(ids)) {
        			
        			StringBuffer error1 = new StringBuffer();
        			StringBuffer error2 = new StringBuffer();
        			boolean ishasCh = false;
        			boolean ishasrm = false;
        			
        			for (String id : ids.split(",")) {
        				//查询菜单ID,是否存在下一级菜单
        				if (menuService.isHasChiredMenu(id)) {//true:存在下一级菜单
        					if (!ishasCh) {
        						ishasCh = true;
        					}
        					if (error1.length() == 0){
        						error1.append("[菜单:");
        					}
        					error1.append(menuService.queryMenuById(id) != null ?menuService.queryMenuById(id).getMenuname() : "" ).append(",");
        					continue;
        				}
        				//查询菜单ID,是否存在权限分配
        				if (menuService.isHasRoleMenu(id)) {//true:存在权限分配
        					if (!ishasrm) {
        						ishasrm = true;
        					}
        					if (error2.length() == 0){
        						error2.append("[菜单:");
        					}
        					error2.append(menuService.queryMenuById(id) != null ?menuService.queryMenuById(id).getMenuname() : "" ).append(",");
        					continue;
        				}
        				menuService.deleleMenuById(id);//如果当前菜单ID,既不存在下一级菜单,又不存在权限分配,则可以直接删除成功
        			}
        			
        			//如果满足其中一条信息,则都不允许删除,返回错误信息
        			if (ishasCh){
        				error1.deleteCharAt(error1.length() - 1).append("]  存在下一级菜单信息,不允许删除");
        			}
        			if (ishasrm){
        				error2.deleteCharAt(error2.length() - 1).append("]  存在权限分配,不允许删除");
        			}
        			
        //			String msgbegin = ishasCh ? error1.toString() : "" + ishasrm ? ishasCh?error1.toString() : "":"
"+error2.toString():""; String msg = error1.toString()+error2.toString(); if (StringUtils.isNotBlank(msg)) { return msg; } //如果都不满足,删除成功 return ReturnConstants.SUCCESS; } return ReturnConstants.PARAM_NULL; } * IMenuService.java: /** * 根据菜单主键ID,判断当前菜单是否存在下一级菜单 * @param id 菜单主键ID * @return */ public boolean isHasChiredMenu(String id); /** * 根据菜单主键ID,判断当前菜单是否存在权限分配 * @param id 菜单主键ID * @return */ public boolean isHasRoleMenu(String id); /** * 根据菜单id,查询菜单信息 * @param id 主键ID * @return */ public Menu queryMenuById(String id); /** * 根据主键ID,删除菜单信息 * @param id */ public void deleleMenuById(String id); MenuServiceImpl.java: public boolean isHasChiredMenu(String id) { Map param = new HashMap(); param.put("mid", id); List list = menuDao.queryByStatment("isHasChiredMenu", param, null); if (list != null && list.size() > 0) { return true; } return false; } public boolean isHasRoleMenu(String id) { Map param = new HashMap(); param.put("mid", id); List list = rmDao.queryByStatment("isHasRoleMenu", param, null); if (list != null && list.size() > 0) { return true; } return false; } public Menu queryMenuById(String id) { Map param = new HashMap(); param.put("mid", id); List list = menuDao.queryByStatment("queryMenuById", param, null); if (list != null && list.size() > 0) { return list.get(0); } return null; } public void deleleMenuById(String id) { if (StringUtils.isNotBlank(id)) { menuDao.deleteByIds(Menu.class, id); } } * RoleMapper.xml: ## 角色管理 ### 跳转页面 略,参考工程文件 ### 查询 略,参考工程文件 ### 增加、修改 略,参考工程文件 ### 删除 略,参考工程文件 ###权限分配 * 需求: 1:选中角色,点击【权限分配】,弹出分配框 2:展示所有的菜单信息,并树形分级展示 3:如果之前已经分配过的菜单,则自动勾选复选框 4:重新勾选菜单之后,点击【保存】按钮,则分配成功 * 开发步骤: 1:查询所有菜单信息,并且已经分配过的菜单,复选框自动勾选 - 查询所有菜单信息list - 查询已经分配过的菜单信息listch - 遍历list和listch,如果listch中的菜单ID在list中存在,则把list.get(i).setSelected(true);设置为true即可 - 遍历list的子菜单信息,和listch对比ID,如果存在,则listchilere.get(j).setSelected(true);子菜单设置为true即可 - 最终返回list的json格式数据 2:权限分配---保存菜单信息 - 删除数据库中开始的角色对应的菜单信息 - 保存一份最新的角色对应菜单信息数据即可 * 示例代码: * RoleController.java: /** * 角色管理模块 * @author likang * @date 2018-4-24 下午3:18:49 */ @Controller public class RoleController extends BaseController{ @Autowired private IRoleService roleService; @Autowired private IMenuService menuService; /** * 跳转角色管理页面 * @param model * @return */ @RequestMapping(value = "/system/roleMang.do",method = RequestMethod.GET) public String roleManger(Model model){ if (UserContext.getLoginUser() != null) { return JumpViewConstants.SYSTEM_ROLE_MANAGE; } return JumpViewConstants.SYSTEM_LOGIN; } /** * 查询角色信息列表 * @param request * @param currentPage 第几页 * @param pageSize 每页多少条 * @return */ @RequestMapping(value = "/role/queryAllRole.do",method = RequestMethod.GET) public @ResponseBody String queryAllRoles(HttpServletRequest request,Integer currentPage,Integer pageSize){ List list = roleService.queryAllRoles(processPageBean(pageSize, currentPage)); return jsonToPage(list); } /** * 权限分配---查询所有菜单信息,并且已经分配过的菜单,复选框自动勾选 * @param request * @param roleid * @return */ @RequestMapping(value = "/rolemenu/queryAllMenuAndSelected.do",method = RequestMethod.GET) public @ResponseBody String queryAllMenuAndSelected(HttpServletRequest request,String roleid){ if (StringUtils.isNotBlank(roleid)) { //查询所有菜单信息 List list = menuService.queryAllMenus();//1,2,3,4,5,6---分级展示 //查询已经分配过的菜单信息 List listch = menuService.queryAlMenuSeleted(roleid);//1,2,3---不分级 if (listch != null && listch.size() > 0) { for (int i = 0; i < list.size(); i++) { Long listid = list.get(i).getMenuid();//上一级的菜单ID for (int j = 0; j < listch.size(); j++) { Long listchid = listch.get(j).getMenuid(); if (listid == listchid) { list.get(i).setSelected(true); // continue; break; } } } for (int i = 0; i < list.size(); i++) { List listchilere = list.get(i).getChildren();//一级菜单的子菜单 for (int j = 0; j < listchilere.size(); j++) { Long listchilereID = listchilere.get(j).getMenuid();//子菜单的主键ID for (int k = 0; k < listch.size(); k++) { Long listchid = listch.get(k).getMenuid();//所有的分配过的菜单ID if (listchilereID == listchid) { listchilere.get(j).setSelected(true); break; } } } } } //打钩 return jsonToPage(list); } return ReturnConstants.PARAM_NULL; } /** * 权限分配---保存菜单信息 * 思路:1:删除数据库中开始的角色对应的菜单信息 * 2:保存一份最新的角色对应菜单信息数据即可 * @param request * @param roleid * @param menuid * @return */ @RequestMapping(value = "/rolemenu/assignMenu.do",method = RequestMethod.POST) public @ResponseBody String assignMenu(HttpServletRequest request,String roleid,String menuid){ if (StringUtils.isNotBlank(roleid)) { //删除数据库中开始的角色对应的菜单信息 menuService.deleteRoleMenu(roleid); //2:保存一份最新的角色对应菜单信息数据即可 Role_menu rm = new Role_menu(); rm.setRoleid(Long.valueOf(roleid)); for (String mid : menuid.split(",")) { rm.setMenuid(Long.valueOf(mid)); menuService.saveRoleMenu(rm); rm.setMenuid(null); } return ReturnConstants.SUCCESS; } return ReturnConstants.PARAM_NULL; } } * IMenuService.java: /** * 菜单管理接口 * @author likang * @date 2018-4-24 下午3:00:35 */ public interface IMenuService { /** * 查询所有菜单信息 * @return */ public List queryAllMenus(); /** * 新增、修改菜单信息 * @param menu */ public void saveOrUpdateMenu(Menu menu); /** * 查询当前角色已经分配过的菜单信息列表 * @param roleid 角色ID * @return */ public List queryAlMenuSeleted(String roleid); /** * 根据角色ID,删除数据库中对应的菜单信息数据 * @param roleid */ public void deleteRoleMenu(String roleid); /** * 保存角色-菜单关系数据 * @param rm */ public void saveRoleMenu(Role_menu rm); } * MenuServiceImpl.java: @Service @Transactional(rollbackFor = Exception.class) public class MenuServiceImpl implements IMenuService { @Autowired IDataAccess menuDao; @Autowired IDataAccess rmDao; public List queryAllMenus() { Map param = new HashMap(); param.put("isparid", "true"); List list = menuDao.queryByStatment("queryAllMenus", param, null); if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { Long menuid = list.get(i).getMenuid(); param.clear(); param.put("isparid", null); param.put("menuparaid", menuid); List listch = menuDao.queryByStatment("queryAllMenus", param, null); list.get(i).setChildren(listch); } } return list; } public void saveOrUpdateMenu(Menu menu) { if (menu != null) { if (menu.getMenuid() != null) {//修改 menu.setUpdate_id(UserContext.getLoginUser().getUserid()); menu.setUpdate_time(new Timestamp(System.currentTimeMillis())); menuDao.update(menu); }else{//增加 menu.setCreate_id(UserContext.getLoginUser().getUserid()); menu.setCreate_time(new Timestamp(System.currentTimeMillis())); menuDao.insert(menu); } } } public List queryAlMenuSeleted(String roleid) { Map param = new HashMap(); param.put("roleid", roleid); List listch = menuDao.queryByStatment("queryAlMenuSeleted", param, null); return listch; } public void deleteRoleMenu(String roleid) { if (StringUtils.isNotBlank(roleid)) { Map param = new HashMap(); param.put("roleid", roleid); rmDao.deleteByStatment("deleteRoleMenu", param); } } public void saveRoleMenu(Role_menu rm) { if (rm != null) { rmDao.insert(rm); } } } * RoleMapper.xml: delete from hj_role_menu where roleid=#{roleid} ## CRM第三方缓存技术 * 开发步骤: 1:在resource文件内,导入缓存的配置文件 2:在事务开启执行之前,使用注解,进行数据缓存 * 常用注解: //增加缓存 @Cacheable(value="baseCache",key="'queryAllDepts'") 其中value代表存放的缓存区域块名称 key:代表区域块中缓存的唯一标识,可有三种取值方式: 1:使用普通的字符串 2:使用方法参数中参数值 #参数名称 3:使用方法中实体对象的属性 //更新缓存---写操作 @CachePut(value = "",key = "") 不管缓存是否有数据,都会更新一遍 //更新缓存---根据条件更新 @CacheEvict(value ="",key="",allEntries=false,beforeInvocation = false) allEntries:true:更新所有的缓存区域块数据,false,则代表只会更新key值的数据 beforeInvocation:true,代表是在方法执行之前进行更新数据,执行之后,不太操作缓存数据 * 示例代码: 参考配置文件applicationContext-ehcache.xml和ecache.xml * applicationcontext.xml: * DeptServceImpl.java: @Cacheable(value="baseCache",key="'queryAllDepts'") public List queryAllDepts() { List list = deptDao.queryByStatment("queryAllDepts", null, null); return list; } ## 调度任务Quartz * 开发步骤: 1:导入调度任务的配置模块文件 2:在spring的配置文件中,引入调度任务的配置信息 * 示例代码: * applicationcontext.xml: * applicationContext-quartz.xml: 参考文件 * 注意: cron表达式,可以百度,找一个在线生成器生成即可 ### 百度编辑器(富文本编辑器) 后台字段设计为:text ## 自定义注解 * 注解的注解: 1.@Target,修饰的对象范围 2.@Retention,保留的时间长短 3.@Documented,标记注解 公共API 没有成员 4.@Inherited 标记注解 @Inherited阐述了某个被标注的类型是被继承的 @Target说明了Annotation所修饰的对象范围 1.CONSTRUCTOR:用于描述构造器 2.FIELD:用于描述域 3.LOCAL_VARIABLE:用于描述局部变量 4.METHOD:用于描述方法 5.PACKAGE:用于描述包 6.PARAMETER:用于描述参数 7.TYPE:用于描述类、接口(包括注解类型) 或enum声明 @Retention定义了该Annotation被保留的时间长短 取值(RetentionPoicy)有: 1.SOURCE:在源文件中有效(即源文件保留) 2.CLASS:在class文件中有效(即class保留) 3.RUNTIME:在运行时有效(即运行时保留) * 代码示例: * Name.java: @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Name { String nameValue() default "java16"; } * NameEntity.java: public class NameEntity { // @Name(nameValue = "java16-1") @Name private String username; private String phone; private String email; 增加getter和setter方法 } * NameTest.java: public class NameTest { public static void main(String[] args) { getValue(NameEntity.class); } public static void getValue(Class clazz){ if (clazz != null) { Field[] fields = clazz.getDeclaredFields();//获取对象属性 for (Field field : fields) { if (field.isAnnotationPresent(Name.class)) {//判断当前field属性是否是Name注解 Name name = field.getAnnotation(Name.class); System.out.println(name.nameValue()); } } } } } ### excel导入、导出 * 解析:POI 本地---数据库 * 导入: 1:读取本地excel文件 2:将文件上传到应用服务器tomcat 3:读取服务器中的excel文件数据,并将数据存放到数据库 * 导出: * 数据库---本地 1:获取要导出的数据 2:在应用服务器中创建一个空的excel文件,并将导出的数据写入 3:将应用服务器中excel文件,下载本地 ### 项目总结 ![](https://i.imgur.com/Mu8amo4.png)