Bootstrap

Spring MVC

1. 用户发起请求

  • 用户行为:用户在浏览器中输入URL或点击链接,向Web服务器(如Tomcat)发起一个HTTP请求。
  • 请求传输:请求被发送到Web容器,Web容器根据配置将请求转发给DispatcherServlet

2. 前端控制器(DispatcherServlet)

  • 作用DispatcherServlet是Spring MVC的核心组件,负责接收所有进入的HTTP请求,并将它们分发给适当的处理器(Controller)。
  • 初始化:在Web应用启动时,DispatcherServlet会被初始化,并且会读取Spring配置文件(如dispatcher-servlet.xml)来初始化相关的Bean。
web.xml配置
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

3. 处理器映射(HandlerMapping)

  • 作用DispatcherServlet接收到请求后,会查询HandlerMapping以确定哪个控制器应该处理该请求。
  • 常见类型
    • RequestMappingHandlerMapping:基于@RequestMapping注解的映射。
    • BeanNameUrlHandlerMapping:基于Bean名称的映射。
    • SimpleUrlHandlerMapping:基于简单的URL映射。
dispatcher-servlet.xml配置
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />

4. 控制器(Controller)

  • 作用:控制器负责处理具体的业务逻辑,可以访问请求参数、表单数据、会话信息等。
  • 返回值:控制器方法处理完请求后,返回一个ModelAndView对象给DispatcherServletModelAndView包含两个部分:
    • Model:模型数据,即业务数据,可以是一个Map对象,用于向视图传递数据。
    • View:逻辑视图名,表示要使用的视图资源的名称。
控制器示例
@Controller
public class HelloController {

    @Autowired
    private SomeService someService;

    @RequestMapping("/hello")
    public ModelAndView hello(@RequestParam("name") String name) {
        // 调用服务层方法
        String message = someService.getMessage(name);

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("message", message);
        modelAndView.setViewName("hello");
        return modelAndView;
    }
}

5. 视图解析器(ViewResolver)

  • 作用DispatcherServlet接收到ModelAndView对象后,会使用ViewResolver来解析逻辑视图名,找到对应的物理视图资源(如JSP页面)。
  • 常见类型
    • InternalResourceViewResolver:用于JSP视图。
    • ThymeleafViewResolver:用于Thymeleaf视图。
    • FreeMarkerViewResolver:用于FreeMarker视图。
dispatcher-servlet.xml配置
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>

6. 视图渲染

  • 作用:找到具体的视图资源后,DispatcherServlet将模型数据传递给视图进行渲染。
  • 渲染过程:视图负责将模型数据转换为HTML或其他格式的输出,这个过程可能包括数据格式化、模板渲染等。
视图示例 (hello.jsp)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Hello Page</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>

7. 响应客户端

  • 作用:渲染完成后,DispatcherServlet将最终的HTML页面通过HTTP响应返回给客户端浏览器,用户可以看到请求的结果。

8. 拦截器(Interceptor)

  • 作用:在请求处理的过程中,可以配置拦截器来执行一些额外的操作,如日志记录、权限验证、性能监控等。
  • 实现方式:通过实现HandlerInterceptor接口或继承HandlerInterceptorAdapter类来创建拦截器。
拦截器示例
@Component
public class LoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Pre-handle: " + request.getRequestURI());
        return true; // 继续处理请求
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Post-handle: " + request.getRequestURI());
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("After completion: " + request.getRequestURI());
    }
}
拦截器配置示例
<mvc:interceptors>
    <bean class="com.example.interceptor.LoggingInterceptor" />
</mvc:interceptors>

9. 异常处理(ExceptionHandler)

  • 作用:Spring MVC提供了异常处理机制,可以在控制器中使用@ExceptionHandler注解来处理特定类型的异常。
  • 全局异常处理:还可以在全局范围内使用@ControllerAdvice注解来定义全局异常处理。
异常处理示例
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ModelAndView handleResourceNotFoundException(ResourceNotFoundException ex) {
        ModelAndView modelAndView = new ModelAndView("error");
        modelAndView.addObject("errorMessage", ex.getMessage());
        return modelAndView;
    }

    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex) {
        ModelAndView modelAndView = new ModelAndView("error");
        modelAndView.addObject("errorMessage", "An unexpected error occurred.");
        return modelAndView;
    }
}

10. 数据绑定和验证

  • 数据绑定:Spring MVC提供了数据绑定机制,可以自动将请求参数绑定到控制器方法的参数上。
  • 数据验证:可以使用@Valid@Validated注解结合JSR 303(如Hibernate Validator)来进行数据验证。
数据绑定和验证示例
@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/users", method = RequestMethod.POST)
    public ModelAndView createUser(@Valid @ModelAttribute User user, BindingResult result) {
        if (result.hasErrors()) {
            return new ModelAndView("userForm");
        }

        userService.createUser(user);
        return new ModelAndView("redirect:/users");
    }
}

