组件 | 作用 | 在 Spring MVC 中的对应部分 |
---|---|---|
Model(模型) | 负责数据处理、业务逻辑 | Service 层 + DAO 层(数据库交互) |
View(视图) | 负责页面显示 | HTML 、JSP 、Thymeleaf 、JSON (REST API) |
Controller(控制器) | 负责处理用户请求 | @Controller 或 @RestController |
SpringMVC
1.请求处理
1.@RequestMapping
作用:将HTTP请求映射到特定的类或方法上,帮助开发者灵活地定义处理HTTP请求的路径和行为
java
@RestController
@RequestMapping("/api")
public class MyController {
@GetMapping("/hello")
public String sayHello() {
return "Hello, world!";
}
}
请求限定属性:
1.method:
指定支持的HTTP请求方法(GET,POST)等
2.headers:
限制请求头必须包含请求头或请求头的值
java
@RequestMapping(value = "/test", headers = "Content-Type=application/json")
public String handleWithHeader() {
return "Handled request with application/json header";
}
限定请求头包含Content-Type=application/json
3.params:
限定请求参数
2.@RequestBody
是Spring框架中的一个注解,用于将HTTP请求的请求体映射到Java对象中。这个注解通常用于接收客户端发送的JSON或XML数据
java
@PostMapping("/example")
public ResponseEntity<String> processRequest(@RequestBody MyRequestBody myRequestBody) {
// 处理从请求体中获取的数据
return ResponseEntity.ok("数据处理成功!");
}
@RequestBody注解会自动将请求体中的JSON数据转换成MyRequestBody对象
3.@RequestParam
@RequestParam 是 Spring 框架中的一个注解,用于将 HTTP 请求中的参数绑定到控制器方法的参数上。它是处理 GET 或 POST 请求中请求参数的一种常用方式
java
@RequestMapping("/handle02")
public String handle02(@RequestParam("username") String name, @RequestParam("password") String pwd){
System.out.println("username = " + name);
System.out.println("password = " + pwd);
return "ok";
}通过注解获取同名参数并返回
请求限定属性:
1.value:
就是默认值,填参数名称
2.required
默认值是true 若填写required = false则是声明参数可以不存在
3.defaultValue:
添加参数的默认值,同样也意味着可以不传参数
4.@RequestHeader
@RequestHeader 是 Spring 框架中的一个注解,用于将 HTTP 请求头中的参数绑定到控制器方法的参数上。从而让我们可以获取请求头的值
请求限定属性和上面的一样
5.@CookieValue:
获取特定Cookie值
使用POJO级联封装请求参数
工作原理:
SpringMVC 会自动从请求参数(如 URL 查询参数 ?name=Wanyan&age=25
或表单提交的数据)中提取值。
如果请求中的参数名称与 POJO 的属性名称一致,SpringMVC 会将这些值绑定到对象的对应属性上。
java
写一个POJO类Person 定义属性
@Data//主要依赖Setter和toString方法
public class Person {
private String username;
private String password;
private String cellphone;
private boolean agreement;
private String grade;
private Address address;
private String[] hobby;
private String sex;
@Data
public static
class Address {
private String province;
private String city;
private String area;
}
}
@RequestMapping("/handle06")
public String handle06(Person person){
System.out.println(person);
return "ok";
}
使用@RequestBody封装数据
1.确保前端发送JSON数据
java
{
"name": "Wanyan",
"age": 25
}
2.创建对应的java类(POJO)
java
@RequestMapping("/handle07")
public String handle07(@RequestBody Person person){//将Http请求的参数映射到pojo实体类中
System.out.println(person);
return "ok";
}
@RequestBody主要是用来应对复杂场景,接受客户端发送的JSON格式的请求数据
使用HttpEntity封装原始请求
java
@RestController
@RequestMapping("/example")
public class ExampleController {
@PostMapping("/process")
public ResponseEntity<String> processRequest(HttpEntity<String> httpEntity) {
// 获取请求头
HttpHeaders headers = httpEntity.getHeaders();
System.out.println("Headers: " + headers);
// 获取请求体
String body = httpEntity.getBody();
System.out.println("Body: " + body);
return ResponseEntity.ok("Request processed successfully!");
}
}
2.响应处理
1.返回Json数据
java
@RestController
@RequestMapping("/example")
public class ExampleController {
@GetMapping("/person")
public Person getPerson() {
Person person = new Person();
person.setName("Wanyan");
person.setAge(25);
return person; // 自动转换为 JSON
}
}
2.文件下载
java
@RequestMapping("/download")
public ResponseEntity<InputStreamResource> download() throws Exception {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\chinaliao\\Documents\\微信图片_20240813134707.jpg");
byte[] bytes = fileInputStream.readAllBytes();
//1.文件名中文会乱码,解决:
String encode = URLEncoder.encode("haaj.jpg","UTF-8");
// 2.文件太大会oom(内存溢出)
InputStreamResource resource = new InputStreamResource(fileInputStream);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(fileInputStream.available())
// 告诉浏览器, 下载的文件名
.header("Content-Disposition", "attachment;filename=haaj.jpg")
.body(resource);
}
RESTful案例
CRUD操作(增删改查)
1.创建操作数据库的DAO接口
2.实现DAO接口,执行查询,插入,更新和删除等方法
3.创建Service层,调用DAO层完成数据库操作,可以整合多个DAO
4.创建Controler层,接受用户请求,调用Service层完成具体业务,与前端交互
分层的好处
1.DAO:将数据库操作集中在这一层,可以避免在控制层中编写复杂的擦汗寻SQL与疾病,保持代码的清晰性
2.Service:业务逻辑和数据访问分离,便于业务逻辑的独立开发和测试
3.Controller:接受响应,验证等操作,增强了模块化
4.总结:分层操作实现了松耦合,代码复用,拓展性强等优点
拦截器
1.拦截器的工作流程
拦截器通过实现 Spring 的 HandlerInterceptor
接口,并覆盖以下三个方法来实现:
-
preHandle()
:在目标方法执行之前进行处理。如果返回false
,请求将被拦截,不会继续往后执行。 -
postHandle()
:在目标方法执行后,但在渲染视图之前执行,用于操作返回数据。 -
afterCompletion()
:在完成整个请求后执行(包括视图的渲染),可以进行清理工作等。
preHandle()
按注册顺序执行
postHandle()
和 afterCompletion()
按注册顺序的反向执行
preHandle()
返回 false
,后续拦截器和 Controller 不执行
afterCompletion()
总会执行(即使 preHandle()
返回 false
)
order()
可以调整拦截器的优先级
2.多拦截器的执行顺序
正常执行

