1.获取请求数据
1.1开发前端发请求
ajax封装代码
// 参数 args 是一个 JS 对象, 里面包含了以下属性
// method: 请求方法
// url: 请求路径
// body: 请求的正文数据
// contentType: 请求正文的格式
// callback: 处理响应的回调函数, 有两个参数, 响应正文和响应的状态码
function ajax(args) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
// 0: 请求未初始化
// 1: 服务器连接已建立
// 2: 请求已接收
// 3: 请求处理中
// 4: 请求已完成,且响应已就绪
if (xhr.readyState == 4) {
args.callback(xhr.status, xhr.responseText)
}
}
xhr.open(args.method, args.url);
if (args.contentType) {
xhr.setRequestHeader('Content-type', args.contentType);
}
if (args.body) {
xhr.send(args.body);
} else {
xhr.send();
}
}
html前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="u" type="text" placeholder="请输入账号">
<br>
<input id="p" type="password" placeholder="请输入密码">
<br>
<button onclick="send()">ajax get提交</button>
<script src="ajax.js"></script>
<script>
var username = document.querySelector("#u");
var password = document.querySelector("#p");
function send() {
ajax({
method: "GET",
url:"request/get?username="+username.value+"&password="+password.value,
callback: function(status,resp){
alert("响应状态码:"+status+",响应正文:"+resp)
}
})
}
</script>
</body>
</html>
1.2开发后端servlet
package org.example.servlet;
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("/request/get")
public class requestGet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.printf("username=%s,password=%s\n",username,password);
}
}
打印结果:
2.客户端发送请求
2.1ajax发请求
(1)8的获取请求数据使用的就是ajax发请求
(2)get方法的执行流程
①点击get提交按钮到绑定的点击事件
②执行绑定的点击事件的函数(ajax代码)
③执行后端代码
(2)可能出现的问题
①按钮点击以后没有反应,抓包解决
②没有发http请求,一定是前端代码的问题,开发者工具,源代码才是浏览器真正运行的代码解决
③抓包出现404,检查请求路径和服务端资源路径
请求路径:
绝对路径写法:
相对路径写法:
④出现405,方法不支持,检查后端代码,看是否提供对应的服务方法
2.2发送form表单格式的请求数据
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="u" type="text" placeholder="请输入账号">
<br>
<input id="p" type="password" placeholder="请输入密码">
<br>
<button onclick="send()">ajax form表单提交</button>
<script src="ajax.js"></script>
<script>
var username = document.querySelector("#u");
var password = document.querySelector("#p");
function send() {
ajax({
method: "POST",
url:"request/post",
contentType: "application/x-www-form-urlencoded",
body:"username="+username.value+"&password="+password.value,
callback: function(status,resp){
alert("响应状态码:"+status+",响应正文:"+resp)
}
})
}
</script>
</body>
</html>
后端代码:
package org.example.servlet;
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("/request/post")
public class requestFormAjax extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.printf("username=%s,password=%s\n",username,password);
}
}
抓包看到的请求正文的结果
2.3发送JSON格式的请求数据
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="u" type="text" placeholder="请输入账号">
<br>
<input id="p" type="password" placeholder="请输入密码">
<br>
<button onclick="send()">ajax json提交</button>
<script src="ajax.js"></script>
<script>
var username = document.querySelector("#u");
var password = document.querySelector("#p");
function send() {
// json对象
var data = {
username:username.value,
password:password.value
};
ajax({
method: "POST",
url:"request/json",
contentType: "application/json",
// 将JSON对象转换为JSON字符串
body: JSON.stringify(data),
callback: function(status,resp){
alert("响应状态码:"+status+",响应正文:"+resp)
}
})
}
</script>
</body>
</html>
servlet代码的第一种写法,了解就行
package org.example.servlet;
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.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@WebServlet("/request/json")
public class requestJSON1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接收请求body为json格式的数据,需要使用inputStream
InputStream is = req.getInputStream();
//接收到的是字节流,需要使用字节字符转换流来转换
InputStreamReader isr = new InputStreamReader(is, "UTF-8");
//最终是:字符流(字节字符转换流(字节流))
BufferedReader br = new BufferedReader(isr);
String str;
//读取一行到字符串,如果不为空,表示没有结束
while ((str=br.readLine()) != null){
System.out.println(str);
}
}
}
抓包看到的请求正文的结果
测试JSON在java中的使用:
引入依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.3</version>
</dependency>
测试JSON在java中的使用
package org.example.servlet;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
public class textJSON {
public static void main(String[] args) throws JsonProcessingException {
// json反序列化:JSON字符串转java对象
String json = "{\"username\":\"in\",\"password\":\"123\"}";
// 需要使用Jackson框架提供的api来完成
// 这个对象就是辅助完成JSON字符串和java对象相互转化
ObjectMapper objectMapper = new ObjectMapper();
// 可以转换为map,但是还是不但方便
HashMap map = objectMapper.readValue(json,HashMap.class);
System.out.println(map);//结果:{password=123, username=in}
// 建议:自定义一个类型,成员变量名就是JSON字符串的键名,类型要保持一致
User user = objectMapper.readValue(json,User.class);
System.out.println(user);//结果:User{username='in', password='123'}
}
}
用户类:
package org.example.servlet;
public class User {
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
servlet代码的第二种写法,也建议这样完成
package org.example.servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
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;
@WebServlet("/request/json")
public class requestJSON2 extends HttpServlet {
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
//接收请求body为json格式的数据,需要使用inputStream
InputStream is = req.getInputStream();
// json反序列化:将JSON字符串转化为java对象
User user = objectMapper.readValue(is,User.class);
System.out.println(user);
}
}
2.4发送form-data格式的数据
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="u" type="text" placeholder="请输入账号">
<br>
<input id="p" type="password" placeholder="请输入密码">
<br>
<button onclick="send()">ajax form-data提交</button>
<script src="ajax.js"></script>
<script>
var username = document.querySelector("#u");
var password = document.querySelector("#p");
function send() {
// form-data数据提交使用FormData对象
var data = new FormData();
data.append("username",username.value);
data.append("password",password.value);
ajax({
method: "POST",
url:"request/form-data",
// form-data不要设置contentType字段,发数据的时候ajax会自动生成
body: data,
callback: function(status,resp){
alert("响应状态码:"+status+",响应正文:"+resp)
}
})
}
</script>
</body>
</html>
后端代码:
package org.example.servlet;
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 java.io.IOException;
@WebServlet("/request/form-data")
//要获取form-data格式的数据就必须加上这个注解
@MultipartConfig
public class requestFormData extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.printf("username=%s,password=%s\n",username,password);
}
}
2.5发送form-data格式的数据(文件上传)
(1)代码:
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="u" type="text" placeholder="请输入账号">
<br>
<input id="p" type="password" placeholder="请输入密码">
<br>
<input id="f" type="file">
<br>
<button onclick="send()">ajax form-data提交</button>
<script src="ajax.js"></script>
<script>
var username = document.querySelector("#u");
var password = document.querySelector("#p");
var head = document.querySelector("#f");
function send() {
// form-data数据提交使用FormData对象
var data = new FormData();
data.append("username",username.value);
data.append("password",password.value);
var choosedFiles = head.files[0];
if(choosedFiles){
data.append("head",choosedFiles);
}
ajax({
method: "POST",
url:"request/form-data-file",
// form-data不要设置contentType字段,发数据的时候ajax会自动生成
body: data,
callback: function(status,resp){
alert("响应状态码:"+status+",响应正文:"+resp)
}
})
}
</script>
</body>
</html>
后端代码:
package org.example.servlet;
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;
@WebServlet("/request/form-data-file")
//要获取form-data格式的数据就必须加上这个注解
@MultipartConfig
public class requestFormDataFile extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// form-data上传简单类型的数据通过getParameter获取
String username = req.getParameter("username");
String password = req.getParameter("password");
// form-data上传文件通过getPath获取,返回值part对象就可以获取文件的相关信息,也可以对其进行操作
Part head = req.getPart("head");
String path = "E:/TMP/" + head.getSubmittedFileName();
head.write(path);//保存客户端上传的文件到服务端本地
System.out.println(head.getSubmittedFileName());//获取上传的文件名
System.out.println(path);
System.out.println(head.getSize());//获取上传文件的字节数
System.out.printf("username=%s,password=%s\n",username,password);
}
}
抓包结果:
打印结果:
(2)保存的文件如何设计
①文件较小且上传文件的数据量不大,可以考虑使用数据库,将二进制数据转换为字符串(Base64),然后保存;文件较大,不考虑使用数据库保存,一般使用单独的服务器来做
②文件较大,放在服务器的本地硬盘上,但是注意不能放在项目的目录下,对于访问问题,可以自己写代码提供服务资源,请求数据包含一些信息就可以返回不同文件的响应
3.服务端返回响应
3.1返回HTML格式的数据(servlet返回动态网页)
(1)原因:HTML是静态的,不通过ajax是无法访问一个网页构造不同的内容
(2)servlet返回动态网页就是根据条件来拼接HTML字符串
package org.example.servlet;
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("/response/html")
public class responseHtml extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String userId = req.getParameter("userId");
String html = "<P>欢迎你,%s</P>";
String name = "张三";
if(!"1".equals(userId)){
name = "李四";
}
String body = String.format(html,name);
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().write(body);
}
}
3.2返回JSON格式的数据
(1)序列化和反序列化
序列化:站在自己程序的角度,把自己程序中的对象转化为其他格式,用于返回响应数据
反序列化:站在自己程序的角度,把其他格式的数据转化为自己程序中的对象,用于接收请求数据
(2)测试json在Java中的使用
成员类:
package org.example.servlet;
public class User {
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
班级类:
package org.example.servlet;
import java.util.List;
public class classes {
private int id;
private String name;
private List<User> student;
@Override
public String toString() {
return "classes{" +
"id=" + id +
", name='" + name + '\'' +
", student=" + student +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<User> getStudent() {
return student;
}
public void setStudent(List<User> student) {
this.student = student;
}
}
测试JSON在java中的使用:
package org.example.servlet;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
public class textJSON {
public static void main(String[] args) throws JsonProcessingException {
// json反序列化:JSON字符串转java对象
String json = "{\"username\":\"in\",\"password\":\"123\"}";
// 需要使用Jackson框架提供的api来完成
// 这个对象就是辅助完成JSON字符串和java对象相互转化
ObjectMapper objectMapper = new ObjectMapper();
// 可以转换为map,但是还是不但方便
// HashMap map = objectMapper.readValue(json,HashMap.class);
// System.out.println(map);//结果:{password=123, username=in}
// 建议:自定义一个类型,成员变量名就是JSON字符串的键名,类型要保持一致
User user = objectMapper.readValue(json,User.class);
System.out.println(user);//结果:User{username='in', password='123'}
//简单类型的JSON对象
User user1 = new User();
user1.setUsername("张三");
user1.setPassword("123");
String json1 = objectMapper.writeValueAsString(user1);//结果:{"username":"张三","password":"123"}
System.out.println(json1);
User user2 = new User();
user2.setUsername("李四");
user2.setPassword("456");
//初始化list,包含user1和user2两个对象
List<User> list = Arrays.asList(user1,user2);
String json2 = objectMapper.writeValueAsString(list);//结果:[{"username":"张三","password":"123"},{"username":"李四","password":"456"}]
System.out.println(json2);
//复杂类型的JSON对象
classes classes1 = new classes();
classes1.setId(1);
classes1.setName("hehe");
classes1.setStudent(list);
String json3 = objectMapper.writeValueAsString(classes1);
System.out.println(json3);//结果:{"id":1,"name":"hehe","student":[{"username":"张三","password":"123"},{"username":"李四","password":"456"}]}
}
}
(3)代码
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h4>班级信息</h3>
<p id="class_info"></p>
<ul></ul>
<script src="ajax.js"></script>
<script>
var classInfo = document.querySelector("#class_info");
var studentList = document.querySelector("ul");
ajax({
method: "GET",
url: "response/json",
callback:function(status,resp){
console.log("响应状态码:"+status+",响应正文:"+resp);
var json = JSON.parse(resp);
console.log(json);
// 解析响应的班级信息的数据
classInfo.innerHTML = `
班级id:${json.id},班级姓名:${json.name}
`
// 解析响应的学生列表的信息
var content = '';
for(var stu of json.student){
content += `
<li>学生姓名:${stu.username},账号密码:${stu.password}</li>
`
}
studentList.innerHTML = content;
}
});
</script>
</body>
</html>
ajax封装的代码:
// 参数 args 是一个 JS 对象, 里面包含了以下属性
// method: 请求方法
// url: 请求路径
// body: 请求的正文数据
// contentType: 请求正文的格式
// callback: 处理响应的回调函数, 有两个参数, 响应正文和响应的状态码
function ajax(args) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
// 0: 请求未初始化
// 1: 服务器连接已建立
// 2: 请求已接收
// 3: 请求处理中
// 4: 请求已完成,且响应已就绪
if (xhr.readyState == 4) {
args.callback(xhr.status, xhr.responseText)
}
}
xhr.open(args.method, args.url);
if (args.contentType) {
xhr.setRequestHeader('Content-type', args.contentType);
}
if (args.body) {
xhr.send(args.body);
} else {
xhr.send();
}
}
后端代码:
package org.example.servlet;
import com.fasterxml.jackson.databind.ObjectMapper;
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.util.Arrays;
import java.util.List;
@WebServlet("/response/json")
public class responseJSON extends HttpServlet {
private static final ObjectMapper m = new ObjectMapper();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
User user1 = new User();
user1.setUsername("张三");
user1.setPassword("123");
User user2 = new User();
user2.setUsername("李四");
user2.setPassword("456");
List<User> list = Arrays.asList(user1,user2);
//复杂类型的JSON对象
classes classes1 = new classes();
classes1.setId(1);
classes1.setName("hehe");
classes1.setStudent(list);
//返回给前端一个JSON字符串
String json = m.writeValueAsString(classes1);
//设置响应正文的数据格式
resp.setContentType("application/json");
//设置响应正文的编码
resp.setCharacterEncoding("UTF-8");
//设置到body中
resp.getWriter().write(json);
}
}
完成后端代码的结果
开发前端后的结果
(4)请求和响应
请求:前端如果是发送JSON:JSON.stringify(json对象);
后端如果解析这个JSON:objectMapper.readValue(request.getInputStream, 类.class)
响应:后端返回JSON字符串:response.writer(objectMapper.writerValueAsString(java对象);
前端解析响应:ajax的callback回调函数,JSON.parse(方法参数中的响应正文字符串)
4.实现请求一个路径,实现跳转或返回其他页面内容
4.1实现方式一:前端发ajax,后端返回json,前端解析响应,判断是否要跳转
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="u" type="text" placeholder="请输入账号">
<br>
<input id="p" type="password" placeholder="请输入密码">
<br>
<input type="button" value="模拟用户登录(前端跳转)" onclick="login()">
<br>
<script src="ajax.js"></script>
<script>
var username = document.querySelector("#u");
var password = document.querySelector("#p");
// 实现方式一:前端发ajax,后端返回json,前端解析响应,判断是否要跳转
function login(){
ajax({
method: "POST",
url: "jump",
contentType: "application/x-www-form-urlencoded",
body: "username="+username.value+"&password="+password.value,
callback: function(status,resp){
console.log("响应状态码:"+status+",响应正文:"+resp);
//转换响应正文JSON字符串为JSON对象
var json = JSON.parse(resp);
if(json.ok){
// 登录成功就跳转到这个路径
location.href = "request-ajax.html";
}else{
// 不成功给出弹窗提示
alert("账户或密码错误");
}
}
})
}
</script>
</body>
</html>
后端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input id="u" type="text" placeholder="请输入账号">
<br>
<input id="p" type="password" placeholder="请输入密码">
<br>
<input type="button" value="模拟用户登录(前端跳转)" onclick="login()">
<br>
<script src="ajax.js"></script>
<script>
var username = document.querySelector("#u");
var password = document.querySelector("#p");
// 实现方式一:前端发ajax,后端返回json,前端解析响应,判断是否要跳转
function login(){
ajax({
method: "POST",
url: "jump",
contentType: "application/x-www-form-urlencoded",
body: "username="+username.value+"&password="+password.value,
callback: function(status,resp){
console.log("响应状态码:"+status+",响应正文:"+resp);
//转换响应正文JSON字符串为JSON对象
var json = JSON.parse(resp);
if(json.ok){
// 登录成功就跳转到这个路径
location.href = "request-ajax.html";
}else{
// 不成功给出弹窗提示
alert("账户或密码错误");
}
}
})
}
</script>
</body>
</html>
4.2实现方式二:前端发ajax,后端登录成功直接跳转,登录失败还是跳转本页面
但是不建议返回HTML,这里就不详细介绍了(会出现重定向的问题)