11. 模型属性管理

  • 作用:可以使用@ModelAttribute注解将对象添加到模型中,以便在视图中使用。
模型属性管理示例
@Controller
public class UserController {

    @ModelAttribute("user")
    public User createUserModel() {
        return new User();
    }

    @RequestMapping("/userForm")
    public String showUserForm() {
        return "userForm";
    }
}

12. 国际化(I18N)

  • 作用:Spring MVC支持国际化,可以通过LocaleResolverMessageSource来实现多语言支持。
国际化配置示例
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
    <property name="defaultLocale" value="en_US" />
</bean>

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="classpath:messages" />
    <property name="defaultEncoding" value="UTF-8" />
</bean>
国际化使用示例
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
    <title><fmt:message key="title" /></title>
</head>
<body>
<h1><fmt:message key="welcome.message" /></h1>
</body>
</html>

13. 文件上传

  • 作用:Spring MVC支持文件上传功能,可以通过MultipartFile接口来处理上传的文件。
  • 配置:需要配置CommonsMultipartResolverStandardServletMultipartResolver来处理文件上传。
文件上传配置示例
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10000000" /> <!-- 10MB -->
</bean>
文件上传控制器示例
@Controller
public class FileUploadController {

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public ModelAndView handleFileUpload(@RequestParam("file") MultipartFile file) {
        if (!file.isEmpty()) {
            try {
                byte[] bytes = file.getBytes();
                // 处理文件保存逻辑
                // ...
                return new ModelAndView("success");
            } catch (IOException e) {
                return new ModelAndView("error");
            }
        } else {
            return new ModelAndView("error");
        }
    }
}

14. RESTful API

  • 作用:Spring MVC支持RESTful API的开发,可以通过@RestController@RequestMapping注解来定义RESTful接口。
  • 返回JSON:可以使用@ResponseBody注解将返回对象转换为JSON格式。
RESTful API示例
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
}

15. 安全性(Security)

  • 作用:Spring Security可以与Spring MVC集成,提供安全保护,如认证和授权。
  • 配置:需要配置Spring Security的相关Bean和过滤器。
Spring Security配置示例
<security:http auto-config="true">
    <security:intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
    <security:form-login login-page="/login" default-target-url="/home" authentication-failure-url="/login?error" />
    <security:logout logout-success-url="/login?logout" />
</security:http>

<security:authentication-manager>
    <security:authentication-provider>
        <security:user-service>
            <security:user name="user" password="password" authorities="ROLE_USER" />
            <security:user name="admin" password="password" authorities="ROLE_ADMIN" />
        </security:user-service>
    </security:authentication-provider>
</security:authentication-manager>

16. 异步处理

  • 作用:Spring MVC支持异步处理,可以通过@Async注解和DeferredResult来实现异步请求处理。
异步处理示例
@Controller
public class AsyncController {

    @Autowired
    private AsyncService asyncService;

    @RequestMapping("/async")
    public DeferredResult<String> handleAsyncRequest() {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        asyncService.handleAsync(deferredResult);
        return deferredResult;
    }
}

@Service
public class AsyncService {

    @Async
    public void handleAsync(DeferredResult<String> deferredResult) {
        // 模拟耗时操作
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        deferredResult.setResult("Async processing completed");
    }
}

17. 消息转换器(MessageConverter)

  • 作用:Spring MVC使用消息转换器(MessageConverter)将请求体和响应体转换为Java对象或从Java对象转换为响应体。
  • 常见类型
    • MappingJackson2HttpMessageConverter:用于JSON转换。
    • StringHttpMessageConverter:用于字符串转换。
消息转换器配置示例
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
            <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
        </list>
    </property>
</bean>

18. 模板引擎

  • 作用:Spring MVC支持多种模板引擎,如Thymeleaf、FreeMarker等。
  • 配置:需要配置相应的模板解析器和视图解析器。
Thymeleaf配置示例
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
    <property name="templateResolvers">
        <set>
            <bean class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
                <property name="prefix" value="/WEB-INF/templates/" />
                <property name="suffix" value=".html" />
                <property name="templateMode" value="HTML5" />
            </bean>
        </set>
    </property>
</bean>

<bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine" />
</bean>

19. 拦截器链

  • 作用:Spring MVC支持多个拦截器组成一个拦截器链,按顺序执行。
  • 配置:可以在dispatcher-servlet.xml中配置多个拦截器。
拦截器链配置示例
<mvc:interceptors>
    <bean class="com.example.interceptor.LoggingInterceptor" />
    <bean class="com.example.interceptor.AuthorizationInterceptor" />
</mvc:interceptors>

20. 异常处理策略

  • 作用:Spring MVC提供了多种异常处理策略,如全局异常处理、局部异常处理等。
  • 配置:可以通过@ControllerAdvice@ExceptionHandler注解来定义异常处理策略。
