最近闲来无事,从网上download struts2的源代码来看看,由于这里讲的是拦截器机制,我们直接进入DefaultActionInvocation类的核心方法invoke
(注:本人语言表达能力一般,技术一般,属于刚毕业的菜鸟,有错的地方还请前辈大牛们多多指定)
我们知道Invocation是struts2是核心调试器,在这个类中,可以看到invoke方法依次迭代拦截器有(上图黄色部分)
,最后执行invokeActionOnly方法(红色部分,在invokeActonOlny中实例化我们定义的Action类,通过方法反射调用我们在Action中业务逻辑方法。这里不多讲)
struts2源代码就到这里,我们来看一张被大家经常使用的struts2执行流程图
图中红色圈圈部分对应上面的DefaultActionInvocation类,我们看到一个拦截器包围另一个拦截器,层层包围,最后到最里面的Action层,但具体代码该怎么写呢,上面的代码太复杂,我们把它简化一下
来我们来用最简单的代码演示
package com.jetway.gateway.system.utils.test;
import java.util.Iterator;
public class MyInvocation {
private Iterator<Interceptor> interceptors;
public String invoke() {
if (interceptors.hasNext()) {
Interceptor interceptor = interceptors.next();
return interceptor.interceptor(MyInvocation.this);
}
return "success";
}
}
class Interceptor {
public String interceptor(MyInvocation invocation) {
// 在这里做拦截,如果想继续执行后面的拦截器继续就调用invocation.invke(),
//也可以直接返回一个字符串,后面的拦截器将不再执行,
return invocation.invoke();
//如果这样还不好理解,那就这样写
// String result=invocation.invoke;
// return result;
}
}
这样就更清晰了,上面的代码我想大家都会写,仔细琢磨,好像跟有策略模式很像(本人也不怎么懂设计模式,姑且这样称呼)
这又让我们想起了前不久我在iteye上提的一个问题,怎么消除代码中过多的if{}else{},来看看我之前贴的代码
@Description(info = "登陆系统", actionId = "1")
public String login() {
boolean loginpass = false;
Pckey pckey = null;
// 密码验证标识
int validate = 0;
Integer keyright = 1;
HttpServletRequest request = ServletActionContext.getRequest();
String passFlag = request.getParameter("validate");
if (StringUtils.isNotEmpty(passFlag)) {
validate = Integer.parseInt(passFlag);
}
if (StringUtils.isNotEmpty(username)) {
keyright = Integer.parseInt(userright);
pckey = pckeyService.findKey(username, keyright);
}
if (pckey != null) {
boolean locked = pckeyService.isLocked(pckey);
// 没锁定
if (!locked) {
if (pckeyService.reachMaxCount(pckey)) {
pckeyService.clearErrorCount(pckey);
}
// 验证密码标识
if (validate == 100) {
pckeyService.clearErrorCount(pckey);
HttpSession session = ServletActionContext.getRequest()
.getSession();
session.setAttribute("keyname", username);
session.setAttribute("keyright", userright);
Calendar c = Calendar.getInstance();
c.add(Calendar.HOUR_OF_DAY, 10);
session.setAttribute("logintime", c.getTime().toString());
loginpass = true;
} else {
int errorCount = pckeyService.addErrorCount(pckey);
if (errorCount > 0) {
msg = "密码错误,剩余<font style='font-size:18px;font-weight:bold;'>"
+ errorCount + "</font>次key将被锁定";
} else {
msg = "密码错误,此key已被限制登陆," + pckey.getLimitdate()
+ "分钟后系统自动解锁";
pckeyService.setLockDate(pckey);
}
}
} else {
// 锁定
msg = "此key已经被锁定,您无法登陆系统";
}
} else {
// key 不合法
msg = "请插入合法key";
}
return loginpass == true ? SUCCESS : "error";
}
一个简单的登陆验证功能,代码中充斥着if,else,很不好读。怎样模仿struts2的拦截器让上面的代码看起来更beautiful些呢
可以这样(不管是不是策略模式,小弟在这里就借用一下命名哈)
1:定义一个策略接口(里面只有一个execute方法)
package com.jetway.gateway.system.utils.test;
public interface Strategy {
public String execute(StrategyExecutor executor);
}
2.定义一个策略执行者类(实际上也就是struts2中的调度者),假设如果所有验证都通过,则返回"success",如果有一个验证不通过,则返回对应的错误信息
package com.jetway.gateway.system.utils.test;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class StrategyExecutor {
private Iterator<Strategy> sIterator;
public StrategyExecutor(Strategy... strategies) {
if (strategies.length > 0) {
List<Strategy> list = Arrays.asList(strategies);
sIterator = list.iterator();
}
}
public String invoke() {
if (sIterator != null) {
if (sIterator.hasNext()) {
Strategy strategy = sIterator.next();
return strategy.execute(StrategyExecutor.this);
}
}
return "success";
}
}
3.定义两个策略实现类,也就是具体的验证逻辑,比如验证密码,登陆次数,,这里只是简单模拟
a.用户名密码验证
package com.jetway.gateway.system.utils.test;
import org.apache.commons.lang.StringUtils;
public class AuthorityStraty implements Strategy {
private String name;
private String pwd;
public AuthorityStraty(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
public String execute(StrategyExecutor executor) {
// demo
if (StringUtils.isNotBlank(name) && StringUtils.isNotBlank(pwd)
&& name.equals("11") && pwd.equals("11")) {
return executor.invoke();
}
return "用户名或密码错误";
}
b.再来一个时间验证
package com.jetway.gateway.system.utils.test;
public class TimeOutStrategy implements Strategy {
private int hours;
public TimeOutStrategy(int hours) {
this.hours = hours;
}
public String execute(StrategyExecutor executor) {
if (hours > 9) {
return executor.invoke();
}
return "时间不能小于9小时";
}
}
4:最后就是我们的客户端调用
package com.jetway.gateway.system.utils.test;
public class Client {
public static void main(String[] args) {
Strategy logincheck = new AuthorityStraty("11", "11");
Strategy timecheck = new TimeOutStrategy(10);
String resultInfo = new StrategyExecutor(logincheck, timecheck)
.invoke();
System.out.println(resultInfo);
}
}
在不改变代码的情况下,我们可以添加,删除任意接口实现,并且业务逻辑更清晰。