SSM-SpringMVC篇

一、简介

1.介绍

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

在控制层框架历经Strust、WebWork、Strust2等诸多产品的历代更迭之后,目前业界普遍选择了SpringMVC作为Java EE项目表述层开发的首选方案。

原生Servlet API开发代码片段

java 复制代码
protected void doGet(HttpServletRequest request, HttpServletResponse response) 
                                                        throws ServletException, IOException {  
    String userName = request.getParameter("userName");
    
    System.out.println("userName="+userName);
}

基于SpringMVC开发代码片段

java 复制代码
@RequestMapping("/user/login")
public String login(@RequestParam("userName") String userName,Sting password){
    
    log.debug("userName="+userName);
    //调用业务即可
    
    return "result";
}

2.作用

SSM框架构建起单体项目的技术栈需求!其中的SpringMVC负责表述层(控制层)实现简化!

SpringMVC的作用主要覆盖的是表述层,例如:

  • 请求映射

  • 数据输入

  • 视图界面

  • 请求分发

  • 表单回显

  • 会话控制

  • 过滤拦截

  • 异步交互

  • 文件上传

  • 文件下载

  • 数据校验

  • 类型转换

  • 等等等

总的来说就是,1. 简化前端参数接收( 形参列表 )

  1. 简化后端数据响应(返回值)

  2. 以及其他......

3.核心组件及调用流程

SpringMVC涉及组件理解:

  1. DispatcherServlet : SpringMVC提供,我们需要使用web.xml配置使其生效,它是整个流程处理的核心,所有请求都经过它的处理和分发![ CEO ]

  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数据,不返回页面,那就不需要视图解析器!所以,视图解析器,相对其他的组件不是必须的![财务]

二、SpringMVC接收数据

1.访问路径设置

1.1精准路径匹配

在@RequestMapping注解指定 URL 地址时,不使用任何通配符,按照请求地址进行精确匹配。

java 复制代码
@Controller
public class UserController {

    /**
     * 精准设置访问地址 /user/login
     */
    @RequestMapping(value = {"/user/login"})
    @ResponseBody
    public String login(){
        System.out.println("UserController.login");
        return "login success!!";
    }

    /**
     * 精准设置访问地址 /user/register
     */
    @RequestMapping(value = {"/user/register"})
    @ResponseBody
    public String register(){
        System.out.println("UserController.register");
        return "register success!!";
    }
    
}

1.2模糊路径匹配

在@RequestMapping注解指定 URL 地址时,通过使用通配符,匹配多个类似的地址。

java 复制代码
@Controller
public class ProductController {

    /**
     *  路径设置为 /product/*  
     *    /* 为单层任意字符串  /product/a  /product/aaa 可以访问此handler  
     *    /product/a/a 不可以
     *  路径设置为 /product/** 
     *   /** 为任意层任意字符串  /product/a  /product/aaa 可以访问此handler  
     *   /product/a/a 也可以访问
     */
    @RequestMapping("/product/*")
    @ResponseBody
    public String show(){
        System.out.println("ProductController.show");
        return "product show!";
    }
}

单层匹配和多层匹配:

/*:只能匹配URL地址中的一层,如果想准确匹配两层,那么就写"/*/*"以此类推。

