📄 详细分析三.txt
字号:
<param name="excludeParams">dojo\..*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
而自定义拦截器是要求拦截器是无状态的原因是Struts 2不能保证为每一个请求或者action创建一个实例,所以如果拦截器带有状态,会引发并发问题。所有的Struts 2的拦截器都直接或间接实现接口com.opensymphony.xwork2.interceptor.Interceptor。除此之外,大家可能更喜欢继承类com.opensymphony.xwork2.interceptor.AbstractInterceptor。需实现其public String intercept(ActionInvocation invocation) throws Exception .
而下面的remoteAddrInterceptor:
<interceptor name="remoteAddrInterceptor"
class="com.laoer.bbscs.web.interceptor.RemoteAddrInterceptor">
</interceptor>
我们进入web.interceptor层:
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext ac = invocation.getInvocationContext();
Object action = invocation.getAction();
HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);//得到request请求
String userRemoteAddr = request.getRemoteAddr();
if (action instanceof RemoteAddrAware) { //action是RomoteAddrAware实例?
((RemoteAddrAware)action).setRemoteAddr(userRemoteAddr);
//System.out.println(userRemoteAddr);
}
return invocation.invoke();
}
}
我们可以看到RemoteAddrAware是如下这个接口,这是为了方便将远程地址放入action中:
public interface RemoteAddrAware {
public void setRemoteAddr(String remoteAddr);
}
接下来是userCookieInterceptor:
<interceptor name="userCookieInterceptor"
class="com.laoer.bbscs.web.interceptor.UserCookieInterceptor">
</interceptor>
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext ac = invocation.getInvocationContext();
Object action = invocation.getAction();
if (action instanceof UserCookieAware) {
HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST); //用于UserCookie
HttpServletResponse response = (HttpServletResponse) ac.get(ServletActionContext.HTTP_RESPONSE);//用于UserCookie
ServletContext servletContext = (ServletContext) ac.get(ServletActionContext.SERVLET_CONTEXT);
WebApplicationContext wc = WebApplicationContextUtils.getWebApplicationContext(servletContext);//得到业务层服务!
if (wc == null) {
logger.error("ApplicationContext could not be found.");
} else {
SysConfig sysConfig = (SysConfig) wc.getBean("sysConfig");
UserCookie userCookie = new UserCookie(request, response, sysConfig); //关键点!!!!
//logger.debug("userCookie sid:" + userCookie.getSid());
((UserCookieAware) action).setUserCookie(userCookie);
}
}
return invocation.invoke();
}
而UserCookieAware:
public interface UserCookieAware {
public void setUserCookie(UserCookie userCookie);
}
看最后一个interceptor:requestBasePathInterceptor
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext ac = invocation.getInvocationContext();
Object action = invocation.getAction();
if (action instanceof RequestBasePathAware) {
HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
StringBuffer sb = new StringBuffer();
sb.append(BBSCSUtil.getWebRealPath(request));//得到域名
/**
public static String getWebRealPath(HttpServletRequest request) {
StringBuffer sb = new StringBuffer();
sb.append("http://");
sb.append(request.getServerName());
if (request.getServerPort() != 80) {
sb.append(":");
sb.append(request.getServerPort());
}
return sb.toString(); //返回域名啊!
}
*/
sb.append(request.getContextPath());//request相对路径
sb.append("/");
((RequestBasePathAware) action).setBasePath(sb.toString());//设置BasePath
}
return invocation.invoke();
}
其中,RequestBasePathAware:
public interface RequestBasePathAware {
public void setBasePath(String basePath);
}
我们回到public class Login extends BaseAction implements RequestBasePathAware, RemoteAddrAware, UserCookieAware, SessionAware,可见这个Login实现了我们的这些Aware..并且它继承了BaseAction,而BaseAction继承了ActionSupport,它有几个通用的方法:getAction,setAction,getAjax,setAjax,及page.total(本来私有的)的getter/setter方法,另外还有以下方法:
protected String executeMethod(String method) throws Exception { //子类用!
Class[] c = null;
Method m = this.getClass().getMethod(method, c);
Object[] o = null;
String result = (String) m.invoke(this, o);
return result;
}
public int boolean2int(boolean value) {
if (value) {
return 1;
} else {
return 0;
}
}
public boolean int2boolean(int value) {
if (value == 0) {
return false;
} else {
return true;
}
}
有点类似C++了!true-->1 value!=0--->true
我们进入正题Login:
首先它需要一个静态的logger:private static final Log logger = LogFactory.getLog(Login.class);
还有private static final long serivalVeserionUID...
当然,它需要get/set一下上面的basePath,remoteAddr,userCookie.另外还有一个session
作为struts,它有与表单交互的字段:actionUrl,tourl,passwd,username,hiddenLogin,authCode,urlRewrite,useAuthCode,cookieTime=-1等及其getter/setter方法...注意:
public boolean isUseAuthCode() {
return useAuthCode;
}
另外,我们可以看到其构造方法中:
public Login() {
this.setRadioYesNoListValues();//隐身选择是或否
this.setCookieTimeListValues();//Cookie时间选择一年/一月/一天/浏览器进程
}
private void setRadioYesNoListValues() { //private的注意哦!!
radioYesNoList.add(new RadioInt(0, this.getText("bbscs.no")));//注意getText从资源文件BaseAction中获得字符串值!
radioYesNoList.add(new RadioInt(1, this.getText("bbscs.yes")));
}
private void setCookieTimeListValues() {
cookieTimeList.add(new RadioInt(365 * 24 * 3600, this.getText("login.cookietime0")));//一年以365计算
cookieTimeList.add(new RadioInt(30 * 24 * 3600, this.getText("login.cookietime1")));
cookieTimeList.add(new RadioInt(24 * 3600, this.getText("login.cookietime2")));
cookieTimeList.add(new RadioInt(-1, this.getText("login.cookietime3")));
}
我们来看RadioInt(com.laoer.bbscs.web.ui):它是一个简单的bean,封装了两个属性int的key和String类型的value,而公开其getter/setter方法,和下面的构造方法:
public RadioInt(int key, String value) {
this.key = key;
this.value = value;
}
当然,也有其List<RadioInt> radioYesNoList = new ArrayList<RadioInt>();
public List<RadioInt> getRadioYesNoList() {
return radioYesNoList;
}
public void setRadioYesNoList(List<RadioInt> radioYesNoList) {
this.radioYesNoList = radioYesNoList;
}
也于提供给界面用.而private只能用于类的构造之中.对于一个action,它将调用业务层来处理数据,完成逻辑操作!这里用到了sysConfig,userService,loginErrorService,userOnlineService,在这个action类中提供get/set,由spring的applicationContext.xml注入!我们先看
<bean id="sysConfig"
class="com.laoer.bbscs.service.config.SysConfig">
<constructor-arg>
<ref bean="configService" />
</constructor-arg>
<property name="isLoad">
<value>${bbscs.isloadconfig}</value> //bbscs.isloadconfig=false
</property>
</bean>
而我们看<bean id="configService" parent="txProxyTemplate"> //其它如userService都类似哦!!
<property name="target">
<ref bean="configTarget" />
</property>
</bean>
而txProxyTemplate是一个事务处理的TransactionProxyFactoryBean:
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="myTransactionManager" />
</property>
<property name="transactionAttributes"> //对于如下的内容进行事务
<props>
<prop key="create*">
PROPAGATION_REQUIRED,-com.laoer.bbscs.exception.BbscsException
</prop>
<prop key="save*">
PROPAGATION_REQUIRED,-com.laoer.bbscs.exception.BbscsException
</prop>
<prop key="remove*">
PROPAGATION_REQUIRED,-com.laoer.bbscs.exception.BbscsException
</prop>
<prop key="update*">
PROPAGATION_REQUIRED,-com.laoer.bbscs.exception.BbscsException
</prop>
<prop key="del*">
PROPAGATION_REQUIRED,-com.laoer.bbscs.exception.BbscsException//出错,报BbscsException
</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>//只读
</props>
</property>
</bean>
-->
<bean id="myTransactionManager" //事务管理器
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
-->
<bean id="sessionFactory" //session工厂
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref local="dataSource" /> //dataSource!!数据源bean.
</property>
<property name="mappingResources">
<list>
<value>com/laoer/bbscs/bean/UserInfo.hbm.xml</value>
........
<value> com/laoer/bbscs/bean/Elite-{datasource.type}.hbm.xml
</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
${hibernate.dialect}
</prop>
<prop key="hibernate.show_sql">
${hibernate.show_sql}
</prop>
<prop key="hibernate.jdbc.fetch_size">
${hibernate.jdbc.fetch_size}
</prop>
<prop key="hibernate.jdbc.batch_size">
${hibernate.jdbc.batch_size}
</prop>
</props>
</property>
</bean>
OK!我们回到login.bbscs?action=check,这将getAction()-->check!首先它将执行execute方法:
public String execute() {
this.setUrlRewrite(Constant.USE_URL_REWRITE); //public static boolean USE_URL_REWRITE = false;
this.setUserAuthCodeValue();
....
接下来,根据if (this.getAction().equalsIgnoreCase("index")) {...
}if (this.getAction().equalsIgnoreCase("admin")) {..
}if (this.getAction().equalsIgnoreCase("login")) {
return this.login();
}
if (this.getAction().equalsIgnoreCase("check")) {
return this.check();
}
来进行流程的选择(这就是所为的逻辑吧)!
public String check() { //对cookie的检测!
if (StringUtils.isNotBlank(this.getUserCookie().getUserName())
&& StringUtils.isNotBlank(this.getUserCookie().getPasswd())) {
return this.cookieLogin();//有cookie
} else {
return this.index();
}
}
--->
public String index() {
this.setAction("login");
this.setHiddenLogin(0);
if (Constant.USE_URL_REWRITE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -