day22_用户授权 头像上传
1用户授权
场景分析

sql分析
-- 展示树型菜单 和 根据用户编号选中已有菜单选项
select am2.*,
am1.mid as submid,am1.menuname as submenuname,am1.url as suburl
from admin_menu am1 inner join admin_menu am2 on am1.pid = am2.mid
select mid from rel_admin_user_menu where uid = 7
-- 删除旧的权限信息 添加新的信息
delete from rel_admin_user_menu where uid = 3
insert into rel_admin_user_menu (uid,mid) values (3,11001),(3,12001),(3,13001)
编码
调用多个dao时 需要注意事务控制
@Override
public Boolean changeUserMid(Long uid, List<Long> listMid) {
//未开启自动提交
SqlSession sqlSession = MyBatisHealper.getSqlSession();
AdminMenuDao mapper = sqlSession.getMapper(AdminMenuDao.class);
Boolean flag = false;
try{
//需要一起成功 再提交
mapper.deleteUserMId(uid);
//如果listMid没值 跳过添加环节
if(listMid.size()>0){
mapper.insertUserMId(uid,listMid);
}
//成功再提交
sqlSession.commit();
flag = true;
} catch (Exception e) {
//异常 不提交
throw new RuntimeException(e);
}finally {
//只还连接
//自动回滚
MyBatisHealper.backSqlSession(sqlSession);
return flag;
}
}
tree组件
<el-tree
ref="treeRef"
style="max-width: 600px"
:data="treeData.treeList"
show-checkbox
default-expand-all
node-key="mid"
highlight-current
:props="defaultProps"
/>
//tree组件对象
const treeRef = ref()
//tree组件数据
const treeData = reactive({treeList:[]})
//默认key value 对应关系
const defaultProps = {
children: 'subMenu',
label: 'menuname',
}
tree组件混合form使用
const authVisable = ref(false)
const authForm = reactive({
username:'',
uid:'',
listMid:''
})
//授权开框
const openAuthDialog = async(currentRow)=>{
console.log(currentRow);
// 打开授权对话框
authVisable.value = true
//uid和usernmae赋值
authForm.username = currentRow.username
authForm.uid = currentRow.uid
//tree组件展示和赋值
let resp = await myGet('/users/listAllMenuByUId',{uid:currentRow.uid})
console.log(resp.data.returnData);
//tree组件赋值
treeData.treeList = resp.data.returnData.listAllMenu
//tree组件选中选项
treeRef.value.setCheckedKeys(resp.data.returnData.listMId)
}
//授权提交
const authSubmit = async ()=>{
//把选中的菜单编号 给authForm赋值
authForm.listMid = treeRef.value.getCheckedKeys(true).join(",")
// 关授权对话框
authVisable.value = false
//操作数据公共函数
operationData('/users/changeUserMid',authForm)
}
2文件上传

前端发送文件的基本要求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input id="myFile" type="file" onchange="testSend()">
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
/*
* 1 使用文件框选文件
* 2 文件放入FormData对象中 支持字符串key value 支持文件 key blob
* 3 通过post请求发送FormData
*
* */
const testSend = ()=>{
let currentFile = document.getElementById("myFile").files[0]
console.log(currentFile)
let formData = new FormData();
//在请求体中的key
formData.append("myFile",currentFile)
axios.post("/baseProj/upload",formData)
}
</script>
</html>


