SpringMVC总结

一.SpringMVC简介和体验

(一)介绍

(二)创建SpringMVC项目

1.创建Maven项目
2.导入依赖
XML 复制代码
<properties>
    <spring.version>6.0.6</spring.version>
    <servlet.api>9.1.0</servlet.api>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <!-- springioc相关依赖  -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- web相关依赖  -->
    <!-- 在 pom.xml 中引入 Jakarta EE Web API 的依赖 -->
    <!--
        在 Spring Web MVC 6 中,Servlet API 迁移到了 Jakarta EE API,因此在配置 DispatcherServlet 时需要使用
         Jakarta EE 提供的相应类库和命名空间。错误信息 "'org.springframework.web.servlet.DispatcherServlet'
         is not assignable to 'javax.servlet.Servlet,jakarta.servlet.Servlet'" 表明你使用了旧版本的
         Servlet API,没有更新到 Jakarta EE 规范。
    -->
    <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-web-api</artifactId>
        <version>${servlet.api}</version>
        <scope>provided</scope>
    </dependency>

    <!-- springwebmvc相关依赖  -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>

</dependencies>
3.转成maven/web程序

用jbljavatoweb插件将Java项目转换为Web项目

webapp出现蓝点代表成功转成maven/web程序

4.controller声明

handler就是controller内部的具体方法

java 复制代码
@Controller
public class HelloController {
    @RequestMapping("springmvc/hello")//对外访问的地址 到handlerMapping注册的注解
    @ResponseBody//直接返回字符串给前端,不去找视图解析器
    public String hello() {
        System.out.println("hello,springmvc");
        return "hello springmvc!";
    }
}
5.Spring MVC核心组件配置类

声明springmvc涉及组件信息的配置类

(1)controller配置ioc容器

(2).handlerMapping handlerAdapter加入到ioc容器

java 复制代码
@Configuration
@ComponentScan("com.yan.controller")
public class MvcConfig {
    @Bean
    public RequestMappingHandlerMapping handlerMapping() {
        return new RequestMappingHandlerMapping();
    }
     @Bean
    public RequestMappingHandlerAdapter handlerAdapter(){
        return new RequestMappingHandlerAdapter();
     }

}
6.SpringMVC环境搭建

本类可以被web项目加载,会初始化ioc容器,会设置dispatcherServlet的地址

java 复制代码
public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    /**
     * 指定service / mapper层的配置类
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    /**
     * 指定springmvc的配置类
     *
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{MvcConfig.class};
    }

    /**
     * 设置dispatcherServlet的处理路径!
     * 一般情况下为 / 代表处理所有请求!
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
7将攻击部署在tomcat上,启动测试

(三)WebApplicationInitializer接口

每当web项目启动,就会自动调用WebApplicationInitializer接口的onStartup方法AbstractAnnotationConfigDispatcherServletInitializer, 用于 DispatcherServlet 初始化 (实现了WebApplicationInitializer接口),该基类既要完成 WebApplicationInitializer 接口中配置servlet容器的功能,又完成了配置MVC的功能,即同时配置了 DispatcherServlet 和 ContextLoaderListener 。

二.SpringMVC接收数据

(一)访问路径设置

@RequestMapping注解的作用就是将请求的 URL 地址和处理请求的方式(handler方法)关联起来,建立映射关系。

@WebServlet:必须用/开头

@RequestMapping:不必使用/开头

1.精准路径

精准地址可以有一个或多个

@RequestMapping(value = {"/user/register"})

2.模糊路径

/* 为单层任意字符串,只能匹配URL地址中的一层,如果想准确匹配两层,那么就写"/*/*"以此类推