/**:可以匹配URL地址中的多层。

其中所谓的一层或多层是指一个URL地址字符串被"/"划分出来的各个层次

这个知识点虽然对于@RequestMapping注解来说实用性不大,但是将来配置拦截器的时候也遵循这个规则。

1.3类和方法级别区别

`@RequestMapping` 注解可以用于类级别和方法级别,它们之间的区别如下:

  1. 设置到类级别:`@RequestMapping` 注解可以设置在控制器类上,用于映射整个控制器的通用请求路径。这样,如果控制器中的多个方法都需要映射同一请求路径,就不需要在每个方法上都添加映射路径。

  2. 设置到方法级别:`@RequestMapping` 注解也可以单独设置在控制器方法上,用于更细粒度地映射请求路径和处理方法。当多个方法处理同一个路径的不同操作时,可以使用方法级别的 `@RequestMapping` 注解进行更精细的映射。

java 复制代码
//1.标记到handler方法
@RequestMapping("/user/login")
@RequestMapping("/user/register")
@RequestMapping("/user/logout")

//2.优化标记类+handler方法
//类上
@RequestMapping("/user")
//handler方法上
@RequestMapping("/login")
@RequestMapping("/register")
@RequestMapping("/logout")

1.4附带请求方式限制

HTTP 协议定义了八种请求方式,在 SpringMVC 中封装到了下面这个枚举类:

java 复制代码
public enum RequestMethod {
  GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}

默认情况下:@RequestMapping("/logout") 任何请求方式都可以访问!
如果需要特定指定:

java 复制代码
@Controller
public class UserController {

    /**
     * 精准设置访问地址 /user/login
     * method = RequestMethod.POST 可以指定单个或者多个请求方式!
     * 注意:违背请求方式会出现405异常!
     */
    @RequestMapping(value = {"/user/login"} , method = RequestMethod.POST)
    @ResponseBody
    public String login(){
        System.out.println("UserController.login");
        return "login success!!";
    }

    /**
     * 精准设置访问地址 /user/register
     */
    @RequestMapping(value = {"/user/register"},method = {RequestMethod.POST,RequestMethod.GET})
    @ResponseBody
    public String register(){
        System.out.println("UserController.register");
        return "register success!!";
    }

}

注意:违背请求方式,会出现405异常!!!

1.5进阶注解

还有 `@RequestMapping` 的 HTTP 方法特定快捷方式变体:

  • `@GetMapping`

  • `@PostMapping`

  • `@PutMapping`

  • `@DeleteMapping`

  • `@PatchMapping`

java 复制代码
@RequestMapping(value="/login",method=RequestMethod.GET)
||
@GetMapping(value="/login")

注意:进阶注解只能添加到handler方法上,无法添加到类上!

2.接收参数

2.1param和json参数的区别

在 HTTP 请求中,我们可以选择不同的参数类型,如 param 类型和 JSON 类型。下面对这两种参数类型进行区别和对比:

(1)参数编码:

param 类型的参数会被编码为 ASCII 码。例如,假设 name=john doe,则会被编码为 name=john%20doe。而 JSON 类型的参数会被编码为 UTF-8。

(2)参数顺序:

param 类型的参数没有顺序限制。但是,JSON 类型的参数是有序的。JSON 采用键值对的形式进行传递,其中键值对是有序排列的。

(3)数据类型:

param 类型的参数仅支持字符串类型、数值类型和布尔类型等简单数据类型。而 JSON 类型的参数则支持更复杂的数据类型,如数组、对象等。

(4)嵌套性:

param 类型的参数不支持嵌套。但是,JSON 类型的参数支持嵌套,可以传递更为复杂的数据结构。

(5)可读性:

param 类型的参数格式比 JSON 类型的参数更加简单、易读。但是,JSON 格式在传递嵌套数据结构时更加清晰易懂。

在实际开发中,常见的做法是:在 GET 请求中采用 param 类型的参数,而在 POST 请求中采用 JSON 类型的参数传递。

2.2param参数接收

2.2.1直接接值

客户端请求

handler接收参数

只要形参数名和类型与传递参数相同,即可自动接收!

java 复制代码
@Controller
@RequestMapping("param")
public class ParamController {

    /**
     * 前端请求: http://localhost:8080/param/value?name=xx&age=18
     *
     * 可以利用形参列表,直接接收前端传递的param参数!
     *    要求: 参数名 = 形参名
     *          类型相同
     * 出现乱码正常,json接收具体解决!!
     * @return 返回前端数据
     */
    @GetMapping(value="/value")
    @ResponseBody
    public String setupForm(String name,int age){
        System.out.println("name = " + name + ", age = " + age);
        return name + age;
    }
}
2.2.2@RequestParam注解

