登录业务
1. 登录业务
- 有两个页面: 登录页面, 首页(html)
- 业务:
- Servlet 解析请求数据
2. 页面跳转
2.1 客户端
html: <a href="跳转的路径">
链接标签, 点击跳转
js代码: window.location.href = "跳转路径";
2.2 服务端
服务端Servlet跳转页面:
- 转发
- 重定向
2.2.1 转发:
服务算Servlet转发到home.html:
-
url路径没有变
-
只有一次http请求
2.2.2 重定向:
- 请求路径:
- 请求后的路径
(1) url会发生变化
(2) 两次http请求
- 第一次http请求: 响应: 301/302/307 表示重定向的状态码Location的头信息, 指定要跳转的url
- 第二次http请求: 由浏览器解析第一次响应, 发现是 3xx 状态码,就会自动跳转到Location绑定的url地址
2.3 客户端 + 服务端
客户端js代码发送ajax异步请求
使用主流前端框架实现 Vue.js(前端js框架, dom元素和变量等双向绑定) + axios(发ajax框架)
请求数据, 响应数据格式: json(Content-Type绑定的body中的数据类型)
服务端基于json的格式来解析请求/ 返回响应
3. 关于json
- 前段有json对象:
var person = {firstName:"John", lastName:"Doe", age:50, eyeColor:"blue"};
- 请求/响应数据(body), 也可以是 json
此时Content-Type 值为 application/json
java 代码完成对象和 json 字符串转变为 java 对象
- 反序列化, 把json 字符串转变为 java 对象
// 反序列化. 把json 字符串转变为 java 对象
String s ="{\"username\":\"猴哥和我\",\"password\":\"救救我\"}";
User u2 = mapper.readValue(s, User.class);
- 序列化, 把 java对象转变为 json 对象
// 序列化, 把 java对象转变为 json 对象
String json = mapper.writeValueAsString(user);
4. 关于 Vuejs 框架使用
对于HttpServletRequest, 回去请求数据:
- queryString: getParameter 通过键获取值
- Content-Type 为 x-www-form-urlencoded (表单数据类型) ,
body格式和queryString一样, 也通过getParameter获取 - 请求体 (body) 由数据, 此时 Content-Type 一定要指定数据类型
- 后端都可以通过 request.getInputStream() 获取输入流 (包含 body 内容), 只是要自己去解析 body
(表单格式相对来说, getParameter要更方便)
application/json: 使用 json 框架来解析
文件上传: 把输入流二进制获取就是获取文件
关于响应
5. 其他
登录页面 + 后端登录功能, 存在问题?
- 访问敏感资源(前端的敏感资源, 后端的敏感资源)
未登录不允许访问:
前段页面 | 跳转到登录页面 |
---|---|
后端接口(Servlet) | 返回 401 状态码 (Unauthorized未授权访问)/ 返回json数据 |
- 技术实现:
Session 和 Cookie
目前比较好的解决方案: Filter
其他方案:
(1)提供一个校验用户是否登录的接口, 每次前段都请求
(2)每个Servlet都去验证一下用户是否登录
6. 代码
Main
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
public static void main(String[] args) throws JsonProcessingException {
// 序列化, 把 java对象转变为 json 对象
ObjectMapper mapper = new ObjectMapper();
User user = new User();
user.setUsername("猴哥");
user.setPassword("救救我");
String json = mapper.writeValueAsString(user);
System.out.println(json);
// 反序列化. 把json 字符串转变为 java 对象
String s ="{\"username\":\"猴哥和我\",\"password\":\"救救我\"}";
User u2 = mapper.readValue(s, User.class);
System.out.println(u2);
// 反序列化, json键必须对应类中的成员变量, 找不到就会报错
// String s3 = "{\" username1\":\"猴哥和你\",\"password\":\"救救我\"}";
// User u3 = mapper.readValue(s3, User.class);
// System.out.println(u3);
}
}
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<h2>登录页面</h2>
<form action="login" method="post">
用户名:<input type="text" name="username">
<br><br>
密码:<input type="password" name="password">
<br><br>
<input type="submit" value="登录">
</form>
<br><br>
<!--绑定按钮的点击事件, 在用户点击时, 调用绑定的js函数 -->
<!--js 方式跳转 -->
<button onclick="goto()">点我跳转</button>
<br><br>
<!-- 服务端的方式跳转 -->
<button onclick="goto2(1)">服务端转发</button>
<button onclick="goto2(2)">服务端重定向</button>
</body>
<script>
function goto() {
window.location.href = "home.html";
}
function goto2(type) {
window.location.href = "goto?type=" + type;
}
</script>
</html>
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录成功</h1>
</body>
</html>
LoginServlet.java
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;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");
// 解析请求: header, method, url, 请求数据
// 通过键获取值, 如果改键没有值, 返回 null
String username = req.getParameter("username");
String password = req.getParameter("password");
PrintWriter pw = resp.getWriter();
// 数据库根据客户端用户输入的账号密码, 查询有没有该数据
// 简单的模拟
if ("abc".equals(username) && "123".equals(password)) {
pw.println("<h1>欢迎你 " + username + "</h1>");
} else {
pw.println("<h1>用户名或密码错误</h2>");
}
}
}
GotoServlet.java
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;
@WebServlet("/goto")
public class GotoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// req.setCharacterEncoding("UTF-8");
// resp.setCharacterEncoding("UTF-8");
// 解析请求数据: 键为type, 为1转发. 为2重定向
String type = req.getParameter("type");
if ("1".equals(type)) {
// 转发
req.getRequestDispatcher("home.html")
.forward(req, resp);
} else {
// 重定向
resp.sendRedirect("home.html");
}
}
}
login2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h2>用户登录</h2>
<div id="app">
用户名:<input type="text" v-model="username">
<br><br>
密码:<input type="password" v-model="password">
<br><br>
<button v-on:click="login()">登录</button>
<p style = "color: red" v-if="msg">{{msg}}</p>
</div>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
username: "",
password: "",
msg: false
},
methods: {
login: function () {
let vm = this;
this.msg = false;
// alert("用户名:"+this.username+"\n密码:"+this.password)
//Content-Type:application/json, 请求数据为json字符串(body)
axios.post("login2",{
username: vm.username,
password: vm.password
}).then(function (resp) { // 200 状态码执行
// 获得响应体
// console.log(resp)
let json = resp.data;
if (json.ok) {
// 业务操作成功, 页面跳转
window.location.href="home.html";
} else {
// 业务操作失败, 显示错误信息
alert("错误码:" + json.code + "\n错误信息:" + json.msg);
vm.msg = json.msg;
}
}).catch(function (err) {
console.error(err)// 打印对象
console.error(JSON.stringify(err))
})
}
}
})
</script>
</body>
</html>
Login2Servlet.java
import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.demo.User;
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.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@WebServlet("/login2")
public class Login2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Servlet 返回json字符串, 统一代码
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
resp.setContentType("application/json");
/**
* 1. 解析请求数据
* (1) request.getParameter("键") 获取值
* queryString, body格式 和 queryString 一样
* (2) 请求头 Content-Type 为 application/json
* 此时请求体 (body) 为json字符串
* request.getInputStream()获取属土流
* 通过输入流来获取body数据
*/
// 目前是 json 字符串作为请求体内容, 需要反序列化为 java对象
ObjectMapper mapper = new ObjectMapper();
// 通过 request 获取输入流(包含body数据)
InputStream is = req.getInputStream();
// 请求数据反序列化为java对象, 其实就是用户输入的数据
User input = mapper.readValue(is, User.class);
PrintWriter pw = resp.getWriter();
Map<String, Object> map = new HashMap<>();
// 2. 根据请求数据执行业务
if ("abc".equals(input.getUsername()) && "123".equals(input.getPassword())) {
// 业务操作成功, 有些接口需要返回业务数据
map.put("ok", true);
} else {
// 业务操作失败, 返回错误码(开发人员), 错误信息(用户看)
map.put("ok", false);
map.put("code", "LOG001");
map.put("msg", "用户名或密码错误");
}
// 3. 返回响应的业务数据
pw.println(mapper.writeValueAsString(map));
}
}