【开发模板】Vue和SpringBoot的前后端分离开发模板(二)

简介: 【开发模板】Vue和SpringBoot的前后端分离开发模板

部门管理模块

部门是用户的一个属性,即用户属于某个部门,一个部门可以拥有多位员工,部门管理模块用于维护部门档案,用户可以新增、编辑、查询、删除和导出部门档案,架构图如下所示。

部门实体类的字段明细如下:

  • 部门名称
  • 部门状态
  • 排序值
  • 父部门 ID

因为部门档案是一个树形结构的模块,所以设置了父部门 ID。我指定顶级部门的父 ID 为 0,初始状态下前端请求父 ID 为 0 的数据,再使用深度优先搜索(dfs)的方法迭代搜索下面的子部门,从而实现部门管理模块的查询和删除功能,其中深度优先搜索(dfs)的删除部门代码如下所示。

// 深度优先搜索(dfs)的删除部门代码 
@ApiOperation(value = "迭代删除部门")
public void deleteRecursion(String id, String[] ids) {
    QueryWrapper<User> userQw = new QueryWrapper<>();
    userQw.eq("department_id",id);
    long userCountInDepartment = iUserService.count(userQw);
    if(userCountInDepartment > 0L){
        throw new ZwzException("不能删除包含员工的部门");
    }
    Department department = iDepartmentService.getById(id);
    Department parentDepartment = null;
    if(department != null && !ZwzNullUtils.isNull(department.getParentId())){
        parentDepartment = iDepartmentService.getById(department.getParentId());
    }
    iDepartmentService.removeById(id);
    QueryWrapper<DepartmentHeader> dhQw = new QueryWrapper<>();
    dhQw.eq("department_id",id);
    iDepartmentHeaderService.remove(dhQw);
    if(parentDepartment != null){
        QueryWrapper<Department> depQw = new QueryWrapper<>();
        depQw.eq("parent_id",parentDepartment.getId());
        depQw.orderByAsc("sort_order");
        List<Department> childrenDepartmentList = iDepartmentService.list(depQw);
        if(childrenDepartmentList == null || childrenDepartmentList.size() < 1){
            parentDepartment.setIsParent(false);
            iDepartmentService.saveOrUpdate(parentDepartment);
        }
    }
    QueryWrapper<Department> depQw = new QueryWrapper<>();
    depQw.eq("parent_id",id);
    depQw.orderByAsc("sort_order");
    List<Department> departmentList = iDepartmentService.list(depQw);
    for(Department judgeDepartment : departmentList){
        if(!CommonUtil.judgeIds(judgeDepartment.getId(), ids)){
            deleteRecursion(judgeDepartment.getId(), ids);
        }
    }
}

部门管理模块的操作界面如下图所示。

用户可以点击左上角的添加按钮,系统会弹出一个“添加一级部门”界面,添加的部门父 ID 会被指定为 0,也就是顶级的部门。

如果用户在左侧树形组件中选择了某个部门(如选择人力资源部),系统会弹出一个“添加部门”界面,添加的部门父 ID 就是当前树形组件选择部门的 ID,从而实现添加子部门的功能。

用户可以在右上侧的部门编辑界面中完成对部门信息的编辑操作,最后点击保存按钮即可完成数据更新。

用户也可以在树形组件中勾选部门,然后点击顶部的删除按钮,触发部门的删除操作,如下图所示。

删除部门默认为级联状态,若选择了某个部门,其下层的部门也会被级联选择,若用户不需要此功能,需要关闭级联 Switch 开关,如下图所示。

文件管理模块

文件存储是大多数管理系统的必备功能,所以基于 Vue 和 SpringBoot 的通用管理系统对文件管理进行了封装,在其他模块上传的文件都会被集成到这个文件管理模块。在这里用户可以对文件进行上传、下载、预览、删除等操作,其架构图如下图所示。

文件实体类的字段明细如下:

  • 上传文件名
  • 存储路径
  • 存储硬盘
  • 文件大小
  • 实际文件名
  • 文件类型

文件管理模块的操作界面如下所示。

在初次部署系统时,用户需要对文件的存储情况进行配置,也就是告诉系统文件放在哪里,还有就是文件的预览端口,文件存储配置的操作界面如下图所示,通过文件管理模块主界面的配置按钮进入。

当用户将 a.txt 文件上传到系统中,系统首先会在后端接收到这个文件的内容,将文件命名为 UUID 的随机字符串,持久化到数据库,并且将文件存储到用户配置的磁盘路径,文件上传的后端核心代码如下所示。

