一,Spring MVC简介
Spring MVC 是 Spring 框架中用于构建 Web 应用程序的核心模块,它基于 MVC(Model-View-Controller)设计模式,提供了灵活、解耦的架构,适合开发动态网页或 RESTful API。
核心概念
- MVC 模式:
- Model(模型):封装业务数据和业务逻辑(如 Java 对象、Service 层)。
- View(视图):负责数据展示(如 JSP、Thymeleaf、HTML)。
- Controller(控制器):处理用户请求,协调 Model 和 View(如
@Controller类)。
- 核心组件:
DispatcherServlet:前端控制器,统一处理请求和响应。HandlerMapping:将请求映射到对应的 Controller 方法。Controller:处理具体业务逻辑。ViewResolver:解析视图名称到具体的视图技术(如 JSP)。ModelAndView:封装模型数据和视图信息。
二,快速入门
-
导包
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.12.RELEASE</version> </dependency> -
创建SpringMVC控制类(等同于Servlet功能)
@Controller public class DemoController { @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("user save..."); return "{'info':'springmvc'}"; } } -
初始化SpringMVC环境(同Spring环境)设定SpringMVC加载对应的bean
@Configuration @ComponentScan("com.springmvc.controller") public class SpringMvcConfig { } -
初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理请求
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createServletApplicationContext() { //注册springmvc的配置 AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } @Override protected String[] getServletMappings() { //设定哪些请求交给SpringMVC处理 return new String[]{"/"}; } @Override protected WebApplicationContext createRootApplicationContext() { return null; } }简化写法:
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { //设置Spring配置类 return new Class[]{SpringConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { //设置SpringMvc配置类 return new Class[]{SpringMvcConfig.class}; } @Override protected String[] getServletMappings() { //设定哪些请求交给SpringMVC处理 return new String[]{"/"}; } }
几个注解:
@Controller注解- 类型:类注解
- 位置:SpringMVC控制器类定义上方
- 作用:设定SpringMVC的核心控制器
@RequestMapping注解- 类型:方法/类注解
- 位置:SpringMVC控制器类/方法定义上方
- 作用:设定当前控制器类/方法的请求路径,设定在类上面就相当于这个类的所有方法的前缀路径
@ResponseBody注解- 类型:方法注解
- 位置:SpringMVC控制器方法定义上方
- 作用:设置当前控制器方法响应内容为当前返回值,无需解析
入门案例工作流程分析:
- 启动服务器初始化过程
- 服务器启动,执行
ServletContainerInitconfig类,初始化web容器。 - 执行
createServletApplicationContext方法,创建了WebApplicationContext对象 - 加载
SpringMvcConfig - 执行
@ComponentScan加载对应的bean - 加载
UserController,每个@RequestMapping的名称对应一个具体的方法 - 执行
getServletMapping方法,定义所有请求都通过SpringMVC
- 服务器启动,执行
- 单次请求过程
- 发送请求localhost/save
- web容器发现所有的请求都经过SpringMvc,将请求交给SpringMVC处理
- 解析请求路径/save
- 由/save匹配执行对应的方法save()
- 执行save()
- 检测到有
@RequestBody直接将save()方法的返回值作为响应体返回给请求方。
三,bean加载控制
在上述案例中,SpringMVC有SpringMVC相关的bean,Spring有他相关的bean这就会出现,SpringMVC可能加载到Spring相关的bean
解决方法:
-
SpringMVC相关bean加载控制:
- SpringMVC加载的bean对应的包均在com.xxx.controller包内
-
Spring相关bena加载控制:
-
方法一:Spring加载的bean设定范围为com.xxx排除controller里面的bean
@Configuration @ComponentScan(value = "com.springmvc", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION,//按照注解过滤 classes = Controller.class ) ) public class SpringConfig { } -
方法二:Spring加载的bean设定扫描范围为精度范围,例如service包,dao包等。
@Configuration @ComponentScan({"com.springmvc.service","com.springmvc.dao"}) public class SpringConfig { } -
方法三:不区分Spring和SpringMVC环境,统一加载到同一环境。
-
@ComponentScan注解:
- 类型:类注解
- 属性:
excludeFilters:排除扫描路径中加载的bean,需要指定类别type与具体项classesincludeFilters:指定加载的bean,需要指定类别type与具体项classes
四,请求
4.1 Get请求和Post请求发起方式
Get请求传参是直接在url里面传递的:
传参方式举例:
hppt://localhost/getParam?key1=value1&key2=value2
控制层代码:
@RequestMapping("/getParam")
@ResponseBody
public String save(String key1,String key2){
System.out.println("user save...");
return "{'info':'springmvc'}";
}
Post请求参数是写在body里面的,控制层的接受和get请求是一样的。
中文乱码处理:在Servlet配置类中配置过滤器
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//配置过滤器
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
4.2 五种类型参数传递
4.2.1 普通参数传递
4.2.2 实体类参数传递
4.2.3 嵌套实体类参数传递
4.2.4 数组参数传递
4.2.5 集合参数传递
4.3 json数据传递
大部分情况下我们前后端都是通过json来交互的,故json数据传递,如下:
-
导入jason坐标
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency> -
在SpringMVC配置文件中开启json转化
@Configuration @ComponentScan("com.springmvc.controller") @EnableWebMvc//开启json转化 public class SpringMvcConfig { } -
在控制层加入注解
@RequestBody@RequestMapping("/save") @ResponseBody public String save(@RequestBody User user){ System.out.println("user save..."); return "{'info':'springmvc'}"; }@RequestBody注解:-
类型**:形参注解**
-
位置:SpringMVC控制器方法形参定义前面
-
作用:将请求体中所包含的数据传递给请求对象,此注解一个处理器方法只能使用一次。
-
4.4 日期类型参数传递
- 日期类型数据基于系统不同,格式也是不同的,例如:
- 2088-08-18
- 2088/8/18
- 08/18/2088
这个String转化为Data底层采用的是类型转化器如下:
4.5 路径参数传递
@PathVarible注解:
- 类型:形参注解
- 位置:SpringMVC控制器方法形参定义签名
- 作用:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应。
五,响应
5.1 响应页面
响应页面只需要返回String字符串,返回这个页面的路径即可,这个路径就是从resource目录开始走的路径。
5.2 响应数据
5.2.1 文本数据
文本数据的返回只需要添加注解@ReponseBody在方法上即可
5.2.2 json数据
返回Json数据就是在方法上返回对象,然后加上注解@ReponseBody在方法上即可
@ReponseBody注解:
- 类型:方法/类注解注解
- 位置:SpringMVC控制器方法/类上方定义
- 作用:设置当前控制器方法响应内容为当前返回值,无需解析
- 如果定义在类上就代表这个类所有方法响应内容为当前返回值,无需解析
这个转换底层采用了如下接口:
5.3 统一响应格式
我们在正常的请求中需要按照格式返回统一的json格式,格式如下:
@Data
public class ApiResponse {
private int status;
private String message;
private Object data;
public ApiResponse() {}
public ApiResponse(int status, String message, Object data) {
this.status = status;
this.message = message;
this.data = data;
}
public static ApiResponse success(Object data) {
return new ApiResponse(200, "Success", data);
}
public static ApiResponse success(String message, Object data) {
return new ApiResponse(200, message, data);
}
public static ApiResponse error(int status, String message) {
return new ApiResponse(status, message, null);
}
public static ApiResponse error(int status, String message, Object data) {
return new ApiResponse(status, message, data);
}
@Override
public String toString() {
return "ApiResponse{" +
"status=" + status +
", message='" + message + '\'' +
", data=" + data +
'}';
}
}
六,RESTFUL风格
- REST(Representational State Transfer):表现形式状态转换。
- 传统风格资源描述形式:
http://localhost/user/getById?id=1http://localhost/user/getById?id=1
- REST风格描述形式:
http://localhost/user/1http://localhost/user
- 传统风格资源描述形式:
- 优点:
- 隐藏资源的访问行为,无法通过地址得知对资源进行何种操作
- 书写简化
把@RequestMapping添加对应属性
@RequestMapping(value="/user",method=RequestMethod.GET)对应GET方法@RequestMapping(value="/user",method=RequestMethod.PUT)对应PUT方法@RequestMapping(value="/user",method=RequestMethod.DELETE)对应DELETE方法@RequestMapping(value="/user",method=RequestMethod.POST)对应POST方法
也可以通过如下方法
@GetMapping("")对应GET方法@PutMapping("")对应PUT方法@DeleteMapping("")对应DELETE方法@PostMapping("")对应POST方法
举例:
@RestController
public class Demo{
@GetMapping("/save")
@ResponseBody
public String save(@RequestBody User user){
System.out.println("user save...");
return "{'info':'springmvc'}";
}
}
@RestController注解:
- 类型:类注解
- 位置:基于SpringMVC的RESTful开发控制器类上方
- 作用:设置当前控制器类为RESTful风格,等同于@Controller和@ResponseBody两个注解组合
七,拦截器
拦截器:一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行。
作用:
- 在指定的方法调用前后执行预先设定的代码。
- 阻止原始方法的执行。
拦截器与过滤器的区别:
- 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
- 拦截内容不同:Filter对所有访问进行增强,Interceptor只对SpringMVC的访问进行增强。
7.1 快速入门
-
声明拦截器bean,并实现
HandlerInterceptor接口(注意加载bean扫描)@Component public class ProjectInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //方法执行之前运行 //true代表放行,false代表拦截不放行 return true; } @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 { //postHandle方法执行后运行 } } -
定义配置类,继承
WebMvcConfiguartionSupport实现addInterceptor方法(注意扫码配置)@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { } } -
添加拦截器并设定拦截器的访问路径,路径可以通过可变参数设置多个
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor) .addPathPatterns("/book","/users"); } }单个拦截器执行流程
7.2 拦截器参数
-
前置处理
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //方法执行之前运行 //true代表放行,false代表拦截不放行 return true; }- 参数:
request:请求对象response:响应对象jamdr:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再封装。
- 返回值:
- 返回值为false:被拦截的处理器不执行。
- 返回值为true:放行。
- 参数:
-
后置处理器
@Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { //方法执行后运行 }- 参数:
modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息并进行调整。
- 参数:
-
完成后处理:
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //postHandle方法执行后运行 }- 参数:
ex:如果处理器执行过程中出现异常,可以针对异常情况单独处理。
- 参数:
7.3 拦截路径
-
拦截器可以根据需求,配置不同的拦截路径