全局异常处理示例
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
        ErrorResponse errorResponse = new ErrorResponse("NOT_FOUND", ex.getMessage());
        return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception ex) {
        ErrorResponse errorResponse = new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred.");
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

21. 拦截器的生命周期

  • 作用:拦截器有三个主要的生命周期方法:preHandlepostHandleafterCompletion
  • 方法说明
    • preHandle:在请求处理之前调用,返回true继续处理请求,返回false中断请求处理。
    • postHandle:在请求处理之后、视图渲染之前调用。
    • afterCompletion:在请求处理完成之后调用,无论是否发生异常。
拦截器生命周期示例
@Component
public class LoggingInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Pre-handle: " + request.getRequestURI());
        return true; // 继续处理请求
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Post-handle: " + request.getRequestURI());
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("After completion: " + request.getRequestURI());
    }
}

22. 跨域请求(CORS)

  • 作用:Spring MVC支持跨域请求(CORS),可以在控制器或全局配置中启用CORS支持。
  • 配置:可以通过@CrossOrigin注解或WebMvcConfigurer接口来配置CORS。
跨域请求配置示例
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://example.com")
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true);
    }
}
控制器级别的CORS配置
@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "http://example.com")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    // 其他方法...
}

23. 自定义注解

  • 作用:Spring MVC支持自定义注解,可以通过自定义注解来简化代码或实现特定的功能。
  • 实现方式:定义自定义注解并使用HandlerMethodArgumentResolver来解析注解。
自定义注解示例
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUser {
}
自定义注解解析器
@Component
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private HttpServletRequest request;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(CurrentUser.class) != null;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 从请求中获取当前用户信息
        User user = (User) request.getSession().getAttribute("user");
        return user;
    }
}
注册自定义注解解析器
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver;

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(currentUserMethodArgumentResolver);
    }
}
使用自定义注解
@RestController
@RequestMapping("/api/users")
public class UserController {

    @GetMapping("/current")
    public User getCurrentUser(@CurrentUser User user) {
        return user;
    }
}

24. 缓存支持

  • 作用:Spring MVC支持缓存,可以通过@Cacheable@CacheEvict@CachePut注解来实现缓存管理。
  • 配置:需要配置缓存管理器(如ConcurrentMapCacheManagerRedisCacheManager)。
缓存配置示例
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("users");
    }
}
缓存注解示例
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    @Cacheable(value = "users", key = "#id")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }

    @PostMapping
    @CachePut(value = "users", key = "#user.id")
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }

    @PutMapping("/{id}")
    @CachePut(value = "users", key = "#id")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }

    @DeleteMapping("/{id}")
    @CacheEvict(value = "users", key = "#id")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
}

25. AOP(面向切面编程)

  • 作用:Spring MVC支持AOP,可以通过切面来实现横切关注点的分离,如日志记录、事务管理等。
  • 实现方式:使用@Aspect注解定义切面,并使用@Before@After@Around等注解定义通知。
切面示例
@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.controller.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }

    @After("execution(* com.example.controller.*.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("After method: " + joinPoint.getSignature().getName());
    }

    @Around("execution(* com.example.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around before method: " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed();
        System.out.println("Around after method: " + joinPoint.getSignature().getName());
        return result;
    }
}

26. 事务管理

  • 作用:Spring MVC支持事务管理,可以通过@Transactional注解来管理事务。
  • 配置:需要配置事务管理器(如DataSourceTransactionManager)。
事务管理配置示例
@Configuration
@EnableTransactionManagement
public class TransactionConfig {

    @Autowired
    private DataSource dataSource;

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource);
    }
}
事务管理注解示例
@Service
@Transactional
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User createUser(User user) {
        return userRepository.save(user);
    }

    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

27. 异步任务调度

  • 作用:Spring MVC支持异步任务调度,可以通过@Scheduled注解来定期执行任务。
  • 配置:需要配置任务调度器(如TaskScheduler)。
任务调度配置示例
@Configuration
@EnableScheduling
public class SchedulingConfig {

    @Bean
    public TaskScheduler taskScheduler() {
        return new ThreadPoolTaskScheduler();
    }
}
任务调度注解示例
@Component
public class ScheduledTasks {

    @Scheduled(fixedRate = 5000)
    public void scheduledTask() {
        System.out.println("Scheduled task executed at " + new Date());
    }
}

28. 配置类

  • 作用:Spring MVC支持使用Java配置类来替代传统的XML配置文件。
  • 配置:可以通过@Configuration注解定义配置类,并使用@ComponentScan@EnableWebMvc等注解来启用Web MVC功能。
Java配置类示例
@Configuration
@ComponentScan(basePackages = "com.example")
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/views/", ".jsp");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor());
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/resources/");
    }

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("classpath:messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        localeResolver.setDefaultLocale(Locale.US);
        return localeResolver;
    }
}

总结

通过上述详细的步骤和示例,我们可以看到Spring MVC的工作流程涉及多个组件的协同工作。每个组件都有其特定的职责,确保请求能够被正确地处理和响应。

;