拦截器的preHandler()返回false

3.拦截器和过滤器的区别
1.定义方式:
1.过滤器:
要实现Filter接口,在doFilter方法中写过滤操作,用chain.doFilter方法放行请求传递给下一个过滤器或目标资源,要写@WebFilter注解
2.拦截器:
自定义拦截器实现HandlerInterceptor接口,重写三个方法,配置拦截器实现WebMvcConfigurer(),重写addInterceptors()方法,传入自定义的拦截器
2.执行时机不同
过滤器:在请求进入容器后、到达Servlet之前执行;响应时在Servlet处理完后执行。
拦截器:在请求进入框架的控制器之前、之后或渲染视图前后执行,控制更贴近业务逻辑。
异常处理
1.局部异常处理
@ExceptionHandler
(局部异常处理)
通常声明在Controller内部
java
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/exception")
public String exceptionTest() {
if (true) {
throw new IllegalArgumentException("参数错误");
}
return "正常返回";
}
@ExceptionHandler(IllegalArgumentException.class)
public String handleIllegalArgumentException(IllegalArgumentException e) {
return "捕获到异常:" + e.getMessage();
}
}
2.全局异常处理
@ControllerAdvice
+@ExceptionHandler
对项目的所有Handler生效
java
import org.springframework.web.bind.annotation.*;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public String handleIllegalArgumentException(IllegalArgumentException e) {
return "【全局】参数错误:" + e.getMessage();
}
@ExceptionHandler(Exception.class)
public String handleException(Exception e) {
return "【全局】服务器异常:" + e.getMessage();
}
}
为了让异常信息统一,我们定义一个Common类来返回异常信息
java
@Data
public class R<T> {
private Integer code;
private String msg;
private T data;
public static<T> R<T> ok(T data){
R r = new R<>();
r.setCode(200);
r.setMsg("ok");
r.setData(data);
return r;
}
public static R ok(){
R r = new R<>();
r.setCode(200);
r.setMsg("ok");
return r;
}
public static<T> R<T> error(Integer code,String msg,Object data){
R r = new R<>();
r.setCode(code);
r.setMsg(msg);
r.setData(data);
return r;
}
把异常处理的返回值变成R就可以返回
SpringMVC - 数据校验
-
导入校验包
-
编写校验注解
-
使用 @Valid 告诉SpringMVC进行校验
-
编写一个全局异常处理器来处理校验异常
前端发来的数据,通常不能完全相信,要通过spring-boot-starter-validation中的约束注解来验证字符串或者集合
@NotNull
: 用于校验字段是否为空(只有null)
✅ "John"
(通过) ❌ null
(不通过) ✅ ""
(通过)
@NotEmpty
: 既用于校验字段是否为空,也检查长度是否大于零
✅ "John"
(通过) ❌ null
(不通过) ❌ ""
(不通过) ✅ " "
(通过,因为长度大于 0)
@NotBlank
:仅适用于字符串类型,会把空格去掉在判断是否为空
✅ "John"
(通过) ❌ null
(不通过) ❌ ""
(不通过) ❌ " "
(不通过,因为去掉空格后为空)
1. 数值约束
约束注解 | 作用 | 适用类型 |
---|---|---|
@Positive |
必须为正数(>0 ) |
int 、long 、double 、BigDecimal |
@PositiveOrZero |
必须为正数或零(>=0 ) |
同上 |
@Negative |
必须为负数(<0 ) |
同上 |
@NegativeOrZero |
必须为负数或零(<=0 ) |
同上 |
@Min(value) |
必须 ≥ value |
数字类型 |
@Max(value) |
必须 ≤ value |
数字类型 |
@DecimalMin(value, inclusive = true/false) |
必须 大于等于/大于 value |
BigDecimal 、double 、float |
@DecimalMax(value, inclusive = true/false) |
必须 小于等于/小于 value |
同上 |
@Digits(integer, fraction) |
限制整数和小数的位数 | BigDecimal 、double 、float |
约束类别 | 主要注解 |
---|---|
通用 | @NotNull 、@NotEmpty 、@NotBlank |
数值 | @Min 、@Max 、@Positive 、@Negative |
字符串 | @Size 、@Pattern |
日期时间 | @Past 、@Future |
特殊格式 | @Email 、@UUID |
2.自定义校验器
java
1.自定义注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = {MyCustomValidator.class}) // 指定校验器
@Target({ElementType.FIELD, ElementType.METHOD}) // 作用范围:字段或方法
@Retention(RetentionPolicy.RUNTIME) // 运行时生效
public @interface MyCustomConstraint {
String message() default "字段不符合要求"; // 自定义错误消息
Class<?>[] groups() default {}; // 分组校验
Class<? extends Payload>[] payload() default {}; // 负载信息
}
2. 实现ContraintValidator接口
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class MyCustomValidator implements ConstraintValidator<MyCustomConstraint, String> {
@Override
public void initialize(MyCustomConstraint constraintAnnotation) {
// 初始化逻辑(通常不需要)
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
// 这里自定义校验逻辑,比如判断字符串是否只包含字母
return value != null && value.matches("^[a-zA-Z]+$");
}
}
3. 创建实体类在要校验的数据上写自定义注解
4.在Controller中使用 @Valid 或 @Validated 触发校验。
5.在全局异常中统一处理
接口文档
1.定义
接口文档 (API 文档)是用于描述系统提供的接口的详细说明文档。它主要用于前后端或系统之间的对接,确保不同团队可以正确理解和调用接口。
2.使用Swagger自动生成API文档
1.添加依赖
XML
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version> <!-- 适用于 Spring Boot 3.x -->
</dependency>
2.编写controller类
java
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
@RestController
@RquestMapping("/user")
@Tag(name = "用户管理", description = "用户相关接口") // 分组名称
public class UserController {
@PostMapping("/create")
@Operation(summary = "创建用户", description = "用于创建新用户")
public String createUser(@RequestBody UserDTO userDTO) {
return "用户创建成功:" + userDTO.getUsername();
}
@GetMapping("/{userId}")
@Operation(summary = "查询用户", description = "根据用户ID查询用户信息")
public String getUser(@PathVariable int userId) {
return "用户:" + userId;
}
}