Spring MVC实践与高级架构特性全
- 发布时间:2025-02-19 09:48:25
- 本文热度:浏览 27 赞 0 评论 0
- 文章标签: Spring MVC Java Web开发 REST API
- 全文共1字,阅读约需1分钟
Spring MVC核心架构与处理流程剖析
1. 架构组件深度解析
Spring MVC采用经典前端控制器模式,其核心架构由以下关键组件构成:
- DispatcherServlet(中央调度器)
- 继承自HttpServlet,作为统一请求入口
- 初始化时加载WebApplicationContext
- 默认配置路径:/WEB-INF/
-servlet.xml - 多DispatcherServlet配置示例:
<servlet>
<servlet-name>adminServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/admin-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
- HandlerMapping 策略
- BeanNameUrlHandlerMapping:Bean名称映射
- ControllerClassNameHandlerMapping:类名约定映射
- RequestMappingHandlerMapping(推荐):注解驱动
- 自定义映射策略实现:
public class VersionHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String version = request.getHeader("API-Version");
// 根据版本选择处理器
return super.getHandlerInternal(request);
}
}
- HandlerAdapter 适配器体系
- HttpRequestHandlerAdapter
- SimpleControllerHandlerAdapter
- RequestMappingHandlerAdapter
- 自定义适配器示例:
public class GraphQLHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
return handler instanceof GraphQLController;
}
@Override
public ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 处理GraphQL请求逻辑
return new ModelAndView();
}
}
2. 请求处理全生命周期
典型请求处理流程:
- 请求到达阶段
- 字符编码过滤(CharacterEncodingFilter)
- 请求上下文路径处理
- 多部分解析(MultipartResolver)
- 核心处理阶段
sequenceDiagram
participant Client
participant DispatcherServlet
participant HandlerMapping
participant HandlerAdapter
participant Interceptor
participant Controller
Client->>DispatcherServlet: HTTP Request
DispatcherServlet->>HandlerMapping: getHandler()
HandlerMapping-->>DispatcherServlet: HandlerExecutionChain
DispatcherServlet->>HandlerAdapter: handle()
HandlerAdapter->>Interceptor: preHandle()
Interceptor-->>HandlerAdapter: boolean
HandlerAdapter->>Controller: execute()
Controller-->>HandlerAdapter: ModelAndView
HandlerAdapter->>Interceptor: postHandle()
DispatcherServlet->>ViewResolver: resolveViewName()
ViewResolver-->>DispatcherServlet: View
DispatcherServlet->>View: render()
View-->>Client: Response
- 异常处理流程
- HandlerExceptionResolver 体系
- @ExceptionHandler 方法优先级
- 全局异常处理 vs 控制器局部异常处理
3. 控制器进阶设计模式
3.1 方法参数绑定机制
@PostMapping("/users")
public ResponseEntity<User> createUser(
@Valid @RequestBody UserDTO userDTO,
@RequestHeader("X-Client-Version") String clientVersion,
UriComponentsBuilder uriBuilder) {
User savedUser = userService.save(userDTO);
URI location = uriBuilder.path("/users/{id}")
.buildAndExpand(savedUser.getId())
.toUri();
return ResponseEntity.created(location).body(savedUser);
}
3.2 参数验证进阶
自定义验证注解示例:
@Target({FIELD, PARAMETER})
@Retention(RUNTIME)
@Constraint(validatedBy = PhoneNumberValidator.class)
public @interface ValidPhoneNumber {
String message() default "Invalid phone number";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class PhoneNumberValidator implements ConstraintValidator<ValidPhoneNumber, String> {
private static final Pattern PHONE_PATTERN =
Pattern.compile("^1[3-9]\\d{9}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && PHONE_PATTERN.matcher(value).matches();
}
}
3.3 响应处理策略
内容协商配置示例:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer
.favorParameter(true)
.parameterName("format")
.ignoreAcceptHeader(false)
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("json", MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML);
}
}
4. 视图技术深度集成
4.1 Thymeleaf高级集成
模板布局示例:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Default Title</title>
</head>
<body>
<div layout:fragment="header">
<!-- 公共头部 -->
</div>
<div layout:fragment="content">
<!-- 内容占位 -->
</div>
</body>
</html>
4.2 PDF导出实现
使用Flying Saucer生成PDF:
@GetMapping(value = "/report.pdf", produces = "application/pdf")
public ResponseEntity<byte[]> generatePdfReport() throws Exception {
Context context = new Context();
context.setVariable("data", reportService.getData());
String html = templateEngine.process("report-template", context);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(html);
renderer.layout();
renderer.createPDF(outputStream);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
headers.setContentDisposition(
ContentDisposition.attachment().filename("report.pdf").build());
return new ResponseEntity<>(outputStream.toByteArray(), headers, HttpStatus.OK);
}
5. 异步处理与响应式支持
5.1 DeferredResult应用
长轮询示例:
@GetMapping("/async/events")
public DeferredResult<ResponseEntity<List<Event>>> getEvents() {
DeferredResult<ResponseEntity<List<Event>>> deferredResult =
new DeferredResult<>(30_000L);
eventQueue.register(deferredResult);
deferredResult.onTimeout(() ->
deferredResult.setErrorResult(
ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).build()));
deferredResult.onCompletion(() ->
eventQueue.unregister(deferredResult));
return deferredResult;
}
5.2 WebFlux整合
混合使用MVC和WebFlux:
@RestController
@RequiredArgsConstructor
public class HybridController {
private final WebClient webClient;
@GetMapping("/hybrid")
public Mono<String> hybridEndpoint() {
return webClient.get()
.uri("http://api.example.com/data")
.retrieve()
.bodyToMono(String.class)
.flatMap(data -> Mono.fromCallable(() -> processData(data)));
}
@Async
private String processData(String data) {
// 阻塞操作放入单独线程池
return expensiveProcessing(data);
}
}
6. 安全增强实践
6.1 CSRF防护配置
自定义CSRF令牌仓库:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.csrfTokenRepository(new CookieCsrfTokenRepository())
.requireCsrfProtectionMatcher(
new RequestMatcher() {
private final Pattern allowedMethods =
Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
@Override
public boolean matches(HttpServletRequest request) {
return !allowedMethods.matcher(request.getMethod()).matches();
}
});
}
}
6.2 XSS防御策略
自定义HTML转义器:
public class CustomHtmlEscaper extends HtmlUtils {
public static String escape(String input) {
if (input == null) return null;
return StringEscapeUtils.escapeHtml4(input)
.replace("'", "'")
.replace("`", "`");
}
}
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatterForFieldAnnotation(new StringFormatFormatter());
}
private static class StringFormatFormatter implements AnnotationFormatterFactory<XssSafe> {
@Override
public Set<Class<?>> getFieldTypes() {
return Collections.singleton(String.class);
}
@Override
public Printer<?> getPrinter(XssSafe annotation, Class<?> fieldType) {
return (Printer<String>) CustomHtmlEscaper::escape;
}
@Override
public Parser<?> getParser(XssSafe annotation, Class<?> fieldType) {
return (Parser<String>) text -> CustomHtmlEscaper.escape(text);
}
}
}
7. 性能优化策略
7.1 缓存配置示例
方法级缓存:
@GetMapping("/products/{id}")
@Cacheable(value = "products", key = "#id",
unless = "#result == null || #result.price < 100")
public Product getProduct(@PathVariable Long id) {
return productRepository.findById(id).orElseThrow();
}
7.2 连接池优化
HikariCP配置:
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.idle-timeout=600000
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.leak-detection-threshold=5000
8. 微服务环境下的Spring MVC
8.1 分布式Session管理
Spring Session Redis配置:
@EnableRedisHttpSession
@Configuration
public class SessionConfig {
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(
new RedisStandaloneConfiguration("redis-server", 6379));
}
@Bean
public HttpSessionIdResolver sessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
}
8.2 API版本控制策略
Content Negotiation版本控制:
@GetMapping(value = "/api/products",
produces = "application/vnd.company.v1+json")
public List<Product> getProductsV1() {
return productService.getAllProducts();
}
@GetMapping(value = "/api/products",
produces = "application/vnd.company.v2+json")
public List<ProductDTO> getProductsV2() {
return productService.getAllProductDTOs();
}
9. 测试驱动开发实践
9.1 MockMvc高级用法
REST API测试示例:
@SpringBootTest
@AutoConfigureMockMvc
class ProductControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturnProduct() throws Exception {
mockMvc.perform(get("/api/products/123")
.header("X-API-Version", "2")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(123))
.andExpect(jsonPath("$.price").isNumber())
.andDo(document("get-product",
pathParameters(
parameterWithName("id").description("Product ID")
),
responseFields(
fieldWithPath("id").description("产品ID"),
fieldWithPath("name").description("产品名称"),
fieldWithPath("price").description("产品价格")
)));
}
}
9.2 集成测试策略
Testcontainers集成示例:
@SpringBootTest
@Testcontainers
class IntegrationTest {
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgres::getJdbcUrl);
registry.add("spring.datasource.username", postgres::getUsername);
registry.add("spring.datasource.password", postgres::getPassword);
}
@Test
void contextLoads() {
// 测试数据库交互
}
}
正文到此结束
相关文章
热门推荐
评论插件初始化中...