全部学科
NodeJS全栈
nodejs
Python全栈
python
小程序首页
📅 2026-05-18 6 分钟 ✍️ juanwangdev

Spring MVC preHandle方法详解

preHandle是HandlerInterceptor接口的第一个方法,在Controller执行前调用,是请求预处理的核心入口。

方法签名

Java
boolean preHandle(HttpServletRequest request,
                  HttpServletResponse response,
                  Object handler) throws Exception;

参数详解

参数类型说明
requestHttpServletRequest当前HTTP请求对象
responseHttpServletResponse当前HTTP响应对象
handlerObject处理器对象,通常是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时需自行处理响应(重定向或返回错误)
  • 适用于登录验证、权限检查、参数预处理等场景
  • 抛出异常会中断请求

📝 发现内容有误?点击此处直接编辑

← 上一篇 Spring MVC postHandle方法详解
下一篇 → Spring MVC 多个拦截器的执行顺序
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库