/** 为任意层任意字符串,可以匹配URL地址中的多层。

3.类和方法级别区别
(1)设置到类级别

类上提取通用的访问地址

(2)设置到方法级别

方法上是具体的handler地址

访问:类地址+方法地址即可

4.请求方式指定
java 复制代码
public enum RequestMethod {
  GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}
(1)默认情况下:

@RequestMapping("/logout")

只要地址正确,任何请求方式都可以访问!

(2)指定请求方式下:

@RequestMapping(value = "regist", method = {RequestMethod.GET})

不符合请求方式会出现405异常

5.进阶注解

@GetMapping

@PostMapping

@PutMapping

@DeleteMapping

@PatchMapping

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

(二)接收参数

1.param和json参数比较
(1)参数编码

param类型:ASCII码

JSON类型:UTF-8

(2)参数顺序

param参数没有顺序限制,但是JSON类型的参数是有序的,JSON采用键值对形式

(3)数据类型

param类型的参数支持字符串类型,数组类型和布尔类型等简单类型

JSON适合更复杂的格式

(4)可读性

param类型参数更简单,易读但是JSON格式在传递嵌套数据结构更勤洗易懂

2.param参数接收
(1)直接接值

-形参列表填写对应名称的参数即可 请求参数名=形参参数名

-可以不给形参传递值

java 复制代码
  @RequestMapping("data")
    @ResponseBody
    public String data(String name, int age) {
        System.out.println("name=" + name + ",age" + age);
        return "name = " + name + "age = " + age;
    }
(2)@RequestParam注解

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

@RequestParam(

value="指定请求参数,如果形参名和参数名一致,可以省略",

required=false 前端是否必须传递,默认为必须,不传报错400异常,

defaultValue="1" 当非必须传递时,可以设置默认值)

使用场景

-指定绑定的请求参数名

-要求请求参数必须传递

-为请求参数提供默认值

java 复制代码
  @RequestMapping("data1")
    @ResponseBody
    public String data1(@RequestParam(value = "account") String username, @RequestParam(required = false, defaultValue = "1") int page) {
        return "username = " + username + " , page= " + page;
    }
(3)特殊场景接值
-一名多值

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

不加@RequestParam将hbs对应的一个字符赋值给集合,类型异常

加了注解,HandlerAdapter用集合的add方法加入字符串

java 复制代码
   //hbs=吃&hbs=玩&hbs=打
    @GetMapping("data2")
    @ResponseBody
    public String data2(@RequestParam List<String> hbs) {
        System.out.println("hbs=" + hbs);
        return "ok";
    }
-实体接收

可以在方法内部直接使用对象的属性来访问请求参数,要求声明实体类属性名等于请求参数名

java 复制代码
@Data
public class User {
    private String name;
    private int age;
}
java 复制代码
  @RequestMapping("data3")
    @ResponseBody
    public String data3(User user) {
        System.out.println(user);
        return user.toString();
    }

3.路径参数接收

Spring MVC 框架提供了 @PathVariable 注解来处理路径传递参数。

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

-动态路径设计: /user/{动态部分}/{动态部分} 动态部分使用{}包含即可! {}内部动态标识!

-形参列表取值:

@PathVariable Long id 如果形参名 = {动态标识} 自动赋值!

@PathVariable("动态标识") Long id 如果形参名 != {动态标识} 可以通过指定动态标识赋值!

java 复制代码
 @RequestMapping("{account}/{password}")
    public String login(@PathVariable(value = "account", required = true) String username, @PathVariable String password) {
        return username+password;
    }
4.JSON参数接收

定义一个用于接收 JSON 数据的 Java 类

java 复制代码
@Data
public class Person {
    private String name;
    private int age;
    private String gender;

}

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

java 复制代码
@RequestMapping("json")
@Controller
@ResponseBody
public class JsonController {

    @PostMapping("data")
    public String data(@RequestBody Person person) {
        System.out.println("person:" + person);
        return person.toString();
    }

}

测试:

原因:

Java原生的api只支持路径参数和param参数,不支持json

json是前端格式

解决:导入json处理的依赖 ,handlerAdopter配置json转换器

使用此注解@EnableWebMvc加入json处理器

XML 复制代码
@EnableWebMvc //handlerAdopter 配置json转换器
@Configuration
@ComponentScan("com.yan")
public class MvcConfig {
    @Bean
    public RequestMappingHandlerMapping handlerMapping() {
        return new RequestMappingHandlerMapping();
    }
     @Bean
    public RequestMappingHandlerAdapter handlerAdapter(){
        return new RequestMappingHandlerAdapter();
     }

}

pom.xml 加入jackson依赖

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

@EnableWebMvc注解说明

添加 HandlerMapping,HandlerAdapter,给HandlerAdapter添加jacksonJson处理器

(三)接收Cookie数据

java 复制代码
@Controller
@RequestMapping("cookie")
@ResponseBody
public class CookieController {
    @RequestMapping("data")
    public String data(@CookieValue(value = "cookieName") String value) {
        System.out.println("value=" + value);
        return value;
    }
    @GetMapping("save")
    public String save(HttpServletResponse response){
        Cookie cookie = new Cookie("cookieName", "root");
        response.addCookie(cookie);
        return "ok";
    }
}

(四)接收请求头数据

java 复制代码
@Controller
@RequestMapping("header")
@ResponseBody
public class HeaderController {
    @GetMapping("data")
    public String data(@RequestHeader("Host") String host) {
        System.out.println("host = " + host);
        return "host = " + host;
    }
}

(五)原生Api对象获取

想要获取请求或者响应对象,或者会话等,可以直接在形参列表传入,并且不分先后顺序!

举例:

获取ServletContext和HttpSession对象

java 复制代码
 @GetMapping("api")
    public  String getApi(HttpServletRequest req, HttpServletResponse resp, HttpSession httpSession){
        ServletContext servletContext = req.getServletContext();
        return null;
    }

springmvc会在初始化容器的时候,将servletContext对象存储到ioc容器中,也可以用@Autowired注解自动装配servletContext对象

三.SpringMVC响应数据

(一)转发和重定向

1.方法的返回值都是String

2.不加responseBody注解

3.返回字符串前面 redirect:/重定向地址 forward:/请求转发地址

转发和重定向都一样,都是项目下路径!转到项目内的资源都不需要添加项目根路径!

转发只能向项目下的资源跳转

重定向可以是项目下的资源也可以是项目外的资源,重定向到项目外的资源如百度网址

redirect:http://www.baidu.com

java 复制代码
 @GetMapping("forward")
    public String forward() {
        return "forward:/index";
    }

    @GetMapping("redirect")
    public String redirect() {
        return "redirect:/jsp/index";
    }

(二)返回JSON数据

1.前置准备

(1)导入json依赖

(2)@EnableWebMvc

2.@ResponseBody注解

@RestController =@Controller + @ResponseBody

所以使用了 @RestController 注解就相当于给类中的每个方法都加了 @ResponseBody 注解。

如果类中每个方法上都标记了 @ResponseBody 注解,那么这些注解就可以提取到类上。

java 复制代码
@RequestMapping("json")
@Controller
@ResponseBody
public class JsonController {
    @GetMapping("data")
    public User data() {
        User user = new User();
        user.setName("two dogs");
        user.setAge(2);
        return user;
    }

    @GetMapping("data2")
    public List<User> data1() {
        User user = new User();
        user.setName("two dogs");
        user.setAge(2);
        List<User> users = new ArrayList<>();
        users.add(user);
        return users;
    }
}

(三)返回静态资源

1.原因

对 SpringMVC 来说,必须有对应的 @RequestMapping 才能找到处理请求的方法

现在 images/photo.jpg 请求没有对应的 @RequestMapping 所以返回 404

2.问题解决

在 SpringMVC 配置配置类:

java 复制代码
@EnableWebMvc // 配置json转换器
@Configuration
@ComponentScan("com.yan")
public class MvcConfig implements WebMvcConfigurer {
    //开启静态资源处理
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

四.RESTful风格设计和实践

(一)请求方式要求

GET用来获取资源

POST用来新建资源(也可以用于更新资源)

PUT用来更新资源

DELETE用来删除资源

(二)路径要求

使用URL+请求方式确定具体的动作,handler的地址+请求方式都相同才是重复

通用原则:

-路径参数 应该用于指定资源的唯一标识或者 ID,而请求参数 应该用于指定查询条件或者操作参数。

  • 请求参数应该限制在 10 个以内,过多的请求参数可能导致接口难以维护和使用。

  • 对于敏感信息,最好使用 POST 和请求体来传递参数。

(三)接口设计

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

-对于查询用户详情,使用路径传递参数是因为这是一个单一资源的查询,即查询一条用户记录。使用路径参数可以明确指定所请求的资源,便于服务器定位并返回对应的资源,也符合 RESTful 风格的要求。

-而对于多条件模糊查询,使用请求参数传递参数是因为这是一个资源集合的查询,即查询多条用户记录。使用请求参数可以通过组合不同参数来限制查询结果,路径参数的组合和排列可能会很多,不如使用请求参数更加灵活和简洁。

(四)代码实现

java 复制代码
public class User {

    private Integer id;
    private String name;
    private Integer age;


}
java 复制代码
@RestController
@RequestMapping("user")
public class UserController {
    @GetMapping
    public List<User> page(@RequestParam(required = false, defaultValue = "1") int page,
                           @RequestParam(required = false, defaultValue = "10") int size) {
        System.out.println("page=" + page + "size" + size);
        return null;
    }

    @PostMapping
    public User save(@RequestBody User user) {
        return user;
    }

    @GetMapping("{id}")
    public User detail(@PathVariable Integer id) {
        return null;
    }

    @PutMapping
    public User update(@RequestBody User user) {
        return user;
    }

    @DeleteMapping("{id}")
    public User delete(@PathVariable Integer id) {
        return null;
    }

    @GetMapping("search")
    public List<User> search(String keywork,
                             @RequestParam(required = false, defaultValue = "1") int page,
                             @RequestParam(required = false, defaultValue = "10") int size) {
        return null;
    }
}

五.SpringMVC扩展

(一)全局异常处理机制

声明式异常处理:则是将异常处理的逻辑从具体的业务逻辑中分离出来,通过配置等方式进行统一的管理和处理。

1.声明异常处理控制器类

@ControllerAdvice 代表当前类的异常处理controller!

@RestControllerAdvice=@ControllerAdvice+@ResponseBody

2.声明异常处理hander方法

@ExceptionHandler(HttpMessageNotReadableException.class)

该注解标记异常处理Handler,并且指定发生异常调用该方法!指定的异常,可以精准查找,找不到才查找父异常

3.配置文件扫描控制器类配置

确保异常处理控制类被扫描

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ArithmeticException.class)
    public Object ArithmeticExceptionHandler(ArithmeticException e) {
        //自定义处理异常即可
        String message = e.getMessage();
        return message;
    }

    @ExceptionHandler(Exception.class)
    public Object ExceptionHandler(Exception e) {
        String message = e.getMessage();
        return message;
    }

}

(二)拦截器的使用

1.创建拦截器类
java 复制代码
public class MyInterceptor implements HandlerInterceptor {


    /**
     * 执行handeler之前,调用的拦截方法
     *
     * @param request
     * @param response
     * @param handler  我们要调用的方法的对象
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    /**
     * 当handler执行完毕后触发的方法,没有拦截机制
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView 返回的视图和共享域数据对象
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 整体处理完毕
     *
     * @param request
     * @param response
     * @param handler
     * @param ex       报错了异常对象
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
2.修改配置类添加拦截器
java 复制代码
@Configuration
@ComponentScan("com.yan")
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    //添加拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
    }
}
3.配置详解
a.默认拦截全部
java 复制代码
@Configuration
@ComponentScan("com.yan")
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor());
               
    }
}
b.精准配置

设置拦截器处理指定请求 路径可以设置一个或者多个,为项目下路径即可

也支持 /* 和 /** 模糊路径。 * 任意一层字符串 ** 任意层 任意字符串

java 复制代码
@Configuration
@ComponentScan("com.yan")
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/user/data");
    }
}
c.排除设置

排除匹配,排除应该在匹配的范围内排除

java 复制代码
@Configuration
@ComponentScan("com.yan")
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/user/**").excludePathPatterns("/user/data");
    }
}
4.多个拦截器的执行顺序

preHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置顺序调用各个 preHandle() 方法。

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

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

(三)参数校验

1.导入依赖
XML 复制代码
<!-- 校验注解 -->
<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.创建实体类,为其添加校验对象

要求:

(1)name 不为null且不为空 字符串

@NotBlank 集合 @NotEmpty 包装 @NotNull

(2)password长度大于6

(3)age必须>=1

(4)email 邮箱格式字符串

(5)birthday 过去时间

java 复制代码
public class User {
    @NotBlank
    private String name;
    @Length(min = 6)//标注值字符串大小必须在指定的范围内
    private String password;
    @Min(1) //标注值必须大于或等于 value
    private int age;
    @Email //标注值必须是格式正确的 Email 地址
    private String email;
    @Past //标注值只能用于日期型,且必须是过去的日期
    private Date birthday;
}
3.handler(@Validated 实体类 对象)

要接收json,还要加上@RequestBody 注解

java 复制代码
@RequestMapping("user")
@RestController
public class UserController {
    @GetMapping
    public User regist(@Validated @RequestBody User user){
    return  user;
    }
}

测试:

4.handler标记和绑定错误收集

捕捉绑定错误信息

在实体类参数和 BindingResult 之间不能有任何其他参数

BindingResult可以接受错误信息,避免信息抛出

java 复制代码
    @GetMapping
    public Object regist(@Validated @RequestBody User user, BindingResult result) {
        if (result.hasErrors()) {
            Map data = new HashMap();
            data.put("code", 400);
            data.put("msg", "参数校验异常");
            return data;
        }
        return user;
    }

测试:

相关推荐
哲此一生9845 分钟前
创建一个SpringBoot项目(连接数据库)
java·spring boot·后端
文心快码BaiduComate6 分钟前
Comate Zulu实测:不会编程也能做软件?AI程序员现状令人震惊
java·程序员·前端框架
Michael_lcf15 分钟前
Java的UDP通信:DatagramSocket和DatagramPacket
java·开发语言·udp
摇滚侠24 分钟前
Spring Boot 3零基础教程,WEB 开发 HttpMessageConverter @ResponseBody 注解实现内容协商源码分析 笔记33
java·spring boot·笔记
计算机毕业设计小帅41 分钟前
【2026计算机毕业设计】基于Springboot的校园电动车短租平台
spring boot·后端·课程设计
调试人生的显微镜41 分钟前
Web前端开发工具实战指南 从开发到调试的完整提效方案
后端
静心观复41 分钟前
drawio画java的uml的类图时,class和interface的区别是什么
java·uml·draw.io
Java水解42 分钟前
【SQL】MySQL中空值处理COALESCE函数
后端·mysql
Laplaces Demon43 分钟前
Spring 源码学习(十四)—— HandlerMethodArgumentResolver
java·开发语言·学习
guygg881 小时前
Java 无锁方式实现高性能线程
java·开发语言