springmvc 讲解(2)

系列文章目录

springmvc讲解(1 )点击此处即可


文章目录

  • 系列文章目录
  • 一、Springmvc发送数据
    • 1、快速跳转页面
      • 1.1 开发模式讲解
      • 1.2 jsp简述
      • 1.3 页面跳转控制
      • 1.4 转发和重定向
    • 2、返回json数据
      • 2.1 @ResponseBody 注解
      • 2.2 @RestController注解
    • 3、访问静态资源
      • 3.1 静态资源概念
      • 3.2 静态资源访问
  • 二、RESTFul风格设计与实战
    • 2.1 概述
    • 2.2 RESFul风格特点
    • 2.3 RESFul 风格设计规范
    • 2.4 RESFul 风格设计好处
    • 2.5 实战
      • 2.5.1 需求分析
      • 2.5.2 接口分析与设计
        • 2.5.2.1 问题taolun
      • 2.5.3 后台接口实现
  • 三、Springmvc其它扩展
    • 3.1 全局异常配置
      • 3.1.1 异常处理的两种机制
      • 3.1.2 基于注解机制的全局异常配置
    • 3.2 拦截器概念和基本使用
      • 3.2.1 拦截器和javaweb中的过滤器
      • 3.2.2 拦截器的使用
    • 3.3 参数校验注解jsr303
      • 3.1 常用注解
      • 3.2 操作演示
        • 3.2.1 导入依赖
        • 3.2.2 创建实体类同时加上校验注解
        • 3.2.3 handler方法接收实体类进行判断
        • 3.2.4结果
        • 3.2.5 注意:
        • 3.2.6 易混
  • 总结


一、Springmvc发送数据

我们知道springmvc最重要的两个功能①简化参数接收 ②简化数据响应

1、快速跳转页面

1.1 开发模式讲解

在当前,主要有两种开发模式,一是前后端分离【主要】,二是前后端混合开发。
①前后端分离模式
指将前端的界面和后端的业务逻辑通过接口分离开发的一种方式。开发人员使用不同的技术栈和框架,前端开发人员主要负责页面的呈现和用户交互,后端开发人员主要负责业务逻辑和数据存储。前后端通信通过 API 接口完成,数据格式一般使用 JSON 或 XML。前后端分离模式可以提高开发效率,同时也有助于代码重用和维护。
②前后端混合开发
指将前端和后端的代码集成在同一个项目中,共享相同的技术栈和框架。这种模式在小型项目中比较常见,可以减少学习成本和部署难度。但是,在大型项目中,这种模式会导致代码耦合性很高,维护和升级难度较大。

对于混合开发,我们就需要使用动态页面技术,动态展示Java的共享域数据!!

1.2 jsp简述

JSP(JavaServer Pages)是一种动态网页开发技术,它是由 Sun 公司提出的一种基于 Java 技术的 Web 页面制作技术,可以在 HTML 文件中嵌入 Java 代码,使得生成动态内容的编写更加简单。

JSP 最主要的作用是生成动态页面。它允许将 Java 代码嵌入到 HTML 页面中,以便使用 Java 进行数据库查询、处理表单数据和生成 HTML 等动态内容。另外,JSP 还可以与 Servlet 结合使用,实现更加复杂的 Web 应用程序开发。

JSP 的主要特点包括:

  1. 简单:JSP 通过将 Java 代码嵌入到 HTML 页面中,使得生成动态内容的编写更加简单。
  2. 高效:JSP 首次运行时会被转换为 Servlet,然后编译为字节码,从而可以启用 Just-in-Time(JIT)编译器,实现更高效的运行。
  3. 多样化:JSP 支持多种标准标签库,包括 JSTL(JavaServer Pages 标准标签库)、EL(表达式语言)等,可以帮助开发人员更加方便的处理常见的 Web 开发需求。

总之,JSP 是一种简单高效、多样化的动态网页开发技术,它可以方便地生成动态页面和与 Servlet 结合使用,是 Java Web 开发中常用的技术之一。

1.3 页面跳转控制

在这里我们访问一个地址,其返回一个jsp页面,这也是前后端混合开发。
a 、导入jsp依赖