可以使用 @RequestParam 注释将 Servlet 请求参数(即查询参数或表单数据)绑定到控制器中的方法参数。

@RequestParam使用场景:

指定绑定的请求参数名

要求请求参数必须传递

为请求参数提供默认值
基本用法:

java 复制代码
 /**
 * 前端请求: http://localhost:8080/param/data?name=xx&stuAge=18
 * 
 *  使用@RequestParam注解标记handler方法的形参
 *  指定形参对应的请求参数@RequestParam(请求参数名称)
 */
@GetMapping(value="/data")
@ResponseBody
public Object paramForm(@RequestParam("name") String name, 
                        @RequestParam("stuAge") int age){
    System.out.println("name = " + name + ", age = " + age);
    return name+age;
}

默认情况下,使用此批注的方法参数是必需的,但您可以通过将 @RequestParam 批注的 required 标志设置为 false!
将参数设置非必须,并且设置默认值:

java 复制代码
@GetMapping(value="/data")
@ResponseBody
public Object paramForm(@RequestParam("name") String name, 
                        @RequestParam(value = "stuAge",required = false,defaultValue = "18") int age){
    System.out.println("name = " + name + ", age = " + age);
    return name+age;
}
2.2.3特殊场景接值
(1)一名多值

多选框,提交的数据的时候一个key对应多个值,我们可以使用集合进行接收!

java 复制代码
  /**
   * 前端请求: http://localhost:8080/param/mul?hbs=吃&hbs=喝
   *
   *  一名多值,可以使用集合接收即可!但是需要使用@RequestParam注解指定
   */
  @GetMapping(value="/mul")
  @ResponseBody
  public Object mulForm(@RequestParam List<String> hbs){
      System.out.println("hbs = " + hbs);
      return hbs;
  }
(2)实体接收

Spring MVC 是 Spring 框架提供的 Web 框架,它允许开发者使用实体对象来接收 HTTP 请求中的参数。通过这种方式,可以在方法内部直接使用对象的属性来访问请求参数,而不需要每个参数都写一遍。下面是一个使用实体对象接收参数的示例:

java 复制代码
public class User {

  private String name;

  private int age = 18;

  // getter 和 setter 略
}
java 复制代码
@Controller
@RequestMapping("param")
public class ParamController {

    @RequestMapping(value = "/user", method = RequestMethod.POST)
    @ResponseBody
    public String addUser(User user) {
        // 在这里可以使用 user 对象的属性来接收请求参数
        System.out.println("user = " + user);
        return "success";
    }
}

在上述代码中,将请求参数name和age映射到实体类属性上!要求属性名必须等于参数名!否则无法映射!

2.3路径参数接收

路径传递参数是一种在 URL 路径中传递参数的方式。在 RESTful 的 Web 应用程序中,经常使用路径传递参数来表示资源的唯一标识符或更复杂的表示方式。而 Spring MVC 框架提供了 `@PathVariable` 注解来处理路径传递参数。

`@PathVariable` 注解允许将 URL 中的占位符映射到控制器方法中的参数。

例如,如果我们想将 `/user/{id}` 路径下的 `{id}` 映射到控制器方法的一个参数中,则可以使用 `@PathVariable` 注解来实现。

下面是一个使用 `@PathVariable` 注解处理路径传递参数的示例:

java 复制代码
 /**
 * 动态路径设计: /user/{动态部分}/{动态部分}   动态部分使用{}包含即可! {}内部动态标识!
 * 形参列表取值: @PathVariable Long id  如果形参名 = {动态标识} 自动赋值!
 *              @PathVariable("动态标识") Long id  如果形参名 != {动态标识} 可以通过指定动态标识赋值!
 *
 * 访问测试:  /param/user/1/root  -> id = 1  uname = root
 */
@GetMapping("/user/{id}/{name}")
@ResponseBody
public String getUser(@PathVariable Long id, 
                      @PathVariable("name") String uname) {
    System.out.println("id = " + id + ", uname = " + uname);
    return "user_detail";
}

2.4json参数接收

