关于listener的原理我这里就不过多叙述了,大家百度一下,一大堆。
我写一个实际案例:(代码非常简单,很多主要是业务的,我就没有删除,不要觉得麻烦,很简单)
情景描述:我监听到一个事件后,想让监听器里面延时10秒执行一些操作,但是controller继续执行自己的代码,返回视图层。
本人先是用拦截器。(只贴出来相关的配置)
先来spring核心容器的配置
<!-- 拦截器配置,拦截顺序:先执行后定义的,排在第一位的最后执行。-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="${adminPath}/**" />
<mvc:exclude-mapping path="${adminPath}/"/>
<mvc:exclude-mapping path="${adminPath}/login"/>
<mvc:exclude-mapping path="${adminPath}/sys/menu/tree"/>
<mvc:exclude-mapping path="${adminPath}/sys/menu/treeData"/>
<mvc:exclude-mapping path="${adminPath}/oa/oaNotify/self/count"/>
<bean class="com.thinkgem.jeesite.modules.sys.interceptor.LogInterceptor" />
</mvc:interceptor>
<!-- finebi拦截器 拦截user和role里面的save方法 -->
<mvc:interceptor>
<mvc:mapping path="${adminPath}/sys/user/save" />
<mvc:mapping path="${adminPath}/sys/role/save" />
<bean class="com.thinkgem.jeesite.modules.sys.interceptor.FineBIInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
下面是拦截器的内容
package com.thinkgem.jeesite.modules.sys.interceptor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.thinkgem.finebi.entity.Curep;
import com.thinkgem.finebi.service.CurepService;
import com.thinkgem.finebi.service.CustomRoleService;
import com.thinkgem.finebi.utils.FineBIUtils;
import com.thinkgem.jeesite.common.service.BaseService;
import com.thinkgem.jeesite.modules.sys.dao.MenuDao;
import com.thinkgem.jeesite.modules.sys.dao.RoleDao;
import com.thinkgem.jeesite.modules.sys.entity.Menu;
import com.thinkgem.jeesite.modules.sys.entity.Role;
/**
* @description 描述:FineBI拦截器,拦截user和role controller里面的save方法
* @author 作者:siqiangming
* @date 创建时间:2017年8月9日 下午2:32:31
* @edit 修改时间:
*/
public class FineBIInterceptor extends BaseService implements HandlerInterceptor {
@Autowired
private RoleDao roleDao;
@Autowired
private MenuDao menuDao;
@Resource
private CurepService curepService;//FineBI自定义角色权限
@Resource
private CustomRoleService customRoleService;//FineBI自定义角色
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request,HttpServletResponse response,
Object handler, Exception ex) throws Exception {
HandlerMethod HandlerMethod = (HandlerMethod)handler;
MethodParameter[] methodParameters = HandlerMethod.getMethodParameters();//获取请求参数数组
List<String> list = new ArrayList<String>();
for (MethodParameter methodParameter : methodParameters) {
list.add(methodParameter.getParameterName());
}
System.out.println("本次拦截请求参数============="+list.toString());
//因为FineBI每隔10秒同步一次
Thread.sleep(10000);
//如果是拦截的user的save方法 调用给角色赋予权限的方法
if (list.indexOf("user") > -1) {
String[] roleIdArray = request.getParameterValues("roleIdList");
List<String> roleIdList = Arrays.asList(roleIdArray);
System.out.println(roleIdList+"------------");
Iterator<String> it = roleIdList.iterator();
while (it.hasNext()) {
Role role = roleDao.get(it.next());
insertFineBIRoleMenu(role.getName(), role.getMenuList());
}
}
//如果是拦截的role的save方法 调用给角色赋予权限的方法
if (list.indexOf("role") > -1) {
String id = request.getParameter("id");
Role role = roleDao.get(id);
if (role != null) {
insertFineBIRoleMenu(role.getName(), role.getMenuList());
}
}
FineBIUtils.refreshCache();//调用FineBI接口刷新缓存
}
/**
* @description 描述:同时将角色的权限添加到finebi数据库
* @author 作者:siqiangming
* @date 创建时间:2017年8月8日 下午7:34:54
* @edit 修改时间:
* @parameter 参数:角色id,菜单list
*/
public void insertFineBIRoleMenu(String name,List<Menu> menuList){
Integer roleId = customRoleService.getRoleIdByName(name);
if(roleId != null){
deleteFineBIRoleMenu(name);
if (menuList.size() > 0){
//遍历角色的权限菜单
Iterator<Menu> it = menuList.iterator();
while(it.hasNext()){
Menu menu = menuDao.get(it.next().getId());
//查询FineBI中菜单对应的id
Integer entryId = curepService.getEntryIdByName(menu.getName());
if(entryId == null){
continue;
}
Curep curep = new Curep(roleId, 7, entryId, 1, 1, 1);
//检查是否存在这条记录
if(curepService.checkIfExistCurep(curep)){
continue;
}
curepService.save(curep);
}
}
}
}
/**
* @description 描述:删除FineBI中的角色权限
* @author 作者:siqiangming
* @date 创建时间:2017年8月8日 下午7:35:37
* @edit 修改时间:
* @parameter 参数:角色id
*/
public void deleteFineBIRoleMenu(String name){
Integer roleId = customRoleService.getRoleIdByName(name);
if(roleId != null){
curepService.deleteCurep(roleId);
System.out.println(name+":角色的finebi的角色权限已经删除");
}
}
}
结果发现页面操作也要等10秒钟,这样的话,太影响了。
百度无数,没有找到解决办法。自己想的是异步调用,没有找到类似的案例。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
果断抛弃使用监听器。
监听器简单说一下:
1、事件 继成一个ApplicationEvent类
2、事件监听者 实现一个ApplicationListener<RoleEvent>接口,接口监听事件,或者集成他的实现类。
3、事件发布者 也就是事件的触发者,监听者怎么知道事件产生呢,就是通过他。
好了,废话不多说了,贴出代码
事件
package com.thinkgem.jeesite.modules.sys.listener;
import java.util.List;
import org.springframework.context.ApplicationEvent;
import com.thinkgem.jeesite.modules.sys.entity.Role;
/**
* @description 描述:事件
* @author 作者:siqiangming
* @date 创建时间:2017年8月11日 下午3:05:44
* @edit 修改时间:
*/
public class RoleEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private List<Role> roleList;
private Role role;
public RoleEvent(Object source, List<Role> roleList) {
super(source);
this.roleList = roleList;
System.out.println("我是保存用户的时候。。。");
}
public RoleEvent(Object source, Role role) {
super(source);
this.role = role;
System.out.println("我是保存角色的时候。。。");
}
public List<Role> getRoleList() {
return roleList;
}
public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
监听者
package com.thinkgem.jeesite.modules.sys.listener;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import com.thinkgem.finebi.entity.Curep;
import com.thinkgem.finebi.service.CurepService;
import com.thinkgem.finebi.service.CustomRoleService;
import com.thinkgem.finebi.utils.FineBIUtils;
import com.thinkgem.jeesite.modules.sys.entity.Menu;
import com.thinkgem.jeesite.modules.sys.entity.Role;
import com.thinkgem.jeesite.modules.sys.service.SystemService;
/**
* @description 描述:事件监听者
* @author 作者:siqiangming
* @date 创建时间:2017年8月11日 下午3:14:21
* @edit 修改时间:
*/
@Component
public class RoleListener implements ApplicationListener<RoleEvent> {
private Logger logger = Logger.getLogger(RoleListener.class);
@Resource
private SystemService systemService;
@Resource
private CurepService curepService;//FineBI自定义角色权限
@Resource
private CustomRoleService customRoleService;//FineBI自定义角色
@Override
public void onApplicationEvent(RoleEvent event) {
logger.debug("我监听到----------事件发生");
try {
Thread.sleep(10000);
logger.debug("我睡眠了----------ok");
} catch (InterruptedException e) {
e.printStackTrace();
logger.debug("我睡眠了----------报错");
}
List<Role> roleList = event.getRoleList();
if (roleList != null && roleList.size() >0) {
logger.debug("我监听到----------"+roleList.toString());
Iterator<Role> it = roleList.iterator();
while (it.hasNext()) {
Role role = systemService.getRole(it.next().getId());
insertFineBIRoleMenu(role.getName(), role.getMenuList());
}
}
Role role = event.getRole();
if (role != null) {
logger.debug("我监听到----------"+role.toString());
insertFineBIRoleMenu(role.getName(), role.getMenuList());
}
FineBIUtils.refreshCache();//调用FineBI接口刷新缓存
}
/**
* @description 描述:同时将角色的权限添加到finebi数据库
* @author 作者:siqiangming
* @date 创建时间:2017年8月8日 下午7:34:54
* @edit 修改时间:
* @parameter 参数:角色id,菜单list
*/
public void insertFineBIRoleMenu(String name,List<Menu> menuList){
Integer roleId = customRoleService.getRoleIdByName(name);
if(roleId != null){
deleteFineBIRoleMenu(name);
if (menuList.size() > 0){
//遍历角色的权限菜单
Iterator<Menu> it = menuList.iterator();
while(it.hasNext()){
Menu menu = systemService.getMenu(it.next().getId());
//查询FineBI中菜单对应的id
Integer entryId = curepService.getEntryIdByName(menu.getName());
if(entryId == null){
continue;
}
Curep curep = new Curep(roleId, 7, entryId, 1, 1, 1);
//检查是否存在这条记录
if(curepService.checkIfExistCurep(curep)){
continue;
}
curepService.save(curep);
}
}
}
}
/**
* @description 描述:删除FineBI中的角色权限
* @author 作者:siqiangming
* @date 创建时间:2017年8月8日 下午7:35:37
* @edit 修改时间:
* @parameter 参数:角色id
*/
public void deleteFineBIRoleMenu(String name){
Integer roleId = customRoleService.getRoleIdByName(name);
if(roleId != null){
curepService.deleteCurep(roleId);
System.out.println(name+":角色的finebi的角色权限已经删除");
}
}
}
发布者
package com.thinkgem.jeesite.modules.sys.listener;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import com.thinkgem.jeesite.modules.sys.entity.Role;
/**
* @description 描述:事件发布者
* @author 作者:siqiangming
* @date 创建时间:2017年8月11日 下午3:16:52
* @edit 修改时间:
*/
@Component
public class RoleEventpPublisher {
@Autowired
private ApplicationContext applicationContext;
public void publishEventByRole(Role role){
applicationContext.publishEvent(new RoleEvent(this, role));
}
public void publishEventByUser(List<Role> roleList){
applicationContext.publishEvent(new RoleEvent(this, roleList));
}
}
到这里,是否可以了呢,当然不行了,你得有人去发布,或者说有地方调用他。
因为代码太多我只拿出来了一部分,先注入发布者
@Autowired
private RoleEventpPublisher publisher;//事件发布者
if (StringUtils.isNotBlank(user.getId())){
// 更新用户与角色关联
userDao.deleteUserRole(user);
if (user.getRoleList() != null && user.getRoleList().size() > 0){
userDao.insertUserRole(user);
//TODO 发布事件
publisher.publishEventByUser(user.getRoleList());
}else{
throw new ServiceException(user.getLoginName() + "没有设置角色!");
}
// 将当前用户同步到Activiti
saveActivitiUser(user);
// 清除用户缓存
UserUtils.clearCache(user);
// // 清除权限缓存
// systemRealm.clearAllCachedAuthorizationInfo();
}
OK,到这里完事,但是这是同步的,结果和拦截器是一样的。
干货来了,看下嘛的重点,在spring核心容器配置下面代码,其他不用更改。
<!-- 异步事件处理 20170811-->
<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
<!-- 注入任务执行器 这样就实现了异步调用 (缺点是全局的,要么全异步,要么全同步,删除这个属性既是同步) -->
<property name="taskExecutor" ref="coreTaskExecutor" />
</bean>
<!-- 20170811 -->
<bean id="coreTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10"/><!-- 核心线程数 -->
<property name="maxPoolSize" value="20"/><!-- 最大线程数 -->
<property name="queueCapacity" value="25"/><!-- 队列最大长度 -->
<property name="threadNamePrefixSet" value="weiqiao-taskExecutor"/><!-- 线程名前缀集主要用来打印日志区分方便 -->
</bean>
到这里才是真正的异步调用,将结果发图上来。