day24_头像上传 密码加密 验证码
day24_头像上传 密码加密 验证码
1头像上传
1上传要求(文件上传)

2基础上传代码
页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input id="myfile" type="file" onchange="uploadFile()" >
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script >
// axios.post('/xxxx',xxx,{headers:{
// contentType:'multi-part/formdata'
// }})
// var formData = new FormData();
// formData.set("myfile",文件)
// axios.post("/xxxx",formData)
const uploadFile = ()=>{
//找到文件数据
let upfile = document.getElementById("myfile").files[0]
console.log(upfile)
//表单对象
var formData = new FormData();
//把文件放入表单对象(axios检测到有文件数据 会自动写请求头 multi-part/formdata)
formData.append("myfile",upfile)
formData.append("name",'jack')
//发送请求 把表单数据放入axios请求
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: UploadServlet
* @description:
* @author: gfs
* @date: 2025/8/25 9:59
* @version: 0.1
* @since: jdk17
*/
@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
* 注意: 1 需要增加 @MultipartConfig注解 让tomcat解析读取请求体中的流数据
* 2 文件对象 需要通过特殊api读取 Part myfile = req.getPart("myfile");
* 3 本地io操作 可以通过Part对象的write方法 指定路径和文件名 自动写文件
* */
System.out.println(req.getParameter("name"));
System.out.println(req.getParameter("myfile"));
//对应multipart中的 一段文件
Part myfile = req.getPart("myfile");
//写保存的路径 自动写入
myfile.write("D:\\test.png");
}
}
3.文件上传接口
1接收上传的流数据
2控制文件存储的地址(通常需要通过url访问)
还需要考虑是否允许覆盖 改变文件名 或者存储目录
3把url访问的实际路径 回传给页面 方便页面的后续数据操作
package com.javasm.controller;
import com.alibaba.fastjson.JSON;
import com.javasm.entity.Result;
import com.javasm.entity.ReturnCode;
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
* @description:
* @author: gfs
* @date: 2025/8/25 9:59
* @version: 0.1
* @since: jdk17
*/
@WebServlet("/upload")
@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
* 注意: 1 需要增加 @MultipartConfig注解 让tomcat解析读取请求体中的流数据
* 2 文件对象 需要通过特殊api读取 Part myfile = req.getPart("myfile");
* 3 本地io操作 可以通过Part对象的write方法 指定路径和文件名 自动写文件
* */
System.out.println(req.getParameter("name"));
System.out.println(req.getParameter("myfile"));
//对应multipart中的 一段文件
Part myfile = req.getPart("myfile");
//2 控制文件在服务端存储位置 文件名与目录
/*
存储文件的位置
* 1存储的文件地址
* 需要能通过网络请求访问
* 2找到运行的代码的路径
* req.getServletContext().getRealPath("/")
* 3存储的文件名
* myfile.getSubmittedFileName()
注意:如何避免文件互相覆盖
1.原文件名(不重要 可以改文件名)
2.原文件名(重要 可以改目录)
按登录的用户名 按日期 按公司信息 组合使用
* */
String realPath = req.getServletContext().getRealPath("/");
System.out.println(realPath);
//改路径
String folderPath = "imgs/";
//原文件名
String fileName = myfile.getSubmittedFileName();
//修改原文件名 组合UUID
String newFileName = UUID.randomUUID()+myfile.getSubmittedFileName().substring(myfile.getSubmittedFileName().lastIndexOf("."));
//写保存的路径 自动写入
myfile.write(realPath+folderPath+newFileName);
//3把文件查看使用的路径url 回传给界面
Result result = new Result(ReturnCode.OPERATION_DATA_SUCCESS.getCode(),ReturnCode.OPERATION_DATA_SUCCESS.getMsg(),
"http://localhost:8080/baseProj/"+folderPath+newFileName);
resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
writer.print(JSON.toJSONString(result));
writer.close();
}
}
4使用上传组件 配合上传接口
地址输入框 换成上传组件
上传组件的img标签 绑定图片地址
上传框 需要设置样式
<el-form-item label="头像地址" prop="headImg">
<!-- <el-input v-model="insertForm.headImg" /> -->
<el-upload
class="avatar-uploader"
action=""
:show-file-list="false"
:http-request="addUpload"
>
<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>
1
<style scoped>
img{
width: 50px;
height: 50px;
}
.avatar-uploader .avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
<style>
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
text-align: center;
}
</style>
通过 :http-request="addUpload" 自定义上传的js
/**上传函数 */
const addUpload = async (rawFile)=>{
//1找到文件
let curretFile = rawFile.file
//2创建formData 把文件放进去
let formData = new FormData()
formData.append("myfile",curretFile)
let resp = await axios.post("http://localhost:8080/baseProj/upload",formData)
//给上传组件 配置图片显示的路径
insertForm.headImg = resp.data.returnData
}
2密码加密
通过加密算法 把用户数据的数据 转换成密文 再与数据库中的密文对比 如果相同 表示原文相同