// 文件上传核心代码
@SystemLog(about = "文件上传", type = LogType.DATA_CENTER,doType = "FILE-06")
@RequestMapping(value = "/file", method = RequestMethod.POST)
@ApiOperation(value = "文件上传")
public Result<Object> upload(@RequestParam(required = false) MultipartFile file,@RequestParam(required = false) String base64) {
    if(StrUtil.isNotBlank(base64)){
        file = Base64DecodeMultipartFile.base64Convert(base64);
    }
    String result = null;
    String fKey = CommonUtil.renamePic(file.getOriginalFilename());
    File f = new File();
    try {
        InputStream inputStream = file.getInputStream();
        result = zwzFileUtils.inputStreamUpload(inputStream, fKey, file);
        f.setLocation(0);
        f.setName(file.getOriginalFilename());
        f.setSize(file.getSize());
        f.setType(file.getContentType());
        f.setFKey(fKey);
        f.setUrl(result);
        iFileService.saveOrUpdate(f);
    } catch (Exception e) {
        return ResultUtil.error(e.toString());
    }
    OssSettingVo vo = getOssSetting();
    return ResultUtil.data(vo.getFileHttp() + vo.getFileView() + "/" + f.getId());
}

当用户需要查询文件的时候,系统根据数据库的数据,匹配到硬盘目录中的文件,回显到前端,回显的后端核心代码如下所示。

// 文件预览核心代码  
@SystemLog(about = "预览文件", type = LogType.DATA_CENTER,doType = "FILE-05")
@RequestMapping(value = "/view/{id}", method = RequestMethod.GET)
@ApiOperation(value = "预览文件")
public void view(@PathVariable String id,@RequestParam(required = false) String filename,@RequestParam(required = false, defaultValue = "false") Boolean preview,HttpServletResponse httpServletResponse) throws IOException {
    File selectFile = iFileService.getById(id);
    if(selectFile == null){
        throw new ZwzException("文件不存在");
    }
    if(ZwzNullUtils.isNull(filename)){
        filename =  selectFile.getFKey();
    }
    if(!preview){
        httpServletResponse.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
    }
    httpServletResponse.setContentLengthLong(selectFile.getSize());
    httpServletResponse.setContentType(selectFile.getType());
    httpServletResponse.addHeader("Accept-Ranges", "bytes");
    if(selectFile.getSize() != null && selectFile.getSize() > 0){
        httpServletResponse.addHeader("Content-Range", "bytes " + 0 + "-" + (selectFile.getSize()-1) + "/" + selectFile.getSize());
    }
    zwzFileUtils.view(selectFile.getUrl(), httpServletResponse);
}

对于图片格式的文件,系统使用了 viewerjs 依赖,后端会返回图片格式的文件流,支持直接预览,预览的效果如下图所示。

对于其他类型的文件,系统后端会返回文件格式的文件流,浏览器会根据文件类型进行预览或下载,如 PDF 文档会直接触发预览,界面如下所示。

对于不可预览的文件,浏览器会自动触发下载,用户需要下载后使用本地的软件进行预览,如下图所示。

权限管理模块

基于 Vue 和 SpringBoot 的通用管理系统采用了基于角色的访问控制,角色和菜单关联,一个角色可以配置多个菜单权限;然后再将用户和角色关联,一位用户可以赋予多个角色。这样用户就可以根据角色拿到该有的菜单权限,更方便管理者进行权限管控,权限管理模块的内容包括了菜单管理模块和角色管理模块,接下来对这两个模块进行介绍。

菜单管理模块用于维护系统的菜单数据,当开发者编写完成指定模块的代码之后,需要整合到系统的路由系统中,这就需要开发者将模块的名称、路由名称、代码路径配置到菜单管理模块,菜单管理模块的主界面如下所示。

当用户开发完成指定的模块后,需要在菜单管理模块中新建菜单,即点击顶部的添加菜单按钮,系统会弹出添加下单的界面。当用户没有选择左侧树形组件的菜单时,默认添加顶级菜单,若选择了则添加选择菜单的子菜单,相关逻辑和部门管理模块相似,添加菜单的界面如下图所示。

系统页面顶部的为一级菜单,也就是顶级菜单,如下图所示。

系统左侧展示了二级和三级菜单,如下图所示。

假设用户新建的模块路径为 views/demo/demo1/index,如下图所示。

那么用户就需要在前端代码输入组件中输入 demo/demo1/index,完成和前端代码的匹配。另外路径字段和路由英文名字段随意填写,不和现有菜单重复即可。

用户也可以在菜单管理模块编辑菜单的数据,编辑完成后点击“保存菜单”按钮即可,如下图所示。

另外系统还支持根据单个菜单查询权限用户的功能,让用户快速知晓这个菜单能够被哪些人看到,这个功能的后端核心代码如下所示。

// 查询菜单权限拥有者核心代码  
@SystemLog(about = "查询菜单权限拥有者", type = LogType.DATA_CENTER,doType = "PERMISSION-01")
@ApiOperation(value = "查询菜单权限拥有者")
@RequestMapping(value = "/getUserByPermission", method = RequestMethod.GET)
public Result<List<UserByPermissionVo>> getUserByPermission(@RequestParam String permissionId){
    Permission permission = iPermissionService.getById(permissionId);
    if(permission == null) {
        return ResultUtil.error("该菜单已被删除");
    }
    List<UserByPermissionVo> ansList = new ArrayList<>();
    // 查询用户
    QueryWrapper<RolePermission> qw = new QueryWrapper<>();
    qw.eq("permission_id",permissionId);
    List<RolePermission> rolePermissionList = iRolePermissionService.list(qw);
    for (RolePermission rp : rolePermissionList) {
        Role role = iRoleService.getById(rp.getRoleId());
        if(role != null) {
            QueryWrapper<UserRole> urQw = new QueryWrapper<>();
            urQw.eq("role_id",role.getId());
            List<UserRole> userRoleList = iUserRoleService.list(urQw);
            for (UserRole ur : userRoleList) {
                User user = iUserService.getById(ur.getUserId());
                if(user != null) {
                    boolean flag = false;
                    for (UserByPermissionVo vo : ansList) {
                        if(Objects.equals(vo.getUserId(),user.getId())) {
                            flag = true;
                            vo.setRoleStr(vo.getRoleStr() + role.getName() + "(" + role.getDescription() + ") ");
                            break;
                        }
                    }
                    if(!flag) {
                        UserByPermissionVo vo = new UserByPermissionVo();
                        vo.setUserId(user.getId());
                        vo.setUserName(user.getNickname());
                        vo.setRoleStr(role.getName());
                        vo.setCode(user.getUsername());
                        vo.setMobile(user.getMobile());
                        ansList.add(vo);
                    }
                }
            }
        }
    }
    return new ResultUtil<List<UserByPermissionVo>>().setData(ansList);
}

对于角色管理模块而言,存在的意义就是实现基于角色的访问控制,操作界面如下图所示。

用户可以对角色分配权限菜单,分配后有这个角色的用户就可以进入配置的菜单,进行相关的操作,菜单权限分配界面如下图所示,用户分配完成后点击底部的保存菜单权限按钮即可完成更新操作。

用户还可以对角色进行设置默认操作,设置默认角色后,新注册的用户会被赋予该角色,拥有这个角色的菜单权限,默认角色支持有多个。

相关文章
|
21天前
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
120 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
10天前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
115 79
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的留守儿童爱心网站设计与实现(计算机毕设项目实战+源码+文档)
博主是一位全网粉丝超过100万的CSDN特邀作者、博客专家,专注于Java、Python、PHP等技术领域。提供SpringBoot、Vue、HTML、Uniapp、PHP、Python、NodeJS、爬虫、数据可视化等技术服务,涵盖免费选题、功能设计、开题报告、论文辅导、答辩PPT等。系统采用SpringBoot后端框架和Vue前端框架,确保高效开发与良好用户体验。所有代码由博主亲自开发,并提供全程录音录屏讲解服务,保障学习效果。欢迎点赞、收藏、关注、评论,获取更多精品案例源码。
|
2月前
|
监控 Java 应用服务中间件
SpringBoot是如何简化Spring开发的,以及SpringBoot的特性以及源码分析
Spring Boot 通过简化配置、自动配置和嵌入式服务器等特性,大大简化了 Spring 应用的开发过程。它通过提供一系列 `starter` 依赖和开箱即用的默认配置,使开发者能够更专注于业务逻辑而非繁琐的配置。Spring Boot 的自动配置机制和强大的 Actuator 功能进一步提升了开发效率和应用的可维护性。通过对其源码的分析,可以更深入地理解其内部工作机制,从而更好地利用其特性进行开发。
63 6
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的家政服务管理平台设计与实现(计算机毕设项目实战+源码+文档)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
|
2月前
|
JavaScript 搜索推荐 Java
基于SpringBoot+Vue实现的家乡特色推荐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
|
2月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue实现的高校食堂移动预约点餐系统设计与实现(源码+文档+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
|
2月前
|
JavaScript NoSQL Java
基于SpringBoot+Vue实现的大学生体质测试管理系统设计与实现(系统源码+文档+数据库+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
|
2月前
|
JavaScript NoSQL Java
基于SpringBoot+Vue实现的冬奥会科普平台设计与实现(系统源码+文档+数据库+部署)
面向大学生毕业选题、开题、任务书、程序设计开发、论文辅导提供一站式服务。主要服务:程序设计开发、代码修改、成品部署、支持定制、论文辅导,助力毕设!
|
3月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
177 1

热门文章

最新文章