<!-- jsp需要依赖! jstl-->
<dependency>
    <groupId>jakarta.servlet.jsp.jstl</groupId>
    <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
    <version>3.0.0</version>
</dependency>

b、 准备一个jsp页面 放在web-inf 下 避免外部访问
WEB-INF/views/index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<!-- 可以获取共享域的数据,动态展示! jsp== 后台vue -->
${data}
</body>
</html>

c、准备一个handler

注意:返回页面 需要视图解析器 不能添加@ResponseBody注解


@Controller
@RequestMapping("jsp")
public class JspController {
    @GetMapping("data")
    public String data(HttpServletRequest request){
        request.setAttribute("data","cui"); //设置一个数据共享域
        System.out.println("FileController.jumpJsp");
        return "index"; //这里是返回一个视图函数 会加前缀和后缀 见下方
    }

d、配置jsp视图解析器(配置类)
@EnableWebMvc 注解会将handlermapping 和handleradapter 放入ioc容器中 所以我们不必再加入其第三方类,同时也会给adapter加上json转换器。

配置jsp视图解析器 我们可以实现WebMvcConfigurer 类,重载其方法,WebMvcConfigurer类有很多方法,比如configureViewResolvers,我们可以重载该方法,可以很方便的配置jsp模板语言对应的前缀和后缀。

@Configuration
@ComponentScan(basePackages = "com.cky.controller")
@EnableWebMvc
public class Myconfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
    //配置jsp模板语言对应的前缀和后缀 是字符串拼接 注意/
        registry.jsp("/WEB-INF/jsp/",".jsp");
    }
}

e、初始化配置 (比如配置类 等)

package com.cky.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class ConfigInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{Myconfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

1.4 转发和重定向


    /**
     * 1、转发
     *   ① 方法返回值要写成字符串
     *   ②不能加@RequestBody方法
     *   ③返回字符串前面加上 forward:
     */
    @GetMapping("forward")
    public String forward(){
        System.out.println("JspController.forward");
        return "forward:/jsp/data";
    }
    /**
     * 1、重定向
     *   ① 方法返回值要写成字符串
     *   ②不能加@RequestBody方法
     *   ③返回字符串前面加上 redirect:
     */

    @GetMapping("redirect")
    public String redirect(){
        System.out.println("JspController.redirect");
        return "redirect:/jsp/data";
    }
    /**
     *  路径细节:不使用springmvc时 request,respond
     *   ① 转发:都是自己项目路径下的项目:不用加Application Context
     *   ②重定向:二次转发 可以是外部资源项目地址 要加上Application Context
     *    使用Springmvc时 springmvc会为我们做一个优化
     *    ①转发 和上边相同
     *    ②重定向:会自动为我们加上自己项目路径 也不用加Application Context
     *    如果要重定向到外部资源的话,就直接在redirect后 写要重定向的地址即可
     */
    @GetMapping("redirectbaidu")
    public String baidu(){
        System.out.println("JspController.baidu");
        return "redirect:https://www.baidu.com/";
    }

转发时页面地址仍然是第一个 不会改变。
重定向会改变页面地址。

2、返回json数据

对于json数据,我们可以直接返回一个实体类 或者实体类集合。
handleradapter会自动帮我们解析该实体类,返回成一个可以接收的json数据。
比如我们有一个User类

package com.cky.pojo;

import lombok.Data;

@Data
public class User {
    private String name;
    private int age;
}

我们的handler方法


    /**
     * 返回json数据
     *  注意要加上@ResponseBody 注解 证明我们返回的是信息体 可以让Handleradapter 帮我们转化为json数据
     */
    @ResponseBody
    @GetMapping("user")
    public User user(){
        User user = new User();
        user.setAge(18);
        user.setName("cui");
        return user;
    }
    @GetMapping("userlist")
    @ResponseBody
    public List<User> users(){
        List<User> userList=new ArrayList<>();
        User user = new User();
        user.setName("jiang");
        user.setAge(23);
        userList.add(user);
        return userList;
    }
}

在这里插入图片描述

在这里插入图片描述

2.1 @ResponseBody 注解

