jfinal3.3和shiro3.2整合问题

package com.huajian.common.core;


import com.huajian.common.interceptor.GlobalInterceptor;

import com.huajian.common.interceptor.LoginInterceptor;

import com.huajian.common.model._MappingKit;

import com.huajian.common.route.AdminRoutes;

import com.huajian.common.route.BuyRoutes;

import com.huajian.common.route.ProdRoutes;

import com.huajian.common.route.QaRoutes;

import com.huajian.common.route.SaleRoutes;

import com.huajian.common.route.TechRoutes;

import com.huajian.common.route.WareRoutes;

import com.huajian.common.route.WebRoutes;

import com.huajian.dict.model.GlueSetDetail;

import com.huajian.dict.model.StructDesc;

import com.huajian.dict.model.SysSeqno;

import com.huajian.system.model.Dept;

import com.huajian.system.model.Log;

import com.huajian.system.model.Menu;

import com.huajian.system.model.Role;

import com.huajian.system.model.RoleMenu;

import com.huajian.system.model.User;

import com.huajian.system.model.UserLoginLog;

import com.huajian.system.model.UserRole;


import com.alibaba.druid.filter.stat.StatFilter;

import com.jfinal.config.Constants;

import com.jfinal.config.Handlers;

import com.jfinal.config.Interceptors;

import com.jfinal.config.JFinalConfig;

import com.jfinal.config.Plugins;

import com.jfinal.config.Routes;

import com.jfinal.core.JFinal;

import com.jfinal.ext.handler.ContextPathHandler;

import com.jfinal.ext.plugin.shiro.ShiroPlugin3;

import com.jfinal.kit.PathKit;

import com.jfinal.kit.Prop;

import com.jfinal.kit.PropKit;

import com.jfinal.plugin.activerecord.ActiveRecordPlugin;

import com.jfinal.plugin.cron4j.Cron4jPlugin;

import com.jfinal.plugin.druid.DruidPlugin;

import com.jfinal.plugin.ehcache.EhCachePlugin;

import com.jfinal.render.ViewType;

import com.jfinal.template.Engine;


public class AppConfig extends JFinalConfig{

private static Prop p = PropKit.use("config.properties"); // 加载配置文件

/**

* 供Shiro插件使用

*/

private static Routes routes;

/**

* 配置常量

*/

@Override

public void configConstant(Constants me) {

me.setDevMode(p.getBoolean("devMode", false));

//me.setBaseUploadPath("upload"); //设置上传文件保存的基础路径

me.setViewType(ViewType.JFINAL_TEMPLATE); 

me.setError500View("/error/500.html");

me.setError403View("/error/403.html");

me.setError404View("/error/404.html");

me.setError401View("/error/401.html");

me.setBaseDownloadPath("/download");

}

/**

* 配置路由

*/

@Override

public void configRoute(Routes me) {

this.routes = me;

me.add(new WebRoutes());  //前台管理

me.add(new AdminRoutes()); //后台管理

me.add(new SaleRoutes()); //销售部门

me.add(new TechRoutes()); //技术部门

me.add(new QaRoutes());    //质量部门

me.add(new ProdRoutes());   //生产部门

me.add(new WareRoutes());   //仓库部门

me.add(new BuyRoutes());   //采购部门

}

public static DruidPlugin createDruidPlugin() {

return new DruidPlugin(p.get("jdbcUrl"), p.get("user"), p.get("password").trim());

}

/**

* 配置插件

*/

@Override

public void configPlugin(Plugins me) {

// 配置Druid数据库连接池插件

DruidPlugin druidPlugin = createDruidPlugin();

   druidPlugin.addFilter(new StatFilter());    // 添加 StatFilter 才会有统计数据

   me.add(druidPlugin);

// 配置ActiveRecord插件

ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);

String baseSqlTemplatePath = PathKit.getWebRootPath()+"/WEB-INF/sql";

arp.setBaseSqlTemplatePath(baseSqlTemplatePath);

arp.addSqlTemplate("_common.sql");

// File[] files = new File(baseSqlTemplatePath).listFiles();

// for(File f : files) {

// if(f.isFile() && f.getName().endsWith(".sql") ){

// arp.addSqlTemplate(f.getName());

// }

// }

if (p.getBoolean("devMode", false)) {

            arp.setShowSql(true);

        }

me.add(arp);

arp.addMapping("sys_user","id", User.class); // 映射sys_user 表到 User模型

arp.addMapping("sys_role","id", Role.class); // 映射sys_role 表到 Role模型

arp.addMapping("sys_menu","id", Menu.class); // 映射sys_menu 表到 Menu模型

arp.addMapping("sys_dept","id", Dept.class); // 映射sys_dept 表到 Dept模型

arp.addMapping("sys_user_role","id", UserRole.class); // 映射sys_user_role 表到 UserRole模型

arp.addMapping("sys_role_menu","id", RoleMenu.class); // 映射sys_role_menu 表到 RoleMenu模型

arp.addMapping("sys_log", "id",Log.class); //日志

arp.addMapping("user_login_log", "id",UserLoginLog.class); //日志

arp.addMapping("struct_desc", "id",StructDesc.class); //结构描述

arp.addMapping("sys_seq_no", "id",SysSeqno.class); //序列号

arp.addMapping("glue_set_detail", "id",GlueSetDetail.class); //胶配置详情

// 权限系统相关表以外的所有配置在_MappingKit中通过_JFinalGenerator自动生成

_MappingKit.mapping(arp);

//配置任务调度插件 每小时执行一次

//me.add(new Cron4jPlugin(p));

me.add(new EhCachePlugin());


// 开启shiro插件控制权限

me.add(new ShiroPlugin3(routes));

}