前端传递 JSON 数据时,Spring MVC 框架可以使用 @RequestBody 注解来将 JSON 数据转换为 Java 对象。@RequestBody 注解表示当前方法参数的值应该从请求体中获取,并且需要指定 value 属性来指示请求体应该映射到哪个参数上。其使用方式和示例代码如下:

(1)前端传递 JSON 数据

XML 复制代码
{
  "name": "张三",
  "age": 18,
  "gender": "男"
}

(2)定义一个用于接收 JSON 数据的 Java 类,例如:

java 复制代码
public class Person {
  private String name;
  private int age;
  private String gender;
  // getter 和 setter 略
}

(3)在控制器中,使用 @RequestBody 注解来接收 JSON 数据,并将其转换为 Java 对象,例如:

java 复制代码
@PostMapping("/person")
@ResponseBody
public String addPerson(@RequestBody Person person) {

  // 在这里可以使用 person 对象来操作 JSON 数据中包含的属性
  return "success";
}

(4)配置json数据类型处理配置类 springboot环境下不用

java 复制代码
//TODO: SpringMVC对应组件的配置类 [声明SpringMVC需要的组件信息]

//TODO: 导入handlerMapping和handlerAdapter的三种方式
 //1.自动导入handlerMapping和handlerAdapter [推荐]
 //2.可以不添加,springmvc会检查是否配置handlerMapping和handlerAdapter,没有配置默认加载
 //3.使用@Bean方式配置handlerMapper和handlerAdapter
@EnableWebMvc  //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller") //TODO: 进行controller扫描

//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {


}

(5)导入json类型处理的工具(jackson) springboot环境下不用

pom.xml 加入jackson依赖

XML 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.0</version>
</dependency>

3.接收Cookie数据

可以使用 @CookieValue 注释将 HTTP Cookie 的值绑定到控制器中的方法参数。

考虑使用以下 cookie 的请求:

java 复制代码
JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

下面的示例演示如何获取 cookie 值:

java 复制代码
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) { 
  //...
}

4.接收请求头数据

可以使用 @RequestHeader 批注将请求标头绑定到控制器中的方法参数。

请考虑以下带有标头的请求:

TypeScript 复制代码
Host                    localhost:8080
Accept                  text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language         fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding         gzip,deflate
Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive              300

下面的示例获取 Accept-Encoding 和 Keep-Alive 标头的值:

java 复制代码
@GetMapping("/demo")
public void handle(
    @RequestHeader("Accept-Encoding") String encoding, 
    @RequestHeader("Keep-Alive") long keepAlive) { 
  //...
}

5.共享域对象操作

5.1属性(共享)域作用回顾

在 JavaWeb 中,共享域指的是在 Servlet 中存储数据,以便在同一 Web 应用程序的多个组件中进行共享和访问。常见的共享域有四种:ServletContext、HttpSession、HttpServletRequest、PageContext。

1.ServletContext 共享域:ServletContext 对象可以在整个 Web 应用程序中共享数据,是最大的共享域。一般可以用于保存整个 Web 应用程序的全局配置信息,以及所有用户都共享的数据。在 ServletContext 中保存的数据是线程安全的。

2.HttpSession 共享域:HttpSession 对象可以在同一用户发出的多个请求之间共享数据,但只能在同一个会话中使用。比如,可以将用户登录状态保存在 HttpSession 中,让用户在多个页面间保持登录状态。

3.HttpServletRequest 共享域:HttpServletRequest 对象可以在同一个请求的多个处理器方法之间共享数据。比如,可以将请求的参数和属性存储在 HttpServletRequest 中,让处理器方法之间可以访问这些数据。

4.PageContext 共享域:PageContext 对象是在 JSP 页面Servlet 创建时自动创建的。它可以在 JSP 的各个作用域中共享数据,包括pageScope、requestScope、sessionScope、applicationScope 等作用域。
共享域的作用是提供了方便实用的方式在同一 Web 应用程序的多个组件之间传递数据,并且可以将数据保存在不同的共享域中,根据需要进行选择和使用。

