NutzCN Logo
问答 关于自定义拦截器对多个action都起作用的问题
发布于 2708天前 作者 qq_7fafbecc 2417 次浏览 复制 上一个帖子 下一个帖子
标签:

自定义了一个拦截器:

@IocBean
public class ActionInterceptor implements MethodInterceptor  {

	@Override
	public void filter(InterceptorChain chain) throws Throwable {
		// TODO Auto-generated method stub

		String ActionName = chain.getCallingObj().getClass().getName();
		
		int loc = ActionName.indexOf("$");//首先获取字符的位置
		ActionName = ActionName.substring(0,loc);//再对字符串进行截取,获得想要得到的字符串
		
		String ActionMethodName = chain.getCallingMethod().getName();


		Date beforeDate = new Date();
		System.out.println("===================================Action调用开始:【"+ActionName+"】=====方法:【"+ActionMethodName+"】=========================>"); 
        chain.doChain();// 继续执行其他拦截器
		Date afterDate = new Date();
        System.out.println("===================================Action调用结束:【"+ActionName+"】=====方法:【"+ActionMethodName+"】==============耗时:"+(afterDate.getTime()-beforeDate.getTime())+"毫秒===========>"); 
	}
	

    
}

能够其作用:

===================================Action调用开始:【com.shlx.blood.action.UserAction】=====方法:【login】=========================>
sunxu - 666
2017-07-24 10:05:39,970 com.shlx.blood.service.ComServices.ExcuteServices(ComServices.java:80) INFO  - FunctionId : B06.04.11 params:{loginName=sunxu, loginPwd=666}
2017-07-24 10:05:39,976 com.alibaba.druid.pool.DruidDataSource.getConnectionDirect(DruidDataSource.java:1057) DEBUG - skip not validate connection.
2017-07-24 10:05:39,995 org.nutz.dao.impl.sql.run.NutDaoExecutor.printSQL(NutDaoExecutor.java:388) DEBUG - SELECT * FROM SYSFUNCTION  WHERE functionid=?
    |         1 |
    |-----------|
    | B06.04.11 |
  For example:> "SELECT * FROM SYSFUNCTION  WHERE functionid='B06.04.11'"
2017-07-24 10:05:39,998 org.nutz.ioc.impl.NutIoc.get(NutIoc.java:151) DEBUG - Get 'userService'<class com.shlx.blood.service.business.UserService>
2017-07-24 10:05:39,999 org.nutz.dao.impl.sql.run.NutDaoExecutor.printSQL(NutDaoExecutor.java:388) DEBUG - SELECT * FROM SYSUSER  WHERE LOGINNAME=? AND password=?
    |     1 |   2 |
    |-------|-----|
    | sunxu | 666 |
  For example:> "SELECT * FROM SYSUSER  WHERE LOGINNAME='sunxu' AND password='666'"
===================================Action调用结束:【com.shlx.blood.action.UserAction】=====方法:【login】==============耗时:31毫秒===========>

但必须要在每个action中的每个方法上面标注一条@Aop({"actionInterceptor"}) 吗?
例如:

@At("/login")
	@Aop({"actionInterceptor"}) 
	public Object login(@Param("loginName")String loginName,@Param("loginPwd")String loginPwd) {
... ...
}

有没有其他方法可以让多个ACTION的每个方法都用到这个拦截器?

21 回复
//IocBy 设置应用所采用的 Ioc 容器
@IocBy(type=ComboIocProvider.class, args={"*js", "ioc/",
        // 这个package下所有带@IocBean注解的类,都会登记上
                            "*anno", "com.shlx.blood",
                            "*tx", // 事务拦截 aop
                            "*async",
                            "*com.shlx.blood.aop.AopLoader" // 自定义aop注解加载器
                            }) // 异步执行aop
@SetupBy(value=MainSetup.class)  //SetupBy应用启动以及关闭时的额外处理
@Modules(scanPackage=true) //Modules声明应用的所有子模块
@Ok("json")
@Fail("json")
public class MainModule {
public class AopLoader extends SimpleAopMaker<SysLog>{