/**

* 配置全局拦截器

*/

@Override

public void configInterceptor(Interceptors me) {

//添加控制层全局拦截器

me.add(new GlobalInterceptor());

//me.add(new LoginInterceptor());

//me.addGlobalActionInterceptor(new LoginInterceptor());

// 添加事物,对save、update和delete自动进行拦截

//me.add(new TxByMethods("save", "update", "delete","deleteBatch","updateBatch"));

}

/**

* 配置处理器

*/

@Override

public void configHandler(Handlers me) {           // index、detail 两类 action 的 url seo

//me.add(new FakeStaticHandler(".do"));  //   http://localhost:8080/jfinal_pkm/user/login.do

me.add(new ContextPathHandler("ctx"));

}


    /**

     * 配置模板引擎,通常情况只需配置共享的模板函数

     */

@Override

public void configEngine(Engine me) {

me.addSharedFunction("/common/_title.html");

me.addSharedFunction("/common/_core.html");

me.addSharedFunction("/common/_home.html");

me.addSharedFunction("/common/_normal.html");

me.addSharedFunction("/common/_header.html");

me.addSharedFunction("/common/_footer.html");

}

    /**

     * 本方法会在 jfinal 启动过程完成之后被回调,详见 jfinal 手册

     */

@Override

public void afterJFinalStart() {


}

/**

* 建议使用 JFinal 手册推荐的方式启动项目

* 运行此 main 方法可以启动项目,此main方法可以放置在任意的Class类定义中,不一定要放于此

*/

public static void main(String[] args) {

/**

* 特别注意:Eclipse 之下建议的启动方式

*/

JFinal.start("WebRoot", 80, "/", 5);


/**

* 特别注意:IDEA 之下建议的启动方式,仅比 eclipse 之下少了最后一个参数

*/

// JFinal.start("WebRoot", 80, "/");

}

}

在这个类中,由于public void configPlugin(Plugins me) 先执行,所以me.add(new ShiroPlugin3(routes));这个地方传入shiro插件中的routes=null。

评论区

chenli5430

2018-07-27 00:38