5.2Request级别属性(共享)域

5.2.1使用 Model 类型的形参
java 复制代码
@RequestMapping("/attr/request/model")
@ResponseBody
public String testAttrRequestModel(
    
        // 在形参位置声明Model类型变量,用于存储模型数据
        Model model) {
    
    // 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
    // 存入请求域这个动作也被称为暴露到请求域
    model.addAttribute("requestScopeMessageModel","i am very happy[model]");
    
    return "target";
}
5.2.2使用 ModelMap 类型的形参
java 复制代码
@RequestMapping("/attr/request/model/map")
@ResponseBody
public String testAttrRequestModelMap(
    
        // 在形参位置声明ModelMap类型变量,用于存储模型数据
        ModelMap modelMap) {
    
    // 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
    // 存入请求域这个动作也被称为暴露到请求域
    modelMap.addAttribute("requestScopeMessageModelMap","i am very happy[model map]");
    
    return "target";
}
5.2.3使用 Map 类型的形参
java 复制代码
@RequestMapping("/attr/request/map")
@ResponseBody
public String testAttrRequestMap(
    
        // 在形参位置声明Map类型变量,用于存储模型数据
        Map<String, Object> map) {
    
    // 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
    // 存入请求域这个动作也被称为暴露到请求域
    map.put("requestScopeMessageMap", "i am very happy[map]");
    
    return "target";
}
5.2.4使用原生 request 对象
java 复制代码
@RequestMapping("/attr/request/original")
@ResponseBody
public String testAttrOriginalRequest(
    
        // 拿到原生对象,就可以调用原生方法执行各种操作
        HttpServletRequest request) {
    
    request.setAttribute("requestScopeMessageOriginal", "i am very happy[original]");
    
    return "target";
}
5.2.5使用 ModelAndView 对象
java 复制代码
@RequestMapping("/attr/request/mav")
public ModelAndView testAttrByModelAndView() {
    
    // 1.创建ModelAndView对象
    ModelAndView modelAndView = new ModelAndView();
    // 2.存入模型数据
    modelAndView.addObject("requestScopeMessageMAV", "i am very happy[mav]");
    // 3.设置视图名称
    modelAndView.setViewName("target");
    
    return modelAndView;
}

5.3Session级别属性共享域

java 复制代码
@RequestMapping("/attr/session")
@ResponseBody
public String testAttrSession(HttpSession session) {
    //直接对session对象操作,即对会话范围操作!
    return "target";
}

5.4Application级别属性(共享)域

解释:springmvc会在初始化容器的时候,将servletContext对象存储到ioc容器中!

java 复制代码
@Autowired
private ServletContext servletContext;

@RequestMapping("/attr/application")
@ResponseBody
public String attrApplication() {
    
    servletContext.setAttribute("appScopeMsg", "i am hungry...");
    
    return "target";
}

三、SpringMVC响应数据

1.handler方法分析

java 复制代码
/**
 * TODO: 一个controller的方法是控制层的一个处理器,我们称为handler
 * TODO: handler需要使用@RequestMapping/@GetMapping系列,声明路径,在HandlerMapping中注册,供DS查找!
 * TODO: handler作用总结:
 *       1.接收请求参数(param,json,pathVariable,共享域等) 
 *       2.调用业务逻辑 
 *       3.响应前端数据(页面(不讲解模版页面跳转),json,转发和重定向等)
 * TODO: handler如何处理呢
 *       1.接收参数: handler(形参列表: 主要的作用就是用来接收参数)
 *       2.调用业务: { 方法体  可以向后调用业务方法 service.xx() }
 *       3.响应数据: return 返回结果,可以快速响应前端数据
 */
@GetMapping
public Object handler(简化请求参数接收){
    调用业务方法
    返回的结果 (页面跳转,返回数据(json))
    return 简化响应前端数据;
}

总结: 请求数据接收,我们都是通过handler的形参列表

前端数据响应,我们都是通过handler的return关键字快速处理!

