实现自己的权限管理系统(六):部门模块开发

 

开发:首先我们遵从MVC模式

部门模块开发:

1、利用validator进行参数校验

public class DeptParam {
    private Integer id;

    @NotBlank(message = "部门名称不可以为空")
    @Length(max = 15, min = 2, message = "部门名称长度需要在2-15个字之间")
    private String name;
    //指定parentId初始值,避免空值异常
    private Integer parentId = 0;

    @NotNull(message = "展示顺序不可以为空")
    private Integer seq;

    @Length(max = 150, message = "备注的长度需要在150个字以内")
    private String remark;

}

2、因为部门下面可能会有子部门,需要构成部门树。解决方法:适配一个类来继承原来的类,增加属性 。

     通过一个List集合来包含部门。使用到了org.springframework.beans.BeanUtils中的copyProperties()

     可以对两个字段相同的对象进行复制

public class DeptLevelDto extends SysDept {
    //继承:一个部门,又有一个部门属性,构成部门包含部门,即构成树形结构
    private List deptList = Lists.newArrayList();

    public static DeptLevelDto adapt(SysDept dept) {
        DeptLevelDto dto = new DeptLevelDto();
        //字段相同的对象进行复制
        BeanUtils.copyProperties(dept, dto);
        return dto;
    }
}

3、在dao层中使用逆向工程生成的代码,然后我们通过情况进行修改和增删 ,简化开发。

       例如:给参数id加上  @Param("id") Integer id : 保证了参数不一致问题

4、services层: 对部门的增删改查

在设计数据库的时候有个level值,我们可以通过这个level来构建部门的树形结构,我们规定了level的计算方式:

根部门的level为 0 。如果一个部门存在父部门,那么它的level值为 父部门level值 . 父部门id

例如:父部门level 为 0 ,id 为 1 ,则它同一级的的部门level值为 0.1

package com.mmall.util;

import org.apache.commons.lang3.StringUtils;

public class LevelUtil {

    public final static String SEPARATOR = ".";

    public final static String ROOT = "0";

    // 0
    // 0.1
    // 0.1.2
    // 0.1.3
    // 0.4
    public static String calculateLevel(String parentLevel, int parentId) {
        if (StringUtils.isBlank(parentLevel)) {
            return ROOT;
        } else {
            return StringUtils.join(parentLevel, SEPARATOR, parentId);
        }
    }
}

 增加部门

public void save(DeptParam param) {
        //首先对参数进行校验
        BeanValidator.check(param);
        //如果插入的部门参数已经存在,即同一层级下存在相同名称的部门,抛出参数异常
        if(checkExist(param.getParentId(), param.getName(), param.getId())) {
            throw new ParamException("同一层级下存在相同名称的部门");
        }
        //Builder模式简化get set方法,构造一个SysDept对象
        SysDept dept = SysDept.builder().id(param.getId()).name(param.getName()).parentId(param.getParentId())
                .seq(param.getSeq()).remark(param.getRemark()).build();

        //通过id查到该部门的级别,再通过自定义的level计算工具计算对应的level
        dept.setLevel(LevelUtil.calculateLevel(getLevel(param.getParentId()), param.getParentId()));
        //通过RequestHolder拿到当前用户的用户名
        dept.setOperator(RequestHolder.getCurrentUser().getUsername());
        //ip计算工具,可以不理
        dept.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));
        dept.setOperateTime(new Date());

        sysDeptMapper.insertSelective(dept);
        //日志记录
        sysLogService.saveDeptLog(null, dept);
    }

当我们保存了一个/多个部门后,这仅仅是保存了它的数据(具有能构成树的数据),接下来需要把这些数据用来构成部门树

1、拿到所有部门列表适配为我们的dto结构

2、通过一个高级的数据结构Multimap:他可以构造像Map>或者Map>这样比较复杂的集合类型的数据结构。

     恰好我们需要构造:level -> [dept1, dept2, ...],以level为key,部门列表为值的map结构。

     最终形成:levelDeptMap:{{level0,{dept1,..}},{level1,{dept1,..}},{...}}

3、生成一个递归树:不断去levelDeptMap取元素,设置部门的父子结构