	@Override
	public List<? extends MethodInterceptor> makeIt(SysLog t, Method method, Ioc ioc) {
		// TODO Auto-generated method stub
		return Arrays.asList(new ActionInterceptor());
	}
}
@Retention(RetentionPolicy.RUNTIME) // 必须带这个,不然读取不到的
@Target({ElementType.METHOD}) // aop,一般指方法
@Documented // 记录到javadoc
public @interface SysLog {
	
}
@Aop({"actionInterceptor"}) 

然后把原来ACTION方法前面的注解,注释掉,就一直无法起作用,这个拦截器????

按示例上的步骤弄了以后,怎么不起作用了呢,这个ActionInterceptor ??

方法要加上自定义注解才行

想了想,这应该不是你想要的效果

你想要的估计是js去匹配配置?

你的意思是,假如这个注解叫做 @ActionNote,那么每个Action的方法都加上@ActionNote就起作用了,是吧?

那估计还是得,每个Action的每个的方法上头,标注拦截器,才能统一执行拦截器的内容。。

只打算针对Action方法吗??

是,因为页面所有请求,都是发送给各种Action的,然后action再去调用业务逻辑
那么我就想,把拦截器放在action这里,会在后台打印 ===开始/结束===耗时=== 等信息,
还可以抓取session,判断是否过期,过期了,就把所有请求,在执行业务逻辑前,拦住并返回到初始的login.jsp
这是我做拦截器的想法,后期可能还在拦截器中加上权限判断等
@wendal ,你觉得这样可行吗?

	@Override
	public void filter(final InterceptorChain chain) throws Throwable {
		// TODO Auto-generated method stub
		//private static final Log log = Logs.get();	
		String ActionName = chain.getCallingObj().getClass().getName();
		
		int loc = ActionName.indexOf("$");//首先获取字符的位置
		ActionName = ActionName.substring(0,loc);//再对字符串进行截取,获得想要得到的字符串
		
		String ActionMethodName = chain.getCallingMethod().getName();


		
		Date beforeDate = new Date();
		System.out.println("===================================Action调用开始:【"+ActionName+"】=====方法:【"+ActionMethodName+"】=========================>"); 
		SysUser user = (SysUser)Mvcs.getHttpSession().getAttribute(Globals.SESSION_USER_CODE);
		if(user == null || "".equals(user) ){
			System.out.println("===================================用户登录超时或未登录,请重新登录!=========================>"); 
			//重新登录,如何定位到UserAction下的loginOut方法??
		}
		
		chain.doChain();// 继续执行其他拦截器
		Date afterDate = new Date();
        System.out.println("===================================Action调用结束:【"+ActionName+"】=====方法:【"+ActionMethodName+"】==============耗时:"+(afterDate.getTime()-beforeDate.getTime())+"毫秒===========>"); 
	}

动作链没搞懂,决定先用注解来调用拦截器了,那么请教一下,
怎么才能定位到UserAction下的loginOut方法呢?

	@SysLog
	@At("/loginOut")
    public Object loginOut(@Param("..")NutMap map) {
		Object result = null;
		Mvcs.getHttpSession().invalidate();
		return WriteToClient(Globals.Code.OK_CODE, "/login.jsp");


    }

chain.getMethod()

... 建议换个名字啊...

弄清楚动作链是更好的解决办法...

刚把论坛的相关帖子都翻了一遍,发现 @wendal 说过这么一句:要做过滤,用动作链比较好,aop不适合做mvc操作
于是,决定用aop方法拦截器,来做方法日志:
===========Action的xxx方法调用开始=================
===========Action的xxx方法调用结束=====耗时xxxx=====
以后也把权限、角色的判断都放在aop拦截器里?

@IocBean
public class ActionInterceptor  implements MethodInterceptor  {

	@Override
	public void filter(final InterceptorChain chain) throws Throwable {
		//***************************要做过滤,用动作链比较好,aop不适合做mvc操作***********************************
		//***************************可以考虑用ActionFilter***********************************
		// TODO Auto-generated method stub
		//private static final Log log = Logs.get();	
		String ActionName = chain.getCallingObj().getClass().getName();
		
		int loc = ActionName.indexOf("$");//首先获取字符的位置
		ActionName = ActionName.substring(0,loc);//再对字符串进行截取,获得想要得到的字符串
		
		String ActionMethodName = chain.getCallingMethod().getName();

		Date beforeDate = new Date();
		System.out.println("===================================Action调用开始:【"+ActionName+"】=====方法:【"+ActionMethodName+"】=========================>"); 
		//SysUser user = (SysUser)Mvcs.getHttpSession().getAttribute(Globals.SESSION_USER_CODE);
		//if(user == null || "".equals(user) ){
			//System.out.println("===================================用户登录超时或未登录,请重新登录!=========================>"); 
			//chain.getCallingMethod().invoke(UserAction.class, "loginOut");
//			UserAction ua = new UserAction();
//			ua.loginOut(null);
//			return new JspView("/login");
			//重新登录,如何定位到UserAction下的loginOut方法??
		//}
		chain.doChain();// 继续执行其他拦截器
		Date afterDate = new Date();
        System.out.println("===================================Action调用结束:【"+ActionName+"】=====方法:【"+ActionMethodName+"】==============耗时:"+(afterDate.getTime()-beforeDate.getTime())+"毫秒===========>"); 
	} 
}

用MVC动作链来做session用户失效判断,如果失效就强制跳转到login.jsp:

public class LogTimeProcessor extends AbstractProcessor {