springmvc简化了参数接收和响应!

2.转发和重定向

在 Spring MVC 中,Handler 方法返回值来实现快速转发,可以使用 redirect 或者 forward 关键字来实现重定向。

java 复制代码
@RequestMapping("/redirect-demo")
public String redirectDemo() {
    // 重定向到 /demo 路径 
    return "redirect:/demo";
}

@RequestMapping("/forward-demo")
public String forwardDemo() {
    // 转发到 /demo 路径
    return "forward:/demo";
}

//注意: 转发和重定向到项目下资源路径都是相同,都不需要添加项目根路径!填写项目下路径即可!

3.返回JSON数据

3.1使用@ResponseBody

java 复制代码
@RequestMapping(value = "/user/detail", method = RequestMethod.POST)
@ResponseBody
public User getUser(@RequestBody User userParam) {
    System.out.println("userParam = " + userParam);
    User user = new User();
    user.setAge(18);
    user.setName("John");
    //返回的对象,会使用jackson的序列化工具,转成json返回给前端!
    return user;
}

3.2使用@RestController

类上的 @ResponseBody 注解可以和 @Controller 注解合并为 @RestController 注解。所以使用了 @RestController 注解就相当于给类中的每个方法都加了 @ResponseBody 注解。

四、SpringMVC其他扩展

1.全局异常处理

1.1异常处理两种方式

开发过程中是不可避免地会出现各种异常情况的,例如网络连接异常、数据格式异常、空指针异常等等。异常的出现可能导致程序的运行出现问题,甚至直接导致程序崩溃。因此,在开发过程中,合理处理异常、避免异常产生、以及对异常进行有效的调试是非常重要的。

对于异常的处理,一般分为两种方式:

**编程式异常处理:**是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。

**声明式异常处理:**则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws 或 @ExceptionHandler),就可以处理特定类型的异常。相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。

1.2基于注解异常声明异常处理