//把部门列表查出来,适配为我们的dto
    public List deptTree() {
        List deptList = sysDeptMapper.getAllDept();

        List dtoList = Lists.newArrayList();
        for (SysDept dept : deptList) {
            DeptLevelDto dto = DeptLevelDto.adapt(dept);
            dtoList.add(dto);
        }
        //把所有的部门列表转化为树形结构,把每个dto中的list属性列出来
        return deptListToTree(dtoList);
    }

private List deptListToTree(List deptLevelList) {
        //如果列表是空的,直接返回一个空列表
        if (CollectionUtils.isEmpty(deptLevelList)) {
            return Lists.newArrayList();
        }
        //需要构造像Map>或者Map>这样比较复杂的集合类型的数据结构,Multimap在合适不过
        // level -> [dept1, dept2, ...] 形如Map>
        //这样就可以实现我们以level为key,部门列表为值的map结构
        Multimap levelDeptMap = ArrayListMultimap.create();
        //建立一个存放根的列表,即level值为0的列表
        List rootList = Lists.newArrayList();
        //接下来只需要我们把level和列表put进去就好
        for (DeptLevelDto dto : deptLevelList) {
            levelDeptMap.put(dto.getLevel(), dto);
            //存放根列表
            if (LevelUtil.ROOT.equals(dto.getLevel())) {
                rootList.add(dto);
            }
        }
        // 把根列表按照seq从小到大排序
        Collections.sort(rootList, new Comparator() {
            public int compare(DeptLevelDto o1, DeptLevelDto o2) {
                return o1.getSeq() - o2.getSeq();
            }
        });
        // 递归生成树
        transformDeptTree(rootList, LevelUtil.ROOT, levelDeptMap);
        return rootList;
    }

 // 首先传进来level:0, 0, all 0->0.1,0.2(根部门id为1的下属部门为了level为.0.1)
    // level:0.1
    // level:0.2
    // levelDeptMap:{{level0,{dept1,..}},{level1,{dept1,..}},{...}}
    // deptLevelList: rootList
    private void transformDeptTree(List deptLevelList, String level, Multimap levelDeptMap) {
        //如果根列表还有值,就一直取
        for (int i = 0; i < deptLevelList.size(); i++) {
            // 遍历该层的每个元素
            DeptLevelDto deptLevelDto = deptLevelList.get(i);
            // 处理当前层级的数据,通过根部门id计算出它下层部门
            String nextLevel = LevelUtil.calculateLevel(level, deptLevelDto.getId());
            // 处理下一层  {level1,{dept1,..}
            List tempDeptList = (List) levelDeptMap.get(nextLevel);
            //如果下一层不为空
            if (CollectionUtils.isNotEmpty(tempDeptList)) {
                // 排序
                Collections.sort(tempDeptList, deptSeqComparator);
                // 设置下一层部门 :把tempDeptList设置进dto的列表属性中
                deptLevelDto.setDeptList(tempDeptList);
                // 进入到下一层处理
                transformDeptTree(tempDeptList, nextLevel, levelDeptMap);
            }
        }

    }

    public Comparator deptSeqComparator = new Comparator() {
        public int compare(DeptLevelDto o1, DeptLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

更新部门

1、首先进行参数的检验:同一层级下不能存在相同名称的部门,通过传进来部门id查看部门存不存在,不存在抛异常

2、检验当前部门有没有子部门,有的话父部门的level值更新了,相应子部门的level值也要更新(注意:更新操作必须的事务性的,不能父部门更新成功了,子部门没有更新)

   2.1:首先要把当前部门的所有子部门查出来,更新子部门level的前缀:记录新老父部门level , 通过字符串的查找截取拼接构成新level

 public void update(DeptParam param) {
        BeanValidator.check(param);
        if(checkExist(param.getParentId(), param.getName(), param.getId())) {
            throw new ParamException("同一层级下存在相同名称的部门");
        }
        SysDept before = sysDeptMapper.selectByPrimaryKey(param.getId());
        Preconditions.checkNotNull(before, "待更新的部门不存在");

        SysDept after = SysDept.builder().id(param.getId()).name(param.getName()).parentId(param.getParentId())
                .seq(param.getSeq()).remark(param.getRemark()).build();
        after.setLevel(LevelUtil.calculateLevel(getLevel(param.getParentId()), param.getParentId()));
        after.setOperator(RequestHolder.getCurrentUser().getUsername());
        after.setOperateIp(IpUtil.getRemoteIp(RequestHolder.getCurrentRequest()));
        after.setOperateTime(new Date());

        updateWithChild(before, after);
        sysLogService.saveDeptLog(before, after);
    }
    @Transactional
    void updateWithChild(SysDept before, SysDept after) {
        //更新后的level
        String newLevelPrefix = after.getLevel();
        //更新前的level
        String oldLevelPrefix = before.getLevel();
        //如果两者不相等,说明子部门的level要更新
        if (!newLevelPrefix.equals(oldLevelPrefix)) {
            //先查出来之前的子部门
            List deptList = sysDeptMapper.getChildDeptListByLevel(oldLevelPrefix);
            if (CollectionUtils.isNotEmpty(deptList)) {
                //子部门不为空,则遍历其列表
                for (SysDept dept : deptList) {
                    String level = dept.getLevel();
                    //查找指定字符或字符串在字符串中第一次出现地方的索引,未找到的情况返回 -1
                    if (level.indexOf(oldLevelPrefix) == 0) {
                        //新level  = 新前缀加时之前的后缀
                        level = newLevelPrefix + level.substring(oldLevelPrefix.length());
                        dept.setLevel(level);
                    }

                }
                sysDeptMapper.batchUpdateLevel(deptList);
            }
        }
        sysDeptMapper.updateByPrimaryKey(after);
    }

删除部门:注意判断三个点

1、待删除的部门不存在,无法删除

2、当前部门下面有子部门,无法删除

3、当前部门下面有用户,无法删除

public void delete(int deptId) {
        //删除之前判断当前部门是否存在
        SysDept dept = sysDeptMapper.selectByPrimaryKey(deptId);
        Preconditions.checkNotNull(dept, "待删除的部门不存在,无法删除");
        //查是否有子部门和用户
        if (sysDeptMapper.countByParentId(dept.getId()) > 0) {
            throw new ParamException("当前部门下面有子部门,无法删除");
        }
        if(sysUserMapper.countByDeptId(dept.getId()) > 0) {
            throw new ParamException("当前部门下面有用户,无法删除");
        }
        //根据id删除
        sysDeptMapper.deleteByPrimaryKey(deptId);
    }

  两个辅助函数

private boolean checkExist(Integer parentId, String deptName, Integer deptId) {
        //计算一共有多少符合条件(name,parentId)的行,大于0说明该部门已经存在
        return sysDeptMapper.countByNameAndParentId(parentId, deptName, deptId) > 0;
    }

    private String getLevel(Integer deptId) {
        SysDept dept = sysDeptMapper.selectByPrimaryKey(deptId);
        if (dept == null) {
            return null;
        }
        return dept.getLevel();
    }

Controller层比较简单:要遵从之前约定的url规范

package com.mmall.controller;

import com.mmall.common.JsonData;
import com.mmall.dto.DeptLevelDto;
import com.mmall.param.DeptParam;
import com.mmall.service.SysDeptService;
import com.mmall.service.SysTreeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.util.List;

@Controller
@RequestMapping("/sys/dept")
public class SysDeptController {
    private final static Logger log = LoggerFactory.getLogger(SysDeptController.class);

    @Autowired
    private SysDeptService sysDeptService;
    @Autowired
    private SysTreeService sysTreeService;

    @RequestMapping("/save.json")
    @ResponseBody
    public JsonData saveDept(DeptParam param) {
        sysDeptService.save(param);
        return JsonData.success();
    }

    @RequestMapping("/tree.json")
    @ResponseBody
    public JsonData tree() {
        List dtoList = sysTreeService.deptTree();
        return JsonData.success(dtoList);
    }

    @RequestMapping("/update.json")
    @ResponseBody
    public JsonData updateDept(DeptParam param) {
        sysDeptService.update(param);
        return JsonData.success();
    }

    @RequestMapping("/dept.page")//回去views中查找dept.jsp
    public ModelAndView page() {
        return new ModelAndView("dept");
    }

    @RequestMapping("/delete.json")
    @ResponseBody
    public JsonData delete(@RequestParam("id") int id) {
        sysDeptService.delete(id);
        return JsonData.success();
    }
}

   

 

你可能感兴趣的:(实现自己的权限管理系统)