写在前面:
今天在Jfinal官方群上有朋友提到Jfinal3.0环境中使用jfinal-shiro-2.0.0.jar报java.lang.NoSuchMethodError。粗略看一下jfinal源码,Jfinal3.0对Routes这块做了调整,给朋友提了个方案,无奈他没实现,下班回来自己码5行代码解决了这个问题。
jfinal3.0的Routes调整:
Jfinal 2.2 前 Jfinal使用Map<ControllerKey,Controller>存放信息,jfinal3.0后调整为List<Routes>,使用内部静态类Route代替了之前的Map,所以getEntrySet()方法也随之调整成了getRouteItemList(),知道这个调整,就好解决问题,就是把这个方法替换一下就可以收工了。
问题解决:
创建一个新的类ShiroPlugin3,将之前ShiroPlugin的代码copy一份即可,只要改动3行代码,如下(1、2、3):
public boolean start() { Set<String> excludedMethodName = buildExcludedMethodName(); ConcurrentMap<String, AuthzHandler> authzMaps = new ConcurrentHashMap<String, AuthzHandler>(); //逐个访问所有注册的Controller解析Controller及action上的所有Shiro注解。 //并依据这些注解,actionKey提前构建好权限检查处理器。 //for (Entry<String,Class<? extends Controller>>entry : routes.getEntrySet()) { // 1.使用getRouteItemList()替换以前的getEntrySet() for (Route route : routes.getRouteItemList()) { //Class<? extends Controller> controllerClass = entry.getValue(); // 2.调整为route.getControllerClass() Class<? extends Controller> controllerClass = route.getControllerClass(); //String controllerKey = entry.getKey(); // 3.调整为route.getControllerKey() String controllerKey = route.getControllerKey(); // 获取Controller的所有Shiro注解。 List<Annotation> controllerAnnotations = getAuthzAnnotations(controllerClass); // 逐个遍历方法。 Method[] methods = controllerClass.getMethods(); for (Method method : methods) { //排除掉Controller基类的所有方法,并且只关注没有参数的Action方法 if (!excludedMethodName.contains(method.getName()) && method.getParameterTypes().length == 0) { //若该方法上存在ClearShiro注解,对该action不访问控制检查。 if(isClearShiroAnnotationPresent(method)){ continue; } //获取方法的所有Shiro注解。 List<Annotation> methodAnnotations = getAuthzAnnotations(method); //依据Controller的注解和方法的注解来生成访问控制处理器。 AuthzHandler authzHandler = createAuthzHandler(controllerAnnotations, methodAnnotations); //生成访问控制处理器成功。 if (authzHandler != null) { //构建ActionKey,参考ActionMapping中实现 String actionKey = createActionKey(controllerClass, method, controllerKey); //添加映射 authzMaps.put(actionKey, authzHandler); } } } } //注入到ShiroKit类中。ShiroKit类以单例模式运行。 ShiroKit.init(authzMaps); /** * 设定登录,登录成功,未授权等url地址 */ ShiroKit.setLoginUrl(loginUrl); ShiroKit.setSuccessUrl(successUrl); ShiroKit.setUnauthorizedUrl(unauthorizedUrl); return true; }
这里由于该类有几个private方法,所以采用简单粗暴的方法,直接copy jfinal-shiro的源码改了3行代码。
config方面改为:
me.add(new ShiroPlugin3(routes));
特别注意:ShiroPlugin3的包名一定要是com.jfinal.ext.plugin.shiro。
中午提问题的朋友还在问为什么,这个是java的基础问题,可以到下图这个包下很多类都是非public的。
好啦,到这问题就解决了,虽然简答粗暴,但还是解决了,看了jfinal-shiro作者的项目已经2年没更新代码了,希望作者可以更新一下,虽然毕业半年来没用过jfinal,也没什么机会用(毕竟公司不用这个),但是jfinal还是挺好用的,jfinal-shiro也好像有不少人用。
PS: 下班等同事一起坐车等了一小时,撸码不太及时。·····