可以在方法上使用 @ResponseBody注解,用于将方法返回的对象序列化为 JSON 或 XML 格式的数据,并发送给客户端。在前后端分离的项目中使用!
如果每个方法上都加了该注解,我们可以直接在类上使用。
具体来说,@ResponseBody 注解可以用来标识方法或者方法返回值,表示方法的返回值是要直接返回给客户端的数据,而不是由视图解析器来解析并渲染生成响应体(viewResolver没用)。

2.2 @RestController注解

该注解 等同于@Controller+@ResponseBody注解
直接在类上使用

3、访问静态资源

3.1 静态资源概念

资源本身已经是可以直接拿到浏览器上使用的程度了,不需要在服务器端做任何运算、处理。典型的静态资源包括:

  • 纯HTML文件
  • 图片
  • CSS文件
  • JavaScript文件
  • ……

3.2 静态资源访问

在这里插入图片描述
打包和编译部署后 图片都存在
但是在访问时 却显示404错误
在这里插入图片描述
解决方法:
在配置文件中添加上

    @Override
      //开启静态资源处理 <mvc:default-servlet-handler/>
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

为什么会报404 错误呢?
这是因为在使用springmvc时,dispatcherhandler会首先找handlermapping这个秘书,看是否有该地址对应的handler,如果有在访问其handler,如果没有会报404错误。
当我们开启了该配置之后。相当于给ceo配置了一个二秘书,首先找handlermapping这个秘书,如果没有对应handler,就会去找该项目下的静态资源。
再添加上该类之后,我们就可以访问静态资源了。

二、RESTFul风格设计与实战

2.1 概述

RESTful(Representational State Transfer)是一种软件架构风格,用于设计网络应用程序和服务之间的通信。它是一种基于标准 HTTP 方法的简单和轻量级的通信协议,广泛应用于现代的Web服务开发。

通过遵循 RESTful 架构的设计原则,可以构建出易于理解、可扩展、松耦合和可重用的 Web 服务。RESTful API 的特点是简单、清晰,并且易于使用和理解,它们使用标准的 HTTP 方法和状态码进行通信,不需要额外的协议和中间件。

总而言之,RESTful 是一种基于 HTTP 和标准化的设计原则的软件架构风格,用于设计和实现可靠、可扩展和易于集成的 Web 服务和应用程序!
学习RESTful设计原则可以帮助我们更好去设计HTTP协议的API接口!!

主要解决了
1、URL
2、哪种请求方式
3、如何传递参数
这也是http请求的必要项

2.2 RESFul风格特点

  1. 每一个URI代表1种资源(URI 是名词);
  2. 客户端使用GET、POST、PUT、DELETE 4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
  3. 资源的表现形式是XML或者JSON
  4. 客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。

2.3 RESFul 风格设计规范

  1. HTTP协议请求方式要求

    REST 风格主张在项目设计、开发过程中,具体的操作符合HTTP协议定义的请求方式的语义

操作请求方式
查询操作GET
保存操作POST
删除操作DELETE
更新操作PUT
  1. URL路径风格要求

    REST风格下每个资源都应该有一个唯一的标识符,例如一个 URI(统一资源标识符)或者一个 URL(统一资源定位符)。资源的标识符应该能明确地说明该资源的信息,同时也应该是可被理解和解释的!

    使用URL+请求方式确定具体的动作,他也是一种标准的HTTP协议请求!

操作传统风格REST 风格
保存/CRUD/saveEmpURL 地址:/CRUD/emp 请求方式:POST
删除/CRUD/removeEmp?empId=2URL 地址:/CRUD/emp/2 请求方式:DELETE
更新/CRUD/updateEmpURL 地址:/CRUD/emp 请求方式:PUT
查询/CRUD/editEmp?empId=2URL 地址:/CRUD/emp/2 请求方式:GET
  • 总结

    根据接口的具体动作,选择具体的HTTP协议请求方式

    路径设计从原来携带动标识,改成名词,对应资源的唯一标识即可!