package com.javasm.utils;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @className: MyUtils
* @description:
* @author: gfs
* @date: 2025/8/25 11:31
* @version: 0.1
* @since: jdk17
*/
public class MyUtils {
public static String transPwd(String pwd){
String transPwd;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(pwd.getBytes());
//32位16进制字符
transPwd = new BigInteger(1, md5.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return transPwd.toUpperCase();
}
}

3验证码
操作流程中 增加流程的复杂度
1人机检测 2降低一定程度的瞬时流量 (前台系统中用的多 后台管理系统一般不用)
vue3-puzzle-vcode
安装
pnpm install vue3-puzzle-vcode --save
配置代码
<template>
<button @click="onShow">开始验证</button>
<Vcode :show="isShow" @success="onSuccess" @close="onClose" />
</template>
<script setup>
import { ref } from "vue";
import Vcode from "vue3-puzzle-vcode";
const isShow = ref(false);
const onShow = () => {
isShow.value = true;
};
const onClose = () => {
isShow.value = false;
};
const onSuccess = () => {
onClose(); // 验证成功,需要手动关闭模态框
};
</script>
改造到登录流程中
验证完输入框 直接发请求
验证完输入框 弹出验证码 验证码通过发请求
<template>
<el-card class="loginPanel" style="max-width: 399px">
<template #header>
<div class="card-header">
<img src="../assets/login.png"/>
</div>
</template>
<el-form ref="formRef" hide-required-asterisk :rules="rules" :model="loginForm" label-width="60" style="max-width: 380px">
<el-form-item label="用户名" prop="username">
<el-input v-model="loginForm.username" :suffix-icon="User"/>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input type="password" show-password v-model="loginForm.password" :suffix-icon="Lock" />
</el-form-item>
<el-form-item>
<el-button plain color="#626aef" @click="loginSubmit">登录</el-button>
<el-button plain color="#626aef" @click="loginReset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<Vcode :show="isShow" @success="onSuccess" @close="onClose" />
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { Check, Delete, Edit, Message, Search, Star, Share,User,Lock } from '@element-plus/icons-vue'
import router from '@/router'
import { ElMessage,ElMessageBox } from 'element-plus'
import {myGet,myPost} from '@/myaxios'
import Vcode from "vue3-puzzle-vcode";
/** 测试验证码... */
//控制验证码弹出框显示.隐藏
const isShow = ref(false);
//关框
const onClose = () => {
isShow.value = false;
};
//拖动成功
const onSuccess = () => {
onClose(); // 验证成功,需要手动关闭模态框
console.log("提交表单数据",loginForm);
myGet("/login",loginForm)
.then(resp=>{
console.log(resp.data);
if(resp.data.code == 10010){
ElMessage.success(resp.data.msg)
//在前端缓存数据
sessionStorage.setItem("loginUser",JSON.stringify(resp.data.returnData) )
//跳转到主页面
router.push("/main")
}else if(resp.data.code == 10011){
ElMessage.error(resp.data.msg)
}else if(resp.data.code == 10012){
ElMessage.warning(resp.data.msg)
}else if(resp.data.code == 10013){
ElMessage.info(resp.data.msg)
}
})
};
const loginForm = reactive({
username:'',
password:''
})
const formRef = ref()
const loginReset = ()=>{
formRef.value.resetFields()
}
const loginSubmit = ()=>{
formRef.value.validate((valid,fields)=>{
if(valid){
//验证通过开框
isShow.value = true
}
})
}
const rules = reactive({
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' },
],
password:[
{ required: true, message: '请输入密码', trigger: 'blur' },
{ min: 4, max: 8, message: '长度4-8位之间', trigger: 'blur' },
]
})
/*
跨域(domain)请求
当产生了 从一个网站 访问另一个网站数据 会出现跨域请求 CORS 会通知浏览器做访问限制
默认不然产生跨域数据访问
符合CORS 在服务端 设置允许访问
浏览器对跨域的限定
http:// 127.0.0.1 : 8080
协议 地址 端口号
浏览器自动发送预检请求 method options 检测响应头 是否符合CORS要求
通过后会缓存一定事件
*/
// onMounted(()=>{
// myGet("/login",{username:'aa',password:'bbb'})
// })
</script>
<style scoped>
/* scoped只对当前vue文件生效 */
.loginPanel {
margin: 300px auto;
background-color: rgba(219, 219, 219, 0.541);
}
</style>
4监听器
JAVAEE中监听器
域对象
request
session
servletContext 服务器对象
围绕对象的生命中后期监控
ServletContextListener 一般用在服务器启动时 加载第三方工具和启动资源上
package com.javasm.listener;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.InputStream;
/**
* @className: MyListener1
* @description:
* @author: gfs
* @date: 2025/8/25 15:05
* @version: 0.1
* @since: jdk17
*/
@WebListener
public class MyBatisHealperPro implements ServletContextListener {
private static SqlSessionFactory sqlSessionFactory;
@Override
public void contextInitialized(ServletContextEvent sce) {
//服务器对象创建了
System.out.println("contextInitialized.......");
try{
//创建mybatis公共对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
//SqlSession sql会话
//SqlSessionFactory sql会话 工厂 mybatis全局对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//获得连接
public static SqlSession getSqlSession(){
SqlSession sqlSession = sqlSessionFactory.openSession();
return sqlSession;
}
//归还连接
public static void backSqlSession(SqlSession sqlSession){
sqlSession.close();
}
//提交事务 归还连接
public static void backAndSaveSqlSession(SqlSession sqlSession){
sqlSession.commit();
sqlSession.close();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
//服务器对象销毁了
System.out.println("contextDestroyed.......");
}
}
5版本控制工具

操作说明
1.配置idea中 版本控制插件


注意 检查有没有svn.exe
如果没有 重新安装 勾选命令行 继续安装


2导出项目
服务器先放一份项目代码

通过idea导出


3设置忽略列表



注意: 忽略时 尽量不要用扩展名 指定目录 或指定文件
4文件操作过程 提交更新 处理冲突


注意: 删除文件操作 要提交 其他要更新
目录名 文件名 提交定好 不要随便改 删除+新增
修改了代码 目录结构 新增了文件 删除了文件 都需要提交
更新代码

一般以目录 更新
冲突情况

处理冲突 先更新

merge界面

确定后 改好新版本 可以提交了

浙公网安备 33010602011771号