前面strust2已经部署好了,现在要写一个action,并且调试通,很简单的一个action,贴出代码:
package com.yj.ssh.action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { @Override public String execute() throws Exception { return SUCCESS; } }
ActionSupport可以继承也可以不继承,继承的好处是它自己定义了不少方法和常量,如SUCCESS,但是将让该类受到框架侵入,一般情况为了方便就继承他。我写了一个jsp,代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>index.jsp</title> </head> <body> <form action="login.action"> <input type="submit" value="登陆"/> </form> </body> </html>
现在要创建strust2配置文件将jsp和action衔接起来,如果把action比作是strust2骨架,那么strust2配置文件就是strust2的灵魂和血液。为了了解strust2的作用,可做如下测试,不创建strust2配置文件,直接启动tomcat,发现启动期未发现任何异常,但是我点登陆按钮,则出现异常:
There is no Action mapped for namespace / and action name login. - [unknown location] at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:178) at org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:61) at org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39) at com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:47) at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:478) at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77) at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) at java.lang.Thread.run(Thread.java:619)
很明显,如果没有配置文件,strust2处理器将无法识别action,现在跟踪strust2源文件,看看strust2如何加载配置文件的。我们知道StrutsPrepareAndExecuteFilter是一个Filter,它的一切初始化操作都是在方法init里进行的,现在查看init方法源码:
public void init(FilterConfig filterConfig) throws ServletException { InitOperations init = new InitOperations(); try { FilterHostConfig config = new FilterHostConfig(filterConfig); init.initLogging(config); Dispatcher dispatcher = init.initDispatcher(config); init.initStaticContentLoader(config, dispatcher); prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher); execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher); this.excludedPatterns = init.buildExcludedPatternsList(dispatcher); postInit(dispatcher, filterConfig); } finally { init.cleanup(); } }
首先创建了一个InitOperations对象,即是初始化操作对象,然后然后生成了该Filter的主配置文件,初始化了日志模块,生成了Dispatcher,查询可知,他是一个调度器,重点就在于这个调度器,他是下面创建准备操作对象和执行操作对象的依赖对象,进入方法init.initDispatcher(config)查看:
/** * Creates and initializes the dispatcher */ public Dispatcher initDispatcher( HostConfig filterConfig ) { Dispatcher dispatcher = createDispatcher(filterConfig); dispatcher.init(); return dispatcher; }
很简单根据配置文件生成一个Dispatcher,并且初始化操作init();进入createDispatcher(filterConfig):
/** * Create a {@link Dispatcher} */ private Dispatcher createDispatcher( HostConfig filterConfig ) { Map<String, String> params = new HashMap<String, String>(); for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) { String name = (String) e.next(); String value = filterConfig.getInitParameter(name); params.put(name, value); } return new Dispatcher(filterConfig.getServletContext(), params); }
原来只是从配置文件里读取参数,然后生成Dispatcher。然后进入init查看:
/** * Load configurations, including both XML and zero-configuration strategies, * and update optional settings, including whether to reload configurations and resource files. */ public void init() { if (configurationManager == null) { configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME); } try { init_DefaultProperties(); // [1] init_TraditionalXmlConfigurations(); // [2] init_LegacyStrutsProperties(); // [3] init_CustomConfigurationProviders(); // [5] init_FilterInitParameters() ; // [6] init_AliasStandardObjects() ; // [7] Container container = init_PreloadConfiguration(); container.inject(this); init_CheckConfigurationReloading(container); init_CheckWebLogicWorkaround(container); if (!dispatcherListeners.isEmpty()) { for (DispatcherListener l : dispatcherListeners) { l.dispatcherInitialized(this); } } } catch (Exception ex) { if (LOG.isErrorEnabled()) LOG.error("Dispatcher initialization failed", ex); throw new StrutsException(ex); } }
通读源码才发现,原来这个方法主要是读取配置文件并将自己加载到监听器列表内。看完源码,中央处理器所有的操作都是基于一个对象Dispatcher,他的名字可以看出是分发器类,他主要是通过读取strust2的配置文件来判断该将http请求分发给哪个action,至于分发请求是交给基于Dispatcher对象创建的准备操作类和执行操作类去做的,稍后可以分析doFilter方法。现在先完成strust2的配置文件strust.xml,如下:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="default" namespace="/" extends="struts-default"> <default-action-ref name="login" /> <action name="login" class="com.yj.ssh.action.LoginAction"> <result name="success">/page/index.jsp</result> </action> </package> <!-- Add packages here --> </struts>
当然这是默认的写法,而且要放在默认路径下,那么如果我基于某些原因想换个名而且不想放在默认路径下该怎么办的,通过刚才的分析很清楚的明白,所有的操作都是基于Dispatcher这个对象,而这个对象的创建是基于FilterConfig对象,其实它就是抽象了的web.xml,所以还要从web.xml下手,查询文档可以发现,需要在web.xml增加初始化参数,如下:
<filter> <filter-name>strust2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>config</param-name> <param-value>struts-default.xml,config/struts.xml</param-value> </init-param> </filter> <filter-mapping> <filter-name>strust2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping>
增加config参数配置就可以实现非默认情况下的strust.xml文件的配置,不过注意要包含strust-default.xml这个strust的配置文件,否则会报异常,debug跟踪了一下,似乎是不会再加载其他的配置文件了,只加载你配置的文件,所以需要设置这个,设置完之后,就可以启动测试,发现没有什么问题。