一、审核功能实现的方式1、普通

方案:经办时入A表,审核后从A表读取数据,然后操作目标B表;

优势:思路简单

劣势:对后端功能实行高度的嵌入;审核功能数据操作不统一

2、弹框式

方案:前台实现,操作时判断是否需要权限控制,如果需要,则弹出框,由审核人员进行审核,审核通过后,进行后续操作。

优势:对后台功能无嵌入;可支持查询、导出、操作等全部功能;

劣势:需要经办人和审核人同时在场操作

3、入参缓冲时

方案:审核功能是独立的功能,前台发起业务后,入参存入数据库。待审核通过后,后台触发调用相应的接口,并将执行结果通知到经办人。

优势:对前后台功能均无嵌入;支持导出及操作类;经办人和审核人可以异步操作;审核功能数据操作统一;

劣势:需要框架层支持;实现逻辑稍微复杂

4、临时表

方案:所有需要审核功能涉及的表均增加相应的表,该表比源表主要增加1个字段,即审核流水,其余字段命名完全一致;所有功能操作时先入该表,审核通过后,由后台从该表将数据同步至正表。

优势:无需要框架支持;支持导出及操作类;经办人和审核人可以异步操作;审核功能数据操作统一;

劣势:对后端功能实行高度的嵌入;

Spring Boot 基础就不介绍了,推荐看这个实战项目:

https://github.com/javastacks/spring-boot-best-practice

二、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.核心代码

      审核通过    审核不通过  

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)、前台功能页面

前台负责新增请求,然后保存请求之后,我们管理员审核通过之后就不可以编辑和删除我们的请求,我们会保留数据在前台页面

  
搜索 刷新
新增 删除 编辑
点击上传
取 消 确 定 export default { name: "Audit", data() { return { tableData: [], total: 0, pageNum: 1, pageSize: 5, name: "", form: {}, dialogFormVisible: false, multipleSelection: [], headerBg: "headerBg", roles: [], user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {} } }, created() { this.load() }, methods: { load: function () { this.request.get("/audit/page", { params: { pageNum: this.pageNum, pageSize: this.pageSize, name: this.name, } }).then(res => { this.tableData = res.data.records this.total = res.data.total }) // this.request.get("/role").then(res => { // this.roles = res.data // }) }, home() { this.$router.push("/") }, save() { this.request.post("/audit", this.form).then(res => { if (res.code === '200') { this.$message.success("保存成功") this.dialogFormVisible = false this.load() } else { this.$message.error("保存失败") } }) }, handleAdd() { this.dialogFormVisible = true this.form = {} }, handleEdit(row) { this.form = row this.dialogFormVisible = true }, handleSelectionChange(val) { console.log(val) this.multipleSelection = val; }, delBatch() { let ids = this.multipleSelection.map(v => v.id) //[{}, {}, {}] => [1,2,3] this.request.post("/audit/del/batch", ids).then(res => { if (res.code === '200') { this.$message.success("删除信息成功") this.load() } else { this.$message.error("删除信息失败") } }) }, reset() { this.name = "" this.load() }, handleSizeChange(pageSize) { console.log(pageSize) this.pageSize = pageSize this.load() }, handleCurrentChange(pageNum) { console.log(pageNum) this.pageNum = pageNum this.load() }, handleImgUploadSuccess(res) { this.form.img = res }, }} .headerBg { background: #eee!important;}

(2)、后台管理功能页面

  
<!--
--><!-- --><!-- 搜索--><!-- 刷新-->
<!-- 新增--> 删除 审核通过 审核不通过
export default { name: "Audit", data() { return { tableData: [], total: 0, pageNum: 1, pageSize: 5, username: "", form: {}, // dialogFormVisible: false, multipleSelection: [], headerBg: "headerBg", roles: [], user: localStorage.getItem("user") ? JSON.parse(localStorage.getItem("user")) : {}, } }, created() { this.load() }, methods: { load: function () { this.request.get("/audit/page", { params: { pageNum: this.pageNum, pageSize: this.pageSize, username: this.username, } }).then(res => { this.tableData = res.data.records this.total = res.data.total }) this.request.get("/role").then(res => { this.roles = res.data }) }, home() { this.$router.push("/") }, save() { this.request.post("/audit", this.form).then(res => { if (res.code === '200') { this.$message.success("保存成功") this.dialogFormVisible = false this.load() } else { this.$message.error("保存失败") } }) }, handleAdd() { this.dialogFormVisible = true this.form = {} }, handleEdit(row) { this.form = row this.dialogFormVisible = true }, handleSelectionChange(val) { console.log(val) this.multipleSelection = val; }, delBatch() { let ids = this.multipleSelection.map(v => v.id) //[{}, {}, {}] => [1,2,3] this.request.post("/audit/del/batch", ids).then(res => { if (res.code === '200') { this.$message.success("删除信息成功") this.load() } else { this.$message.error("删除信息失败") } }) }, reset() { this.username = "" this.load() }, handleSizeChange(pageSize) { console.log(pageSize) this.pageSize = pageSize this.load() }, handleCurrentChange(pageNum) { console.log(pageNum) this.pageNum = pageNum this.load() }, changeState(row, state) { this.form = JSON.parse(JSON.stringify(row)) this.form.state = state; this.save(); }, // handleImgUploadSuccess() { // this.$message.success("图片上传成功") // this.load() // }, }} .headerBg { background: #eee!important;}

重点!!!!图片上传

核心代码

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的作用,为我们的知识储备又加上一笔。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!