Spring MVC preHandle方法详解
preHandle是HandlerInterceptor接口的第一个方法,在Controller执行前调用,是请求预处理的核心入口。
方法签名
Java
boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception;
参数详解
| 参数 | 类型 | 说明 |
|---|---|---|
| request | HttpServletRequest | 当前HTTP请求对象 |
| response | HttpServletResponse | 当前HTTP响应对象 |
| handler | Object | 处理器对象,通常是HandlerMethod |
handler参数解析
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// Controller类信息
Class<?> beanType = handlerMethod.getBeanType();
String controllerName = beanType.getSimpleName();
// 方法信息
Method method = handlerMethod.getMethod();
String methodName = method.getName();
// 返回类型
Class<?> returnType = method.getReturnType();
// 参数信息
MethodParameter[] parameters = handlerMethod.getMethodParameters();
for (MethodParameter param : parameters) {
String paramName = param.getParameterName();
Class<?> paramType = param.getParameterType();
}
// 注解信息
Annotation[] annotations = method.getAnnotations();
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
}
return true;
}
返回值规则
| 返回值 | 行为 |
|---|---|
| true | 继续执行后续拦截器和Controller |
| false | 中断请求,不再执行后续拦截器和Controller |
返回true继续执行
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 验证通过,继续执行
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
返回false中断请求
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 未登录,中断请求
if (!isAuthenticated(request)) {
response.setStatus(401);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":401,\"message\":\"未登录\"}");
return false;
}
return true;
}
典型应用场景
登录验证
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null) {
response.sendRedirect("/login");
return false;
}
User user = tokenService.validate(token);
if (user == null) {
response.setStatus(401);
response.getWriter().write("{\"code\":401,\"message\":\"Token无效\"}");
return false;
}
UserContext.setUser(user);
return true;
}
权限检查
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequirePermission annotation =
handlerMethod.getMethodAnnotation(RequirePermission.class);
if (annotation != null) {
User user = UserContext.getUser();
if (!permissionService.hasPermission(user, annotation.value())) {
response.setStatus(403);
response.getWriter().write("{\"code\":403,\"message\":\"无权限\"}");
return false;
}
}
}
return true;
}
参数预处理
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 设置公共请求参数
request.setAttribute("requestId", UUID.randomUUID().toString());
request.setAttribute("startTime", System.currentTimeMillis());
request.setAttribute("clientIp", getClientIp(request));
// 解析用户信息
String token = request.getHeader("Authorization");
if (token != null) {
User user = parseUserFromToken(token);
request.setAttribute("currentUser", user);
}
return true;
}
请求限流
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String ip = getClientIp(request);
String uri = request.getRequestURI();
if (!rateLimiterService.allowRequest(ip, uri)) {
response.setStatus(429);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":429,\"message\":\"请求过于频繁\"}");
return false;
}
return true;
}
日志记录
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String requestId = UUID.randomUUID().toString().substring(0, 8);
request.setAttribute("requestId", requestId);
request.setAttribute("startTime", System.currentTimeMillis());
log.info("[{}] 请求开始: {} {}",
requestId, request.getMethod(), request.getRequestURI());
return true;
}
多拦截器执行逻辑
Java
// 注册顺序:A → B → C
// preHandle执行顺序:A → B → C
// 若A.preHandle返回false:
// B.preHandle、C.preHandle不执行
// Controller不执行
// postHandle全部不执行
// afterCompletion(A)执行(已执行preHandle的)
// 若B.preHandle返回false:
// C.preHandle不执行
// Controller不执行
// postHandle全部不执行
// afterCompletion(B) → afterCompletion(A)执行
异常处理
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
try {
// 执行验证逻辑
validateRequest(request);
return true;
} catch (Exception e) {
log.error("preHandle异常: {}", e.getMessage());
// 抛出异常会中断请求
throw e;
}
}
preHandle抛出异常会中断请求,异常会被DispatcherServlet捕获处理。
请求信息获取
Java
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 请求基本信息
String method = request.getMethod();
String uri = request.getRequestURI();
String url = request.getRequestURL().toString();
String queryString = request.getQueryString();
String contextPath = request.getContextPath();
// 客户端信息
String ip = request.getRemoteAddr();
String userAgent = request.getHeader("User-Agent");
String referer = request.getHeader("Referer");
// 会话信息
HttpSession session = request.getSession(false);
String sessionId = session != null ? session.getId() : null;
return true;
}
获取真实客户端IP
Java
private String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// 多个代理时取第一个IP
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
要点总结
- preHandle在Controller执行前调用
- handler参数可获取Controller类和方法信息
- 返回true继续执行,返回false中断请求
- 返回false时需自行处理响应(重定向或返回错误)
- 适用于登录验证、权限检查、参数预处理等场景
- 抛出异常会中断请求
📝 发现内容有误?点击此处直接编辑