Spring MVC
Spring MVC
MVC是什么?MVC设计模式的好处有哪些?
MVC是一种软件设计模式,将应用程序分为三个核心部分:Model、View和Controller。这种模式通过分离关注点,使代码更加模块化、可维护和可扩展。
MVC模式的核心思想是将应用程序的不同职责分离到不同的组件中。Model负责处理数据和业务逻辑,View负责展示数据,Controller负责协调Model和View,处理用户输入。
MVC模式的好处主要体现在以下几个方面:
关注点分离: MVC模式将应用程序的不同职责分离到不同的组件中,使得每个组件只需要关注自己的职责,降低了代码的复杂度。
代码复用: 由于Model、View和Controller是分离的,因此可以在不同的场景下复用这些组件,提高了代码的复用性。
可维护性: MVC模式使得代码结构更加清晰,每个组件的职责明确,因此更容易维护和修改。
可扩展性: MVC模式使得应用程序的不同部分可以独立扩展,例如可以更换不同的View而不影响Model和Controller。
可测试性: 由于Model、View和Controller是分离的,因此可以独立测试这些组件,提高了代码的可测试性。
在实际开发中,MVC模式广泛应用于Web应用程序的开发。Spring MVC框架就是基于MVC模式设计的,它提供了丰富的功能来支持MVC模式的实现。
Spring MVC常用的注解有哪些?
Spring MVC常用的注解包括:@Controller、@RequestMapping、@GetMapping、@PostMapping、@RequestParam、@PathVariable、@ResponseBody、@RequestBody、@ModelAttribute、@SessionAttribute等。这些注解用于定义控制器、映射请求、处理参数和返回响应。
@Controller注解用于标识一个类为Spring MVC的控制器。它会被Spring容器扫描并注册为Bean,同时它也是一个特殊的@Component注解,专门用于Web层。
@Controller
public class UserController {
// 控制器方法
}
@RequestMapping注解用于将Web请求映射到Spring MVC控制器方法上。它可以指定请求的URL路径、HTTP方法、请求参数、请求头等条件,是Spring MVC中最基础的路由注解。
@Controller
@RequestMapping("/api/users")
public class UserController {
@RequestMapping(value = "/list", method = RequestMethod.GET)
public String getUserList() {
return "userList";
}
@RequestMapping(value = "/add", method = RequestMethod.POST)
public String addUser() {
return "success";
}
}
@GetMapping、@PostMapping等注解是@RequestMapping的特化版本,分别用于处理不同的HTTP方法。使用这些特化注解,不仅可以让代码更加简洁,还能提高代码的可读性。
@Controller
public class UserController {
@GetMapping("/users")
public String getUsers() {
return "userList";
}
@PostMapping("/users")
public String createUser() {
return "success";
}
@PutMapping("/users/{id}")
public String updateUser(@PathVariable Long id) {
return "success";
}
@DeleteMapping("/users/{id}")
public String deleteUser(@PathVariable Long id) {
return "success";
}
}
@RequestParam注解用于从请求中获取参数值。它可以获取查询参数或表单数据。@RequestParam注解支持设置参数是否必需、默认值等属性,使用非常灵活。
@Controller
public class UserController {
@GetMapping("/search")
public String searchUsers(
@RequestParam String keyword,
@RequestParam(defaultValue = "1") int page,
@RequestParam(required = false) String sortBy
) {
// keyword: 必需参数
// page: 有默认值1
// sortBy: 可选参数
return "searchResult";
}
}
@PathVariable注解用于从URL路径中获取变量值。它通常用于RESTful API中,如"/users/{id}"这样的URL。@PathVariable注解可以获取URL路径中的变量,并将其绑定到方法参数上。
@Controller
public class UserController {
@GetMapping("/users/{id}")
public String getUserById(@PathVariable Long id) {
// 访问 /users/123 时,id = 123
return "userDetail";
}
@GetMapping("/users/{userId}/orders/{orderId}")
public String getUserOrder(
@PathVariable Long userId,
@PathVariable Long orderId
) {
// 访问 /users/123/orders/456 时
// userId = 123, orderId = 456
return "orderDetail";
}
}
@ResponseBody注解用于将方法的返回值自动转换为JSON格式。它可以用于方法级别,将方法的返回值自动转换为JSON格式,然后写入响应体。
@Controller
public class UserController {
@GetMapping("/api/users/{id}")
@ResponseBody
public User getUser(@PathVariable Long id) {
User user = userService.findById(id);
return user; // 自动转换为JSON: {"id":1,"name":"张三","email":"zhangsan@example.com"}
}
@GetMapping("/api/users")
@ResponseBody
public List<User> getAllUsers() {
return userService.findAll(); // 自动转换为JSON数组
}
}
@RequestBody注解用于将请求体自动转换为Java对象。它通常用于处理POST请求的JSON数据,将JSON数据自动转换为Java对象。
@Controller
public class UserController {
@PostMapping("/api/users")
@ResponseBody
public User createUser(@RequestBody User user) {
// 接收JSON: {"name":"李四","email":"lisi@example.com","age":25}
// 自动转换为User对象
return userService.save(user);
}
@PutMapping("/api/users/{id}")
@ResponseBody
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.update(user);
}
}
@ModelAttribute注解用于将请求参数绑定到Model对象上。它可以用在方法参数上,将请求参数绑定到Model对象上,然后可以在视图中使用这些数据。
@Controller
public class UserController {
@GetMapping("/users/form")
public String showUserForm(Model model) {
model.addAttribute("user", new User());
return "userForm";
}
@PostMapping("/users/save")
public String saveUser(@ModelAttribute User user, Model model) {
// 表单数据自动绑定到User对象
userService.save(user);
model.addAttribute("message", "用户保存成功");
return "success";
}
// 在类级别使用@ModelAttribute
@ModelAttribute("userTypes")
public List<String> getUserTypes() {
return Arrays.asList("普通用户", "VIP用户", "管理员");
}
}
@SessionAttribute注解用于将Model对象存储到Session中。它可以用在类级别,将Model对象存储到Session中,然后在不同的请求之间共享这些数据。
@Controller
@SessionAttributes("user") // 将名为"user"的Model属性存储到Session
public class UserController {
@GetMapping("/login")
public String loginForm() {
return "loginForm";
}
@PostMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password,
Model model) {
User user = userService.login(username, password);
if (user != null) {
model.addAttribute("user", user); // 存储到Session
return "redirect:/dashboard";
}
return "loginForm";
}
@GetMapping("/dashboard")
public String dashboard(@SessionAttribute("user") User user) {
// 从Session中获取用户信息
return "dashboard";
}
@GetMapping("/logout")
public String logout(SessionStatus status) {
status.setComplete(); // 清除Session
return "redirect:/login";
}
}
SpringMVC有哪些核心组件?
Spring MVC的核心组件包括:DispatcherServlet、HandlerMapping、HandlerAdapter、ViewResolver、View等。这些组件协同工作,处理Web请求并返回响应。
DispatcherServlet是Spring MVC的前端控制器,它负责接收所有的Web请求,并将请求分发给相应的处理器。DispatcherServlet是Spring MVC的核心组件,它协调其他组件的工作,是Spring MVC的入口点。
HandlerMapping负责将请求映射到处理器。它根据请求的URL、HTTP方法、请求参数等条件,找到能够处理该请求的处理器。Spring MVC提供了多种HandlerMapping实现,如RequestMappingHandlerMapping、SimpleUrlHandlerMapping等。
HandlerAdapter负责调用处理器。它根据处理器的类型,调用相应的处理方法。Spring MVC提供了多种HandlerAdapter实现,如RequestMappingHandlerAdapter、SimpleControllerHandlerAdapter等。
ViewResolver负责将逻辑视图名解析为实际的视图对象。它根据逻辑视图名,找到对应的视图对象。Spring MVC提供了多种ViewResolver实现,如InternalResourceViewResolver、FreeMarkerViewResolver等。
View负责渲染视图。它根据Model数据,生成最终的响应内容。Spring MVC提供了多种View实现,如JstlView、FreeMarkerView等。
这些核心组件协同工作,处理Web请求并返回响应。DispatcherServlet接收请求,HandlerMapping找到处理器,HandlerAdapter调用处理器,处理器返回逻辑视图名,ViewResolver解析逻辑视图名,View渲染视图,最终返回响应。
在实际开发中,我们通常不需要直接使用这些核心组件,Spring MVC框架已经为我们封装了这些组件,我们只需要使用注解来定义控制器、映射请求、处理参数和返回响应即可。
SpringMVC的执行流程了解吗?
Spring MVC的执行流程主要包括:请求进入DispatcherServlet、HandlerMapping找到处理器、HandlerAdapter调用处理器、处理器处理请求、ViewResolver解析视图、View渲染视图、返回响应。这个过程是Spring MVC处理Web请求的标准流程。
当Web请求进入Spring MVC应用时,首先由DispatcherServlet接收请求。DispatcherServlet是Spring MVC的前端控制器,它负责接收所有的Web请求,并将请求分发给相应的处理器。
DispatcherServlet接收到请求后,会调用HandlerMapping组件,根据请求的URL、HTTP方法、请求参数等条件,找到能够处理该请求的处理器。HandlerMapping会返回一个HandlerExecutionChain对象,该对象包含了处理器和拦截器。
找到处理器后,DispatcherServlet会调用HandlerAdapter组件,根据处理器的类型,调用相应的处理方法。HandlerAdapter会调用处理器的处理方法,处理请求,并返回一个ModelAndView对象,该对象包含了模型数据和视图信息。
处理器处理完请求后,DispatcherServlet会调用ViewResolver组件,将逻辑视图名解析为实际的视图对象。ViewResolver会根据逻辑视图名,找到对应的视图对象。
解析出视图对象后,DispatcherServlet会调用View组件,渲染视图。View会根据Model数据,生成最终的响应内容。
最后,DispatcherServlet将响应返回给客户端,完成整个请求处理流程。
Spring MVC 拦截器是什么?
Spring MVC拦截器是一种用于拦截请求的组件,它可以在请求处理的不同阶段执行自定义逻辑。拦截器可以用于日志记录、权限检查、性能监控等场景,是Spring MVC中实现横切关注点的重要工具。
Spring MVC拦截器实现了HandlerInterceptor接口,该接口定义了三个方法:preHandle、postHandle和afterCompletion。preHandle方法在处理器执行前调用,postHandle方法在处理器执行后调用,afterCompletion方法在视图渲染完成后调用。
拦截器可以在请求处理的不同阶段执行自定义逻辑,例如在preHandle方法中检查用户权限,在postHandle方法中记录请求处理时间,在afterCompletion方法中清理资源。
拦截器可以通过实现HandlerInterceptor接口或继承HandlerInterceptorAdapter类来创建。HandlerInterceptorAdapter类提供了HandlerInterceptor接口的默认实现,开发者只需要重写需要的方法即可。
拦截器需要在Spring MVC配置中注册,可以通过实现WebMvcConfigurer接口或继承WebMvcConfigurerAdapter类来配置拦截器。配置拦截器时,需要指定拦截器的路径模式,即哪些请求需要被拦截。
拦截器的使用场景有哪些?
拦截器的使用场景包括:日志记录、权限检查、性能监控、参数验证、跨域处理等。拦截器可以在请求处理的不同阶段执行自定义逻辑,是Spring MVC中实现横切关注点的重要工具。
日志记录:拦截器可以用于记录请求的详细信息,如请求URL、请求方法、请求参数、请求头、响应状态码、响应时间等。这些信息可以用于问题排查、性能分析、安全审计等。
权限检查:拦截器可以用于检查用户的权限,如是否已登录、是否有权限访问某个资源等。如果用户没有权限,拦截器可以重定向到登录页面或返回错误信息。
性能监控:拦截器可以用于监控请求的处理时间,如记录请求开始时间、请求结束时间、请求处理时间等。这些信息可以用于性能分析、性能优化等。
参数验证:拦截器可以用于验证请求参数,如检查参数是否为空、参数格式是否正确等。如果参数验证失败,拦截器可以返回错误信息。
跨域处理:拦截器可以用于处理跨域请求,如设置响应头、处理预检请求等。跨域处理是Web应用开发中常见的问题,拦截器可以统一处理这个问题。
在实际开发中,拦截器是Spring MVC中实现横切关注点的重要工具,它可以在不修改业务代码的情况下,实现日志记录、权限检查、性能监控等功能,提高了代码的可维护性和可扩展性。
Spring MVC 怎么配置拦截器?
Spring MVC配置拦截器主要有两种方式:实现WebMvcConfigurer接口或继承WebMvcConfigurerAdapter类。配置时需要指定拦截器的路径模式,即哪些请求需要被拦截。
实现WebMvcConfigurer接口是Spring 5.0之后推荐的方式。WebMvcConfigurer接口提供了多个方法,用于配置Spring MVC的各个方面,包括拦截器、视图解析器、消息转换器等。配置拦截器时,需要重写addInterceptors方法,在该方法中注册拦截器并指定拦截器的路径模式。
继承WebMvcConfigurerAdapter类是Spring 5.0之前的方式。WebMvcConfigurerAdapter类提供了WebMvcConfigurer接口的默认实现,开发者只需要重写需要的方法即可。配置拦截器时,需要重写addInterceptors方法,在该方法中注册拦截器并指定拦截器的路径模式。
配置拦截器时,需要指定拦截器的路径模式,即哪些请求需要被拦截。路径模式可以使用Ant风格的路径匹配,如"/user/**"表示拦截所有以"/user/"开头的请求。还可以使用excludePathPatterns方法排除不需要拦截的请求。
如何实现过滤器?
实现过滤器需要实现javax.servlet.Filter接口或继承javax.servlet.http.HttpFilter类。过滤器需要在web.xml中配置或使用@WebFilter注解配置,指定过滤器的URL模式。
实现javax.servlet.Filter接口是Java EE标准的方式。Filter接口定义了三个方法: init、doFilter和destroy。init方法在过滤器初始化时调用,doFilter方法在请求处理时调用,destroy方法在过滤器销毁时调用。在doFilter方法中,可以编写过滤器的逻辑,如检查请求、修改请求、修改响应等。
继承javax.servlet.http.HttpFilter类是Java EE 9之后的方式。HttpFilter类提供了Filter接口的默认实现,开发者只需要重写需要的方法即可。HttpFilter类还提供了一些便利方法,如getRequest、getResponse等,方便开发者获取请求和响应对象。
过滤器需要在web.xml中配置或使用@WebFilter注解配置,指定过滤器的URL模式。URL模式可以使用Ant风格的路径匹配,如"/user/*"表示过滤所有以"/user/"开头的请求。还可以使用dispatcher元素指定过滤器的分发类型,如REQUEST、FORWARD、INCLUDE、ERROR等。
拦截器和过滤器区别是什么?
拦截器和过滤器都是用于拦截请求的组件,但它们的实现方式、使用场景和功能不同。
拦截器是Spring MVC的组件,过滤器是Java EE的组件;拦截器可以访问Spring上下文,过滤器不能;拦截器只能拦截Spring MVC的请求,过滤器可以拦截所有请求。
实现方式:拦截器实现了HandlerInterceptor接口,过滤器实现了Filter接口。拦截器是Spring MVC的组件,过滤器是Java EE的组件。拦截器可以访问Spring上下文,过滤器不能。
使用场景:拦截器通常用于实现横切关注点,如日志记录、权限检查、性能监控等;过滤器通常用于实现请求和响应的预处理和后处理,如字符编码转换、压缩、加密等。
功能:拦截器可以访问Spring上下文,可以使用Spring的依赖注入、AOP等功能;过滤器不能访问Spring上下文,只能使用Java EE的功能。拦截器只能拦截Spring MVC的请求,过滤器可以拦截所有请求,包括静态资源、JSP等。
执行顺序:过滤器的执行顺序在拦截器之前。当请求进入Web应用时,首先经过过滤器,然后经过拦截器,最后到达处理器。当响应返回时,首先经过拦截器,然后经过过滤器,最后到达客户端。
Spring MVC异常处理是什么?
Spring MVC异常处理是一种机制,用于统一处理应用程序中的异常。它可以将异常转换为友好的错误信息,返回给客户端,提高用户体验。
Spring MVC异常处理主要有三种方式:使用@ExceptionHandler注解、实现HandlerExceptionResolver接口、使用@ControllerAdvice注解。
使用@ExceptionHandler注解是最简单的方式。@ExceptionHandler注解可以用在控制器方法上,指定该方法处理哪些异常。当控制器方法抛出异常时,Spring MVC会调用对应的@ExceptionHandler方法处理异常。
实现HandlerExceptionResolver接口是更灵活的方式。HandlerExceptionResolver接口定义了resolveException方法,用于处理异常。开发者可以实现HandlerExceptionResolver接口,编写自己的异常处理逻辑。
使用@ControllerAdvice注解是Spring 3.2之后引入的方式。@ControllerAdvice注解可以用在类上,指定该类处理哪些控制器的异常。@ControllerAdvice注解通常和@ExceptionHandler注解一起使用,实现全局异常处理。
在实际开发中,我们通常使用@ControllerAdvice注解和@ExceptionHandler注解实现全局异常处理。这种方式不仅使用简单,而且能够统一处理所有控制器的异常,提高代码的可维护性。
