手把手教你如何利用SpringBoot實現(xiàn)審核功能
一、審核功能實現(xiàn)的方式
1、普通
方案:經(jīng)辦時入A表,審核后從A表讀取數(shù)據(jù),然后操作目標B表;
優(yōu)勢:思路簡單
劣勢:對后端功能實行高度的嵌入;審核功能數(shù)據(jù)操作不統(tǒng)一
2、彈框式
方案:前臺實現(xiàn),操作時判斷是否需要權(quán)限控制,如果需要,則彈出框,由審核人員進行審核,
審核通過后,進行后續(xù)操作。
優(yōu)勢:對后臺功能無嵌入;可支持查詢、導出、操作等全部功能;
劣勢:需要經(jīng)辦人和審核人同時在場操作
3、入?yún)⒕彌_時
方案:審核功能是獨立的功能,前臺發(fā)起業(yè)務后,入?yún)⒋嫒霐?shù)據(jù)庫。
待審核通過后,后臺觸發(fā)調(diào)用相應的接口,并將執(zhí)行結(jié)果通知到經(jīng)辦人。
優(yōu)勢:對前后臺功能均無嵌入;支持導出及操作類;經(jīng)辦人和審核人可以異步操作;審核功能數(shù)據(jù)操作統(tǒng)一;
劣勢:需要框架層支持;實現(xiàn)邏輯稍微復雜
4、臨時表
方案:所有需要審核功能涉及的表均增加相應的表,該表比源表主要增加1個字段,即審核流水,其余字段命名完全一致;
所有功能操作時先入該表,審核通過后,由后臺從該表將數(shù)據(jù)同步至正表。
優(yōu)勢:無需要框架支持;支持導出及操作類;經(jīng)辦人和審核人可以異步操作;審核功能數(shù)據(jù)操作統(tǒng)一;
劣勢:對后端功能實行高度的嵌入;
二、SpringBoot實現(xiàn)
1.創(chuàng)建數(shù)據(jù)庫表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后端
其實審核功能最主要的就是我們的新增功能,用戶只有新增過后,我們的管理員才能去對你的申請進行審核,最后實現(xiàn)效果。
AuditController.Controller
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<Integer> ids) {//批量刪除 return Result.success(auditService.removeByIds(ids)); } //查詢所有數(shù)據(jù) @GetMapping public Result findAll() { return Result.success(auditService.list()); } // @GetMapping("/role/{role}") // public Result findNames(@PathVariable String role) { // QueryWrapper<Audit> queryWrapper = new QueryWrapper<>(); // queryWrapper.eq("role", role); // List<Audit> 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<Audit> 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<Audit> 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)); } }
三、前端調(diào)用
1.實現(xiàn)效果
2.核心代碼
<el-table-column label="審核" width="240"> <template v-slot="scope"> <el-button type="success" @click="changeState(scope.row, '審核通過...師傅正在趕來的路上')" :disabled="scope.row.state !== '待審核'">審核通過</el-button> <el-button type="danger" @click="changeState(scope.row, '審核不通過')" :disabled="scope.row.state !== '待審核'">審核不通過</el-button> </template> </el-table-column>
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<Integer> ids) {//批量刪除 return Result.success(auditService.removeByIds(ids)); } //查詢所有數(shù)據(jù) @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<Audit> 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<Audit> 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)、前臺功能頁面
前臺負責新增請求,然后保存請求之后,我們管理員審核通過之后就不可以編輯和刪除我們的請求,我們會保留數(shù)據(jù)在前臺頁面
<template> <div> <div style="margin: 10px 0"> <el-input style="width: 200px; margin-left: 10px" placeholder="請輸入報修描述" clearable v-model="name" ></el-input> <el-button class="ml-5" type="primary" @click="load"><i class="el-icon-search" />搜索</el-button> <el-button type="warning" @click="reset"><i class="el-icon-refresh" />刷新</el-button> </div> <div style="margin: 10px 0"> <el-button type="primary" @click="handleAdd" class="ml-10"><i class="el-icon-circle-plus-outline" />新增</el-button> <el-popconfirm class="ml-5" confirm-button-text='確認' cancel-button-text='取消' icon="el-icon-info" icon-color="red" title="確定批量刪除這些信息嗎?" @confirm="delBatch"> <el-button type="danger" slot="reference" ><i class="el-icon-remove-outline" />刪除</el-button> </el-popconfirm> </div> <el-table :data="tableData" border stripe :header-cell-class-name="headerBg" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55"></el-table-column> <el-table-column prop="name" label="報修描述" ></el-table-column> <el-table-column prop="user" label="用戶" ></el-table-column> <el-table-column prop="createTime" label="創(chuàng)建時間" ></el-table-column> <el-table-column label="圖片"> <template slot-scope="scope"> <el-image style="width: 100px; height: 100px" :src="scope.row.img" :preview-src-list="[scope.row.img]"></el-image> </template> </el-table-column> <el-table-column prop="state" label="進度"></el-table-column> <el-table-column label="操作"> <template slot-scope="scope"> <el-button type="success" @click="handleEdit(scope.row)" :disabled="scope.row.state !== '待審核'"><i class="el-icon-edit-outline" />編輯</el-button> </template> </el-table-column> </el-table> <div style="padding: 10px 0"> <el-pagination @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"> </el-pagination> </div> <el-dialog title="用戶信息" :visible.sync="dialogFormVisible" width="30%"> <el-form label-width="100px" size="small"> <el-form-item label="報修描述" > <el-input v-model="form.name" autocomplete="off"></el-input> </el-form-item> <el-form-item label="物品圖片"> <el-upload action="http://localhost:9090/file/upload" ref="img" :on-success="handleImgUploadSuccess"> <el-button size="small" type="primary">點擊上傳</el-button> </el-upload> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">取 消</el-button> <el-button type="primary" @click="save">確 定</el-button> </div> </el-dialog> </div> </template> <script> 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 }, } } </script> <style> .headerBg { background: #eee!important; } </style>
(2)、后臺管理功能頁面
<template> <div> <!-- <div style="margin: 10px 0">--> <!-- <el-input style="width: 200px; margin-left: 10px" placeholder="請輸入用戶名" clearable suffix-icon="el-icon-user" v-model="username" ></el-input>--> <!-- <el-button class="ml-5" type="primary" @click="load"><i class="el-icon-search" />搜索</el-button>--> <!-- <el-button type="warning" @click="reset"><i class="el-icon-refresh" />刷新</el-button>--> <!-- </div>--> <div style="margin: 10px 0"> <!-- <el-button type="primary" @click="handleAdd" class="ml-10"><i class="el-icon-circle-plus-outline" />新增</el-button>--> <el-popconfirm class="ml-5" confirm-button-text='確認' cancel-button-text='取消' icon="el-icon-info" icon-color="red" title="確定批量刪除這些信息嗎?" @confirm="delBatch"> <el-button type="danger" slot="reference" ><i class="el-icon-remove-outline" />刪除</el-button> </el-popconfirm> </div> <el-table :data="tableData" border stripe :header-cell-class-name="headerBg" @selection-change="handleSelectionChange"> <el-table-column type="selection" width="55"></el-table-column> <el-table-column prop="name" label="報修描述" ></el-table-column> <el-table-column prop="user" label="用戶" ></el-table-column> <el-table-column prop="createTime" label="創(chuàng)建時間" ></el-table-column> <el-table-column prop="img" label="詳情圖片" > <template slot-scope="scope"> <el-image style="width: 100px; height: 100px" :src="scope.row.img" :preview-src-list="[scope.row.img]"></el-image> </template> </el-table-column> <el-table-column prop="state" label="進度"></el-table-column> <el-table-column label="審核" width="240"> <template v-slot="scope"> <el-button type="success" @click="changeState(scope.row, '審核通過...師傅正在趕來的路上')" :disabled="scope.row.state !== '待審核'">審核通過</el-button> <el-button type="danger" @click="changeState(scope.row, '審核不通過')" :disabled="scope.row.state !== '待審核'">審核不通過</el-button> </template> </el-table-column> </el-table> <div style="padding: 10px 0"> <el-pagination @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"> </el-pagination> </div> </div> </template> <script> 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() // }, } } </script> <style> .headerBg { background: #eee!important; } </style>
重點?。。?!圖片上傳
核心代碼
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); // 判斷配置的文件目錄是否存在,若不存在則創(chuàng)建一個新的文件目錄 File parentFile = uploadFile.getParentFile(); //判斷目錄是否存在,不存在就新建 if (!parentFile.exists()) { parentFile.mkdirs(); } String url; // 獲取文件的md5 String md5 = SecureUtil.md5(file.getInputStream()); // 從數(shù)據(jù)庫查詢是否存在相同的記錄 Files dbFiles = getFileByMd5(md5); if (dbFiles != null) { url = dbFiles.getUrl(); } else { // 上傳文件到磁盤 file.transferTo(uploadFile); // 數(shù)據(jù)庫若不存在重復文件,則不刪除剛才上傳的文件 url = "http://" + serverIp + ":9090/file/" + fileUUID; } //存儲到數(shù)據(jù)庫 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; // } // //存儲到數(shù)據(jù)庫 // 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 { // 根據(jù)文件的唯一標識碼獲取文件 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"); // 讀取文件的字節(jié)流 os.write(FileUtil.readBytes(uploadFile)); os.flush(); os.close(); } /** * 通過文件的md5查詢文件 * @param md5 * @return */ private Files getFileByMd5(String md5) { // 查詢文件的md5是否存在 QueryWrapper<Files> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("md5", md5); List<Files> 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為要清空的數(shù)據(jù) // @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<Integer> ids) { // select * from sys_file where id in (id,id,id...) QueryWrapper<Files> queryWrapper = new QueryWrapper<>(); queryWrapper.in("id", ids); List<Files> 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<Files> 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); } }
?小結(jié)
以上就是對怎么利用SpringBoot實現(xiàn)審核功能簡單的概述,讓我們更加了解SpringBoot的作用,為我們的知識儲備又加上一筆。
總結(jié)
到此這篇關于手把手教你如何利用SpringBoot實現(xiàn)審核功能的文章就介紹到這了,更多相關SpringBoot實現(xiàn)審核功能內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
在SpringBoot項目中如何實現(xiàn)線程池的動態(tài)監(jiān)控
Spring Boot因其簡便、高效的特點廣受開發(fā)者喜愛,在復雜的業(yè)務場景下,如何確保Spring Boot應用的高性能和穩(wěn)定性成為了一個關鍵問題,其中,線程池的管理策略直接影響到系統(tǒng)的吞吐量和資源利用效率,本文將重點探討在Spring Boot項目中,如何實現(xiàn)線程池的動態(tài)監(jiān)控2023-10-10spring boot 配置freemarker及如何使用freemarker渲染頁面
springboot中自帶的頁面渲染工具為thymeleaf 還有freemarker這兩種模板引擎,本文重點給大家介紹spring boot 配置freemarker及如何使用freemarker渲染頁面,感興趣的朋友一起看看吧2023-10-10基于Tomcat7、Java、WebSocket的服務器推送聊天室實例
HTML5 WebSocket實現(xiàn)了服務器與瀏覽器的雙向通訊,本篇文章主要介紹了基于Tomcat7、Java、WebSocket的服務器推送聊天室實例,具有一定的參考價值,有興趣的可以了解一下。2016-12-12Spring JPA聯(lián)表查詢之OneToOne源碼詳解
這篇文章主要為大家介紹了Spring JPA聯(lián)表查詢之OneToOne源碼詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04