SpringMVC学习记录
- 1.SpringMVC简介
-
- 1.1什么是SpringMVC
- [1.2 核心组件和调用流程](#1.2 核心组件和调用流程)
- [1.3 快速开始代码案例](#1.3 快速开始代码案例)
- 2.访问路径
-
- [2.1 对RequestMapping注解的说明](#2.1 对RequestMapping注解的说明)
- [2.2 路径匹配](#2.2 路径匹配)
- [3. 参数和数据的接收](#3. 参数和数据的接收)
-
- [3.1 param参数接收](#3.1 param参数接收)
- [3.2 json参数接收](#3.2 json参数接收)
- [3.2 路径参数接收](#3.2 路径参数接收)
- [3.4 cookie数据接收](#3.4 cookie数据接收)
- [4. 参数响应](#4. 参数响应)
-
- [4.1 handler方法分析](#4.1 handler方法分析)
- [4.2 返回json数据](#4.2 返回json数据)
- [4.3 返回静态资源](#4.3 返回静态资源)
- 5.SpringMVC其他扩展
-
- [5.1 RESTful简介](#5.1 RESTful简介)
- [5.2 声明式异常处理](#5.2 声明式异常处理)
- [5.3 拦截器](#5.3 拦截器)
- [5.4 参数校验](#5.4 参数校验)
1.SpringMVC简介
1.1什么是SpringMVC
- MVC:即Model(模型) View(视图) Controller(控制器) ,是一种设计模式。Model代表一个存取数据的对象或 JAVA POJO,
View代表模型包含的数据的可视化,Controller作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
-SpringMVC是Spring框架基于Servlet API构建的原始Web框架,全称Spring Web MVC。主要作用是:简化来自前端数据的接收和简化对前端数据的响应。
1.2 核心组件和调用流程
- DispatcherServlet : SpringMVC提供,我们需要使用web.xml配置使其生效,它是整个流程处理的核心,所有请求都经过它的处理和分发![ CEO ]
- 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.3 快速开始代码案例
-SpingMVC环境搭建
java
public class MvcInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
//指定springmvc的配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{MvcConfig.class};
}
// 设置dispatcherServlet的处理路径,一般情况下为 / 代表处理所有请求!
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
- Spring MVC配置类
java
@Configuration
@ComponentScan("com.daoheng.Controller")
public class MvcConfig {
@Bean
public RequestMappingHandlerMapping handlerMapping(){
return new RequestMappingHandlerMapping();
}
@Bean
public RequestMappingHandlerAdapter handlerAdapter(){
return new RequestMappingHandlerAdapter();
}
}
- Controller类
java
@Controller
public class HelloController {
//handlers
/**
* handler就是controller内部的具体方法
* @RequestMapping("/springmvc/hello") 就是用来向handlerMapping中注册的方法注解!
* @ResponseBody 代表向浏览器直接返回数据!
*/
@RequestMapping(value="springmvc/hello")
@ResponseBody
public String hello(){
System.out.println("HelloController.hello");
return "hello springmvc!!";
}
}
2.访问路径
2.1 对RequestMapping注解的说明
- RequestMapping注解的作用就是将请求的 URL 地址和处理请求的方式(handler方法)关联起来,建立映射关系。即若在方法上添加如下注解:则表明当浏览器请求.../springmvc/hello的时候,框架会跳转到hello方法体中。
java
@RequestMapping("springmvc/hello")
public String hello(){...}
- RequestMapping注解可以作用于类和方法体:作用于类上时时用于映射整个控制器的通用请求路径。如果控制器中的多个方法都需要映射同一请求路径,就不需要在每个方法上都添加映射路径。例如当所有的请求前缀都是.../user/...,那么就可以在类上用注解@RequestMapping("user")。作用于方法的时候,用于更细粒度地映射请求路径。
java
//以下注解都作用于方法,属于类Fruit类
@RequestMapping(value="/user/login")
public void login(...){...}
@RequestMapping(value="/user/product")
public void product(...){...}
//等价于
@RequestMapping(value="/user")
public void Fruit{
@RequestMapping(value="login")
public void login(...){...}
@RequestMapping(value="product")
public void product(...){...}
}
- RequestMapping注解并没有限制前端的请求方式,当需要限制请求方式的时候,可以指定,例如POST、GET等。在RequestMapping注解的内部提供了method属性,如下:
java
public enum RequestMethod {GET,HEAD,POST,PUT, PATCH,DELETE,OPTIONS,TRACE;}
所以可以是以下方式注解:
java
@RequestMapping(value="springmvc/hello",method="method = RequestMethod.POST")
上述注解方式还等价于以下注解,但是以下等价注解只能作用于方法而不能作用于类。即RequestMapping+Post等价于PostMapping。
java
@GetMapping @PostMapping @PutMapping @DeleteMapping @PatchMapping
2.2 路径匹配
- 精准路径匹配:即将访问的路径清晰完全的写出来,而不进行任何模糊匹配,如下所示:
java
@RequestMapping("springmvc/hello")
- 模糊路径匹配
假设有/user/one,user/two,user/three等路径,但是前端需要匹配user所属的所有地址,此时就需要模糊匹配。
(1)单层模糊:单个星号 user/* user/a user/aaa 都可以访问此handler ,但是user/a/a不可以访问。
(2)多层模糊:2个星号 user/** user/a user/aaa user/a/a user/a/a/a 都可以访问。
java
@RequestMapping("/user/*")
public String show(){...}
3. 参数和数据的接收
3.1 param参数接收
param类型即url类似如下:
java
localhost:8080/param/user?name=tom&age=20
- 直接接收 :只要形参数名和类型与传递参数相同,即可自动接收。
java
@RequestMapping(value = "user")
@ResponseBody
public String Info(String name ,Integer age){
System.out.println("name="+name+"age="+age);
return "name="+name+" age="+age;
}
- RequestParam注解
当前端URL中参数的key与后端handler中的形参不一样的时候,可以使用RequestParam注解来指定前端参数的key**,还可以指定当参数为空的时候的默认值,不过要设置不强制需要提供值,即required=false。
java
value="前端的参数名"
required="是否强制前端提供值"
defaultValue="前端不提供参数时的默认值"
java
@RequestMapping(value = "userParam")
@ResponseBody
public String InfoParam(@RequestParam(value = "nickname",required = false,defaultValue = "jerry") String name ,
@RequestParam(value = "old",required = false,defaultValue ="1") Integer age){
System.out.println("name="+name+"age="+age);
return "name="+name+" age="+age;
}
对实体类的接收:前端发送请求时的url中的参数名需要与实体类中的属性名保持一致。
java
@Data
public class User {
private String name;
private Integer age;
}
java
@RequestMapping(value = "userPojo")
@ResponseBody
public String InfoPojo(User user){
System.out.println(user); //User(name=tom, age=20)
return "success";
}
3.2 json参数接收
前后端分离的项目,一般使用json格式的数据在前后端中传递。接收json数据的时候使用数据RequestBody注解,该注解会将寄送数据转化为java对象。
java
@PostMapping("/person")
@ResponseBody
public String addPerson(@RequestBody Person person) {
// 在这里可以使用 person 对象来操作 JSON 数据中包含的属性
return "success";
}
3.2 路径参数接收
路径参数,即将url已经隐藏在了路径中,如下所示:其中,root,admin是用户名,123456/654321是密码。
java
localhost:8080/user/root/123456
localhost:8080/user/admin/654321
接收的时候使用PathVariable注解,如下:
java
@RequestMapping(value = "userPath/{name}/{age}")
@ResponseBody
public String InfoPath(@PathVariable String name ,
@PathVariable Integer age){
System.out.println("name="+name+"age="+age);
return "name="+name+" age="+age;
}
3.4 cookie数据接收
使用 @CookieValue 注释将 HTTP Cookie 的值绑定到控制器中的方法参数
java
@RequestMapping("cookie")
@ResponseBody
public String getCookie(@CookieValue String cookie){
System.out.println(cookie);
return cookie;
}
4. 参数响应
4.1 handler方法分析
-什么是handler方法:Controller层的一个方法.handler方法需要使用@RequestMapping @GetMapping 等注解声明路径,在HandlerMapping中注册,供DispatcherServlet查找。
- handler作用:接收请求参数、调用业务逻辑、响应前端数据
java
@GetMapping
public Object handler(简化请求参数接收){
调用业务方法
返回的结果 (页面跳转,返回数据(json))
return 简化响应前端数据;
}
4.2 返回json数据
后端接收前端的json数据的时候,使用了RequestBody注解,会自动的将json数据转化为java对象。当后端需要给前端返回json数据的时候,只需要使用ResponseBody 注解将java对象转化为json对象返回。
注意:@ResponseBody+ @Controller 等价于 @RestController
java
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan("com.daoheng.Controller")
public class MvcConfig {
@Bean
public RequestMappingHandlerMapping handlerMapping(){
return new RequestMappingHandlerMapping();
}
@Bean
public RequestMappingHandlerAdapter handlerAdapter(){
return new RequestMappingHandlerAdapter();
}
}
java
@Controller
public class JsonController {
@RequestMapping("json")
@ResponseBody
public User Json(){
return new User("tom",20);
}
}
4.3 返回静态资源
java
@EnableWebMvc //json数据处理,必须使用此注解,因为他会加入json处理器
@Configuration
@ComponentScan(basePackages = "com.atguigu.controller") //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();
}
}
5.SpringMVC其他扩展
5.1 RESTful简介
- RESTful(Representational State Transfer)是一种软件架构风格,用于设计网络应用程序和服务之间的通。主要规范3件事:如何设计路径 、如何参数传递 、如何选择请求方式。
- 风格特点
1.每一个URI代表1种资源(URI是名词);即URI中只有名词而没有动词,例如删除id=2的用户,普通的url和RESTful风格的url如下:可以看出,RESTful风格的URL更安全,隐藏了目的。
java
localhost:8080/user/remove?id=2
localhost:8080/user/2 使用post请求方式
2.客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作 :GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;
3.资源的表现形式是XML或者JSON。
4.客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。
5.2 声明式异常处理
编程式异常处理,需要在异常发生的时候手动处理,有重复的异常发生的时候仍然需要多次重复处理。使用声明式异常处理的时候,可以可以统一项目处理异常思路。类似AOP(底层应该是调用AOP实现的)
- 声明异常处理类和异常处理方法
声明异常处理类的时候使用@RestControllerAdvice,该注解只能作用于类。
声明异常处理方法的时候使用@ExceptionHandler(异常的类型)
当发生对应异常的时候就会在异常处理类中的异常处理方法中寻找对应的handler。当没有对应的方法的时候,会寻找其父类异常。例如发生除0异常的时候会执行 handlerArithmeticException,当发生ClassCastException异常的时候,没有对应的异常处理代码,会执行Exception中的异常处理代码。
java
@RestControllerAdvice
public class ExceptionController {
@ExceptionHandler(ArithmeticException.class)
public ArithmeticException handlerArithmeticException(ArithmeticException e){
System.out.println("handlerArithmeticException");
return e;
}
@ExceptionHandler(Exception.class)
public Exception handleException(Exception e){
System.out.println("handleException");
return e;
}
}
5.3 拦截器
- SpringMVC拦截器 VS 过滤器
- 拦截器工作点:调用handler之前和之后与返回前端数据前。
- 代码示例
创建拦截器
java
public class ProcessInterceptor implements HandlerInterceptor {
// 在处理请求的目标 handler 方法前执行:比如登录检查
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("ProcessInterceptor.preHandle");
// 返回true:放行
// 返回false:不放行
return true;
}
// 在目标 handler 方法之后,handler报错不执行! 比如:敏感词检查
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("ProcessInterceptor.postHandle");
}
// 渲染视图之后执行(最后),一定执行!
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("ProcessInterceptor.afterCompletion");
}
}
//输出如下:说明在执行handler之前和之后以及最后都经过了拦截器
ProcessInterceptor.preHandle
name=tom age=1
ProcessInterceptor.postHandle
ProcessInterceptor.afterCompletion
配置类添加拦截器
java
@EnableWebMvc
@Configuration
@ComponentScan({"com.daoheng.Controller","com.daoheng.Interceptor"})
public class MvcConfig implements WebMvcConfigurer{
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 ProcessInterceptor());
}
}
- 配置中拦截的设置
全部拦截
java
@Override
public void addInterceptors(InterceptorRegistry registry) {
//将拦截器添加到Springmvc环境,默认拦截所有Springmvc分发的请求
registry.addInterceptor(new Process01Interceptor());
}
精准拦截
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");
}
排除拦截
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");
}
5.4 参数校验
在 Web 应用三层架构体系中,表述层负责接收浏览器提交的数据,业务逻辑层负责数据的处理。为了能够让业务逻辑层基于正确的数据进行处理,我们需要在表述层对数据进行检查,将错误的数据隔绝在业务逻辑层之外。
- 代码示例
导入依赖
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>
-数据校验
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;
}
}