写在前面:
今天在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: 下班等同事一起坐车等了一小时,撸码不太及时。·····