Spring 03 Web springMVC

发布于:2025-08-05 ⋅ 阅读:(17) ⋅ 点赞:(0)

Springboot 常用 Spring MVC 实现 web 服务。

Spring MVC 请求处理流程

《Spring 实战第四版》
图片来自《Spring 实战第四版》

浏览器请求首先被交给 DispatcherServlet 前端控制器。
DispatcherServlet 查询处理器映射以决定将请求发送给哪个控制器。控制器处理业务逻辑后,向 DispatcherServlet 返回处理结果(被称为模型)和逻辑视图名。DispatcherServlet 使用视图解析器为逻辑视图名匹配特定视图。最后视图渲染结果,交给响应对象返回浏览器。

MVC 启动

Springboot 启动 Spring MVC 时,动态加载\org\springframework\web\servlet\DispatcherServlet.properties文件定义的组件。

控制器

@Controller 注解定义控制器。它与 @Component 注解功能相同,因此Spring 会创建 MyController bean。
@RequestMapping 注解定义请求路径(value 属性)和控制器方法(hello())的映射关系。映射关系被存储到HandlerMapping(处理器映射)对象。DispatcherServlet 将请求发送给处理器映射,处理器映射返回的不是 Controller,而是 HandlerExecutionChain 对象。

@Controller
public class MyController {
    @RequestMapping(value = "/", method=GET)
    public String hello() {
		return "hello";
	}
}

HandlerExecutionChain 对象包含处理器 handler 和拦截器 interceptorList 。处理器是对控制器 controller 的封装。拦截器增强处理器功能。

public class HandlerExecutionChain {
	private final Object handler;
	private final List<HandlerInterceptor> interceptorList = new ArrayList<>();

HandlerAdapter 实现类执行 HandlerExecutionChain 对象的内容。即执行控制器并返回结果。
控制器返回的结果被称为模型。视图解析器根据逻辑视图名称定位视图,视图渲染模型给响应体。前后端分离场景下一般用 json 格式响应体,此时不需要视图解析器和视图。

@RequestMapping

@RequestMapping 注解有主要有两个参数,一个是路径 value,一个是请求方法 method。它的简化版本 @GetMapping 注解表示 get 请求类型,@PostMapping 注解表示 Post 请求类型。

获取控制器参数

@RequestParam 注解可以定义HTTP参数和方法参数的映射关系。

@RequestMapping(value = "/param", method=GET)
public String param(
		@RequestParam("user") String user,
		@RequestParam("age") int age) {
	return service(user, age);
}

@RequestBody 注解可以将 json 参数转换为对应 java 对象。

@RequestMapping(value = "/param", method=GET)
public String param(@RequestBody User user) {
	return service(user);
}

@PathVariable 注解可以获取路径参数。Restful 风格要求用路径,而不是用参数表示资源。

@RequestMapping(value = "/param/{id}", method=GET)
public String param(@PathVariable("id") String id) {
	return service(id);
}

@DataTimeFormat 注解和 @NumberFormat 注解可以定义格式化参数。

自定义获取控制器参数的规则

SpringMVC 通过 WebDataBinder 机制来获取参数。它解析 HTTP 请求上下文,转换参数并且提供验证功能。转换参数的接口有三个:Converter,Formatter 和 GenericConverter。第一个是转换类型,第二个是转换格式,第三个是转换数组。
SpringMVC 将三个接口的默认实现类注册到注册机,这就是大部分类型转换无需开发者开发的原因。
我们可以定义自己的转换器,只需实现接口,SpringMVC自动注册到注册机。

@Component
public class MyConvrter implements Converter<String, User> {
	@Override
	public User convert(String str) {...}
}

参数验证

SpringMVC 支持参数验证。通过 @Valid 注解启动验证机制,通过 @NotNull, @Max, @Range, @Email 等注解验证字段。

用户也可以在 WebDataBinder 注册验证器自定义验证机制。

public class MyValidator implements Validator {
	// 指定验证类型
	@Override
	public boolean supports(Class<?> clazz) {
		return clazz.equals(User.class);
	}
	// 执行验证方法
	@Override
	public void validate(Object target, Errors erros) {...}
}

MyValidator 类没有 @Component 注解。在控制器类用 @InitBinder 注解注册验证类。

@RequestMapping("/user")
public class UserController {
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		binder.setValidator(new MyValidator()); // 绑定验证器
	}
	
	@GetMapping("/validate")
	public Map<String, Object> validator(@Valid User user, Errors erros) {
		if (errors.hasErrors()) {
			// 没通过验证,返回错误结果
		}
	}
}

视图

SpringMVC 视图分为逻辑视图和非逻辑视图。逻辑视图需要视图解析器进一步定位视图,比如 JSP。非逻辑视图不需定位,直接渲染,比如 json。

拦截器

拦截器用于拦截处理器,增强处理器功能。preHandle 方法在处理器执行前执行,postHandle 方法在处理器执行后执行,afterCompletion 方法在处理器完成且视图渲染后后执行。

public class MyInterceptor extends HandlerInterceptor {
	@Override
	public boolean preHandle(HttpServltRequest request, HttpServletResponse response, Object handler) {...}
	@Override
	public boolean postHandle(HttpServltRequest request, HttpServletResponse response, Object handler) {...}
	@Override
	public boolean afterCompletion(HttpServltRequest request, HttpServletResponse response, Object handler) {...}
}

开发拦截器后需要注册拦截器。

@Configuration
public class MyApplication implements WebMvcConfigurer {
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		InterceptorRegistry ir = registry.addInterceptor(new MyInterceptor());
		ir.addPathPatterns("/user/*");
	}
}

多个拦截器按照责任链模式装配。对于 preHandle 方法,先注册先执行。对于 postHandle 和 afterCompletion 方法,先注册后执行。如果某个拦截器的 preHandle 为 false,后续的 preHandle 和 postHandle 都不会执行。


网站公告

今日签到

点亮在社区的每一天
去签到