服务端接收和保存
package com.javasm.controller;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
/**
* @className: UploadDemoServlet
* @author: gfs
* @date: 2025/10/30 14:33
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebServlet("/upload")
//解析字节数据
@MultipartConfig
public class UploadDemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.接收
//取到文件对象
Part myFile = req.getPart("myFile");
System.out.println(myFile.getSize());
System.out.println(myFile.getSubmittedFileName());
//2保存
//向本地写文件
myFile.write("d:\\"+myFile.getSubmittedFileName());
}
}
2.1存到本地 可以访问的目录

上传接口
package com.javasm.controller;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.ReturnResult;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @className: UploadDemoServlet
* @author: gfs
* @date: 2025/10/30 14:33
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebServlet("/upload")
//解析字节数据
@MultipartConfig
public class UploadDemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.接收
//取到文件对象
Part myFile = req.getPart("myFile");
System.out.println(myFile.getSize());
System.out.println(myFile.getSubmittedFileName());
//2保存
//获取部署的根目录
String basePath = req.getServletContext().getRealPath("/");
System.out.println(basePath);
//存入指定目录
String folderName = "uploadTest/";
//向本地写文件
myFile.write(basePath+folderName+myFile.getSubmittedFileName());
ReturnResult returnResult = new ReturnResult();
returnResult.setCode(ReturnCode.DATA_OPERATION_SUCCESS.getCode());
returnResult.setMsg(ReturnCode.DATA_OPERATION_SUCCESS.getMsg());
//返回前端显示时使用的路径
returnResult.setReturnData("http://localhost:8080/baseProj/"+folderName+myFile.getSubmittedFileName());
//输出json数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(returnResult));
writer.close();
}
}
防止文件重复的策略
//防止文件重复
//1 文件名不重要 配合UUID 重置文件名
//2 改目录名 读登录的用户信息 或者时间戳 建出不同的目录
package com.javasm.controller;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.ReturnResult;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;
/**
* @className: UploadDemoServlet
* @author: gfs
* @date: 2025/10/30 14:33
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebServlet("/upload")
//解析字节数据
@MultipartConfig
public class UploadDemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.接收
//取到文件对象
Part myFile = req.getPart("myFile");
System.out.println(myFile.getSize());
System.out.println(myFile.getSubmittedFileName());
//2保存
//获取部署的根目录
String basePath = req.getServletContext().getRealPath("/");
System.out.println(basePath);
//防止文件重复
//1 文件名不重要 配合UUID 重置文件名
//2 改目录名 读登录的用户信息 或者时间戳 建出不同的目录
//存入指定目录
String folderName = "uploadTest/";
//文件名
String newFileName = UUID.randomUUID()+myFile.getSubmittedFileName().substring(myFile.getSubmittedFileName().lastIndexOf(".")); // myFile.getSubmittedFileName();
//向本地写文件
myFile.write(basePath+folderName+newFileName);
ReturnResult returnResult = new ReturnResult();
returnResult.setCode(ReturnCode.DATA_OPERATION_SUCCESS.getCode());
returnResult.setMsg(ReturnCode.DATA_OPERATION_SUCCESS.getMsg());
//返回前端显示时使用的路径
returnResult.setReturnData("http://localhost:8080/baseProj/"+folderName+newFileName);
//输出json数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(returnResult));
writer.close();
}
}
存本地的接口
package com.javasm.controller;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.ReturnResult;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;
/**
* @className: UploadServlet
* @author: gfs
* @date: 2025/10/30 15:02
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.取文件
Part myFile = req.getPart("myFile");
//2.拼出保存到本地的路径
String basePath = req.getServletContext().getRealPath("/");
String folderName = "uploadTest/";
String newFileName = UUID.randomUUID()+myFile.getSubmittedFileName().substring(myFile.getSubmittedFileName().lastIndexOf(".")); // myFile.getSubmittedFileName();
//保存到本地
myFile.write(basePath+folderName+newFileName);
//3.给页面操作反馈和预览地址
String domain = "http://localhost:8080/baseProj/";
ReturnResult returnResult = new ReturnResult();
//返回操作成功
returnResult.setCode(ReturnCode.DATA_OPERATION_SUCCESS.getCode());
returnResult.setMsg(ReturnCode.DATA_OPERATION_SUCCESS.getMsg());
//返回前端显示时使用的路径
returnResult.setReturnData(domain+folderName+newFileName);
//输出json数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(returnResult));
writer.close();
}
}
2.2上传头像的页面
把上传组件替换之前的输入框
<el-form-item label="头像地址" prop="headImg">
<!-- <el-input v-model="insertForm.headImg" /> -->
<el-upload
class="avatar-uploader"
action=""
:show-file-list="false"
:http-request="myUpload"
>
<img v-if="insertForm.headImg" :src="insertForm.headImg" class="avatar" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
</el-form-item>
配合一个自定义上传和响应处理的函数
/**添加上传头像 */
const myUpload = async (rowFile)=>{
console.log(rowFile);
//获取上传文件
let myFile = rowFile.file
//创建formData对象
let formData = new FormData();
formData.append('myFile',myFile);
//发送post请求
let resp = await axios.post("/upload",formData)
insertForm.headImg = resp.data.returnData
}
2.3存到云存储


通过服务器传

七牛云工具类
accessKey和secretKey


bucketName 空间名

外网临时域名(有效期30天 免费)

