引出
在之前的jsp版本的登陆和注册中,如下面博客:
Java网络开发(Tomcat)—— 登陆 和 注册功能 的实现 & 从html 到 jsp 迭代升级 & session保存登陆信息
本质是用同步请求实现登陆和注册功能,在学习Js+axios+vue之后,就可以用异步的方式来实现登陆,主要博客如下:
Java网络开发(Asynchronous)—— 从 Jsp 到 Ajax 的 axios 到 vue & 同步请求 到 异步请求
前端基础(JavaScript)——基础语法(变量,分支…)& Json对象【重要】& 函数定义 & 事件
前端基础(Vue)——基础语法({{}}, v-model, :src=“imagSrc“, v-for)& 事件@click & 属性和方法(this.add() + this.name)
前置工作vue+axios+resp
0.vue版本的jsp模板
要点:head导包;div框+id;script里写逻辑
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/vue.min-v2.5.16.js"></script>
</head>
<body>
<div id="app">
</div>
<script>
let app = new Vue({
// 选择操作的div区域
el:"#app",
// 数据区
data:{},
// 方法区
methods:{},
// 文档加载之后就执行
created(){},
// 整个页面全部加载完成后再执行
mounted(){},
})
</script>
</body>
</html>
带有axios请求的vue框架:
<script>
let app = new Vue({
el:"#app",
data:{
bookTypeList:[]
},
methods(){},
// 文档加载之后就执行
created(){
axios.get("/day06/types/list/vue")
.then(response=>{
console.log(response)
let resp = response.data;
console.log(resp);
this.bookTypeList=resp.data;
},error=>{
console.log(error)
})
},
})
</script>
1.导包–Json:pom.xml文件:
<!-- fastjson包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
2.新建一个专门用来处理响应的实体类ResData
package com.tianju.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 响应的实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResData {
// 返回码,200正常,10001参数错误。。。
private Integer code;
// 正常标识,success,ok
private String msg;
// 具体的信息,可以是对象
private Object data;
}
3.在axios中,所有响应必须是 resp.getWriter().write() 的方式,核心代码如下
resp.getWriter().write(JSON.toJSONString(new ResData(1001, "输入为空", null)));
4.在jsp前端代码中导包:
<head>
<title>用户登陆页面e</title>
<%-- 如果没有加day06--%>
<%-- bug--%>
<link rel="stylesheet" href="/day06/bootstrap/css/bootstrap.css">
<script src="/day06/js/axios.min.js"></script>
<script src="/day06/js/jquery-3.5.1.js"></script>
<script src="/day06/bootstrap/js/bootstrap.js"></script>
<script src="/day06/js/vue.min-v2.5.16.js"></script>
</head>
5.删除form表单,把页面都放在div框里,并且加上id=“app”
<div id="app">
用户名:<input type="text" v-model="username"><br>
密 码:<input type="password" v-model="password"><br>
<span style="color: darkred">{{msg}}</span><br>
<button @click="login">登陆</button>
<button @click="reset">重置</button>
</div>
6.在script中写逻辑
<script>
let app = new Vue({
el:"#app",
data:{},
methods:{},
})
</script>
登陆功能+保存登陆的用户名
登陆功的代码如下:
1.前端代码,loginVue.jsp文件 & 保存登陆用户名
- localStorage.setItem(“username”,resp.data)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户登陆页面e</title>
<%-- 如果没有加day06--%>
<%-- bug--%>
<link rel="stylesheet" href="/day06/bootstrap/css/bootstrap.css">
<script src="/day06/js/axios.min.js"></script>
<script src="/day06/js/jquery-3.5.1.js"></script>
<script src="/day06/bootstrap/js/bootstrap.js"></script>
<script src="/day06/js/vue.min-v2.5.16.js"></script>
</head>
<body>
<%--如果忘记删除form表单--%>
<%--bug--%>
<div id="app">
用户名:<input type="text" v-model="username"><br>
密 码:<input type="password" v-model="password"><br>
<span style="color: darkred">{{msg}}</span><br>
<button @click="login">登陆</button>
<button @click="reset">重置</button>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
username:"",
password:"",
msg:""
},
methods:{
login(){
let params = new URLSearchParams();
params.append("username",this.username);
params.append("password",this.password)
axios.post("/day06/comUser/login/vue",params)
.then(response=>{
console.log(response);
console.log(response.data);
let resp=response.data;
if (resp.code==200)
{
alert(resp.msg);
localStorage.setItem("username",resp.data)
location.href = "/day06/company/messList"
}
else
{
this.msg=resp.msg;
}
})
},
reset(){
this.username="";
this.password="";
this.msg=""
}
}
})
</script>
</body>
</html>
2.后端代码如下,LoginServlet.java文件:
package com.tianju.servlet.comUser;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.tianju.entity.ComUser;
import com.tianju.entity.ResData;
import com.tianju.service.IComUserService;
import com.tianju.service.impl.ComUserServiceImpl;
import com.tianju.util.StringUtils;
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;
/**
* 用户登陆的servletVue
*/
@WebServlet("/comUser/login/vue")
public class LoginServletVue extends HttpServlet {
private IComUserService comUserService = new ComUserServiceImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 输入不为空
String username = req.getParameter("username");
String password = req.getParameter("password");
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)){
resp.getWriter().write(JSON.toJSONString(
new ResData(1001, "输入为空", null)));
return;
}
// 进行验证
ComUser comUser = comUserService.queryByUsername(username);
if (comUser==null || !comUser.getPassword().equals(SecureUtil.md5(password))){
resp.getWriter().write(JSON.toJSONString(new ResData(1002, "用户名 | 密码错误", null)));
return;
}
// ++++++登陆成功的用户对象存储到session中=====用户确定后续的操作是谁做的
req.getSession().setAttribute("user", comUser);
resp.getWriter().write(JSON.toJSONString(new ResData(200, "ok", comUser.getUsername())));
}
}
3.然后在index页面显示登陆的用户名
欢迎您:
<%--这个改成vue的 --%>
<%--${sessionScope.user.username}--%>
{{username}}
核心代码如下:
<script>
let app = new Vue({
el:"#app",
data:{
username:"",
},
methods:{},
created(){
this.username=localStorage.getItem("username")
}
})
</script>
注册功能
1.前端代码registerVue.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户注册页面</title>
<link rel="stylesheet" href="/day06/bootstrap/css/bootstrap.css">
<script src="/day06/js/axios.min.js"></script>
<script src="/day06/js/jquery-3.5.1.js"></script>
<script src="/day06/bootstrap/js/bootstrap.js"></script>
<script src="/day06/js/vue.min-v2.5.16.js"></script>
</head>
<body>
<div id="app">
用户名:<input type="text" v-model="username"><br>
密 码:<input type="text" v-model="password"><br>
确认密码:<input type="text" v-model="rePassword"><br>
性 别:
男<input type="radio" v-model="gender" value="男">
女<input type="radio" v-model="gender" value="女"><br>
出生日期:<input type="date" v-model="birthday"><br>
<%-- 如果要让验证码在点击时自动更新--%>
验证码:<input type="text" v-model="imgCode">
<img :src="imgsrc" @click="imgbtn">
<br>
<span style="color: darkred">{{msg}}</span><br>
<button @click="register">注册</button>
<button @click="reset">重置</button>
<a href="/index.jsp">退出</a>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
username:"",
password:"",
rePassword:"",
gender:"",
birthday:"",
imgCode:"",
msg:"",
imgsrc:"/day06/register/image/get",
},
methods:{
register(){
let params = new URLSearchParams();
params.append("username",this.username);
params.append("password",this.password);
params.append("rePassword",this.rePassword);
params.append("gender",this.gender);
params.append("birthday",this.birthday);
params.append("imgCode",this.imgCode);
console.log(params);
axios.post("/day06/comUser/register/vue",params)
.then(response=>{
console.log(response);
console.log(response.data);
let resp = response.data;
if (resp.code==200)
{
alert("登陆成功");
// 保存登陆到local
localStorage.setItem("username",this.username);
// 跳转到index
location.href = "/day06/compMess/list.jsp";
}
else if (resp.code==1002){
// 更新一下验证码
this.imgbtn();
this.msg=resp.msg;
}
else
{
this.msg=resp.msg;
}
})
},
reset() {
this.username="";
this.password="";
this.rePassword="";
this.gender="";
this.birthday="";
this.imgCode="";
this.msg="";
},
imgbtn(){
// 切换图片
this.imgsrc = '/day06/register/image/get?'+new Date().getMilliseconds();
}
}
})
</script>
</body>
</html>
2.后端代码RegisterServletVue.java
package com.tianju.servlet.comUser;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.tianju.entity.ComUser;
import com.tianju.entity.ResData;
import com.tianju.service.IComUserService;
import com.tianju.service.impl.ComUserServiceImpl;
import com.tianju.util.StringUtils;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* 用vue版本的注册的servlet
*/
@WebServlet("/comUser/register/vue")
public class RegisterServletVue extends HttpServlet {
private IComUserService comUserService = new ComUserServiceImpl();
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 用户注册的业务逻辑
String username = req.getParameter("username");
String password = req.getParameter("password");
String rePassword = req.getParameter("rePassword");
String sex = req.getParameter("gender");
String birthday = req.getParameter("birthday");
System.out.println(username+password+rePassword+sex+birthday);
// +++加入+验证码输入
String imgCode = req.getParameter("imgCode");
// 1.输入不为空;
if (StringUtils.isBlank(username)
|| StringUtils.isBlank(password)
|| StringUtils.isBlank(rePassword)
|| StringUtils.isBlank(sex)
|| StringUtils.isBlank(birthday)
|| StringUtils.isBlank(imgCode)){
resp.getWriter().write(JSON.toJSONString(
new ResData(1001, "输入为空", null)));
return;
}
// +++++判断验证码是否正确
HttpSession session = req.getSession();
// 从session中获取验证码
String yzm = (String)session.getAttribute("yzm");
// 忽略大小写 .equalsIgnoreCase
if (!yzm.equalsIgnoreCase(imgCode)){
resp.getWriter().write(JSON.toJSONString(
new ResData(1002, "验证码不正确", null)));
return;
}
// 2.用户名不重复;
ComUser comUserDb = comUserService.queryByUsername(username);
if (comUserDb!=null){
resp.getWriter().write(JSON.toJSONString(
new ResData(1003, "用户名重复", null)));
return;
}
// 3.两次密码输入一致;
if (!password.equals(rePassword)){
// 两次密码不一致
resp.getWriter().write(JSON.toJSONString(
new ResData(1004, "两次密码输入不一致,请检查", null)));
return;
}
// 进行密码加密存储
ComUser comUser = new ComUser();
comUser.setPassword(SecureUtil.md5(password));
comUser.setUsername(username);
try {
comUser.setBirthday(sdf.parse(birthday));
} catch (ParseException e) {
throw new RuntimeException(e);
}
comUser.setSex(sex);
System.out.println(comUser);
// 4.保存信息到数据库
comUserService.add(comUser);
// 5.注册成功跳转到登陆页面
resp.getWriter().write(JSON.toJSONString(
new ResData(200, "注册成功", null)));
}
}
附录:Vue+Axios遇到的bug汇总
1.导包失败net:ERR ABORTED 404
报错信息:
GET http://localhost:8080/bootstrap/css/bootstrap.css net:ERR ABORTED 404
2.未定义错误msg is not defined,data写成date
报错信息:ReferenceError:msg is not defined
另一种情况,不太好找:
3.之前的form表单没有删
导致发送两次请求
4.没有加this,报未定义异常imgbtn is not defined
Uncaught (in promise) ReferenceError: imgbtn is not defined
5.post请求没加上下文,POST请求404,Uncaught (in promise)
报错信息:
http://localhost:8080/comUser/register/vue 404
Uncaught (in promise)
{message:‘Request failed with status code 404’,name:‘AxiosError’,
6.let app = new Vue没有加new
报错信息:
vue.min-v2.5.16.js:6 Uncaught TypeError: Cannot read properties of undefined (reading ‘_init’)
7.一个没有报错信息的bug–应该写在created里
8.一个报错定位不清楚的bug
报错信息:
Uncaught TypeError: e.bind is not a function
9.一个一堆人找了半天的bug:value写成vlaue
同上,不太好找的bug
10.属性里面写了插值表达式【困扰】
问题描述:
前端没有list页面数据,但是前端拿到了后端的响应数据,而且前端没有报错,原因是属性里面写了插值表达式
<%-- TODO:属性里面不能写插值表达式,也不报错--%>
<button @click="remove({{opus.id}})" class="btn btn-warning btn-sm">删除</button>
解决方案:不要加插值表达式
<button @click="remove(opus.id)" class="btn btn-danger btn-sm">删除</button>
修改后果然出现了
总结
1.vue+axios前端固定格式,后端必须用resp.getWriter().write() ;
2.localStorage的应用,保存登陆成功的用户名;
3.登陆和注册功能的异步实现,JavaScript + axios + vue + resp;
4.遇到的诸多bug汇总,