You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring AOP中获取控制器方法的token参数以简化重复代码

How to Retrieve Token Parameter in Spring AOP @Before Advice for Controller Methods

Great call extracting that repetitive session validation logic into an AOP aspect—it’s exactly the kind of problem AOP was made to solve! Let’s walk through how to reliably grab the token parameter from your controller methods and execute your validation logic.

Step 1: Create Your AOP Aspect Class

We’ll build an aspect that targets all methods in your AdminController, extracts the token, and runs your validation. The key here is to identify the token either by its @PathVariable annotation or parameter name (with a small build config tweak).

Here’s the complete aspect:

@Component
@Aspect
public class AdminSessionValidationAspect {

    private final Map<String, OurSession> clientSessions;

    // Inject your clientSessions map via constructor
    public AdminSessionValidationAspect(Map<String, OurSession> clientSessions) {
        this.clientSessions = clientSessions;
    }

    @Before("execution(* com.example.couponproject.controller.AdminController.*(..))")
    public void validateAdminSession(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method targetMethod = methodSignature.getMethod();
        Object[] methodArgs = joinPoint.getArgs();
        Annotation[][] paramAnnotations = targetMethod.getParameterAnnotations();

        String token = null;

        // 1. Find the token parameter using its @PathVariable annotation
        for (int i = 0; i < paramAnnotations.length; i++) {
            for (Annotation annotation : paramAnnotations[i]) {
                if (annotation instanceof PathVariable) {
                    PathVariable pathVar = (PathVariable) annotation;
                    if ("token".equals(pathVar.value()) || "token".equals(pathVar.name())) {
                        token = (String) methodArgs[i];
                        break;
                    }
                }
            }
            if (token != null) break;
        }

        // 2. Handle missing token (fail fast)
        if (token == null) {
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "UNAUTHORIZED login");
        }

        // 3. Run your original validation logic
        OurSession session = clientSessions.get(token);
        if (session == null) {
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "UNAUTHORIZED login");
        }

        AdminFacade admin = (AdminFacade) session.getFacade();
        long currentTime = System.currentTimeMillis();
        if (currentTime - session.getLastAccessed() > 1000 * 60 * 30) {
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "UNAUTHORIZED login");
        }
        session.setLastAccessed(currentTime);

        // 4. Pass the AdminFacade to the controller method (optional, using ThreadLocal)
        AdminContextHolder.setAdmin(admin);
    }

    // Clean up ThreadLocal to avoid memory leaks
    @After("execution(* com.example.couponproject.controller.AdminController.*(..))")
    public void clearAdminContext() {
        AdminContextHolder.clear();
    }
}

Step 2: Simplify Your Controller Methods

Now you can strip out all the repetitive validation code from your controller methods. Use a ThreadLocal helper to access the pre-validated AdminFacade:

First, create the helper class:

public class AdminContextHolder {
    private static final ThreadLocal<AdminFacade> ADMIN_HOLDER = new ThreadLocal<>();

    public static void setAdmin(AdminFacade admin) {
        ADMIN_HOLDER.set(admin);
    }

    public static AdminFacade getAdmin() {
        return ADMIN_HOLDER.get();
    }

    public static void clear() {
        ADMIN_HOLDER.remove();
    }
}

Then update your addCompany method:

@PostMapping("addCompany/{token}")
public ResponseEntity<?> addCompany(@PathVariable String token, @RequestBody Company company){
    try {
        AdminFacade admin = AdminContextHolder.getAdmin();
        admin.addCompany(company);
        return ResponseEntity.ok(company);
    } catch (CompanyAlreadyExistsException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
    }
}

Alternative: Use Parameter Names (Requires Build Config)

If you prefer to match the parameter by its name (token) instead of the annotation, you need to enable parameter name retention in your build tool. For Maven, add this to your pom.xml:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <parameters>true</parameters>
                <source>11</source> <!-- Match your JDK version -->
                <target>11</target>
            </configuration>
        </plugin>
    </plugins>
</build>

Then replace the annotation-based token lookup with this simpler code in the aspect:

String[] paramNames = methodSignature.getParameterNames();
for (int i = 0; i < paramNames.length; i++) {
    if ("token".equals(paramNames[i])) {
        token = (String) methodArgs[i];
        break;
    }
}

Key Notes

  • Using ResponseStatusException lets Spring automatically convert the exception to the correct ResponseEntity response, so you don’t have to handle that in your controller.
  • The @After advice cleans up the ThreadLocal to prevent memory leaks, which is critical for long-running applications.
  • This approach works regardless of where the token parameter appears in your controller method’s parameter list.

内容的提问来源于stack exchange,提问作者wedew2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 13:17:40