/**
* Copyright (c) 2011-2017, dafei 李飞 (myaniu AT gmail DOT com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jfinal.ext.plugin.shiro;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;

import com.jfinal.config.Routes;
import com.jfinal.config.Routes.Route;
import com.jfinal.core.ActionKey;
import com.jfinal.core.Controller;
import com.jfinal.plugin.IPlugin;

/**
* Shiro插件,启动时加载所有Shiro访问控制注解。
*
* @author dafei
*
*/
@SuppressWarnings("unchecked")
public class ShiroPlugin3 implements IPlugin {

/**
* 登录成功时所用的页面。
*/
private String successUrl = "/";

/**
* 登录成功时所用的页面。
*/
private String loginUrl = "/";

/**
* action的扩展名,比如.action或者 .do
*/
private String extName = "";

/**
* 登录成功时所用的页面。
*/
private String unauthorizedUrl = "/401.jsp";

private final String SLASH = "/";

/**
* Shiro的几种访问控制注解
*/
private static final Class[] AUTHZ_ANNOTATION_CLASSES = new Class[] {
RequiresPermissions.class, RequiresRoles.class, RequiresUser.class, RequiresGuest.class,
RequiresAuthentication.class };

/**
* 路由设定
*/
private final Routes routes;

/**
* 构造函数
*
* @param routes
* 路由设定
*/
public ShiroPlugin3(Routes routes) {
this.routes = routes;
}

/**
* 停止插件
*/
public boolean stop() {
return true;
}

/**
* 启动插件
*/
public boolean start() {
Set excludedMethodName = buildExcludedMethodName();
ConcurrentMap authzMaps = new ConcurrentHashMap();
//逐个访问所有注册的Controller,解析Controller及action上的所有Shiro注解。
//并依据这些注解,actionKey提前构建好权限检查处理器。
for (Routes routes : getRoutesList()) {
for (Routes.Route route : routes.getRouteItemList()) {
Class controllerClass = route.getControllerClass();

String controllerKey = route.getControllerKey();

// 获取Controller的所有Shiro注解。
List 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 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);

// ShiroKit.init(jdbcAuthzService, authzMaps, false);
/**
* 设定登录,登录成功,未授权等url地址
*/
ShiroKit.setLoginUrl(loginUrl);
ShiroKit.setSuccessUrl(successUrl);
ShiroKit.setUnauthorizedUrl(unauthorizedUrl);
return true;
}

/**
* 获取所有配置的Route
* @return
*/
private List getRoutesList() {
List routesList = Routes.getRoutesList();
List ret = new ArrayList(routesList.size() + 1);
ret.add(routes);
ret.addAll(routesList);
return ret;
}

/**
* 从Controller方法中构建出需要排除的方法列表
*
* @return
*/
private Set buildExcludedMethodName() {
Set excludedMethodName = new HashSet();
Method[] methods = Controller.class.getMethods();
for (Method m : methods) {
if(Modifier.isPublic(m.getModifiers())) {
excludedMethodName.add(m.getName());
}
}
return excludedMethodName;
}

/**
* 依据Controller的注解和方法的注解来生成访问控制处理器。
*
* @param controllerAnnotations
* Controller的注解
* @param methodAnnotations
* 方法的注解
* @return 访问控制处理器
*/
private AuthzHandler createAuthzHandler(List controllerAnnotations,
List methodAnnotations) {

// 没有注解
if (controllerAnnotations.size() == 0 && methodAnnotations.size() == 0) {
return null;
}
// 至少有一个注解
List authzHandlers = new ArrayList(AUTHZ_ANNOTATION_CLASSES.length);
for (int index = 0; index < AUTHZ_ANNOTATION_CLASSES.length; index++) {
authzHandlers.add(null);
}

// 逐个扫描注解,若是相应的注解则在相应的位置赋值。
scanAnnotation(authzHandlers, controllerAnnotations);
// 逐个扫描注解,若是相应的注解则在相应的位置赋值。函数的注解优先级高于Controller
scanAnnotation(authzHandlers, methodAnnotations);

// 去除空值
List finalAuthzHandlers = new ArrayList();
for (AuthzHandler a : authzHandlers) {
if (a != null) {
finalAuthzHandlers.add(a);
}
}
authzHandlers = null;
// 存在多个,则构建组合AuthzHandler
if (finalAuthzHandlers.size() > 1) {
return new CompositeAuthzHandler(finalAuthzHandlers);
}
// 一个的话直接返回
return finalAuthzHandlers.get(0);
}

/**
* 逐个扫描注解,若是相应的注解则在相应的位置赋值。 注解的处理是有顺序的,依次为RequiresRoles,RequiresPermissions,
* RequiresAuthentication,RequiresUser,RequiresGuest
*
* @param authzArray
* @param annotations
*/
private void scanAnnotation(List authzArray, List annotations) {
if (null == annotations || 0 == annotations.size()) {
return;
}
for (Annotation a : annotations) {
if (a instanceof RequiresRoles) {
authzArray.set(0, new RoleAuthzHandler(a));
} else if (a instanceof RequiresPermissions) {
authzArray.set(1, new PermissionAuthzHandler(a));
} else if (a instanceof RequiresAuthentication) {
authzArray.set(2, AuthenticatedAuthzHandler.me());
} else if (a instanceof RequiresUser) {
authzArray.set(3, UserAuthzHandler.me());
} else if (a instanceof RequiresGuest) {
authzArray.set(4, GuestAuthzHandler.me());
}
}
}

/**
* 构建actionkey,参考ActionMapping中的实现。
*
* @param controllerClass
* @param method
* @param controllerKey
* @return
*/
private String createActionKey(Class controllerClass, Method method, String controllerKey) {
String methodName = method.getName();
String actionKey = "";

ActionKey ak = method.getAnnotation(ActionKey.class);
if (ak != null) {
actionKey = ak.value().trim();
if ("".equals(actionKey))
throw new IllegalArgumentException(controllerClass.getName() + "." + methodName
+ "(): The argument of ActionKey can not be blank.");
if (!actionKey.startsWith(SLASH))
actionKey = SLASH + actionKey;
} else if (methodName.equals("index")) {
actionKey = controllerKey;
} else {
actionKey = controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;
}
return actionKey;
}

/**
* 返回该方法的所有访问控制注解
*
* @param method
* @return
*/
private List getAuthzAnnotations(Method method) {
List annotations = new ArrayList();
for (Class annClass : AUTHZ_ANNOTATION_CLASSES) {
Annotation a = method.getAnnotation(annClass);
if (a != null) {
annotations.add(a);
}
}
return annotations;
}

/**
* 返回该Controller的所有访问控制注解
*
* @param method
* @return
*/
private List getAuthzAnnotations(Class targetClass) {
List annotations = new ArrayList();
for (Class annClass : AUTHZ_ANNOTATION_CLASSES) {
Annotation a = targetClass.getAnnotation(annClass);
if (a != null) {
annotations.add(a);
}
}
return annotations;
}

/**
* 该方法上是否有ClearShiro注解
*
* @param method
* @return
*/
private boolean isClearShiroAnnotationPresent(Method method) {
Annotation a = method.getAnnotation(ClearShiro.class);
if (a != null) {
return true;
}
return false;
}

/**
* 登录成功连接
*
* @param successUrl
*/
public final void setSuccessUrl(String successUrl) {
this.successUrl = successUrl;
}

/**
* 登录连接
*
* @param loginUrl
*/
public final void setLoginUrl(String loginUrl) {
this.loginUrl = loginUrl;
}

/**
* 未授权连接
*
* @param unauthorizedUrl
*/
public final void setUnauthorizedUrl(String unauthorizedUrl) {
this.unauthorizedUrl = unauthorizedUrl;
}

/**
* 扩展名,比如.action/.do
*
* @param extName
*/
public final void setExtName(String extName) {
this.extName = extName;
}
}
这样在这个类中,由于在构造函数中传入的routes=null,所以在start函数中,由于routes为null,异常退出。导致启动shiro插件失败。这个问题该如何解决?

热门反馈

扫码入社