毕设小结(四)

有关于菜单权限分配和文件的上传下载功能

菜单权限分配

实现效果

1.png

逻辑分析

数据库分为角色表,菜单表,和角色菜单关联表
菜单表需要自己的id生成子id来调用自己,这样来形成2级菜单
2.png
角色表
3.png
角色菜单关系表
4.png

查询菜单列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
1.点击选择菜单按钮,前端获取当前的roleid和roleflag ,设置roleId和roleFlag
this.roleId = role.id
this.roleFlag = role.flag
2.请求后端数据,发送请求,获取菜单数据
this.request.get("/menu").then(res => {
this.menuData = res.data
// 把后台返回的菜单数据处理成 id数组
this.expends = this.menuData.map(v => v.id)
console.log(expends)
})
@GetMapping
public Result findAll(@RequestParam(defaultValue = "") String name) {
return Result.success( menuService.findMenus(name));
}

@Override
public List<Menu> findMenus(String name) {

QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
if (StrUtil.isNotBlank(name)) {
queryWrapper.like("name", name);
}
//查询所有数据
List<Menu> list = list(queryWrapper);
//找出pid为null的一级菜单
List<Menu> parentNodes = list.stream().filter(menu -> menu.getPid() == null).collect(Collectors.toList());
//找出一级菜单的子菜单
for (Menu menu : parentNodes) {
//筛选所有数据中pid=父级的id就是二级菜单
menu.setChildren(list.stream().filter(m -> menu.getId().equals(m.getPid())).collect(Collectors.toList()));
}
return parentNodes;
}

前端渲染

发送请求,获取角色和菜单之间的关系,并且渲染成一个树形表
角色和菜单之间的关系,维护在一张表中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
this.request.get("/role/roleMenu/" + this.roleId).then(res => {
//后端根据roleid查询menuid并且返回一个列表
this.checks = res.data
//判断列表项中是否包含查询到的id,如果不是就设置不选中
this.ids.forEach(id => {
if (!this.checks.includes(id)) {
// 可能会报错:Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'setChecked')
this.$nextTick(() => {//使用$nextTick来处理未来元素,等元素渲染了,再来
this.$refs.tree.setChecked(id, false)
})
}
})
this.menuDialogVis = true//先渲染弹窗
})
//nextTick里面的代码会在DOM更新后执行

文件上传

前端页面点击上传按钮,向后端发送请求,后端先生成文件信息上传到磁盘,再存储到数据库。返回文件的url地址。

文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@Value("${files.upload.path}")
private String fileuploadPath;

@PostMapping("/upload")
public String upload(@RequestParam MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
String type = FileUtil.extName(originalFilename);
long size = file.getSize();
//定义一个文件的标识码
String uuid = IdUtil.fastSimpleUUID();
String fileUuid = uuid + StrUtil.DOT + type;
File file1 = new File(fileuploadPath + fileUuid);
//判断配置的文件夹是否存在,没有则创建
File parentFile=file1.getParentFile();
if(!parentFile.exists()){
parentFile.mkdirs();
}
String url;
//先上传到磁盘
File uploadFile = new File(fileuploadPath);
file.transferTo(file1);
//获取文件的MD5
String md5 = SecureUtil.md5(file1);
//从数据库中查询是否有相关记录
Files one = getFileByMD5(md5);
if (one != null) {
url = one.getUrl();
//由于文件存在,所以删除刚刚上传的
file1.delete();
}else {
//数据库不存在则,不删除
url = "http://localhost:9091/file/" + fileUuid;
}

//存储数据库
Files files = new Files();
files.setName(originalFilename);
files.setType(type);
files.setUrl(url);
files.setSize(size / 1024);
// files.setIsDelete(true);
// files.setEnable(true);
files.setMd5(md5);
fileMapper.insert(files);
//返回图片的url地址
return url;
}
//MD5方法
private Files getFileByMD5(String md5) {
QueryWrapper<Files> queryWrapper = new QueryWrapper();
queryWrapper.eq("md5", md5);
List<Files> filesList = fileMapper.selectList(queryWrapper);
return filesList.size()==0?null:filesList.get(0);
}
//insert方法
@PostMapping("/insert")
public Result save(@RequestBody Files files) {
return Result.success(fileService.updateById(files));
}


文件下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//文件下载
@GetMapping("/{fileUuid}")
public void download(@PathVariable String fileUuid, HttpServletResponse response) throws IOException {
//根据文件uuid获取文件
File file = 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(file));
os.flush();
os.close();
}