2.4 RESFul 风格设计好处

  1. 含蓄,安全

    使用问号键值对的方式给服务器传递数据太明显,容易被人利用来对系统进行破坏。使用 REST 风格携带数据不再需要明显的暴露数据的名称。

  2. 风格统一

    URL 地址整体格式统一,从前到后始终都使用斜杠划分各个单词,用简单一致的格式表达语义。

  3. 无状态

    在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了系统设计的复杂度。

  4. 严谨,规范

    严格按照 HTTP1.1 协议中定义的请求方式本身的语义进行操作。

  5. 简洁,优雅

    过去做增删改查操作需要设计4个不同的URL,现在一个就够了。

操作传统风格REST 风格
保存/CRUD/saveEmpURL 地址:/CRUD/emp 请求方式:POST
删除/CRUD/removeEmp?empId=2URL 地址:/CRUD/emp/2 请求方式:DELETE
更新/CRUD/updateEmpURL 地址:/CRUD/emp 请求方式:PUT
查询/CRUD/editEmp?empId=2URL 地址:/CRUD/emp/2 请求方式:GET

2.5 实战

2.5.1 需求分析

  • 数据结构: User {id 唯一标识,name 用户名,age 用户年龄}
  • 功能分析
    • 用户数据分页展示功能(条件:page 页数 默认1,size 每页数量 默认 10)
    • 保存用户功能
    • 根据用户id查询用户详情功能
    • 根据用户id更新用户数据功能
    • 根据用户id删除用户数据功能
    • 多条件模糊查询用户功能(条件:keyword 模糊关键字,page 页数 默认1,size 每页数量 默认 10)

2.5.2 接口分析与设计

功能接口和请求方式请求参数返回值
分页查询GET /userpage=1&size=10{ 响应数据 }
用户添加POST /user{ user 数据 }{响应数据}
用户详情GET /user/1路径参数{响应数据}
用户更新PUT /user{ user 更新数据}{响应数据}
用户删除DELETE /user/1路径参数{响应数据}
条件模糊GET /user/searchpage=1&size=10&keywork=关键字{响应数据}
2.5.2.1 问题taolun

为什么查询用户详情,就使用路径传递参数,多条件模糊查询,就使用请求参数传递?

误区:restful风格下,不是所有请求参数都是路径传递!可以使用其他方式传递!

在 RESTful API 的设计中,路径和请求参数和请求体都是用来向服务器传递信息的方式。

  • 对于查询用户详情,使用路径传递参数是因为这是一个单一资源的查询,即查询一条用户记录。使用路径参数可以明确指定所请求的资源,便于服务器定位并返回对应的资源,也符合 RESTful 风格的要求。
  • 而对于多条件模糊查询,使用请求参数传递参数是因为这是一个资源集合的查询,即查询多条用户记录。使用请求参数可以通过组合不同参数来限制查询结果,路径参数的组合和排列可能会很多,不如使用请求参数更加灵活和简洁。

此外,还有一些通用的原则可以遵循:

  • 路径参数应该用于指定资源的唯一标识或者 ID,而请求参数应该用于指定查询条件或者操作参数。
  • 请求参数应该限制在 10 个以内,过多的请求参数可能导致接口难以维护和使用。
  • 对于敏感信息,最好使用 POST 和请求体来传递参数。

2.5.3 后台接口实现

a.准备用户实体类

package com.atguigu.pojo;

/**
 * projectName: com.atguigu.pojo
 * 用户实体类
 */
public class User {

    private Integer id;
    private String name;

    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    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;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

b.准备用户Controller

/**
 * projectName: com.atguigu.controller
 *
 * description: 用户模块的控制器
 */
@RequestMapping("user")
@RestController
public class UserController {

    /**
     * 模拟分页查询业务接口
     */
    @GetMapping
    public Object queryPage(@RequestParam(name = "page",required = false,defaultValue = "1")int page,
                            @RequestParam(name = "size",required = false,defaultValue = "10")int size){
        System.out.println("page = " + page + ", size = " + size);
        System.out.println("分页查询业务!");
        return "{'status':'ok'}";
    }


    /**
     * 模拟用户保存业务接口
     */
    @PostMapping
    public Object saveUser(@RequestBody User user){
        System.out.println("user = " + user);
        System.out.println("用户保存业务!");
        return "{'status':'ok'}";
    }