package com.javasm.utils;
import com.alibaba.fastjson.JSON;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import javax.servlet.http.Part;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @className: QiniuUtils
* @author: gfs
* @date: 2025/10/30 15:59
* @version: 0.1
* @since: jdk17
* @description:
*/
public class QiniuUtils {
//根据登录的账号和使用的空间配置
private static final String accessKey = "t0oUPjPwjqQiS2EM3vm5FIIGI8InWKOOXeNnFpZg";
private static final String secretKey = "66Hd-TKVVbwRrHSTtiQqE8i8L-VOsUaJ1iWTO8rv";
private static final String bucketName = "javasm69test";
private static final String domain = "http://t4xpuhvhc.hn-bkt.clouddn.com/";
/**
* 获取七牛token,返回给客户端
*
* @return
*/
public static String getToken() {
//校验 AK 和 SK 是否正确
Auth auth = Auth.create(accessKey, secretKey);
//生成 服务端 Token
String token = auth.uploadToken(bucketName);
return token;
}
/**
* 返回域名
*
* @return
*/
public static String getDomain() {
return domain;
}
public static String upload(String filePath) {
return upload(new File(filePath));
}
public static String upload(File file) {
//构造一个带指定 Region 对象的配置类
/**
* 华东 Region.region0(), Region.huadong()
* 华北 Region.region1(), Region.huabei()
* 华南 Region.region2(), Region.huanan()
* 北美 Region.regionNa0(), Region.beimei()
* 东南亚 Region.regionAs0(), Region.xinjiapo()
*/
Configuration cfg = new Configuration(Region.region2());
cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
UploadManager uploadManager = new UploadManager(cfg);
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = null;
String upToken = getToken();
try {
Response response = uploadManager.put(file, key, upToken);
//解析上传成功的结果
DefaultPutRet putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class);
return domain + putRet.hash;
} catch (QiniuException ex) {
ex.printStackTrace();
}
return null;
}
public static String uploadStream(InputStream is,String key) {
//构造一个带指定 Region 对象的配置类
/**
* 华东 Region.region0(), Region.huadong()
* 华北 Region.region1(), Region.huabei()
* 华南 Region.region2(), Region.huanan()
* 北美 Region.regionNa0(), Region.beimei()
* 东南亚 Region.regionAs0(), Region.xinjiapo()
*/
Configuration cfg = new Configuration(Region.region2());
cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
UploadManager uploadManager = new UploadManager(cfg);
//默认不指定key的情况下,以文件内容的hash值作为文件名
String upToken = getToken();
key = null;
try {
Response response = uploadManager.put(is, key, upToken,null,null);
//解析上传成功的结果
DefaultPutRet putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class);
return domain + putRet.hash;
} catch (QiniuException ex) {
ex.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String fileName = "D:\\尚马壁纸-03.png";
String upload = QiniuUtils.upload(fileName);
System.out.println(upload);
}
}
java上传接口
package com.javasm.controller;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.ReturnResult;
import com.javasm.utils.QiniuUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.UUID;
/**
* @className: UploadServlet
* @author: gfs
* @date: 2025/10/30 15:02
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebServlet("/upload2")
@MultipartConfig
public class UploadServlet2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.取文件
Part myFile = req.getPart("myFile");
//上传文件的流数据
InputStream inputStream = myFile.getInputStream();
//2存储到七牛云存储中
String filePath = QiniuUtils.uploadStream(inputStream, null);
System.out.println(filePath);
//3.给页面操作反馈和预览地址
ReturnResult returnResult = new ReturnResult();
//返回操作成功
returnResult.setCode(ReturnCode.DATA_OPERATION_SUCCESS.getCode());
returnResult.setMsg(ReturnCode.DATA_OPERATION_SUCCESS.getMsg());
//返回前端显示时使用的路径
returnResult.setReturnData(filePath);
//输出json数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(returnResult));
writer.close();
}
}
直接从前端传

java接口 只传token和domain
package com.javasm.controller;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.ReturnCode;
import com.javasm.entity.ReturnResult;
import com.javasm.utils.QiniuUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
/**
* @className: GetQiniuToken
* @author: gfs
* @date: 2025/10/30 16:19
* @version: 0.1
* @since: jdk17
* @description:
*/
@WebServlet("/getQiniuToken")
public class GetQiniuToken extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String token = QiniuUtils.getToken();
String domain = QiniuUtils.getDomain();
//3.给页面操作反馈和预览地址
ReturnResult returnResult = new ReturnResult();
//返回操作成功
returnResult.setCode(ReturnCode.QUERY_SUCCESS.getCode());
returnResult.setMsg(ReturnCode.QUERY_SUCCESS.getMsg());
//返回前端显示时使用的路径
HashMap<String, String> dataMap = new HashMap<>();
dataMap.put("token",token);
dataMap.put("domain",domain);
returnResult.setReturnData(dataMap);
//输出json数据
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(returnResult));
writer.close();
}
}
前端 安装依赖
pnpm i qiniu-js@^3.4.2
页面需要使用时 引入js
import * as qiniu from 'qiniu-js'
上传方法改造
// 直接上传到七牛云存储
const myUpload3 = async (rowFile)=>{
//访问自己的接口 获取token和domain
let resp = await axios.get("/getQiniuToken")
let token = resp.data.returnData.token;
let domain = resp.data.returnData.domain;
console.log(token,domain);
//设置七牛云存储对象
// //获取上传文件
let myFile = rowFile.file
let observable = qiniu.upload(myFile,null,token);
//上传的一些设置
let options = {
//上传过程中
next: (res)=>{
//console.log(res)
},
//上传错误
error: (err)=> {console.log(err)},
//上传成功
complete: (res)=>{
console.log("----------------------------上传成功-------------------------")
console.log(res)
updateForm.updateData.headImg = domain+res.hash
}
}
//实际上传的方法
observable.subscribe(options);
}