关于SpringMVC的学习

关于SpringMVC的学习(一站式)

一.SpringMVC的简介

1.1 介绍

Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring Framework中。正式名称“Spring Web MVC”来自其源模块的名称( spring-webmvc ),但它通常被称为“Spring MVC”。

为什么现在的springmvc这么流行,因为它有以下显著的优势:

  1. Spring 家族原生产品,与IOC容器等基础设施无缝对接
  2. 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
  3. 代码清新简洁,大幅度提升开发效率
  4. 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
  5. 性能卓著,尤其适合现代大型、超大型互联网项目要求

在代码优化方面,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框架实现流程的核心组件:

  1. DispatcherServlet : SpringMVC提供,我们需要使用web.xml配置使其生效,它是整个流程处理的核心,所有请求都经过它的处理和分发
  2. HandlerMapping : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它内部缓存handler(controller方法)和handler访问路径数据,被DispatcherServlet调用,用于查找路径对应的handler
  3. HandlerAdapter : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它可以处理请求参数和处理响应数据数据,每次DispatcherServlet都是通过handlerAdapter间接调用handler,他是handler和DispatcherServlet之间的适配器
  4. Handler : handler又称处理器,他是Controller类内部的方法简称,是由我们自己定义,用来接收参数,向后调用业务,最终返回响应结果
  5. 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.在选择特定的请求方式的时候,我们也可以使用特殊的注解

  1. @GetMapping ==@RequestMapping(method = RequestMethod.GET)
  2. @PostMapping ==@RequestMapping(method = RequestMethod.POST)
  3. @PutMapping
  4. @PutMapping
  5. @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;
}
  1. @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 两种处理异常的方式

  1. 编程式异常处理:是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。
  2. 声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @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标注值必须是格式正确的 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企业级开发

  • 20
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值