目录
[2.1.1 Spring MVC 原理](#2.1.1 Spring MVC 原理)
[2.1.2 什么是MVC](#2.1.2 什么是MVC)
[2.1.3 什么是SpringMVC](#2.1.3 什么是SpringMVC)
[2.1.3 SpringMVC的特点](#2.1.3 SpringMVC的特点)
[2.2 SpringMVC具体的执行流程是什么?★★★★](#2.2 SpringMVC具体的执行流程是什么?★★★★)
[2.3 SpringMVC常用注解](#2.3 SpringMVC常用注解)
[2.4 SpringMVC中的`@Controller`注解有何作用?](#2.4 SpringMVC中的@Controller
注解有何作用?)
[2.5 `@RequestParam`、`@PathVariable`和`@RequestBody`分别用于什么场景?](#2.5 @RequestParam
、@PathVariable
和@RequestBody
分别用于什么场景?)
[2.6 怎样在Spring MVC中处理文件上传和下载?](#2.6 怎样在Spring MVC中处理文件上传和下载?)
[2.7 什么是Spring MVC的拦截器(Interceptor)?如何配置和使用?](#2.7 什么是Spring MVC的拦截器(Interceptor)?如何配置和使用?)
[2.8 Spring MVC拦截器和Servlet Filter有什么区别?](#2.8 Spring MVC拦截器和Servlet Filter有什么区别?)
[2.9 指出Spring Security如何与Spring MVC拦截器协同工作](#2.9 指出Spring Security如何与Spring MVC拦截器协同工作)
[2.10.1 ResponseEntity★★★★](#2.10.1 ResponseEntity★★★★)
[2.10.2 ResponseEntity中包含了哪些重要属性?](#2.10.2 ResponseEntity中包含了哪些重要属性?)
[2.11 RequestEntity](#2.11 RequestEntity)
[2.12.1 自定义拦截器有哪些方式?★★★★](#2.12.1 自定义拦截器有哪些方式?★★★★)
[2.12.2 自定义拦截器中的`preHandle()`、`postHandle()`和`afterCompletion()`分别在什么阶段执行?](#2.12.2 自定义拦截器中的preHandle()
、postHandle()
和afterCompletion()
分别在什么阶段执行?)
[2.12.3 拦截器的应用场景](#2.12.3 拦截器的应用场景)
一、SpringMVC学习资料
地址:
目录:
二、SpringMVC一些面试题
2.1.1 Spring MVC 原理
- Spring MVC 是 Spring 框架的一个模块,用于构建Web应用程序。它遵循模型-视图-控制器(Model-View-Controller)架构模式。以下是 Spring MVC 工作原理的基本步骤:略。
- Spring 的模型-视图-控制器(MVC)框架是围绕一个 DispatcherServlet 来设计的,这个 Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。
2.1.2什么是MVC
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC的工作流程: 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器。
2.1.3 什么是SpringMVC
- SpringMVC是Spring的一个后续产品,是Spring的一个子项目
- SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。
- 注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
2.1.3 SpringMVC的特点
Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
基于原生的Servlet ,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理
表述层各细分领域需要解决的问题全方位覆盖 ,提供全面解决方案
代码清新简洁,大幅度提升开发效率
内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
性能卓著,尤其适合现代大型、超大型互联网项目要求
2.2 SpringMVC具体的执行流程是什么?★★★★
SpringMVC的执行流程如下:
- 用户发起HTTP请求到达
DispatcherServlet
(前端控制器)。DispatcherServlet
通过HandlerMapping
(处理器映射器)找到对应的Controller
(控制器)方法。HandlerAdapter
(处理器适配器)调用Controller
方法处理业务逻辑。Controller
方法执行完毕,返回一个ModelAndView
对象,包含了视图名和模型数据。ViewResolver
(视图解析器)根据ModelAndView
中的视图名解析出实际的视图对象。- 视图对象负责渲染视图,如JSP页面或其他模板引擎。
- 渲染完成后,响应内容返回给客户端。
2.3 SpringMVC常用注解
在Spring MVC中,一些常用的注解包括:
@Controller
: 标识一个类作为Spring MVC控制器,该类会处理HTTP请求。@RequestMapping
: 用于映射HTTP请求。可以放在类级别表示控制器的基本路径,也可以放在方法级别表示具体的操作路径。@GetMapping
/@PostMapping
/@PutMapping
/@DeleteMapping
: 这些是@RequestMapping
的特殊形式,分别对应HTTP的GET, POST, PUT, DELETE操作。@PathVariable
: 从URL模板中获取值并注入到方法参数中。@RequestParam
: 从请求参数中获取值,通常用于GET请求或POST请求的表单数据。@RequestBody
: 用来读取请求主体内容,通常用于接收JSON或XML数据。@ResponseBody
: 将方法返回的对象序列化成JSON或其他格式并直接写入HTTP响应体。@ExceptionHandler
: 注解在方法上,用于捕获并处理特定的异常。@Autowired
: 自动装配Spring容器中的bean,可以用于字段、构造器、setter方法等。@ModelAttribute
: 用于将方法返回的对象添加到模型中,常用于表单回显或者初始值设置。
2.4 SpringMVC中的`@Controller`注解有何作用?
@Controller
注解在SpringMVC中用于标记一个类作为控制器,它扮演着接收HTTP请求并调用业务逻辑进行处理的角色。当Spring容器启动时,会扫描标记了此注解的类,并将它们注册为bean,以便后续的请求能够与这些控制器关联。使用示例:
javaimport org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class HelloWorldController { @GetMapping("/hello") public String sayHello() { return "hello"; // 返回的字符串会被视图解析器解析为视图名称 } }
在这个例子中,
@Controller
注解定义了一个名为HelloWorldController
的控制器,@GetMapping("/hello")
则标识了sayHello()方法可以处理/hello
的HTTP GET请求。
2.5 `@RequestParam`、`@PathVariable`和`@RequestBody`分别用于什么场景?
@RequestParam
、@PathVariable
和@RequestBody
是Spring MVC中用于处理HTTP请求参数的三种不同方式:
@RequestParam
: 用于从URL查询参数或请求头中获取值。它通常与GET或POST请求一起使用。例如,如果你有一个URLhttp://example.com/user?id=123
,你可以这样做:
javapublic User getUser(@RequestParam("id") int userId) { // ... }
这里的
@RequestParam("id")
会获取URL中的'id'参数值。
@PathVariable
: 用于获取RESTful URL模板中的占位符值。常用于处理基于资源的URI。比如,/users/{userId}
,你可以这样获取路径变量:
javapublic User getUser(@PathVariable("userId") int userId) { // ... }
这里的
@PathVariable("userId")
会获取URL路径中的userId
部分。
@RequestBody
: 用于读取请求正文的内容,并将其绑定到一个Java对象上。这在接收到JSON或XML等数据格式的POST请求时特别有用:
java@PostMapping("/users") public ResponseEntity<User> createUser(@RequestBody User user) { // ... }
在这个例子中,
@RequestBody
会将请求体中的JSON转换为User
对象。
2.6 怎样在Spring MVC中处理文件上传和下载?
在Spring MVC中处理文件上传和下载涉及以下几个步骤:
文件上传:
1)首先,在HTML表单中使用
<form>
标签,并设置enctype="multipart/form-data"
来支持文件上传。
html<form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit" value="Upload"/> </form>
2)在
@Controller
类中,使用@RequestParam("file") MultipartFile file
来接收上传的文件。
java@PostMapping("/upload") public String handleFileUpload(@RequestParam("file") MultipartFile file) { // 验证文件非空 if (!file.isEmpty()) { try { byte[] bytes = file.getBytes(); // 保存文件到服务器 File(dirPath, fileName).writeBytes(bytes); return "You successfully uploaded " + file.getOriginalFilename() + "!"; } catch (IOException e) { return "You failed to upload " + file.getName() + " => " + e.getMessage(); } } else { return "You failed to upload because the file was empty."; } }
2.7 什么是Spring MVC的拦截器(Interceptor)?如何配置和使用?
Spring MVC的拦截器类似于Java Servlet中的Filter,但它们的作用范围更小,只针对DispatcherServlet处理的请求进行拦截。拦截器允许你在请求被控制器处理之前或之后执行一些额外的操作,比如权限检查、日志记录、性能监控等。
配置和使用Spring MVC的拦截器分为几个步骤:
(1)创建拦截器实现HandlerInterceptor接口 创建一个新的类并实现
org.springframework.web.servlet.HandlerInterceptor
接口。通常需要重写三个方法:preHandle()
、postHandle()
和afterCompletion()
。
javaimport org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Pre-handle: Before processing request"); return true; // 返回true表示继续处理,返回false则中断后续处理 } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Post-handle: After controller is executed but before view rendering"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("After completion: After rendering view"); } }
(2)配置拦截器 在Spring MVC的配置文件(如
WebMvcConfigurerAdapter
或WebMvcConfigurationSupport
的子类)中注册拦截器。
java@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()); // 添加更多拦截器... } }
或者使用Java配置(自定义的
WebMvcConfigurer
接口实现类):
java@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()); // ... } }
(3)可选:拦截器链 可以将多个拦截器添加到链中,并通过
registry.order(int)
方法指定其优先级。优先级越高,拦截器越先执行。(4)可选:排除特定路径 使用
addPathPatterns
和excludePathPatterns
方法可以指定哪些URL路径应该被拦截,哪些应该被排除。
javaregistry.addInterceptor(new MyInterceptor()) .addPathPatterns("/api/**") // 匹配/api/下的所有路径 .excludePathPatterns("/api/login"); // 排除/api/login路径
2.8 Spring MVC拦截器和Servlet Filter有什么区别?
Spring MVC拦截器(HandlerInterceptor)和Servlet Filter都是用来增强请求处理的功能,但在作用范围、执行流程以及具体功能上有所不同:
作用范围:
- Spring MVC拦截器仅作用于Spring MVC框架内部,只对由Spring DispatcherServlet处理的请求生效。
- Servlet Filter是对整个Servlet容器内的请求生效,不仅限于Spring MVC,包括其他基于Servlet的应用也可以拦截。
执行流程:
- Spring MVC拦截器在DispatcherServlet调用处理器之前和之后执行,以及视图渲染完成后执行,这些操作都位于Spring MVC的控制流中。
- Servlet Filter是在ServletRequest对象被传递给下一个过滤器或目标servlet之前和之后执行。在Servlet容器层面,filter链是线性的,不像Spring MVC的拦截器有明确的前后关系。
功能与上下文:
- 拦截器可以访问Spring MVC的一些高级特性,如模型AndView对象、Spring Security的SecurityContextHolder等。
- Filter则相对底层,它主要处理ServletRequest和ServletResponse对象,但可以实现任何HTTP级别的修改,比如改变字符编码、压缩响应内容、登录验证等。
2.9 指出Spring Security如何与Spring MVC拦截器协同工作
Spring Security可以通过多种方式与Spring MVC的拦截器协同工作,以提供安全相关的控制。以下是它们协作的基本过程:
(1)配置Filter Security Interceptor (FSI) : 在Spring Security配置类中,通常会定义一个
FilterSecurityInterceptor
bean。这个filter负责根据预设的安全规则(如访问决策管理器和权限表达式)检查HTTP请求。
java@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated() .and() .formLogin() // 添加其他安全设置... } }
(2)Spring Security默认拦截所有请求 :
FilterSecurityInterceptor
默认会被添加到Servlet容器的Filter链中,并在请求到达控制器之前运行。(3)自定义拦截器与Spring Security集成: 可以创建自定义的Spring MVC拦截器来执行额外的操作,例如记录日志或者进行特定的安全检查。要确保自定义拦截器正常工作,需要注意其执行顺序。通常,安全相关的拦截器应排在前面。
(4)使用DelegatingFilterProxy与Spring MVC集成 : 为了将Spring Security Filter作为Spring MVC的一部分,你可以使用
DelegatingFilterProxy
注册Spring Security filter。这允许你在Spring应用上下文中管理Spring Security filter,而不是直接在web.xml中配置。
XML<bean id="springSecurityFilterChain" class="org.springframework.web.filter.DelegatingFilterProxy"> <property name="targetBeanName" value="filterSecurityInterceptor"/> </bean>
(5)调整拦截器顺序 : 使用
Ordered
接口或@Order
注解来自定义拦截器的执行顺序。较低的数字表示较高的优先级,例如,@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
通常用于确保Spring Security过滤器先于其他自定义拦截器运行。
2.10.1 ResponseEntity**★★★★**
ResponseEntity
是 Spring MVC 中的一个类,用于构建 HTTP 响应。它允许你精确地控制响应的状态码、头部和主体。下面是一个简单的用法示例:
java@GetMapping("/example") public ResponseEntity<String> handleExample() { String body = "This is a sample response"; HttpHeaders headers = new HttpHeaders(); headers.add("Custom-Header", "Value"); return new ResponseEntity<>(body, headers, HttpStatus.OK); }
在这个例子中:
- 创建了一个字符串
"This is a sample response"
作为响应体。- 创建了
HttpHeaders
实例,并添加了一个自定义头部"Custom-Header"
。- 使用
HttpStatus.OK
设置响应状态码为 200。- 将上述三个组件组合成一个
ResponseEntity
对象并返回。
2.10.2 ResponseEntity中包含了哪些重要属性?
ResponseEntity
是 Spring MVC 提供的一个类,它代表了一个完整的 HTTP 响应。以下是ResponseEntity
的主要组成部分:
Body: 这是响应的主体内容,可以是任何类型的数据,比如字符串、自定义对象、文件等。通常由泛型参数指定,如
ResponseEntity<String>
或ResponseEntity<MyClass>
。Status: 它表示响应的状态码,可以是
HttpStatus
类中的枚举值,或者直接传递一个整数,例如HttpStatus.CREATED
(201) 表示资源已成功创建。Headers: 包含了响应头部信息,可以通过
HttpHeaders
对象来设置。可以添加自定义的头信息,如 Content-Type、Location 等。示例:
javaimport org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @GetMapping("/example") public ResponseEntity<String> getExample() { String body = "Hello, this is a response!"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); return ResponseEntity.status(HttpStatus.OK) .headers(headers) .body(body); } }
2.11 RequestEntity
RequestEntity
类是 Spring WebFlux 和 Spring MVC 中的一部分,主要用于构建请求对象。它可以用来封装 HTTP 请求的所有关键部分,包括方法(GET, POST 等)、URL、头信息以及请求体。这是一个基本的使用示例:
java@PostMapping("/example") public ResponseEntity<String> handlePost(@RequestBody RequestEntity<String> requestEntity) { String requestBody = requestEntity.getBody(); HttpMethod method = requestEntity.getMethod(); URI requestedUri = requestEntity.getUri(); // 处理请求... return new ResponseEntity<>("Processed successfully", HttpStatus.OK); }
在这个例子中:
@PostMapping
注解定义了处理 POST 请求的方法。@RequestBody RequestEntity<String>
参数允许我们从请求中获取RequestEntity
对象,其中String
表示我们将接收请求体的内容。requestEntity.getBody()
获取请求体内容。requestEntity.getMethod()
返回请求的 HTTP 方法。requestEntity.getUri()
提供了请求的目标 URI。
2.12.1 自定义拦截器有哪些方式?★★★★
自定义拦截器通常有以下两种方式:
实现
HandlerInterceptor
接口:(推荐)
javapublic class CustomInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 方法执行前的操作,如身份验证、日志记录等 return true; // 返回true表示继续处理请求,返回false则中断请求处理 } @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 { // 请求完全处理后执行,包括视图渲染完成 } }
继承
AbstractHandlerInterceptorAdapter
类(Spring框架的一种简化版拦截器实现):
javapublic class SimplifiedCustomInterceptor extends AbstractHandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 类似于上面的preHandle方法,但是代码结构更为简单 return true; } // 不需要实现postHandle和afterCompletion方法,除非你需要使用它们 }
注册拦截器可以通过以下两种方式:
实现
WebMvcConfigurer
接口:
java@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private CustomInterceptor customInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(customInterceptor) .addPathPatterns("/path/to/match") .excludePathPatterns("/path/to/exclude"); } }
使用
@Bean
注解声明拦截器并在WebMvcConfigurationSupport
子类中注册:
java@Configuration public class WebConfig extends WebMvcConfigurationSupport { @Autowired private CustomInterceptor customInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(customInterceptor) .addPathPatterns("/path/to/match") .excludePathPatterns("/path/to/exclude"); } @Bean public CustomInterceptor customInterceptor() { return new CustomInterceptor(); } }
2.12.2 自定义拦截器中的`preHandle()`、`postHandle()`和`afterCompletion()`分别在什么阶段执行?
自定义拦截器中的
preHandle()
、postHandle()
和afterCompletion()
这三个方法分别在以下阶段执行:
preHandle()
:此方法在DispatcherServlet调用目标处理器之前执行,主要用于进行权限校验、日志记录或者数据预处理等工作。如果这个方法返回false
,那么请求处理将被终止;如果返回true
,则将继续执行后续的拦截器以及目标处理器。
postHandle()
:此方法在DispatcherServlet调用目标处理器之后,但在视图渲染之前执行。可以在这个方法里对ModelAndView对象进行修改,或者做一些其他的数据处理工作。
afterCompletion()
:此方法在整个请求处理完成后执行,即视图渲染完毕后。它主要用来进行资源清理或者一些善后工作,例如关闭数据库连接、释放缓存等。preHandle
该方法在处理器方法执行之前执行。其返回值为 boolean,若为 true,则紧接着会执行处理器方法,且会将 afterCompletion()方法放入到一个专门的方法栈中等待执行。
postHandle
该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。
afterCompletion
当preHandle()方法返回 true 时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对 ModelAndView 再操作也对响应无济于事。afterCompletion 最后执行的方法,清除资源,例如在 Controller 方法中加入数据等。
2.12.3 拦截器的应用场景
- 日志记录:记录请求信息的日志
- 权限检查,如登录检查
- 性能检测:检测方法的执行时间