关于SpringMVC的学习(一站式)
文章目录
一.SpringMVC的简介
1.1 介绍
Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring Framework中。正式名称“Spring Web MVC”来自其源模块的名称( spring-webmvc ),但它通常被称为“Spring MVC”。
为什么现在的springmvc这么流行,因为它有以下显著的优势:
- Spring 家族原生产品,与IOC容器等基础设施无缝对接
- 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
- 代码清新简洁,大幅度提升开发效率
- 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
- 性能卓著,尤其适合现代大型、超大型互联网项目要求
在代码优化方面,springmvc与原生servlet api的区别:
Servlet API代码:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//TODO
}
Spring MVC代码:
@RequestMapping("login")
public String login(@RequestParam("userName") String userName,Sting password){
//TODO
return "OK";
}
1.2 主要的作用
在后期我们学习的ssm框架中,springmvc是其中的”三巨头之一“,它主要负责表述层也就是控制层,而控制层主要有以下功能:
请求映射、数据输入、视图界面、请求分发、表单回显、过滤拦截、文件的上传下载、数据的校验、类型的转换·······
1.3 springmvc的核心
与其他的web框架一样,springmvc的底层也是由Servlet构成的,其中有一些组件是构成springmvc框架实现流程的核心组件:
- DispatcherServlet : SpringMVC提供,我们需要使用web.xml配置使其生效,它是整个流程处理的核心,所有请求都经过它的处理和分发
- HandlerMapping : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它内部缓存handler(controller方法)和handler访问路径数据,被DispatcherServlet调用,用于查找路径对应的handler
- HandlerAdapter : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它可以处理请求参数和处理响应数据数据,每次DispatcherServlet都是通过handlerAdapter间接调用handler,他是handler和DispatcherServlet之间的适配器
- Handler : handler又称处理器,他是Controller类内部的方法简称,是由我们自己定义,用来接收参数,向后调用业务,最终返回响应结果
- ViewResovler : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效!视图解析器主要作用简化模版视图页面查找的,但是需要注意,前后端分离项目,后端只返回JSON数据,不返回页面,那就不需要视图解析器!所以,视图解析器,相对其他的组件不是必须的
五大组件的关系:
(1)用户发送请求至前端控制器DispatcherServlet
(2)DispatcherServlet收到请求调用HandlerMapping处理器映射器。
(3)处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
(4)DispatcherServlet调用HandlerAdapter处理器适配器。
(5)HandlerAdapter经过适配调用具体的Handler处理器(Controller,也叫后端控制器)。Controller执行完成返回ModelAndView。
(6)HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
(7)DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
(8)ViewReslover解析后返回具体View视图。
(9)DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
(10)DispatcherServlet响应用户。
这五个组件就大体构成了我们springnvc的实现流程了。
二.Spring MVC接收数据
2.1 访问路径设置
在spring mvc中我们使用 @RequestMapping 注解来指定url地址,也就是用来接受请求的(注:在Servlet中请求地址需要在地址前加上”/“,而在springmvc中不用必须加)
1.精准路径:就是不使用任何的通配符,直接指定
@Controller
public class UserController {
@RequestMapping("/user/login")
public String login(){
return "ok";
}
2.模糊路径:使用通配符,用于匹配多个相似的地址(注:/*:代表一层模糊;/**:代表多层模糊)
@Controller
public class UserController {
@RequestMapping("/user/*")
public String login(){
return "ok";
}
@RequestMapping("/user/**")
public String login(){
return "ok";
}
3.@RequestMapping 注解也可以用于类上,表示在此类中的所有方法都是以此地址为根地址
@Controller
@RequestMapping("user")
public class UserController {
@RequestMapping("login")
public String login(){
return "ok";
}
4.springmvc的请求方式,在默认情况下是所有的请求方式都可以的,都是我们也可以指定某种方式
@Controller
public class UserController {
@RequestMapping("/user/login",method = {RequestMethod.POST,RequestMethod.GET})
public String login(){
return "ok";
}
5.在选择特定的请求方式的时候,我们也可以使用特殊的注解
- @GetMapping ==@RequestMapping(method = RequestMethod.GET)
- @PostMapping ==@RequestMapping(method = RequestMethod.POST)
- @PutMapping
- @PutMapping
- @PatchMapping
2.2 接受参数
2.2.1 param参数的接受
1.直接接受:条件就是从客户端发送过来的参数和形参相匹配,就可以直接接受
2.使用 @RequestParam注解 来绑定参数(注:使用 @RequestParam注解默认是必须有参数传递,如没有就会报错,但是可以使用 @RequestParam(value = “stuAge”,required = false,defaultValue = “18”) required = false 用于设置传参是非必须,,defaultValue = "默认值”用于设置默认值)
@Controller
public class UserController {
@RequestMapping("/user/login")
public String login(@RequestParam("Name") String name,
@RequestParam("Age") int age){
return "ok";
}
3.可以接受集合类型
@Controller
public class UserController {
@RequestMapping("/user/login")
public String login(@RequestParam List<String> name){
return "ok";
}
4.可以接受实体类
@Controller
public class UserController {
@RequestMapping("/user/login")
public String login(User user){
return "ok";
}
5.路径传参,使用 @PathVariable 注解
@Controller
public class UserController {
@RequestMapping("/user/login/{id}")
public String login(@PathVariable int id){
return "ok";
}
2.2.2 json数据的接收
对于json数据的接收,我们在springmvc框架中,我们使用 @RequestBody 注解 来将json数据转换为java对象
要想接收json数据,我们第一步就是需要定义一个接收json数据的实体类,然后 @RequestBody 注解 来接收json数据
@Controller
public class UserController {
@RequestMapping("/user/login")
public String login(@RequestBody User user){
return "ok";
}
而在springmvc中想要接收json数据,我们还需要配置json转换器
1.加入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
2.在配置类中用 @EnableWebMvc 注解声明json转换器的配置 (注: @EnableWebMvc 注解是用于简化 导入handlerMapping和handlerAdapter 的步骤)
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "org.example.controller")
public class SpringMvcConfig implements WebMvcConfigurer {
}
2.3 接收cookie数据
我们在springmvc中需要接收cookie数据可以用 @CookieValue 注解来绑定参数
@Controller
public class UserController {
@RequestMapping("/user/login")
public String login(@CookieValue("JSESSIONID") String cookie){
return "ok";
}
2.4 接收请求头数据
我们在springmvc中需要接收请求头的数据时,可以用 @RequestHeader 注解
@Controller
public class UserController {
@RequestMapping("/user/login")
public String login(@RequestHeader("@Get") String host){
return "ok";
}
2.5 原生的api对象和共享域对象的操作
我们在springmvc中,需要对原生的api对象和共享域对象的操作时,一句话就是,我们在想要对哪个对象进行操作,就把这个对象放入我们的传参里声明,除了 ModelAndView 对象 和 ModelAndView 对象
@RequestMapping("/mav")
public ModelAndView testAttrByModelAndView() {
// 1.创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
// 2.存入模型数据
modelAndView.addObject("requestScopeMessageMAV", "666");
// 3.设置视图名称
modelAndView.setViewName("mav");
return modelAndView;
}
@Autowired
private ServletContext servletContext;
@RequestMapping("/application")
public String attrApplication() {
servletContext.setAttribute("appScopeMsg", "666");
return "target";
}
三. Spring MVC的响应数据
3.1 跳转页面
3.1.1简单跳转
1.准备依赖
<!-- jsp需要依赖! jstl-->
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>3.0.0</version>
</dependency>
2.需要一个jsp页面路径: /WEB-INF/jsp/index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>666</h1>
</body>
</html>
3.配置视图解析器
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "org.example.controller") //TODO: 进行controller扫描
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {
//配置jsp对应的视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//快速配置jsp模板语言对应的
registry.jsp("/WEB-INF/jsp/",".jsp");
}
}
4.控制器的返回
@Controller
public class UserController {
@RequestMapping("/user/login")
public String login(String name){
return "index";
}
3.1.2 转发和重定向
在springmvc中有两种方式来实现快速跳转, redirect 或者 forward 关键字 ,如果跳转页面,那就将关键字后写上页面的相对路径,即可实现页面的跳转
@RequestMapping("/redirect")
public String redirect() {
// 重定向到 /login 路径
return "redirect:/login";
}
@RequestMapping("/forward")
public String forward() {
// 转发到 /login 路径
return "forward:/login";
}
3.2 返回json数据
1.导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
2.在配置类中添加json数据转换器
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller")
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {
}
3.使用 @ResponseBody 注解,用于将方法返回的数据转化为json和xml数据返回回客户端,且不经过视图解析器(注:可以使用在类上,也可以使用在方法上)
@RequestMapping("/user", method = RequestMethod.POST)
@ResponseBody
public User getUser(@RequestBody User userParam) {
User user = new User();
user.setAge(20);
user.setName("小明");
//返回的对象,会使用jackson的序列化工具,转成json返回给前端
return user;
}
- @ResponseBody 注解是 @ResponseBody 注解可以和 @Controller 注解 的合并,所以我们可以简化 (注:可以使用在类上,也可以使用在方法上)
@ResponseBody
@Controller
@RequestMapping("/user")
public class ParamController {
//TODO
}
3.3 返回静态资源
1.在web应用中加入静态资源
2.在配置类中配置静态资源处理
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller")
public class SpringMvcConfig implements WebMvcConfigurer {
//配置jsp对应的视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//快速配置jsp模板语言对应的
registry.jsp("/WEB-INF/jsp/",".jsp");
}
//开启静态资源处理 <mvc:default-servlet-handler/>
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
四.Spring MVC 的全局处理异常
4.1 两种处理异常的方式
- 编程式异常处理:是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。
- 声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws 或 @ExceptionHandler),就可以处理特定类型的异常。相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。 (通常使用声明式异常处理)
4.2 声明式异常处理实现
1.声明一个异常处理控制器类,用于统一处理。@RestControllerAdvice == @ControllerAdvice + @ResponseBody ,代表 当前类的异常处理控制器
@RestControllerAdvice
public class Error {
}
2.在异常处理类中声明异常处理方法。@ExceptionHandler(异常类.class)代表处理的异常类
@RestControllerAdvice
public class Error {
@ExceptionHandler(HttpMessageNotReadableException.class)
public Object handlerJsonDateException(HttpMessageNotReadableException e){
return null;
}
@ExceptionHandler(Exception.class)
public Object handlerException(Exception e){
return null;
}
}
3.在配置类中,让异常处理控制器被扫描到
@ComponentScan(basePackages = {"org.example.controller","org.example.Error"})
五.拦截器
5.1 拦截器的概念
在程序中,使用拦截器在请求到达具体 handler 方法前,统一执行检测,检测成功就通过,进行后面的操作,检测不成功的就不通过
拦截器 Springmvc VS 过滤器 javaWeb:
- 相似点
- 拦截:必须先把请求拦住,才能执行后续操作
- 过滤:拦截器或过滤器存在的意义就是对请求进行统一处理
- 放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源
- 不同点
- 工作平台不同
- 过滤器工作在 Servlet 容器中
- 拦截器工作在 SpringMVC 的基础上
- 拦截的范围
- 过滤器:能够拦截到的最大范围是整个 Web 应用
- 拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求
- IOC 容器支持
- 过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的
- 拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持
- 工作平台不同
选择:
功能需要如果用 SpringMVC 的拦截器能够实现,就不使用过滤器。
5.2 拦截器的实现
1.创建一个拦截器类
public class Process01Interceptor implements HandlerInterceptor {
// if( ! preHandler()){return;}
// 在处理请求的目标 handler 方法前执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 返回true:放行
// 返回false:不放行
return true;
}
// 在目标 handler 方法之后,handler报错不执行!
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
// 渲染视图之后执行(最后),一定执行!
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
2.在配置类中添加拦截器
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller")
public class SpringMvcConfig implements WebMvcConfigurer {
//配置jsp对应的视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//快速配置jsp模板语言对应的
registry.jsp("/WEB-INF/jsp/",".jsp");
}
//开启静态资源处理 <mvc:default-servlet-handler/>
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//将拦截器添加到Springmvc环境,默认拦截所有Springmvc分发的请求
registry.addInterceptor(new Process01Interceptor());
}
}
3.配置拦截
3.1默认拦截全部
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new Process01Interceptor());
}
3.2精准拦截(注:/* 和 /** 模糊路径。 * 任意一层字符串 ** 任意层 任意字符串)
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new Process01Interceptor())
.addPathPatterns("/common/request/one");
}
3.3排除拦截
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new Process01Interceptor())
.addPathPatterns("/common/request/one","/common/request/t
.excludePathPatterns("/common/request/tow");
}
4.有多个拦截器时的执行顺序:先声明的优先级高 优先级高的在外层,就像一个洋葱横切
六.参数校验
6.1 jsr 303校验
注解 | 规则 |
---|---|
@Null | 标注值必须为 null |
@NotNull | 标注值不可为 null |
@AssertTrue | 标注值必须为 true |
@AssertFalse | 标注值必须为 false |
@Min(value) | 标注值必须大于或等于 value |
@Max(value) | 标注值必须小于或等于 value |
@DecimalMin(value) | 标注值必须大于或等于 value |
@DecimalMax(value) | 标注值必须小于或等于 value |
@Size(max,min) | 标注值大小必须在 max 和 min 限定的范围内 |
@Digits(integer,fratction) | 标注值值必须是一个数字,且必须在可接受的范围内 |
@Past | 标注值只能用于日期型,且必须是过去的日期 |
@Future | 标注值只能用于日期型,且必须是将来的日期 |
@Pattern(value) | 标注值必须符合指定的正则表达式 |
标注值必须是格式正确的 Email 地址 | |
@Length | 标注值字符串大小必须在指定的范围内 |
@NotEmpty | 标注值字符串不能是空字符串 |
@Range | 标注值必须在指定的范围内 |
6.2 数据校验的实现
1.导入依赖
<!-- 校验注解 -->
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>9.1.0</version>
<scope>provided</scope>
</dependency>
<!-- 校验注解实现-->
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator-annotation-processor -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>8.0.0.Final</version>
</dependency>
2.应用校验注解
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import org.hibernate.validator.constraints.Length;
@Data
public class User {
//age 1 <= age < = 150
@Min(10)
private int age;
//name 3 <= name.length <= 6
@Length(min = 3,max = 10)
private String name;
//email 邮箱格式
@Email
private String email;
}
3.控制器标记和绑定
@RestController
@RequestMapping("user")
public class UserController {
//@Validated 代表应用校验注解! 必须添加!
@PostMapping("save")
public Object save(@Validated @RequestBody User user,
//在实体类参数和 BindingResult 之间不能有任何其他参数, BindingResult可以接受错误信息,避免信息抛出!
BindingResult result){
//判断是否有信息绑定错误! 有可以自行处理!
if (result.hasErrors()){
System.out.println("错误");
String errorMsg = result.getFieldError().toString();
return errorMsg;
}
//没有,正常处理业务即可
System.out.println("正常");
return user;
}
}
参考于尚硅谷新版SSM框架全套视频教程,Spring6+SpringBoot3最新SSM企业级开发