    private static final Log log = Logs.get();

    @Override
    public void process(ActionContext ac) throws Throwable {
     	
        Stopwatch sw = Stopwatch.begin();
        HttpServletRequest req = ac.getRequest();
        //获取当前session中的用户
        SysUser user = (SysUser)req.getSession().getAttribute(Globals.SESSION_USER_CODE);
        //如果用户为空,就表示失效,就要跳转到login.jsp
        if(user == null || "".equals(user)){
            HttpServletResponse response = ac.getResponse();
            //为什么这里就是不跳转到login.jsp呢 ?????????
            response.sendRedirect("/login.jsp");
        }
        try {
            doNext(ac);
        } finally {
            sw.stop();
            if (log.isDebugEnabled()) {
                log.debugf("[%4s]URI=%s %sms", req.getMethod(), req.getRequestURI(), sw.getDuration());
            }
        }
    }
}
var chain={
    "default" : {
        "ps" : [
              "com.shlx.blood.mvc.LogTimeProcessor",
              "org.nutz.mvc.impl.processor.UpdateRequestAttributesProcessor",
              "org.nutz.mvc.impl.processor.EncodingProcessor",
              "org.nutz.mvc.impl.processor.ModuleProcessor",
                    "!org.nutz.integration.shiro.NutShiroProcessor",
              "org.nutz.mvc.impl.processor.ActionFiltersProcessor",
              "org.nutz.mvc.impl.processor.AdaptorProcessor",
              "org.nutz.mvc.impl.processor.MethodInvokeProcessor",
              "org.nutz.mvc.impl.processor.ViewProcessor"
              ],
        "error" : 'org.nutz.mvc.impl.processor.FailProcessor'
    }
};

这种思路,是对的吧?
问题是在MVC动作链里面,怎么都不能实现跳转到login.jsp,求解惑

执行重定向后要return

return了也没用啊,大哥,哎

你把return加哪里了

    @Override
    public void process(ActionContext ac) throws Throwable {
     	
        Stopwatch sw = Stopwatch.begin();
        HttpServletRequest req = ac.getRequest();
        //获取当前session中的用户
        SysUser user = (SysUser)req.getSession().getAttribute(Globals.SESSION_USER_CODE);
        //如果用户为空,就表示失效,就要跳转到login.jsp
        if(user == null || "".equals(user)){
            HttpServletResponse response = ac.getResponse();
            //为什么这里就是不跳转到login.jsp呢 ?????????
            String contextPath = ac.getServletContext().getContextPath();
            response.sendRedirect(contextPath+"/login.jsp");
            return;
        }
        try {
            doNext(ac);
        } finally {
            sw.stop();
            if (log.isDebugEnabled()) {
                log.debugf("[%4s]URI=%s %sms", req.getMethod(), req.getRequestURI(), sw.getDuration());
            }
        }
        
    }

return加在 response.sendRedirect(contextPath+"/login.jsp");下面了

奇怪的是,这么运行的话,地址栏,敲/shlxoa/user/addUser或者editUser等action映射方法地址,就能返回login.jsp
敲/shlxoa/index.jsp又不能返回login.jsp,会停留在index.jsp
难道是web.xml要改吗?

直接输入jsp路径的话,并不会映射到入口方法,也就不会走动作链了

那咋拦截啊,用户乱敲地址咋办,没登录,直接敲index.jsp之类的

乱敲就是404了

如果jsp需要保护,放在WEB-INF下,经入口方法中转

添加回复
请先登陆
回到顶部