要用Spring的AOP需要引入两个aspectj的包,aspectjrt和aspectjweaver.
配置文件中要加入<aop:aspectj-autoproxy />
给需要的类加上@Aspect注解表示这是一个切面方法,还有需要加上@Component来交给spring的bean管理.
AOP还有很多的用法, 使用自带的@Before, @After注解等等, 下面用一种自己写注解实现AOP的方式.
用来实现web应用controller层调用方法前执行参数验证.
首先, 编写一个Before注解.
/** * 用于方法执行前拦截 */@Inherited@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface Before { Class value();}
Interceptor接口:
public interface Interceptor { /** * 拦截逻辑 * @param inv * @return Object */ Object intercept(Invocation inv);}
Invocation类:用来获取类, 方法, 以及参数和request.
public class Invocation { private Class clazz; private Method method; private Object[] args; private HttpServletRequest request; public Invocation(Class clazz, Method method, Object[] args, HttpServletRequest request) { this(method, args, request); this.request = request; } public Invocation(Class clazz, Method method, Object[] args) { this.clazz = clazz; this.method = method; this.args = args; } public Invocation(Method method, Object[] args, HttpServletRequest request) { super(); this.method = method; this.args = args; this.request = request; } public Class getClazz() { return clazz; } public void setClazz(Class clazz) { this.clazz = clazz; } public Method getMethod() { return method; } public void setMethod(Method method) { this.method = method; } public Object[] getArgs() { return args; } public void setArgs(Object[] args) { this.args = args; } public HttpServletRequest getRequest() { return request; } public void setRequest(HttpServletRequest request) { this.request = request; } }
编写一个切面类来使用@Before注解
@Aspect@Componentpublic class BeforeAop { @Pointcut(value = "@annotation(com.kkdo.core.annotation.Before)") private void cutBefore() { } @Around("cutBefore()") public Object doBefore(ProceedingJoinPoint point) throws Throwable { HttpServletRequest request = HttpKit.getRequest(); MethodSignature ms = (MethodSignature) point.getSignature(); Method method = ms.getMethod(); Object[] args = point.getArgs(); Class clazz = point.getTarget().getClass(); Before before = method.getAnnotation(Before.class); Interceptor ic = before.value().newInstance(); //拦截器进行校验,返回校验结果,如果没有错误,那么执行下去 Object result = ic.intercept(new Invocation(clazz, method, args, request)); //Object result = ic.intercept(new Invocation(clazz, method, args)); if(result == null) { return point.proceed(); } else { return result; } }}
这个切面类就表示在注解有@Before的方法前会执行, 这里的doBefore获取到拦截类, 方法以及参数.
AOP的使用:
@Before(PasswordVaildator.class) //这里使用自己编写的@Before注解 @ResponseBody @RequestMapping("editPassword") public AjaxResult editPasswrod() { String newPassword = getParameter("newPassword"); int id = getParameterToInt("id"); String accountName = getParameter("accountName"); User user = new User(); user.setPassword(newPassword); user.setAccountName(accountName); PasswordHelper.encryptPassword(user); String sql = "UPDATE USER LU SET LU.PASSWORD = '{}', LU.SALT = '{}' WHERE LU.ID = {}"; sql = StrKit.format(sql, user.getPassword(), user.getSalt(), id); Condition condition = new Condition(sql); userMapper.updateBySql(condition); //int a = 1/0; 事务测试 return success("修改密码成功!是否关闭窗口?"); }
这里的PasswordVaildator.class是实现了Interceptor接口的一个类,
public class PasswordVaildator extends KkdoValidator { @Override protected void doValidate(Invocation inv) { validateRequired("newPassword", "请输入新密码"); validateRequired("confirmPassword", "请确认您的密码"); vailequal("newPassword", "confirmPassword"); vaildateLength("newPassword", 6, 18); } private void vaildateLength(String field, int min, int max) { String value = request.getParameter(field); if(value.length() < min) { succeed = false; result.addError("密码太简单,请输入"+ min + "位以上密码!"); } if(value.length() > max) { succeed = false; result.addError("密码太长,请不要超过 + "+ max + "位!"); } } private void vailequal(String field1, String field2) { String value1 = request.getParameter(field1); String value2 = request.getParameter(field2); if(!StrKit.equals(value1, value2)) { succeed = false; result.addError("两次密码不一致!"); } }}
KkdoVaildator:
public abstract class KkdoValidator extends Interceptor { protected boolean succeed = true; protected HttpServletRequest request; protected AjaxResult result = new AjaxResult(); protected static final String EMAIL_ADDRESS_PATTERN = "\\b(^['_A-Za-z0-9-]+(\\.['_A-Za-z0-9-]+)*@([A-Za-z0-9-])+(\\.[A-Za-z0-9-]+)*((\\.[A-Za-z0-9]{2,})|(\\.[A-Za-z0-9]{2,}\\.[A-Za-z0-9]{2,}))$)\\b"; final public Object intercept(Invocation inv) { KkdoValidator validator = null; try { validator = getClass().newInstance(); } catch(Exception e ) { throw new RuntimeException(e); } validator.request = inv.getRequest(); try { validator.doValidate(inv); } catch (Exception e) { e.printStackTrace(); } if(validator.succeed) { return invoke(); } else { //这里还需要改 return validator.result; } } /** * Use validateXxx method to validate the parameters of this action. */ protected abstract void doValidate(Invocation inv); /** * Validate Required. Allow space characters. */ protected void validateRequired(String field, String errorMessage) { String value = request.getParameter(field); if (value == null || "".equals(value)) request.setAttribute("error", errorMessage); }}
这样,在intercept中进行validate方法进行验证, 可以在前台看一下效果: