六年前,我开始从无到有写Lerx的时候,我看的是陈宝峰和张冰的教程。我就猜想是不是可以把权限的事与业务的事分开来搞?张冰的AOP教程中说可能可以实现,他把重点放在dobefore上,认为可以在执行之前检查后决定是否允许执行某个业务方法。当时我才接触SSH2框架,心高,但水平有限,摸索了几天都没搞起来。
这段时间有个业务在手上编写,因为Struts2框架漏洞频频,近期搞得我手忙脚乱。于是我决定抛弃Struts2奔向SpringMVC的怀抱。淘宝上4块钱买的SpringMVC 3和10块钱买的4的教程。看了一遍就开始下手,利用新的业务系统来练手。在练手的时候,我一边在整理自己的“框架”,目的就是大幅减少代码,缩短开发周期,提高效率。当我把后台业务差不多完成时,我考虚权限的事,AOP的经历浮现,然后我就开始再一次尝试了。网上找了一些材料,也有是用自定义注解,但是不是真正的AOP,有的是拦截器,有的是说不上来的东西。最终我如愿以偿。
最后就象盖公章一样,在需要权限检查的方法上盖个章(加个注释)就好了。猛然想起大话西游中的盘丝大仙,给至尊宝盖的那个章(三颗痣)。哈哈,盘丝大法。
好了,以上是背景,下面就直接把方法大致说一下。
1.建立一个自定义标签(上图的RoleCheck.java)
package com.krd.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.web.bind.annotation.ResponseBody; //自定义注解相关设置 @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RoleCheck { /* * role 用于标记权限的等级。比如:0的管理员,1是操作员,2是普通用户 * ajax 用于标记@ResponseBody注解的ajax返回。这类由于没有视图,可以返回一个字符串用于JavaScript判断和提示 * */ public int role() default -1; public boolean ajax() default false; }
2.编写AuthAspect,用于切入检查。我用的是环绕通知,并没有用前置通知。前权限检查成功时,通过return pjp.proceed();执行目标方法,否则返回无权限提示页forbid.jsp。
package com.krd.aop; import javax.servlet.http.HttpSession; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.krd.annotation.RoleCheck; import com.lerx.sys.util.StringUtil; /* * 试图通过aop实现权限控制功能,未能成功。以后再深入了解 * 6.7日晚补充:已成功! */ @Aspect @Component public class AuthAspect { @Around(value="execution(* com.krd.handlers.*.*(..)) && @annotation(annotation)") public Object around(ProceedingJoinPoint pjp,RoleCheck annotation) throws Throwable{ Boolean auth=false; int role=annotation.role(); boolean ajax=annotation.ajax(); ServletRequestAttributes ra =(ServletRequestAttributes)RequestContextHolder.currentRequestAttributes(); HttpSession session=ra.getRequest().getSession(); if (session.getAttribute("mask")==null || !StringUtil.isNumber(""+session.getAttribute("mask"))){ return "forbid"; } int mask=Integer.valueOf(""+session.getAttribute("mask")); boolean adminLogin; String adminLoginStr=""+session.getAttribute("admin_login_"); if (session.getAttribute("admin_login_")!=null && adminLoginStr.trim().equals("true")){ adminLogin=true; }else{ adminLogin=false; } if (adminLogin){ switch (role){ case 0: if (mask==0){ //当是0时,只有0--管理员有权限 auth=true; }else{ auth=false; } break; case 1: if (mask>=0){ //当是1时,0--管理员和菜场管理员有权限 auth=true; }else{ auth=false; } break; default: auth=false; } }else{ auth=false; } if (auth){ return pjp.proceed(); //这一行很重要! }else{ if (ajax){ return "-1"; }else{ return "forbid"; } } } /*@Before(value = "execution(* com.krd.handlers.*.*(..))") public void doBefore(JoinPoint point) { } @Before(value = "execution(* com.krd.handlers.*.*(..))") public void doAfter() { } */ }
3.配置springmvc.xml
<!-- 上略 --> <!-- AOP --> <aop:aspectj-autoproxy proxy-target-class="true" /> <mvc:annotation-driven /> <bean id="aspect" class="com.krd.aop.AuthAspect"/> <!-- 下略 -->
4.下面就简单了。
在方法前加注解就可以了。如下图。
具体分析我懒得写了,有空再补充吧。