    /**
     * 模拟用户详情业务接口
     */
    @PostMapping("/{id}")
    public Object detailUser(@PathVariable Integer id){
        System.out.println("id = " + id);
        System.out.println("用户详情业务!");
        return "{'status':'ok'}";
    }


    /**
     * 模拟用户更新业务接口
     */
    @PutMapping
    public Object updateUser(@RequestBody User user){
        System.out.println("user = " + user);
        System.out.println("用户更新业务!");
        return "{'status':'ok'}";
    }


    /**
     * 模拟条件分页查询业务接口
     */
    @GetMapping("search")
    public Object queryPage(@RequestParam(name = "page",required = false,defaultValue = "1")int page,
                            @RequestParam(name = "size",required = false,defaultValue = "10")int size,
                            @RequestParam(name = "keyword",required= false)String keyword){
        System.out.println("page = " + page + ", size = " + size + ", keyword = " + keyword);
        System.out.println("条件分页查询业务!");
        return "{'status':'ok'}";
    }
}

三、Springmvc其它扩展

3.1 全局异常配置

3.1.1 异常处理的两种机制

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

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

  • 编程式异常处理:是指在代码中显式地编写处理异常的逻辑。它通常涉及到对异常类型的检测及其处理,例如使用 try-catch 块来捕获异常,然后在 catch 块中编写特定的处理代码,或者在 finally 块中执行一些清理操作。在编程式异常处理中,开发人员需要显式地进行异常处理,异常处理代码混杂在业务代码中,导致代码可读性较差。
  • 声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。在声明式异常处理中,开发人员只需要为方法或类标注相应的注解(如 @Throws@ExceptionHandler),就可以处理特定类型的异常。相较于编程式异常处理,声明式异常处理可以使代码更加简洁、易于维护和扩展。

站在宏观角度来看待声明式事务处理:

整个项目从架构这个层面设计的异常处理的统一机制和规范。

一个项目中会包含很多个模块,各个模块需要分工完成。如果张三负责的模块按照 A 方案处理异常,李四负责的模块按照 B 方案处理异常……各个模块处理异常的思路、代码、命名细节都不一样,那么就会让整个项目非常混乱。

使用声明式异常处理,可以统一项目处理异常思路,项目更加清晰明了!

3.1.2 基于注解机制的全局异常配置

写一个类 专门用于配置全局异常
会找到对应的异常类 然后执行handler方法
有异常==》全局配置类==》找对应的精准异常handler方法
//全局配置类
@RestControllerAdvice//== @ResponseBody+@ControllerAdvice
@ExceptionHandler(ArithmeticException.class)

记得将全局异常配置类加到配置类的扫描文件中

package com.cky.controller;

import org.springframework.web.bind.annotation.*;

//全局配置类
@RestControllerAdvice//== @ResponseBody+@ControllerAdvice
public class errorController {
    @ExceptionHandler(ArithmeticException.class)
   public Object ArithmeticExceptionhandler(Exception e){
        System.out.println("errorController.ArithmeticExceptionhandler");
        return "errorController.ArithmeticExceptionhandler";

   }
   //如果有精准异常 则会执行精准异常
    //如果没有精准异常,则会执行父异常
   @ExceptionHandler(Exception.class)
   public Object Exception(Exception e){
       System.out.println("errorController.Exception");
       return "\"errorController.Exception\"";
   }
}

3.2 拦截器概念和基本使用

3.2.1 拦截器和javaweb中的过滤器

相似点:

  • 拦截:必须先把请求拦住,才能执行后续操作
  • 过滤:拦截器或过滤器存在的意义就是对请求进行统一处理
  • 放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源

不同点:

  • 工作平台不同

    • 过滤器工作在 Servlet 容器中
    • 拦截器工作在 SpringMVC 的基础上
  • 拦截的范围

    • 过滤器:能够拦截到的最大范围是整个 Web 应用
    • 拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求
  • IOC 容器支持

    • 过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的
    • 拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持

    选择:
    功能需要如果用 SpringMVC 的拦截器能够实现,就不使用过滤器。
    在这里插入图片描述

3.2.2 拦截器的使用

1、创建拦截类

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、修改配置类添加拦截器

@EnableWebMvc  //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = {"com.atguigu.controller","com.atguigu.exceptionhandler"}) //TODO: 进行controller扫描
//WebMvcConfigurer springMvc进行组件配置的规范,配置组件,提供各种方法! 前期可以实现
public class SpringMvcConfig implements WebMvcConfigurer {

