简体   繁体   中英

Java - How to combine Validation and AOP annotations and use it in Spring Controller?

Currently we are migrating a Struts 1.1 project into Spring 4.x.

We have successfully converted Action class to Controller and formbean to Model and even we are able to convert struts validation to Spring validation.

But we are facing an issue when we try to add AOP for all the controllers. The purpose is to add a log for measuring the time taken for all the controller methods.

below is code snippet,

@Component
@Controller
public class LoginController {

   @Autowired
       private LoginValidator loginValidator;

   @InitBinder
     private void initBinder(WebDataBinder binder) {
        binder.setValidator(loginValidator);
    }

   @RequestMapping(value = "/login", method = RequestMethod.POST)
  public String loginUser(@Valid @ModelAttribute Login form, BindingResult bindingResult) {
    System.out.println("Entering loginController.loginUser method");
   }
}

We are using the below point-cut to apply aop,

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class Logging {

  @Pointcut("execution(* com.controller.*.*(..))")
  public void businessLogicMethods() {}

  @Around("businessLogicMethods()")
  public Object logAround(ProceedingJoinPoint jp) {

    System.out.println("around() is running!");
    System.out.println(jp.getSignature().getName());
    System.out.println(jp.getArgs());
    Object obj = null;
    try {
      obj = jp.proceed();
    } catch (Throwable e) {
      e.printStackTrace();
    }
    System.out.println("******");
    return obj;
  }
}

Either Validation or AOP is working at a time. If AOP is not applied then Validation fired. If aop is applied only AOP is fired.

Can anyone help on this?

Thanks...

I got this working. You have to do 2 changes.

Change No: 1

  1. Your Aspect definition is wrong for some reason.(No idea why). But the below aspect will work.

     @Component @Aspect public class Logging { static final Logger LOG = LoggerFactory.getLogger(Logging.class); @Pointcut("within(@org.springframework.stereotype.Controller *)") public void controller() {} @Pointcut("execution(* *(..))") public void methodPointcut() {} @Pointcut("within(@org.springframework.web.bind.annotation.RequestMapping *)") public void requestMapping() {} @Before("controller() && methodPointcut() && requestMapping()") public void aroundControllerMethod(JoinPoint joinPoint) throws Throwable { LOG.info("Invoked: " + niceName(joinPoint)); } @AfterReturning("controller() && methodPointcut() && requestMapping()") public void afterControllerMethod(JoinPoint joinPoint) { LOG.info("Finished: " + niceName(joinPoint)); } private String niceName(JoinPoint joinPoint) { return joinPoint.getTarget().getClass() + "#" + joinPoint.getSignature().getName() + "\\n\\targs:" + Arrays.toString(joinPoint.getArgs()); } 

    }

Change No:2

initBinder should be declared as public. Currently you have defined this method as private . Again I am not sure why this work correctly without the aspects.

   @InitBinder
     public void initBinder(WebDataBinder binder) {
        binder.setValidator(loginValidator);
     }

The 2 changes will work.

Actually Arun's version should not make a big difference other than being cleaner (as in more general) and more verbose, unless Selvakumar's pointcut is wrong to begin with. Because he is not showing us any package names for aspect or controller, this is speculative, but maybe the controller resides not directly within package com.controller but within some sub-package. In this case the pointcut should rather be

@Pointcut("execution(* com.controller..*(..))")

Please not the double dot syntax .. which roughly means "include any number of sub-package levels".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM