MVC模式
MVC(Model-View-Controller)模式是一种设计模式,用于分离应用程序的不同方面,以提高代码的组织性和可维护性。在Spring MVC框架中,MVC模式的作用是将应用程序的不同职责分开,从而简化开发和维护过程。MVC模式的三个主要组件是:
-
Model(模型):表示应用程序的数据和业务逻辑。模型通常包括与数据库交互的部分以及用于处理业务逻辑的类。在Spring MVC中,模型通常由POJO(Plain Old Java Object)类表示,这些类包含数据和业务逻辑。
-
View(视图):负责呈现数据给用户。视图将模型的数据以用户友好的格式显示出来。在Spring MVC中,视图通常是JSP、Thymeleaf、FreeMarker等模板文件,这些文件负责渲染HTML页面。
-
Controller(控制器):处理用户的输入并更新模型和视图。控制器接收用户请求,调用相应的业务逻辑,并决定使用哪个视图来显示结果。在Spring MVC中,控制器是一个标注了
@Controller
注解的类,负责处理请求并返回一个视图名称或数据。
在Spring MVC框架中,处理请求的流程通常如下:
-
用户发起请求:用户通过浏览器发送一个HTTP请求。
-
前端控制器:Spring MVC的
DispatcherServlet
作为前端控制器接收请求,并根据请求的URL将其分发到合适的控制器。 -
控制器处理请求:控制器处理请求,调用模型中的业务逻辑,并将数据准备好。
-
选择视图:控制器选择一个视图,并将模型数据传递给视图。
-
渲染视图:视图将模型数据呈现给用户。
-
返回响应:前端控制器将视图的渲染结果返回给用户。
通过这种分层结构,MVC模式使得代码更易于理解和维护,因为它将数据处理、业务逻辑和用户界面分开处理。
SpingMVC启动!!!
对于SpringMVC的使用其实很简单,可以看我下面这篇文章:
下面是SpringMVC常用的注解:
1. 控制器注解
-
@Controller
:- 标记一个类为 SpringMVC 的控制器组件,通常与视图解析结合使用。
- 示例:
@Controller public class MyController { // ... }
-
@RestController
:- 组合注解
@Controller
和@ResponseBody
,用于构建 RESTful Web 服务。控制器方法返回的数据会被自动序列化为 JSON 或 XML 格式。 - 示例:
@RestController public class MyRestController { // ... }
- 组合注解
2. 请求映射注解
-
@RequestMapping
:- 用于映射请求路径到控制器方法,可以用于类级别和方法级别的映射。
- 示例:
@RequestMapping("/hello") public String sayHello() { return "helloView"; }
-
@GetMapping
:- 用于映射 HTTP GET 请求到控制器方法。是
@RequestMapping(method = RequestMethod.GET)
的快捷方式。 - 示例:
@GetMapping("/users") public List<User> getUsers() { // ... }
- 用于映射 HTTP GET 请求到控制器方法。是
-
@PostMapping
:- 用于映射 HTTP POST 请求到控制器方法。是
@RequestMapping(method = RequestMethod.POST)
的快捷方式。 - 示例:
@PostMapping("/users") public User createUser(@RequestBody User user) { // ... }
- 用于映射 HTTP POST 请求到控制器方法。是
-
@PutMapping
:- 用于映射 HTTP PUT 请求到控制器方法。是
@RequestMapping(method = RequestMethod.PUT)
的快捷方式。 - 示例:
@PutMapping("/users/{id}") public User updateUser(@PathVariable Long id, @RequestBody User user) { // ... }
- 用于映射 HTTP PUT 请求到控制器方法。是
-
@DeleteMapping
:- 用于映射 HTTP DELETE 请求到控制器方法。是
@RequestMapping(method = RequestMethod.DELETE)
的快捷方式。 - 示例:
@DeleteMapping("/users/{id}") public void deleteUser(@PathVariable Long id) { // ... }
- 用于映射 HTTP DELETE 请求到控制器方法。是
3. 请求参数注解
-
@PathVariable
:- 用于从 URL 路径中提取参数。
- 示例:
@GetMapping("/users/{id}") public User getUserById(@PathVariable Long id) { // ... }
-
@RequestParam
:- 用于从请求参数中提取单个参数。
- 示例:
@GetMapping("/search") public List<User> searchUsers(@RequestParam String query) { // ... }
-
@RequestBody
:- 用于将请求体中的数据绑定到方法参数,通常用于处理 JSON 或 XML 数据。
- 示例:
@PostMapping("/users") public User createUser(@RequestBody User user) { // ... }
-
@RequestHeader
:- 用于提取请求头中的数据。
- 示例:
@GetMapping("/headers") public String getHeaders(@RequestHeader("User-Agent") String userAgent) { // ... }
-
@RequestAttribute
:- 用于从请求属性中提取数据,通常在过滤器或拦截器中设置。
- 示例:
@GetMapping("/attributes") public String getAttributes(@RequestAttribute("attributeName") String attributeValue) { // ... }
4. 其他重要注解
-
@ModelAttribute
:- 用于在请求处理方法执行前将请求参数绑定到方法参数或方法级别的模型属性。
- 示例:
@ModelAttribute public void addAttributes(Model model) { model.addAttribute("attributeName", "attributeValue"); }
-
@SessionAttributes
:- 用于将某些模型属性存储到 HTTP 会话中,使其在多个请求中保持可用。
- 示例:
@Controller @SessionAttributes("user") public class SessionController { // ... }
-
@ControllerAdvice
:- 用于定义全局的异常处理、全局数据绑定和全局模型属性。
- 示例:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) @ResponseBody public ResponseEntity<String> handleException(Exception ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } }
-
@ExceptionHandler
:- 用于处理控制器方法中抛出的异常。
- 示例:
@ExceptionHandler(ResourceNotFoundException.class) @ResponseBody public ResponseEntity<String> handleResourceNotFoundException(ResourceNotFoundException ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); }
SpringMVC处理web请求流程
旧版返回jsp的流程
旧版流程总结
- 浏览器发起请求到
DispatcherServlet
控制器 - DispatcherServlet根据请求路径查询
handle
HandleMapping
根据先前存储的映射规则,返回一个处理器执行链DispatcherServlet
将执行handle
的命令发送到HandleAdapter
处理适配器HandleAdapter
将请求体中的参数映射到处理函数中,然后接收响应数据,并对相应数据做处理然后返回一个ModelAndView
对象给前端控制器- 前端控制器将数据传给视图解析器,视图解析器放回view对象
- 前端控制器返回一个渲染视图
前后端分离开发处理请求流程
前后端分离开发流程
- 浏览器发送请求给前端控制器
- 前端控制器查询
handle
- 处理映射器返回一个处理器执行链给前端控制器
- 前端控制器请求
HandlerAdaptor
执行,HandlerAdaptor
负责处理传入参数和返回值 - 处理器执行后返回结果,
HttpMessageConverter
将返回结果转换为json后直接响应
SpringMVC异常处理
SpringMVC 的异常处理器用于集中处理应用程序中的异常,以便为用户提供一致的错误响应,同时使代码更加干净和可维护。
异常处理器概述
@ExceptionHandler
:在控制器中使用,专门处理某个控制器方法抛出的特定异常。@ControllerAdvice
:用于定义全局异常处理逻辑,可以处理应用程序中的所有控制器的异常。@ResponseStatus
:用于定义异常类的 HTTP 状态码,简化异常响应的处理。
实现异常处理类
以下是一个简短的示例,展示了如何使用 @ControllerAdvice
和 @ExceptionHandler
实现一个全局异常处理类:
1. 创建自定义异常类
首先,定义一个自定义异常类:
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
2. 创建异常处理类
使用 @ControllerAdvice
和 @ExceptionHandler
注解创建一个全局异常处理类:
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
@ResponseBody
public ResponseEntity<String> handleResourceNotFoundException(ResourceNotFoundException ex) {
// 处理资源未找到异常,返回 404 状态码和异常消息
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity<String> handleGenericException(Exception ex) {
// 处理其他异常,返回 500 状态码和异常消息
return new ResponseEntity<>(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
使用方法
- 自定义异常:当控制器方法中抛出
ResourceNotFoundException
时,handleResourceNotFoundException
方法会处理此异常,并返回一个 404 状态码。 - 通用异常:对于其他未处理的异常,
handleGenericException
方法会处理,并返回一个 500 状态码。
SpringMVC拦截器
SpringMVC 的拦截器是用于在请求处理过程中对请求和响应进行预处理和后处理的组件。它们允许开发者在请求到达控制器之前、控制器处理请求之后,以及视图渲染之前执行一些额外的操作,如日志记录、安全检查、性能监控等。
拦截器的核心功能
- 请求预处理:在请求到达控制器之前执行,用于检查权限、设置请求属性等。
- 请求后处理:在控制器处理请求之后,视图渲染之前执行,用于修改模型数据、记录日志等。
- 响应后处理:在视图渲染之后,响应发送给客户端之前执行,用于修改响应数据等。
拦截器接口
SpringMVC 提供了一个 HandlerInterceptor
接口,用于定义拦截器。这个接口包含以下方法:
-
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
:- 在请求处理之前调用。返回
true
继续处理请求,返回false
终止请求处理。
- 在请求处理之前调用。返回
-
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
:- 在请求处理之后,视图渲染之前调用。可以修改模型和视图数据。
-
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
:- 在视图渲染完成后调用。用于清理资源等操作。
示例:实现一个简单的拦截器
1. 创建拦截器类
实现 HandlerInterceptor
接口,并重写其方法:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在请求处理之前执行
System.out.println("Before handling the request");
return true; // 返回 true 继续处理请求,返回 false 中止请求处理
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在请求处理后,视图渲染之前执行
System.out.println("After handling the request but before rendering the view");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 在视图渲染完成后执行
System.out.println("After completing the request");
if (ex != null) {
ex.printStackTrace();
}
}
}
2. 注册拦截器
在 SpringMVC 的配置类中注册拦截器:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**"); // 设置拦截路径
}
}
SpringMVC过滤器
SpringMVC 的过滤器(Filter)是一种用于在请求和响应处理过程中对请求数据和响应数据进行预处理和后处理的机制。它们可以用于实现各种功能,如日志记录、安全检查、请求修改等。过滤器是在 Servlet 容器中运行的,而不是 Spring 容器中。
过滤器的核心功能
- 请求预处理:在请求到达控制器之前执行,可以对请求进行修改、添加属性等。
- 响应后处理:在响应从控制器返回之前执行,可以对响应进行修改或记录日志等。
过滤器接口
javax.servlet.Filter
接口用于定义过滤器。它包含以下方法:
-
void init(FilterConfig filterConfig)
:- 初始化过滤器,通常用于读取配置参数。
-
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
:- 处理请求和响应。可以对请求和响应进行修改,并调用
FilterChain
的doFilter
方法继续处理链中的下一个过滤器或目标资源。
- 处理请求和响应。可以对请求和响应进行修改,并调用
-
void destroy()
:- 关闭过滤器,释放资源。
示例:实现一个简单的过滤器
1. 创建过滤器类
实现 Filter
接口,并重写其方法:
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*") // 通过注解配置过滤器的拦截路径
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化过滤器
System.out.println("Filter initialized");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 处理请求之前
System.out.println("Before request processing");
// 继续处理请求,调用链中的下一个过滤器或目标资源
chain.doFilter(request, response);
// 处理响应之后
System.out.println("After request processing");
}
@Override
public void destroy() {
// 关闭过滤器
System.out.println("Filter destroyed");
}
}
2. 注册过滤器
在 Spring Boot 中,你也可以通过 Java 配置类注册过滤器:
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<MyFilter> loggingFilter() {
FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new MyFilter());
registrationBean.addUrlPatterns("/*"); // 设置过滤器的拦截路径
return registrationBean;
}
}
SpringMVC解决跨域问题
在 SpringMVC 中,跨域问题(Cross-Origin Resource Sharing, CORS)通常是指不同源的客户端请求访问服务器资源时遇到的限制。为了解决这个问题,可以配置允许跨域访问的策略。SpringMVC 提供了多种方式来处理跨域请求。
解决跨域问题的方法
-
全局 CORS 配置:
在 Spring Boot 应用中,可以通过配置全局 CORS 规则来允许特定的来源进行跨域访问。这种方式可以在全局范围内对所有控制器应用 CORS 配置。
示例:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://example.com") // 允许的源 .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的 HTTP 方法 .allowedHeaders("*") // 允许的请求头 .allowCredentials(true); // 是否允许凭证(如 cookies) } }
-
在 Controller 层使用
@CrossOrigin
注解:可以在单个控制器或具体的控制器方法上使用
@CrossOrigin
注解来指定允许的跨域配置。这种方式适用于需要对某些特定控制器或方法进行跨域配置的情况。示例:
import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api") public class MyController { @CrossOrigin(origins = "http://example.com") @GetMapping("/data") public String getData() { return "Some data"; } }
-
在 Spring Security 中配置 CORS:
如果应用程序使用了 Spring Security,必须在 Security 配置中显式启用 CORS 配置。Spring Security 默认情况下不会允许 CORS 请求,因此需要进行额外的配置。
示例:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .cors() // 启用 CORS .and() .csrf().disable() // 根据需要配置 CSRF .authorizeRequests() .anyRequest().authenticated(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://example.com")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }