algiogia
algiogia

Reputation: 965

Spring - Execute code before controller's method is invoked

Is there any annotation similar to @PreAuthorize or @PreFilter that I can use to run code before a method in the Controller is invoked?

I need to add info to the request context (specific to the method being called) to be then retrieved by the ExceptionHandler.

For example

@RestController
public MyController{

  @UnkwonwAnnotation("prepareContext(request.getAgentId())"){
  public ResponseEntity method1(RequestA requestA) {
    ...
  }

  @UnkwonwAnnotation("prepareContext(request.getUserName())"){
  public ResponseEntity method1(RequestB requestB) {
    ...
  }

}

I could actually just use @PreAuthorize but doesn't feel right

Upvotes: 11

Views: 28787

Answers (4)

JosemyAB
JosemyAB

Reputation: 407

A good option is to implement a custom filter that runs every time a request is received.

You need to extend "OncePerRequestFilter" and override the method "doFilterInternal":

public class CustomFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        //Add attributes to request
        request.getSession().setAttribute("attrName", new String("myValue"));

        // Run the method requested by petition
        filterChain.doFilter(request, response);

        //Do something after method runs if you need.
    }
}

You have to register the filter in Spring with FilterRegistrationBean. If you have Spring Security, you need add your filter after security filter.

Upvotes: 5

Niraj Sonawane
Niraj Sonawane

Reputation: 11115

You Can add interceptor for this

Sample Interceptor

public class CustomInterceptor implements HandlerInterceptor {

    
    @Override
    public boolean preHandle(HttpServletRequest request,HttpServletResponse  response) {
    //Add Login here 
        return true;
    }
} 

Configuration

@Configuration
public class MyConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyCustomInterceptor()).addPathPatterns("/**");
    }
}

Hope this helps

Upvotes: 14

algiogia
algiogia

Reputation: 965

Expanding on Sai Prateek answer, I'v created a custom annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationContext {

  String clientId();

  String userId();

  String operation();
}

and a component to handle it:

@Aspect
@Component
public class OperationContextAspect {

  @Before(value = "@annotation(operationContext)", argNames = "operationContext")
  public void preHandle(OperationContext operationContext) {

    RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

    requestAttributes.setAttribute("operation", operationContext.operation, RequestAttributes.SCOPE_REQUEST);
    requestAttributes.setAttribute("clientId", operationContext.clientId(), RequestAttributes.SCOPE_REQUEST);
    requestAttributes.setAttribute("userId", operationContext.userId(), RequestAttributes.SCOPE_REQUEST);

  }
}

I then annotate the controller methods providing the required parameters:

@RestController
public class MyController {

  @OperationContext(clientId = '#request.getClientId', userId = '#request.getUserId', operation = "OPERATION_A")
  public ResponseEntity aMethod(MyRequest request) {
    ...
  }
}

Upvotes: 5

Sai prateek
Sai prateek

Reputation: 11926

Spring Aspect is also a good option to execute code before controller.

@Component
@Aspect
public class TestAspect {

    @Before("execution(* com.test.myMethod(..)))")
    public void doSomethingBefore(JoinPoint jp) throws Exception {

        //code  
    }
}

Here myMethod() will execute before controller.

Upvotes: 7

Related Questions