java 复制代码
/**
 * @RestControllerAdvice = @ControllerAdvice + @ResponseBody
 * @ControllerAdvice 代表当前类的异常处理controller! 
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
        /**
     * 异常处理handler 
     * @ExceptionHandler(HttpMessageNotReadableException.class) 
     * 该注解标记异常处理Handler,并且指定发生异常调用该方法!
     * 
     * 
     * @param e 获取异常对象!
     * @return 返回handler处理结果!
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Object handlerJsonDateException(HttpMessageNotReadableException e){
        
        return null;
    }
    
    /**
     * 当发生空指针异常会触发此方法!
     * @param e
     * @return
     */
    @ExceptionHandler(NullPointerException.class)
    public Object handlerNullException(NullPointerException e){
    
        return null;
    }
    
    /**
     * 所有异常都会触发此方法!但是如果有具体的异常处理Handler! 
     * 具体异常处理Handler优先级更高!
     * 例如: 发生NullPointerException异常!
     *       会触发handlerNullException方法,不会触发handlerException方法!
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public Object handlerException(Exception e){
    
        return null;
    }

  
}

2.拦截器使用

2.1拦截器概念

拦截器 Springmvc VS 过滤器 javaWeb:

相似点:

拦截:必须先把请求拦住,才能执行后续操作

过滤:拦截器或过滤器存在的意义就是对请求进行统一处理

放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源

不同点:

工作平台不同:

过滤器工作在 Servlet 容器中

拦截器工作在 SpringMVC 的基础上

拦截的范围:

过滤器:能够拦截到的最大范围是整个 Web 应用

拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求

IOC 容器支持:

过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的

拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持

2.2拦截器使用

(1)创建拦截器

java 复制代码
public class Process01Interceptor implements HandlerInterceptor {

    // if( ! preHandler()){return;}
    // 在处理请求的目标 handler 方法前执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("request = " + request + ", response = " + response + ", handler = " + handler);
        System.out.println("Process01Interceptor.preHandle");
         
        // 返回true:放行
        // 返回false:不放行
        return true;
    }
 
    // 在目标 handler 方法之后,handler报错不执行!
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", modelAndView = " + modelAndView);
        System.out.println("Process01Interceptor.postHandle");
    }
 
    // 渲染视图之后执行(最后),一定执行!
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("request = " + request + ", response = " + response + ", handler = " + handler + ", ex = " + ex);
        System.out.println("Process01Interceptor.afterCompletion");
    }
}

(2)配置拦截器

在配置类配置

a.默认拦截全部

java 复制代码
@Override
public void addInterceptors(InterceptorRegistry registry) {
    //将拦截器添加到Springmvc环境,默认拦截所有Springmvc分发的请求
    registry.addInterceptor(new Process01Interceptor());
}

b.精准配置

java 复制代码
@Override
public void addInterceptors(InterceptorRegistry registry) {
    
    //将拦截器添加到Springmvc环境,默认拦截所有Springmvc分发的请求
    registry.addInterceptor(new Process01Interceptor());
    
    //精准匹配,设置拦截器处理指定请求 路径可以设置一个或者多个,为项目下路径即可
    //addPathPatterns("/common/request/one") 添加拦截路径
    //也支持 /* 和 /** 模糊路径。 * 任意一层字符串 ** 任意层 任意字符串
    registry.addInterceptor(new Process01Interceptor()).addPathPatterns("/common/request/one","/common/request/tow");
}

c.排除配置

java 复制代码
//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
    
    //将拦截器添加到Springmvc环境,默认拦截所有Springmvc分发的请求
    registry.addInterceptor(new Process01Interceptor());
    
    //精准匹配,设置拦截器处理指定请求 路径可以设置一个或者多个,为项目下路径即可
    //addPathPatterns("/common/request/one") 添加拦截路径
    registry.addInterceptor(new Process01Interceptor()).addPathPatterns("/common/request/one","/common/request/tow");
    
    
    //排除匹配,排除应该在匹配的范围内排除
    //addPathPatterns("/common/request/one") 添加拦截路径
    //excludePathPatterns("/common/request/tow"); 排除路径,排除应该在拦截的范围内
    registry.addInterceptor(new Process01Interceptor())
            .addPathPatterns("/common/request/one","/common/request/tow")
            .excludePathPatterns("/common/request/tow");
}

3.参数校验

在 Web 应用三层架构体系中,表述层负责接收浏览器提交的数据,业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理,我们需要在表述层对数据进行检查,将错误的数据隔绝在业务逻辑层之外。

注解 规则
@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) 标注值必须符合指定的正则表达式

。。。

java 复制代码
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import org.hibernate.validator.constraints.Length;

/**
 * projectName: com.atguigu.pojo
 */
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;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
java 复制代码
@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;
    }
}
相关推荐
奔驰的小野码24 分钟前
SpringAI实现AI应用-搭建知识库
java·人工智能·spring boot·后端·spring·知识图谱
小杜-coding1 小时前
黑马点评day01(基于Redis)
java·数据库·spring boot·redis·spring·缓存·mybatis
燃星cro2 小时前
关于MindVault项目测试报告
java·开发语言·测试工具·spring
-曾牛2 小时前
Spring AI聊天模型API:轻松构建智能聊天交互
java·人工智能·后端·spring·交互·api·springai
汤姆大聪明10 小时前
Spring MVC入门
java·spring·mvc
-曾牛13 小时前
探索 Spring AI 的 ChatClient API:构建智能对话应用的利器
java·人工智能·spring boot·后端·spring·springai·ai指南
白露与泡影13 小时前
使用OAuth2保护Spring AI MCP服务!
java·后端·spring
magic 24513 小时前
Spring 命名空间注入:p、c 与 .util 的深度解析
java·前端·spring
橘猫云计算机设计14 小时前
基于springboot的金院银行厅预约系统的设计及实现(源码+lw+部署文档+讲解),源码可白嫖!
java·数据库·spring boot·后端·爬虫·spring·毕业设计
Aurora_NeAr14 小时前
Spring IoC容器的设计与实现
java·后端·spring