一、审核功能实现的方式 1、普通 方案 :经办时入A表,审核后从A表读取数据,然后操作目标B表;
优势 :思路简单
劣势 :对后端功能实行高度的嵌入;审核功能数据操作不统一
2、弹框式 方案 :前台实现,操作时判断是否需要权限控制,如果需要,则弹出框,由审核人员进行审核,审核通过后,进行后续操作。
优势 :对后台功能无嵌入;可支持查询、导出、操作等全部功能;
劣势 :需要经办人和审核人同时在场操作
3、入参缓冲时 方案 :审核功能是独立的功能,前台发起业务后,入参存入数据库。待审核通过后,后台触发调用相应的接口,并将执行结果通知到经办人。
优势 :对前后台功能均无嵌入;支持导出及操作类;经办人和审核人可以异步操作;审核功能数据操作统一;
劣势 :需要框架层支持;实现逻辑稍微复杂
4、临时表 方案 :所有需要审核功能涉及的表均增加相应的表,该表比源表主要增加1个字段,即审核流水,其余字段命名完全一致;所有功能操作时先入该表,审核通过后,由后台从该表将数据同步至正表。
优势 :无需要框架支持;支持导出及操作类;经办人和审核人可以异步操作;审核功能数据操作统一;
劣势 :对后端功能实行高度的嵌入;
二、SpringBoot实现 1.创建数据库表SQL CREATE TABLE `audit` ( `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID' , `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '报修名称' , `user` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '报修人' , `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '报修时间' , `img` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '详情图片' , `state` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT '待审核' COMMENT '待审核,审核通过,审核不通过' , PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.写Java后端
图片 其实审核功能最主要的就是我们的新增功能,用户只有新增过后,我们的管理员才能去对你的申请进行审核,最后实现效果。
AuditController
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.demo.common.Result; import com.example.demo.entity.Audit; import com.example.demo.entity.Sanitation; import com.example.demo.entity.User; import com.example.demo.mapper.FileMapper; import com.example.demo.service.IAuditService; import com.example.demo.utils.TokenUtils; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; @CrossOrigin @RestController @RequestMapping("/audit" ) public class AuditController { @Resource private IAuditService auditService; @Resource private FileMapper fileMapper; // //新增或者更新 // @PostMapping // public Result save(@RequestBody Audit audit) { // audit.setUser(TokenUtils.getCurrentUser().getUsername()); audit.setImg(Files.url); // return Result.success(auditService.saveOrUpdate(audit)); // } // 新增或者更新 @PostMapping public Result save(@RequestBody Audit audit) { if (audit.getId() == null) { // 新增 audit.setUser(TokenUtils.getCurrentUser().getUsername()); } auditService.saveOrUpdate(audit); return Result.success(); } //删除 // @DeleteMapping("/{id}" ) // public Result delete(@PathVariable Integer id) { // return Result.success(userService.removeById(id)); // } @PostMapping("/del/batch" ) public Result deleteBatch(@RequestBody List ids) {//批量删除 return Result.success(auditService.removeByIds(ids)); } //查询所有数据 @GetMapping public Result findAll () { return Result.success(auditService.list()); } // @GetMapping("/role/{role}" ) // public Result findNames(@PathVariable String role) { // QueryWrapper queryWrapper = new QueryWrapper<>(); // queryWrapper.eq("role" , role); // List list = auditService.list(queryWrapper); // return Result.success(list); // } @GetMapping("/{id}" ) public Result findOne(@PathVariable Integer id) { return Result.success(auditService.getById(id)); } @GetMapping("/username/{username}" ) public Result findByUsername(@PathVariable String username) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("username" , username); return Result.success(auditService.getOne(queryWrapper)); } @GetMapping("/page" ) public Result findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam(defaultValue = "" ) String name) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc("id" ); if (!"" .equals(name)) { queryWrapper.like("name" , name); } User currentUser = TokenUtils.getCurrentUser(); // if (RoleEnum.ROLE_USER.toString().equals(currentUser.getRole())) { // 角色是普通用户 // queryWrapper.eq("user" , currentUser.getUsername()); // } return Result.success(auditService.page(new Page<>(pageNum, pageSize), queryWrapper)); } }
三、前端调用 1.实现效果
图片 2.核心代码
图片 "审核" width="240" > "scope"> type="success" @click="changeState(scope.row, '审核通过...师傅正在赶来的路上')" :disabled="scope.row.state !== '待审核'" >审核通过 type="danger" @click="changeState(scope.row, '审核不通过')" :disabled="scope.row.state !== '待审核'" >审核不通过
3.后台管理
图片 4.后台管理核心代码 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.demo.common.Result; import com.example.demo.entity.Audit; import com.example.demo.entity.User; import com.example.demo.mapper.FileMapper; import com.example.demo.service.IAuditService; import com.example.demo.utils.TokenUtils; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; @CrossOrigin @RestController @RequestMapping("/audit" ) public class AuditController { @Resource private IAuditService auditService; @Resource private FileMapper fileMapper; // //新增或者更新 // @PostMapping // public Result save(@RequestBody Audit audit) { // audit.setUser(TokenUtils.getCurrentUser().getUsername()); audit.setImg(Files.url); // return Result.success(auditService.saveOrUpdate(audit)); // } // 新增或者更新 @PostMapping public Result save(@RequestBody Audit audit) { if (audit.getId() == null) { // 新增 audit.setUser(TokenUtils.getCurrentUser().getUsername()); } auditService.saveOrUpdate(audit); return Result.success(); } //删除 // @DeleteMapping("/{id}" ) // public Result delete(@PathVariable Integer id) { // return Result.success(userService.removeById(id)); // } @PostMapping("/del/batch" ) public Result deleteBatch(@RequestBody List ids) {//批量删除 return Result.success(auditService.removeByIds(ids)); } //查询所有数据 @GetMapping public Result findAll () { return Result.success(auditService.list()); } @GetMapping("/{id}" ) public Result findOne(@PathVariable Integer id) { return Result.success(auditService.getById(id)); } @GetMapping("/username/{username}" ) public Result findByUsername(@PathVariable String username) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("username" , username); return Result.success(auditService.getOne(queryWrapper)); } @GetMapping("/page" ) public Result findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam(defaultValue = "" ) String name) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc("id" ); if (!"" .equals(name)) { queryWrapper.like("name" , name); } User currentUser = TokenUtils.getCurrentUser(); // if (RoleEnum.ROLE_USER.toString().equals(currentUser.getRole())) { // 角色是普通用户 // queryWrapper.eq("user" , currentUser.getUsername()); // } return Result.success(auditService.page(new Page<>(pageNum, pageSize), queryWrapper)); } }
5.vue前台完整代码 (1)、前台功能页面
前台负责新增请求,然后保存请求之后,我们管理员审核通过之后就不可以编辑和删除我们的请求,我们会保留数据在前台页面
"margin: 10px 0"> "width: 200px; margin-left: 10px" placeholder="请输入报修描述" clearable v-model="name" > "ml-5" type ="primary" @click="load" >"el-icon-search" />搜索 type="warning" @click="reset" >"el-icon-refresh" />刷新
"margin: 10px 0"> type="primary" @click="handleAdd" class="ml-10" >"el-icon-circle-plus-outline" />新增 class="ml-5" confirm-button-text='确认' cancel-button-text='取消' icon="el-icon-info" icon-color="red" title="确定批量删除这些信息吗?" @confirm="delBatch" > type="danger" slot="reference" >"el-icon-remove-outline" />删除
"tableData" border stripe :header-cell-class-name="headerBg" @selection-change="handleSelectionChange" > type="selection" width="55" > "name" label="报修描述" > "user" label="用户" > "createTime" label="创建时间" > "图片"> "scope"> "width: 100px; height: 100px" :src="scope.row.img" :preview-src-list="[scope.row.img]" > "state" label="进度" > "操作"> "scope"> type="success" @click="handleEdit(scope.row)" :disabled="scope.row.state !== '待审核'" >"el-icon-edit-outline" />编辑 "padding: 10px 0"> @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageNum" :page-sizes="[ 5, 10, 15]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total" >
"用户信息" :visible.sync="dialogFormVisible" width="30%" > "100px" size="small" > "报修描述" > "form.name" autocomplete="off" > "物品图片"> "http://localhost:9090/file/upload" ref="img" :on-success="handleImgUploadSuccess" > "small" type ="primary" >点击上传 "footer" class="dialog-footer" > "dialogFormVisible = false">取 消 type="primary" @click="save" >确 定
(2)、后台管理功能页面
"margin: 10px 0"> class="ml-5" confirm-button-text='确认' cancel-button-text='取消' icon="el-icon-info" icon-color="red" title="确定批量删除这些信息吗?" @confirm="delBatch" > type="danger" slot="reference" >"el-icon-remove-outline" />删除
"tableData" border stripe :header-cell-class-name="headerBg" @selection-change="handleSelectionChange" > type="selection" width="55" > "name" label="报修描述" > "user" label="用户" > "createTime" label="创建时间" > "img" label="详情图片" > "scope"> "width: 100px; height: 100px" :src="scope.row.img" :preview-src-list="[scope.row.img]" > "state" label="进度" > "审核" width="240" > "scope"> type="success" @click="changeState(scope.row, '审核通过...师傅正在赶来的路上')" :disabled="scope.row.state !== '待审核'" >审核通过 type="danger" @click="changeState(scope.row, '审核不通过')" :disabled="scope.row.state !== '待审核'" >审核不通过 "padding: 10px 0"> @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="pageNum" :page-sizes="[ 5, 10, 15]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total" >
重点!!!!图片上传
图片 核心代码
CREATE TABLE `file` ( `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID' , `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件名称' , `type ` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件类型' , `size` bigint DEFAULT NULL COMMENT '文件大小(kb)' , `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '下载链接' , `md5` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '文件md5' , `creat_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '时间' , `is_delete` tinyint(1) DEFAULT '0' COMMENT '是否删除' , PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=115 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.example.demo.common.Constants; import com.example.demo.common.Result; import com.example.demo.entity.Files; import com.example.demo.mapper.FileMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.util.List; @RestController @RequestMapping("/file" ) public class FileController { @Value("${files.upload.path} " ) private String fileUploadPath; @Value("${server.ip} " ) private String serverIp; @Resource private FileMapper fileMapper; @Autowired private StringRedisTemplate stringRedisTemplate; @PostMapping("/upload" ) public String upload(@RequestParam MultipartFile file) throws IOException { String originalFilename = file.getOriginalFilename(); String type = FileUtil.extName(originalFilename); long size = file.getSize(); // 定义一个文件唯一的标识码 String fileUUID = IdUtil.fastSimpleUUID() + StrUtil.DOT + type ; File uploadFile = new File(fileUploadPath + fileUUID); // 判断配置的文件目录是否存在,若不存在则创建一个新的文件目录 File parentFile = uploadFile.getParentFile(); //判断目录是否存在,不存在就新建 if (!parentFile.exists()) { parentFile.mkdirs(); } String url; // 获取文件的md5 String md5 = SecureUtil.md5(file.getInputStream()); // 从数据库查询是否存在相同的记录 Files dbFiles = getFileByMd5(md5); if (dbFiles != null) { url = dbFiles.getUrl(); } else { // 上传文件到磁盘 file.transferTo(uploadFile); // 数据库若不存在重复文件,则不删除刚才上传的文件 url = "http://" + serverIp + ":9090/file/" + fileUUID; } //存储到数据库 Files saveFile = new Files(); saveFile.setName(originalFilename); saveFile.setType(type ); saveFile.setSize(size/1024); saveFile.setUrl(url); saveFile.setMd5(md5); fileMapper.insert(saveFile); return url; // String md5 = SecureUtil.md5(file.getInputStream()); // Files files = getFileByMd5(md5); // // String url; // if (files != null) { // url = files.getUrl(); // } else { // file.transferTo(uploadFile); // url = "http://localhost:9090/file/" + fileUUID; // } // //存储到数据库 // Files saveFile = new Files(); // saveFile.setName(originalFilename); // saveFile.setType(type ); // saveFile.setSize(size/1024); // saveFile.setUrl(url); // saveFile.setMd5(md5); // fileMapper.insert(saveFile); // return url; } @GetMapping("/{fileUUID}" ) public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException { // 根据文件的唯一标识码获取文件 File uploadFile = new File(fileUploadPath + fileUUID); // 设置输出流的格式 ServletOutputStream os = response.getOutputStream(); response.addHeader("Content-Disposition" , "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8" )); response.setContentType("application/octet-stream" ); // 读取文件的字节流 os.write(FileUtil.readBytes(uploadFile)); os.flush(); os.close(); } /** * 通过文件的md5查询文件 * @param md5 * @return */ private Files getFileByMd5(String md5) { // 查询文件的md5是否存在 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("md5" , md5); List filesList = fileMapper.selectList(queryWrapper); return filesList.size() == 0 ? null : filesList.get(0); } // @CachePut(value = "files" , key = "'frontAll'" ) @PostMapping("/update" ) public Result update(@RequestBody Files files) { fileMapper.updateById(files); flushRedis(Constants.FILES_KEY); return Result.success(); } @GetMapping("/detail/{id}" ) public Result getById(@PathVariable Integer id) { return Result.success(fileMapper.selectById(id)); } //清除一条缓存,key为要清空的数据 // @CacheEvict(value="files" ,key="'frontAll'" ) @DeleteMapping("/{id}" ) public Result delete(@PathVariable Integer id) { Files files = fileMapper.selectById(id); files.setIsDelete(true ); fileMapper.updateById(files); flushRedis(Constants.FILES_KEY); return Result.success(); } @PostMapping("/del/batch" ) public Result deleteBatch(@RequestBody List ids) { // select * from sys_file where id in (id,id,id...) QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.in("id" , ids); List files = fileMapper.selectList(queryWrapper); for (Files file : files) { file.setIsDelete(true ); fileMapper.updateById(file); } return Result.success(); } /** * 分页查询接口 * @param pageNum * @param pageSize * @param name * @return */ @GetMapping("/page" ) public Result findPage(@RequestParam Integer pageNum, @RequestParam Integer pageSize, @RequestParam(defaultValue = "" ) String name) { QueryWrapper queryWrapper = new QueryWrapper<>(); // 查询未删除的记录 queryWrapper.eq("is_delete" , false ); queryWrapper.orderByDesc("id" ); if (!"" .equals(name)) { queryWrapper.like("name" , name); } return Result.success(fileMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper)); } // 删除缓存 private void flushRedis(String key) { stringRedisTemplate.delete(key); } }
小结 以上就是对怎么利用SpringBoot实现审核功能简单的概述,让我们更加了解SpringBoot的作用,为我们的知识储备又加上一笔。
来源:blog.csdn.net/weixin_65950231/article/details/128756143