    //配置jsp对应的视图解析器
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        //快速配置jsp模板语言对应的
        registry.jsp("/WEB-INF/views/",".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、配置详解:
拦截全部

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

精准配置

@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");
}

排除配置

//添加拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
    
    //将拦截器添加到Springmvc环境,默认拦4、截所有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");
}

4、多个拦截器执行顺序

  1. preHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置顺序调用各个 preHandle() 方法。
  2. postHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 postHandle() 方法。
  3. afterCompletion() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 afterCompletion() 方法。

3.3 参数校验注解jsr303

在 Web 应用三层架构体系中,表述层负责接收浏览器提交的数据,业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理,我们需要在表述层对数据进行检查,将错误的数据隔绝在业务逻辑层之外。
jsr303参数校验注解 可以直接使用在我们的实体类上。它是由hibernate实现的,所以我们需要导入其对应的依赖包。

3.1 常用注解

注解规则
@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标注值必须在指定的范围内

3.2 操作演示

3.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>
3.2.2 创建实体类同时加上校验注解
package com.cky.pojo;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class User {
  @NotBlank
    private String name;
  @Min(1)
    private int age;
  @Email
  private String email;
}

3.2.3 handler方法接收实体类进行判断
package com.cky.controller;

@RestController
@RequestMapping("user")
public class UserController {

    @RequestMapping("errorshow")
    public Object errorshow(@Validated @RequestBody User user, BindingResult bindingResult){
        if(bindingResult.hasErrors()){
            Map map=new HashMap();
            map.put("code","404");
            map.put("msg","参数校验错误");
            return map;
        }
        System.out.println("UserController.errorshow");
        return user;
    }
}

3.2.4结果

在这里我们使用json进行接收
如果都验证正确:
在这里插入图片描述
如果验证失败:
在这里插入图片描述

3.2.5 注意:

①我们在hanler 方法参数中验证的实体类必须加上@validated 注解,证明该实体类接收时需要校验,如果我们接收的是param参数,就不用加@ResquestBody了,默认就是接收param参数,如果接收的是json,就需要添加。
②关于校验失败返回信息,如果我们不接受错误信息,则会直接抛出异常,在这里我们绑定错误信息,自定义返回信息。在参数中添加BindingResult参数,注意该参数要紧挨着校验参数,否则自定义信息不起效果。

3.2.6 易混

@NotNull、@NotEmpty、@NotBlank 都是用于在数据校验中检查字段值是否为空的注解,但是它们的用法和校验规则有所不同。

  1. @NotNull (包装类型不为null)

    @NotNull 注解是 JSR 303 规范中定义的注解,当被标注的字段值为 null 时,会认为校验失败而抛出异常。该注解不能用于字符串类型的校验,若要对字符串进行校验,应该使用 @NotBlank 或 @NotEmpty 注解。

  2. @NotEmpty (集合类型长度大于0)

    @NotEmpty 注解同样是 JSR 303 规范中定义的注解,对于 CharSequence、Collection、Map 或者数组对象类型的属性进行校验,校验时会检查该属性是否为 Null 或者 size()==0,如果是的话就会校验失败。但是对于其他类型的属性,该注解无效。需要注意的是只校验空格前后的字符串,如果该字符串中间只有空格,不会被认为是空字符串,校验不会失败。

  3. @NotBlank (字符串,不为null,切不为" "字符串)

    @NotBlank 注解是 Hibernate Validator 附加的注解,对于字符串类型的属性进行校验,校验时会检查该属性是否为 Null 或 “” 或者只包含空格,如果是的话就会校验失败。需要注意的是,@NotBlank 注解只能用于字符串类型的校验。

总之,这三种注解都是用于校验字段值是否为空的注解,但是其校验规则和用法有所不同。在进行数据校验时,需要根据具体情况选择合适的注解进行校验。

总结

核心点掌握目标
springmvc框架主要作用、核心组件、调用流程
简化参数接收路径设计、参数接收、请求头接收、cookie接收
简化数据响应模板页面、转发和重定向、JSON数据、静态资源
restful风格设计主要作用、具体规范、请求方式和请求参数选择
功能扩展全局异常处理、拦截器、参数校验注解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/116194.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

通过在Z平面放置零极点的来设计数字滤波器

文章来源地址&#xff1a;https://www.yii666.com/blog/393376.html 通过在Z平面放置零极点的来设计数字滤波器 要求&#xff1a;设计一款高通滤波器&#xff0c;用在音频信号处理过程中&#xff0c;滤掉100Hz以下的信号。 实现方法&#xff1a;通过在Z平面放置零极点的来设…

独创改进 | RT-DETR 引入双向级联特征融合结构 RepBi-PAN | 附手绘结构图原图

本专栏内容均为博主独家全网首发,未经授权,任何形式的复制、转载、洗稿或传播行为均属违法侵权行为,一经发现将采取法律手段维护合法权益。我们对所有未经授权传播行为保留追究责任的权利。请尊重原创,支持创作者的努力,共同维护网络知识产权。 文章目录 YOLOv6贡献RepBi-…

NLP之Bert介绍和简单示例

文章目录 1. Bert 介绍2. 代码示例2.1 代码流程 1. Bert 介绍 2. 代码示例 from transformers import AutoTokenizertokenizer AutoTokenizer.from_pretrained("bert-base-chinese") input_ids tokenizer.encode(欢迎来到Bert世界, return_tensorstf) print(input…

Linux下input子系统

文章目录 input子系统简单介绍相关的函数input_dev注册过程上报输入事件按键的input子系统实验 input子系统简单介绍 input子系统是管理输入的子系统&#xff0c;和pinctrl和gpio子系统一样&#xff0c;都是Linux内核针对某一类设备而创建的框架。比如按键输入、键盘、鼠标、触…

【强化学习】16 ——PPO(Proximal Policy Optimization)

文章目录 前言TRPO的不足PPO特点 PPO-惩罚PPO-截断优势函数估计算法伪代码PPO 代码实践参考 前言 TRPO 算法在很多场景上的应用都很成功&#xff0c;但是我们也发现它的计算过程非常复杂&#xff0c;每一步更新的运算量非常大。于是&#xff0c;TRPO 算法的改进版——PPO 算法…

PHP 人才招聘管理系统mysql数据库web结构layUI布局apache计算机软件工程网页wamp

一、源码特点 PHP 人才招聘管理系统是一套完善的web设计系统 layUI技术布局 &#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 php人才招聘管理系统 代码 https://download.csdn.net/download/qq_4…

软件开发全文档归档,开发、管理、实施、运维、服务巡检、信息安全、安全运维

在当今高度信息化的时代&#xff0c;软件开发已成为推动社会进步和发展的重要力量。软件开发过程中&#xff0c;文件支撑作为关键的一环&#xff0c;对于保障项目的顺利进行和产品的质量具有不可替代的作用。本文将探讨软件开发所需的主要文件及其作用。 一、引言 软件开发是…

VR博物馆:让博物馆传播转化为品牌影响力

随着VR技术的不断进步&#xff0c;VR全景技术已经成为了文化展示和传播的一项重要工具&#xff0c;相较于传统视频、图文等展现方式&#xff0c;VR全景体验更加直观、便捷&#xff0c;其中蕴涵的信息量也更加丰富&#xff0c;这也为公众了解博物馆和历史文化带来了更为深刻的体…

802.11AX基础---走进HE WLAN

1、WiFi 6 是什么&#xff1f; WiFi 6是IEEE802.11ax的简称&#xff0c;也就是第六代WiFi的标准&#xff1b;它在继承前几代WiFi技术的前提下&#xff0c;不仅对速率进行优化&#xff0c;更着重于对 效率 的提升。 2、WiFi 6 为什么快&#xff1f; WiFi 6 理论速率计算公式&a…

【Midjourney入门教程3】写好prompt常用的参数

文章目录 1、图片描述词&#xff08;图片链接&#xff09;文字描述词后缀参数2、权重划分3、后缀参数版本选择&#xff1a;--v版本风格&#xff1a;--style长宽比&#xff1a;--ar多样性: --c二次元化&#xff1a;--niji排除内容&#xff1a;--no--stylize--seed--tile、--q 4、…

使用Python 脚自动化操作服务器配置

“ 有几十台特殊的服务器&#xff0c;没有合适的批量工具只能手动&#xff0c;要一个一个进行点击设置很耗费时间呀\~”,使用 Python 的简单脚本&#xff0c;即可模拟鼠标键盘进行批量作业 01 — 自动化示例 以某服务器中的添加用户权限为例&#xff0c;演示过程皆未触碰鼠标…

2022年09月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 十六进制数100&#xff0c;对应的十进制数为 &#xff1f;&#xff08; &#xff09; A: 128 B: 256 C: 28 D: 56 答…

如何设置OBS虚拟摄像头给钉钉视频会议使用

环境&#xff1a; OBS Studio 29.1.3 Win10 专业版 钉钉7.1.0 问题描述&#xff1a; 如何设置OBS虚拟摄像头给钉钉视频会议使用 解决方案&#xff1a; 1.打开OBS 底下来源这添加视频采集设备 选择OBS虚拟摄像头 2.源那再建一个图像&#xff0c;随便选一张图片 3.点击虚…

【DriveGPT学习笔记】自动驾驶汽车Autonomous Vehicle Planning

原文地址&#xff1a;DriveGPT - Lei Maos Log Book 自动驾驶汽车的核心软件组件是感知、规划和控制。规划是指在给定场景或一系列场景的情况下为自动驾驶汽车制定行动计划的过程&#xff0c;以实现安全和理想的自动驾驶。 用于规划的场景是从感知软件组件获得的。计划的行动将…

Windows Server 2016使用MBR2GPT.EXE教程!

什么是MBR2GPT.exe&#xff1f; MBR2GPT.exe是微软提供的专业工具&#xff0c;可在命令提示符下运行。使用该工具可以将引导磁盘从MBR转换为GPT分区样式&#xff0c;而无需修改或删除所选磁盘上的任何内容。 在Windows Server 2019和Windows 10&#xff08;1703…

pytorch+LSTM实现使用单参数预测,以及多参数预测(代码注释版)

开发前准备&#xff1a; 环境管理&#xff1a;Anaconda python: 3.8 显卡&#xff1a;NVIDIA3060 pytorch: 到官网选择conda版本&#xff0c;使用的是CUDA11.8 编译器&#xff1a; PyCharm 简述&#xff1a; 本次使用seaborn库中的flights数据集来做试验&#xff0c;我们通过…

c语言经典算法—二分查找,冒泡,选择,插入,归并,快排,堆排

一、二分查找 1、前提条件&#xff1a;数据有序&#xff0c;随机访问&#xff1b; 2、实现&#xff1a;递归实现&#xff0c;非递归实现 3、注意事项&#xff1a; 循环退出条件:low <high,low high.说明还有一个元素&#xff0c;该元素还要与key进行比较 mid的取值&#xf…

Excel文档名称批量翻译的高效方法

在处理大量文件时&#xff0c;我们常常需要借助一些工具来提高工作效率。例如&#xff0c;在需要对Excel文档名称进行批量翻译时&#xff0c;一个方便快捷的工具可以帮助我们省去很多麻烦。今天&#xff0c;我将介绍一款名为固乔文件管家的软件&#xff0c;它能够帮助我们轻松实…

hackergame2023菜菜WP

文章目录 总结Hackergame2023更深更暗组委会模拟器猫咪小测标题HTTP集邮册Docker for everyone惜字如金 2.0Git? Git!高频率星球低带宽星球小型大语言模型星球旅行日记3.0JSON ⊂ YAML? 总结 最近看到科大在举办CTF比赛&#xff0c;刚好我学校也有可以参加&#xff0c;就玩了…

Pytorch网络模型训练

现有网络模型的使用与修改 vgg16_false torchvision.models.vgg16(pretrainedFalse) # 加载一个未预训练的模型 vgg16_true torchvision.models.vgg16(pretrainedTrue) # 把数据分为了1000个类别print(vgg16_true) 以下是vgg16预训练模型的输出 VGG((features): S…