day22_用户授权 头像上传
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.midselect 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时 需要注意事务控制
@Overridepublic 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-treeref="treeRef"style="max-width: 600px":data="treeData.treeList"show-checkboxdefault-expand-allnode-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.usernameauthForm.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();//在请求体中的keyformData.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 {
@Overrideprotected 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 {
@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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-uploadclass="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);//生成 服务端 TokenString 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 {@Overrideprotected 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 {@Overrideprotected 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和domainlet resp = await axios.get("/getQiniuToken")let token = resp.data.returnData.token;let domain = resp.data.returnData.domain;console.log(token,domain);//设置七牛云存储对象// //获取上传文件let myFile = rowFile.filelet 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); }
