Spring MVC postHandle方法详解
postHandle是HandlerInterceptor接口的第二个方法,在Controller执行后、视图渲染前调用,用于修改响应数据。
方法签名
Java
void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception;
执行时机
Java
preHandle() → Controller处理 → postHandle() → 视图渲染 → afterCompletion()
Controller抛出异常时postHandle不执行。
参数详解
| 参数 | 类型 | 说明 |
|---|---|---|
| request | HttpServletRequest | 当前HTTP请求对象 |
| response | HttpServletResponse | 当前HTTP响应对象 |
| handler | Object | 处理器对象(HandlerMethod) |
| modelAndView | ModelAndView | Controller返回的视图模型对象 |
modelAndView参数
| 场景 | modelAndView值 |
|---|---|
| 传统Controller返回视图 | ModelAndView对象 |
| REST Controller返回JSON | null |
| Controller返回String视图名 | ModelAndView包含viewName |
基本实现
Java
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 记录处理完成
log.info("Controller处理完成: {}", request.getRequestURI());
}
添加公共数据
Java
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
if (modelAndView != null) {
// 添加公共视图数据
modelAndView.addObject("siteName", "MyApp");
modelAndView.addObject("version", "1.0.0");
modelAndView.addObject("timestamp", System.currentTimeMillis());
// 添加用户信息
User user = UserContext.getUser();
if (user != null) {
modelAndView.addObject("currentUser", user);
}
}
}
修改视图数据
Java
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
if (modelAndView != null) {
Map<String, Object> model = modelAndView.getModel();
// 统一处理日期格式
Object createTime = model.get("createTime");
if (createTime instanceof Date) {
model.put("createTimeStr",
formatDate((Date) createTime, "yyyy-MM-dd HH:mm:ss"));
}
// 添加处理时间统计
Long startTime = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - startTime;
modelAndView.addObject("processTime", duration);
}
}
修改响应头
Java
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
Long startTime = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - startTime;
response.setHeader("X-Response-Time", String.valueOf(duration));
response.setHeader("X-Request-Id", (String) request.getAttribute("requestId"));
}
REST接口处理
Java
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// REST接口modelAndView为null
if (modelAndView == null) {
// 计算处理时间
Long startTime = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - startTime;
// 设置响应头
response.setHeader("X-Process-Time", String.valueOf(duration));
log.info("REST响应: {} {} 耗时:{}ms",
request.getMethod(), request.getRequestURI(), duration);
return;
}
// 传统视图处理
modelAndView.addObject("processTime", duration);
}
统一响应封装
Java
@Component
public class ResponseWrapperInterceptor implements HandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 只处理传统Controller
if (modelAndView != null) {
Object result = modelAndView.getModel().get("result");
if (result != null && !(result instanceof ApiResult)) {
// 包装为统一响应格式
ApiResult<Object> apiResult = ApiResult.success(result);
modelAndView.addObject("result", apiResult);
}
}
}
}
国际化处理
Java
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
if (modelAndView != null) {
Locale locale = LocaleContextHolder.getLocale();
// 根据语言设置不同的提示信息
String message = messageSource.getMessage("welcome.message", null, locale);
modelAndView.addObject("welcomeMessage", message);
}
}
执行顺序
多拦截器时postHandle逆序执行:
Java
// 注册顺序:A → B → C
// postHandle执行顺序:C → B → A
Java
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptorA)
.addPathPatterns("/**")
.order(1);
registry.addInterceptor(interceptorB)
.addPathPatterns("/**")
.order(2);
}
// postHandle执行:B.postHandle → A.postHandle
不执行的场景
| 场景 | postHandle是否执行 |
|---|---|
| Controller正常返回 | ✅ 执行 |
| Controller抛出异常 | ❌ 不执行 |
| preHandle返回false | ❌ 不执行 |
| 异步请求 | ❌ 不执行 |
异步请求处理
text
@Component
public class AsyncInterceptor implements AsyncHandlerInterceptor {
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// 同步请求的postHandle
log.info("同步请求postHandle");
}
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 异步请求开始时的回调
log.info("异步请求开始");
}
}
典型应用总结
| 应用场景 | 说明 |
|---|---|
| 添加公共数据 | 为所有视图添加公共属性 |
| 统计处理时间 | 计算Controller执行耗时 |
| 修改响应头 | 添加自定义响应头 |
| 国际化处理 | 根据Locale添加消息 |
| 响应格式封装 | 统一包装响应数据 |
要点总结
- postHandle在Controller执行后、视图渲染前调用
- Controller异常时postHandle不执行
- modelAndView为null表示REST接口返回JSON
- 多拦截器时postHandle逆序执行
- 适合添加公共数据、修改响应头等场景
- 异步请求不执行postHandle
📝 发现内容有误?点击此处直接编辑