Author:Dawn_T17🥥
目录
一.请求响应概述
1.Servlet
在 Spring Boot 的 Web 请求响应处理中,Servlet
起着关键的作用。
Servlet
是 Java Web 开发中的基本组件,主要负责处理客户端的请求并生成响应。
具体来说,它具有以下重要作用:
- 接收请求:
Servlet
能够接收来自客户端(如浏览器)发送的 HTTP 请求。 - 处理请求:在接收到请求后,执行相应的业务逻辑处理。这可能包括与数据库交互、进行数据计算、验证用户输入等操作。
- 控制流程:根据请求的类型和参数,决定后续的处理流程和响应方式。
- 生成响应:处理完请求后,生成要返回给客户端的响应数据。
- 与其他组件协作:可以与其他的 Java 类、服务或组件进行协作,以完成复杂的业务功能。
例如,在一个用户登录的场景中,Servlet
接收到用户提交的登录表单数据,然后验证用户名和密码是否正确。如果正确,生成一个成功登录的响应;如果不正确,生成一个错误提示的响应。
在 Spring Boot 中,DispatcherServlet
是一个特殊的 Servlet
,它负责协调和分发请求到具体的控制器(Controller)进行处理,使得整个请求处理流程更加清晰和高效。
Dispatcher:调度员;调度程序;发送器
2.DispatcherServlet
在 Spring Boot 中,DispatcherServlet
是一个核心组件,起着非常重要的作用
DispatcherServlet
主要负责接收客户端的请求,并将请求分发给相应的处理器(Handler)进行处理。它是 Spring Web MVC 框架的前端控制器。
其工作流程大致如下:
当客户端发送一个 HTTP 请求到应用程序时,DispatcherServlet
首先会接收到这个请求。然后,它会根据请求的 URL 和其他相关信息,通过一系列的映射规则,来确定应该调用哪个控制器(Controller)来处理这个请求。
在确定了控制器之后,DispatcherServlet
会将请求传递给对应的控制器方法进行处理。控制器处理完请求后,通常会返回一个模型(Model)和视图(View)的信息。
DispatcherServlet
接着会根据返回的视图信息,选择合适的视图解析器(View Resolver)来将模型数据渲染成最终的响应页面,并将响应返回给客户端。
例如,如果有一个用户请求获取商品列表的页面,DispatcherServlet
会找到处理该请求的商品控制器,然后由控制器获取商品数据并返回给 DispatcherServlet
,DispatcherServlet
再通过视图解析器将数据展示在相应的页面上。
总之,DispatcherServlet
是 Spring Boot 中实现 Web 应用请求处理和响应生成的关键环节,确保了整个 Web 应用的流畅运行和高效响应。
DispatcherServlet
类继承了Servlet
接口
3.请求响应工作概图
DispatcherServlet会根据请求调度Controller控制器,然后获得响应的数据
(1)
HttpServletRequest
是 Java Servlet 规范中定义的一个接口,用于表示客户端发送到服务器的 HTTP 请求。
它包含了大量与请求相关的信息和方法:
请求方法:例如 GET
、POST
、PUT
、DELETE
等,通过 getMethod()
方法获取。
请求 URL:可以通过 getRequestURI()
方法获取请求的资源路径,getQueryString()
方法获取查询字符串。
请求头信息:如 User-Agent
(客户端浏览器和操作系统信息)、Content-Type
(请求体的数据类型)等,使用 getHeader(String name)
方法获取指定的请求头。
请求参数:包括表单提交的参数、URL 中的参数等,通过 getParameter(String name)
方法获取单个参数值,getParameterValues(String name)
方法获取具有多个值的参数。
例如,在一个登录页面中,用户输入用户名和密码后提交表单,服务器端可以通过 HttpServletRequest
来获取用户名和密码的参数值,进行后续的验证处理。
另外,如果客户端发送了一个带有特定 Cookie
的请求,服务器可以通过 getCookies()
方法获取这些 Cookie
信息,从而实现会话跟踪等功能。
HttpServletRequest
为服务器端处理客户端的 HTTP 请求提供了丰富的信息和操作方法,是构建 Web 应用的重要组成部分。
(2)
HttpServletResponse
是 Java Servlet 规范中定义的一个接口,用于表示服务器对客户端 HTTP 请求的响应。
它包含了一系列方法,用于设置响应的状态码、响应头信息、响应体内容等。
一些常见的方法包括:
setStatus(int status)
:设置响应的状态码,例如200
表示成功,404
表示未找到资源,500
表示服务器内部错误等。setHeader(String name, String value)
:设置响应头信息,如设置Content-Type
来指定响应体的数据类型。getWriter()
:获取一个PrintWriter
对象,用于向响应体中写入字符数据。getOutputStream()
:获取一个ServletOutputStream
对象,用于向响应体中写入二进制数据。
4.BS/CS架构
BS即“Browser/Server”(浏览器/服务器模式) :在这种模式下,用户通过浏览器访问服务器上的应用程序。客户端主要负责显示数据和接收用户输入,而大部分的业务逻辑和数据处理都在服务器端完成。例如常见的各类网站、在线办公系统等。其优点包括易于维护和升级、跨平台性好、用户使用方便等。
CS即“Client/Server”(客户端/服务器模式) :这种模式下,需要在客户端安装专门的应用程序来与服务器进行交互。客户端和服务器端都承担一定的业务逻辑和数据处理任务。例如一些大型的游戏客户端、企业级的本地应用程序等。其优点可能包括响应速度快、能充分利用本地资源等,但缺点是部署和维护成本较高,客户端的更新较为复杂。
比如在线购物网站通常采用 BS 架构,用户通过浏览器就能访问和操作;而像一些专业的图形设计软件可能采用 CS 架构,以充分发挥本地计算机的性能。
二.API测试工具
API 测试工具是专门用于对应用程序编程接口(API)进行测试和验证的软件工具。
这些工具的主要目的是帮助开发人员、测试人员和质量保证团队确保 API 按照预期工作,能够正确处理输入请求并返回准确、有效的响应。
ApiPost:
-
优势:
- 提供中文界面,对国内用户更友好。
- 接口文档生成和分享功能便捷,适合团队协作。
- 支持离线使用,适用于特殊网络环境。
-
适用场景:
- 适合国内开发团队,尤其是需要高效协作和生成详细接口文档的项目。
ApiFox:
-
优势:
- 集 API 文档、调试、Mock、自动化测试为一体。
- 支持多种数据格式的导入和导出。
-
适用场景:
- 适用于需要全面管理 API 全生命周期的项目。
Postman:
-
优势:
- 应用广泛,社区活跃,资源丰富。
- 支持丰富的插件扩展。
-
适用场景:
- 适合个人开发者和大型国际化团队。
虽然Postman很好,但是不用魔法我打不开,注册登录不了(囧)
所以我选择Apipost
三.请求
1.简单参数
简单参数通常指的是基本数据类型的参数,例如整数、浮点数、布尔值、字符或字符串等。这些参数通常是独立的值,直接传递给函数或方法进行处理。
(1)原始方式(不推荐)
通过 HttpServletRequest
对象来获取原始的请求信息
get方式
package com.example.demos.controllers;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
public class RequestController {
//原始方式
@RequestMapping("/simpleParam")
public String simpleParam(HttpServletRequest request){
//获取请求参数
String name=request.getParameter("name");
String ageStr = request.getParameter("age");
int age=Integer.parseInt(ageStr);//类型转换
System.out.println(name+":"+age);
return "ok";
}
}
因为繁琐,且要手动进行类型转换,所以一般不用
(2)Spring Boot方式
将请求参数名写在形参列表里,spring boot会自动转换类型
@RequestMapping("/simpleParam")
public String simpleParam(String name,Integer age){
System.out.println(name+":"+age);
return "ok";
若是post方式,要将参数的值写在 body里,如下
若方法形参和请求参数名不一致,不会报错,会接收到空(NULL)
可以使用映射使两个名对应上
@RequestParam
是 Spring 框架中用于处理 HTTP 请求参数的注解。
当在控制器的方法参数上使用 @RequestParam
时,可以将请求中的参数值绑定到方法的参数上。
@RequestParam
还可以设置一些属性,例如:
required
:指定参数是否必需,默认值为true
。如果设置为false
,当请求中没有该参数时,不会抛出异常。defaultValue
:当请求中没有该参数时使用的默认值。
2 .实体参数
实体参数通常指的是一个具有复杂结构或包含多个相关属性的对象或数据结构
POJO(Plain Old Java Object)即普通的 Java 对象 。
{
与 POJO(Plain Old Java Object,普通 Java 对象)相对应的概念包括
- DTO(Data Transfer Object,数据传输对象):主要用于在不同层或不同系统之间传输数据,通常只包含必要的数据字段,并且这些字段通常是只读的。
- VO(Value Object,值对象):用于表示不可变的值,通常只包含属性和访问这些属性的方法,并且没有任何行为逻辑。
- Entity(实体):在数据库相关的设计中,用于表示数据库中的表对应的对象,通常与数据库中的记录相对应,并包含持久化相关的逻辑。
}
POJO user对象
package com.example.demos.pojos;
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "User{name = " + name + ", age = " + age + "}";
}
}
@RequestMapping("/simpleParam")
public String simpleParam(User user){
System.out.println(user.getAge()+ user.getName());
return "ok";
}
复杂实体类型
3.数组集合参数
4.日期参数![](https://i-blog.csdnimg.cn/direct/245de8c2cc5a41c5afd38d89285c4b5d.png)
5.JSON参数
@RequestBody
是 Spring 框架中用于处理 HTTP 请求体的注解。
当在控制器的方法参数上使用 @RequestBody
时,它会将 HTTP 请求体中的数据(通常是 JSON、XML 等格式)绑定到方法的参数对象上。
他还有将数据响应给浏览器的功能,见后文
6.路径参数
路径参数是在 URL 路径中传递的参数。
例如,假设有一个 URL 类似于 https://example.com/user/123
,其中的 123
就是一个路径参数。在 Web 开发中,服务器端可以获取这个路径参数,并根据其值进行相应的处理。
多个路径参数样式
路径参数具有以下重要作用
- 精确资源定位
- 能够准确地指定要访问的特定资源。例如,在一个博客系统中,
/post/123
中的123
可以准确指向特定的文章。
- 能够准确地指定要访问的特定资源。例如,在一个博客系统中,
- 简化 URL 结构
- 使 URL 看起来更简洁和有组织,而不是通过大量的查询参数来传递关键信息。
- 提高路由效率
- 服务器端可以基于路径参数快速进行路由决策,提高请求处理的效率。
- 增强用户体验
- 对于用户来说,直观的路径参数更容易理解和记忆。
- 实现动态内容展示
- 根据不同的路径参数,服务器可以动态地生成和返回不同的内容。
- 便于权限控制和访问管理
- 可以基于路径参数来设置不同的权限规则,控制对特定资源的访问。
例如,在一个在线教育平台,/course/101/lesson/5
这样的路径参数能够清晰地标识特定的课程和课程中的特定章节,服务器可以据此提供准确的教学内容,并进行相应的权限验证。
总结![](https://i-blog.csdnimg.cn/direct/e3c2af810f7741838ec0b5b8e2d141d7.png)
四.响应
1.响应的实现和过程
基本上都使用 @RestController
注解的控s制器方法来直接返回数据
如下图,@RestController
注解包含了 @ResponseBody注解
响应的数据若是较复杂,以JSON格式传递
但这样还是不方便管理和后期维护,所以有统一的响应格式
2.统一响应格式
常见的统一响应格式可以包含以下几个部分:
status
:表示请求的处理状态,通常是一个整数,例如1表示成功,0表示失败。message
:对状态的简要描述信息,解释请求处理的结果。data
:实际要返回的数据内容,可以是对象、数组、字符串等各种数据类型。
Result封装类代码
/**
* 统一响应结果封装类
*/
public class Result {
private Integer code ;//1 成功 , 0 失败
private String msg; //提示信息
private Object data; //数据 data
public Result() {
}
public Result(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static Result success(Object data){
return new Result(1, "success", data);
}
public static Result success(){
return new Result(1, "success", null);
}
public static Result error(String msg){
return new Result(0, msg, null);
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
封装了类的静态方法可以直接调用封装的success()方法 快速返回数据。
例如
@RequestMapping("/simpleParam")
public Result simpleParam(User user){
System.out.println(user.getAge()+ user.getName());
//return new Result(1,"success","Hello");
return Result.success("Hello,SpringBoot");
}
浏览器接收到的JSON数据:
五.样例案例
TIP
DOM4J
DOM4J
是一个 Java 的 XML 操作库。
它具有以下特点和优势:
- 强大的解析功能:能够有效地解析和处理复杂的 XML 文档。
- 灵活的操作:支持对 XML 节点的创建、修改、删除、查询等操作。
- 易于使用:提供了简洁直观的 API,使得开发人员能够轻松上手。
作用:
-
XML 文档解析
能够读取和解析 XML 文档,将其转换为易于操作的 Java 对象结构。 -
节点操作
可以方便地访问、添加、修改和删除 XML 文档中的节点(元素、属性、文本等)。 -
数据提取
从 XML 文档中提取所需的数据,例如特定元素的值或属性的值。 -
构建 XML 文档
能够从零开始创建新的 XML 文档,并按照指定的结构添加内容。 -
遍历文档
支持对 XML 文档进行深度优先或广度优先的遍历,以便处理文档中的各个部分。 -
与其他系统集成
在需要与基于 XML 的外部系统进行数据交互时,DOM4J
可以帮助进行数据的转换和处理。
案例
实现联系前后端展示一个页面
相关数据存储在 一个XML文件里面
因为要使用DOMJ4解析XML对象,导入DOMJ4依赖
相关目录说明
相关代码
(1)本项目构建的XML解析工具类
package com.example.springbootwebpractice.utils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class XmlParserUtils {
public static <T> List<T> parse(String file , Class<T> targetClass) {
ArrayList<T> list = new ArrayList<T>(); //封装解析出来的数据
try {
//1.获取一个解析器对象
SAXReader saxReader = new SAXReader();
//2.利用解析器把xml文件加载到内存中,并返回一个文档对象
Document document = saxReader.read(new File(file));
//3.获取到根标签
Element rootElement = document.getRootElement();
//4.通过根标签来获取 user 标签
List<Element> elements = rootElement.elements("emp");
//5.遍历集合,得到每一个 user 标签
for (Element element : elements) {
//获取 name 属性
String name = element.element("name").getText();
//获取 age 属性
String age = element.element("age").getText();
//获取 image 属性
String image = element.element("image").getText();
//获取 gender 属性
String gender = element.element("gender").getText();
//获取 job 属性
String job = element.element("job").getText();
//组装数据
Constructor<T> constructor = targetClass.getDeclaredConstructor(String.class, Integer.class, String.class, String.class, String.class);
constructor.setAccessible(true);
T object = constructor.newInstance(name, Integer.parseInt(age), image, gender, job);
list.add(object);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
(2) Emp pojo对象
package com.example.springbootwebpractice.pojo;
public class Emp {
private String name;
private Integer age;
private String image;
private String gender;
private String job;
public Emp() {
}
public Emp(String name, Integer age, String image, String gender, String job) {
this.name = name;
this.age = age;
this.image = image;
this.gender = gender;
this.job = job;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", age=" + age +
", image='" + image + '\'' +
", gender='" + gender + '\'' +
", job='" + job + '\'' +
'}';
}
}
(3)EmpController 控制器
package com.example.springbootwebpractice.controller;
import com.example.springbootwebpractice.pojo.Emp;
import com.example.springbootwebpractice.pojo.Result;
import com.example.springbootwebpractice.utils.XmlParserUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Iterator;
import java.util.List;
@RestController
public class EmpController {
@RequestMapping("/listEmp")
public Result list(){
//1.加载并解析xml文件
String file=this.getClass().getClassLoader().getResource("emp.xml").getFile();
System.out.println(file);
List<Emp> emplist=XmlParserUtils.parse(file,Emp.class);
//2.对数据进行转换处理-gender,job
Iterator<Emp> it=emplist.iterator();
while (it.hasNext()){
String gender = it.next().getGender();
if(gender.equals("1")){
it.next().setGender("男");
}else if(gender.equals("2")){
it.next().setGender("女");
}
String job= it.next().getJob();
if(job.equals("1")){
it.next().setJob("讲师");
}else if(job.equals("2")){
it.next().setJob("班主任");
}else if(job.equals("3")){
it.next().setJob("就业指导");
}
}
//3.响应数据
return Result.success(emplist);
}
}
(4)统一响应格式 Result
代码见上文
(5)部分前端代码
基于Vue框架和Axious
<!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>员工信息</title>
</head>
<link rel="stylesheet" href="element-ui/index.css">
<script src="./js/vue.js"></script>
<script src="./element-ui/index.js"></script>
<script src="./js/axios-0.18.0.js"></script>
<body>
<h1 align="center">员工信息列表展示</h1>
<div id="app">
<el-table :data="tableData" style="width: 100%" stripe border >
<el-table-column prop="name" label="姓名" align="center" min-width="20%"></el-table-column>
<el-table-column prop="age" label="年龄" align="center" min-width="20%"></el-table-column>
<el-table-column label="图像" align="center" min-width="20%">
<template slot-scope="scope">
<el-image :src="scope.row.image" style="width: 80px; height: 50px;"></el-image>
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" align="center" min-width="20%"></el-table-column>
<el-table-column prop="job" label="职位" align="center" min-width="20%"></el-table-column>
</el-table>
</div>
</body>
<style>
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: #f0f9eb;
}
</style>
<script>
new Vue({
el: "#app",
data() {
return {
tableData: []
}
},
mounted(){
axios.get('/listEmp').then(res=>{
if(res.data.code){
this.tableData = res.data.data;
}
});
},
methods: {
}
});
</script>
</html>
效果
实时响应
前端页面
注意:这里访问的连接不是直接访问后端,而是访问前端,然后前通过axios异步访问后端,后端再发送给前端,随即渲染展示到页面
浏览器先向服务器请求页面emp.html,挂载时页面的钩子方法mounted根据数据地址/listEmp自动向服务器申请数据