SpringBoot 实现审核功能

news2024/11/24 13:36:35

一、审核功能实现的方式

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<Integer> 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<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));
 
    }
}

三、前端调用

1.实现效果

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));
    }
 
    //查询所有数据
    @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)、前台功能页面

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

<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="创建时间" ></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="创建时间" ></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);
        // 判断配置的文件目录是否存在,若不存在则创建一个新的文件目录
        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<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为要清空的数据
//    @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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/719385.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HummerRisk 配置 HTTPS访问

简介 HummerRisk 是开源的云原生安全平台&#xff0c;以非侵入的方式解决云原生的安全和治理问题。核心能力包括混合云的安全治理和云原生安全检测。 HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是一种通过加密和身份验证来保护网络通信安全的协议。它…

ChatGPT对高等教育的可能影响与对策建议

ChatGPT来袭&#xff0c;将对高等教育带来哪些影响&#xff0c;我们又该如何应对&#xff1f; 对于ChatGPT&#xff0c;有人欢喜有人忧&#xff0c;不同人、不同领域评价不一。在一些人眼里&#xff0c;它就是天使&#xff0c;而在另外一些人眼里&#xff0c;它几乎可以说是魔…

php导出pdf

插件官网&#xff1a;TCPDF 博主用的是tp6框架 、tcpdf插件 composer require tecnickcom/tcpdf --ignore-platform-reqs 后面是忽略平台要求的参数 ---------------中文乱码start------------------ 关于中文乱码问题&#xff1a; 网上说的下载字体放入fonts 利用tools…

Linux之系统管理

系统管理 Linux中的进程和服务 计算机中&#xff0c;一个正在执行的程序或命令&#xff0c;被叫做“进程”&#xff08;process&#xff09;。 启动之后一直存在、常驻内存的进程&#xff0c;一般被称作“服务”&#xff08;service&#xff09; service 服务管理&#xff…

GaussDB OLTP云数据库配套工具DDM

目录 一、前言 二、DDM定义 三、DDM业务架构 四、为什么需要DDM? 五、DDM特性 六、DDM应用场景 一、前言 现在越来越多的企业应用在逐步向云平台迁移&#xff0c;同时这对云平台带了一个严峻的考验和挑战。但针对华为云GaussDB数据库&#xff0c; 我们在生态方面做了比…

利用iptables + zabbix-agent 监控进程端口流量

这几天部署了一台ARM架构的linux系统的监控&#xff0c;服务器系统上没有任何工具可以获取数据来获取端口流量&#xff0c;yum&#xff0c;apt-get软件包管理工具都没有&#xff0c;所以想获取数据比较困难。 最终决定使用iptables来添加几条指定端口的规则来统计入站流量和出站…

电子时钟制作(瑞萨RA)(7)----按键修改数码管时间

概述 前几节课程已经单独驱动了数码管和RTC&#xff0c;同时已经整合成了能够用数码管显示具体时间&#xff0c;但是无法修改时间&#xff0c;这节就来配置使用按键修改具体的日期。 硬件准备 首先需要准备一个开发板&#xff0c;这里我准备的是芯片型号R7FA2E1A72DFL的开发…

【花雕】全国青少年机器人技术一级考试备考实操搭建手册9

随着科技的不断进步&#xff0c;机器人技术已经成为了一个重要的领域。在这个领域中&#xff0c;机械结构是机器人设计中至关重要的一部分&#xff0c;它决定了机器人的形态、运动方式和工作效率。对于青少年机器人爱好者来说&#xff0c;了解机械结构的基础知识&#xff0c;掌…

记录Maven 依赖包版本号奇奇怪怪的问题 - okhttp3、okio 版本指定无效

问题背景 SprintBoot项目使用Okhttp 封装SDK common-http&#xff0c;根据官网使用Maven导入JavaSDK <dependency><groupId>io.github.admin4j</groupId><artifactId>http</artifactId><version>0.7.4</version> </dependency&…

Vue 数据双向绑定

双向数据绑定 : 通过前面学习知道 Vue 是数据驱动的&#xff0c;数据驱动有一个精髓之处是数据双向绑定&#xff0c; 即当数据发生变化的时候&#xff0c;视图也就发生变化&#xff0c;当视图发生变化的时候&#xff0c;数据也会跟着同步变化。&#xff08;就是mvvm数据发生变化…

MyCat2 使用教程(一)初始安装

MyCat2 使用教程&#xff08;一&#xff09;初始安装 Mycat2是Mycat社区开发的一款分布式关系型数据库&#xff08;中间件&#xff09;。它支持分布式SQL查询&#xff0c;兼容MySQL通信协议&#xff0c;以Java生态支持多种后端数据&#xff0c;通过数据分片提高数据查询处理能…

【C++】5.多线程:ThreadPoll线程池实现

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍ThreadPoll线程池实现。 学其所用&#xff0c;用其所学。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;下次更新不迷路…

Web3.0 在中国市场的规模如何?其特点有什么?

随着区块链技术的不断发展和普及&#xff0c;Web3.0 作为下一代互联网的发展趋势&#xff0c;在中国市场也逐渐受到了关注和应用。那么&#xff0c;Web3.0 在中国市场的规模如何&#xff1f;其特点又有哪些呢&#xff1f; 首先&#xff0c;让我们来看一下 Web3.0 在中国市场的规…

Python3,Pandas这4种高频使用的筛选数据的方法,不得不说,确实挺好。

Pandas数据筛选方法 1、引言2、4种高频使用数据筛选方法2.1 布尔索引2.2 isin()方法2.3 query()方法2.4 loc[]方法 3、总结 1、引言 小屌丝&#xff1a;鱼哥&#xff0c;share一下 数据筛选的方法呗 小鱼&#xff1a;Excel就可以啊 小屌丝&#xff1a;我要用Pandas 小鱼&#…

0073. 矩阵置零

73. 矩阵置零 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;解法一&#xff1a;构造一个同等规模的二维数组&#xff0c;即所谓的m*n解法二&#xff1a; int row[] new int[m]; int col[] new int[n];解法三&#xff1a;常数量级 参考代码&#xff1a; 原题…

软件测试技能,JMeter压力测试教程,请求头部自动签名带上X-sign参数(二十二)

一、前言 接口请求 body 带有 sign 签名参数&#xff0c;sign 签名是根据请求 body 除去 sign 本身参数后&#xff0c;拼接请求参数最后 md5 加密生成的 前面一篇是把 sign 前面参数放到请求的 body 里面&#xff0c;这篇继续讲把签名参数放到请求头部的情况 二、实现方式 …

3Ds Max坐标轴切换,使用物体的世界坐标和本地坐标之间切换

标题&#xff1a;当挪动物体的时候想使用&#xff08;本地&#xff09;/&#xff08;世界&#xff09;坐标移动 官方文档 https://help.autodesk.com/view/3DSMAX/2023/CHS/?guidGUID-0F3E2822-9296-42E5-A572-B600884B07E3官方文档 使用“参考坐标系”列表&#xff0c;可以…

怎么把音乐的伴奏提取出来?分享几个方法给大家!

歌曲伴奏提取是一种将歌曲中的人声去除&#xff0c;获得只含伴奏的音乐文件的方法。这项技术可以广泛应用于伴唱、演奏、混音等领域。以下将详细介绍四种常用的歌曲伴奏提取方法&#xff0c;并提供记灵在线工具的使用说明&#xff0c;让您能轻松进行伴奏提取。 一、使用记灵在线…