废话不多说,直接贴图(开发工具:eclipse)
第一张图,但凡是学过servlet的人都知道,映射关系懂吧,不懂得可以去百度。这个是web.xml文件。一个web中可以没有web.xml文件,也就是说,web.xml文件并不是web工程必须的。
web.xml文件是用来初始化配置信息:比如Welcome页面、servlet、servlet-mapping、filter、listener、启动加载级别等。当你的web工程没用到这些时,你可以不用web.xml文件来配置你的Application。(图一如下:)
/*即所有路径都是从这进入,经过Struts2Filter处理。这个 Struts2Filter是我们项目封装好的东西,下一张图我们点击进去就知道是什么了。
StrutsPrepareAndExecuteFilter说明:《》
可以看出structs2是利用的过滤器机制来实现自身。
StrutsPrepareFilter类的主要工作有俩点:
一是为struts2执行做一些相关的准备。如加载相关的配置信息。
二是为struts2的request请求处理相关的信息。如设置编码格式和找到对应的action映射类
field:
protected PrepareOperations prepare; //包含一个请求在执行前的准备操作
protected ExecuteOperations execute; //包含过滤器的执行操作
protected List<Pattern> excludedPatterns = null; //指定不经过struts2框架处理的URL规则
methods:
protected ExecuteOperations createExecuteOperations(Dispatcher dispatcher)
//创建一个用于初始化dispathcer的新的ExecuteOperations实例
protected InitOperations createInitOperations()
//创建一个用于初始化dispathcer的新的InitOperations实例
protected PrepareOperations createPrepareOperations(Dispatcher dispatcher)
//创建一个用于初始化dispathcer的新的PrepareOperations实例
void destroy()
void doFilter(javax.servlet.ServletRequest req, javax.servlet.ServletResponse res, javax.servlet.FilterChain chain)
void init(javax.servlet.FilterConfig filterConfig)
protected void postInit(Dispatcher dispatcher, javax.servlet.FilterConfig filterConfig)
//一个空的方法,用于方法回调初始化
两个主要方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
String uri = RequestUtils.getUri(request);
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
LOG.trace("Request {} is excluded from handling by Struts, passing request to other filters", uri);
chain.doFilter(request, response);
} else {
LOG.trace("Checking if {} is a static resource", uri);
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
LOG.trace("Assuming uri {} as a normal action", uri);
/**************************************************************************************/
prepare.setEncodingAndLocale(request, response);
prepare.createActionContext(request, response);
/*为当前线程创建ActionContext,ActionContext是ThreadLocal的,ActionContext其实就是一个线程安全的HashMap,它内部使用一个HashMap
来储存相关信息这个map包括的信息有session,request,response,ServletContext,RequestMap,SessionMap等各种信息,可以通
个这个ActionContext取得各种信息*/
prepare.assignDispatcherToThread();//部署dispatcher到dispatcher线程本地
request = prepare.wrapRequest(request);//包装request
ActionMapping mapping = prepare.findActionMapping(request, response, true);//得到ActionMapping
//(ActionMapping的主要功能就是管理Action的信息和管理Action执行完成以后的ActionForward的信息。)
/***************************************************************************************/
if (mapping == null) {
LOG.trace("Cannot find mapping for {}, passing to other filters", uri);
chain.doFilter(request, response);
} else {
LOG.trace("Found mapping {} for {}", mapping, uri);
execute.executeAction(request, response, mapping);//执行对应的action。
}
}
}
} finally {
prepare.cleanupRequest(request);//一次请求完毕,清空此请求的缓存
}
}
由此见在一个使用Action的request请求传入容器时,会经过StrutsPrepareAndExecuteFilter为其配置ActionContext,包装request,最后找到Action实现类执行。
public void init(FilterConfig filterConfig) throws ServletException {
InitOperations init = createInitOperations();
Dispatcher dispatcher = null;
try {
//封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中
FilterHostConfig config = new FilterHostConfig(filterConfig);
// 初始化struts内部日志
init.initLogging(config);
//创建dispatcher ,并初始化,dispatcher类的作用还得详细理解
dispatcher = init.initDispatcher(config);
init.initStaticContentLoader(config, dispatcher);
//初始化类属性:prepare 、execute
prepare = createPrepareOperations(dispatcher);
execute = createExecuteOperations(dispatcher);
this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);
//回调空的postInit方法
postInit(dispatcher, filterConfig);
} finally {
if (dispatcher != null) {
dispatcher.cleanUpAfterInit();
}
init.cleanup();
}
}
创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher :
Dispatcher初始化,加载struts2的相关配置文件,将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.xml。。。。
ilterDispatcher是struts2.0.x到2.1.2版本的核心过滤器.!
StrutsPrepareAndExecuteFilter是自2.1.3开始就替代了FilterDispatcher的.!
这样的改革当然是有好处的.!
为什么这么说.? 应该知道如果我们自己定义过滤器的话, 是要放在strtus2的过滤器之前的, 如果放在struts2过滤器之后,你自己的过滤器对action的过滤作用就废了,不会有效!除非你是访问jsp/html!
那我现在有需求, 我必须使用Action的环境,而又想在执行action之前拿filter做一些事, 用FilterDispatcher是做不到的.!
那么StrutsPrepareAndExecuteFilter可以把他拆分成StrutsPrepareFilter和StrutsExecuteFilter,可以在这两个过滤器之间加上我们自己的过滤器
下面是我工程的 struts.xml:(上面提到StrutsPrepareAndExecuteFilter这个鬼东西会加载这个struts.xml鬼文件)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<constant name="struts.enable.SlashesInActionNames" value="true"/>
<package name="fbs-default" extends="struts-default" abstract="true">
<result-types>
<result-type name="json" class="org.apache.struts2.json.JSONResult" />
</result-types>
<interceptors>
<interceptor name="exception" class="com.chsoft.fbs.core.interceptor.FbsExceptionMappingInterceptor" >
<param name="logEnabled">true</param>
</interceptor>
<interceptor name="sessionOut" class="com.chsoft.fbs.core.interceptor.SessionInterceptor" />
<interceptor name="json" class="org.apache.struts2.json.JSONInterceptor" />
<interceptor-stack name="ufbpStack">
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="debugging"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="json" />
<interceptor-ref name="sessionOut"/>
<interceptor-ref name="exception"/>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="ufbpStack"/>
<global-results>
<!-- 全局Result配置 -->
<result name="login" type="json">
<param name="root">result</param>
</result>
<result name="exception" type="json">
<param name="root">exception</param>
</result>
</global-results>
<global-exception-mappings>
<!-- 全局异常跳转配置 -->
<exception-mapping exception="java.lang.Exception"
result="exception" />
</global-exception-mappings>
</package>
<include file="com/chsoft/fbs/struts/fbs-struts-support.xml" />
</struts>
看到上面代码的第二行哈,include file=........fbs-struts-support.xml这行,下面贴这个fbs-struts-support.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>
<constant name="struts.multipart.saveDir" value="/home/ch/tmp" />
<!-- jsp请求统一入口 -->
<package name="support" extends="fbs-default">
<default-action-ref name="msg/index"> </default-action-ref>
<action name="msg/index" class="com.chsoft.fbs.core.ufbp.action.TJWIndexAction"
method="execute">
<result name="admin" type="dispatcher">
/WEB-INF/jsp/msg/msgadmin.jsp
</result>
<result name="user" type="dispatcher">
/WEB-INF/jsp/msg/msguser.jsp
</result>
<result name="send" type="dispatcher">
/WEB-INF/jsp/msg/msgsend.jsp
</result>
<result name="success" type="dispatcher">
/WEB-INF/jsp/msg/msgindex.jsp
</result>
<result name="login" type="dispatcher">
/msg/login.jsp
</result>
</action>
<!-- json请求统一入口 -->
<action name="*/*" class="com.chsoft.fbs.core.ufbp.action.FBSActionSupport"
method="execute">
<result name="success" type="json">
<param name="root">result</param>
<param name="contentType">text/html</param>
</result>
<result name="login" type="json">
<param name="root">result</param>
<param name="contentType">text/html</param>
</result>
<result name="nopage" type="dispatcher">
/404.jsp
</result>
</action>
<!-- 下载excel -->
<action name="upload/downloadExcelFile"
class="com.chsoft.fbs.logic.component.upload.actioner.FBSUploadActioner"
method="execute">
<result name="success" type="stream">
<!--
动态文件下载的,事先并不知道未来的文件类型,那么我们可以把它的值设置成为:application/octet-stream;charset=ISO8859-1
,注意一定要加入charset,否则某些时候会导致下载的文件出错;
-->
<param name="contentType">application/octet-stream;charset=UTF-8</param>
<param name="contentDisposition">attachment;filename="export.xls"</param>
<!--
使用经过转码的文件名作为下载文件名,downloadFileName属性 对应action类中的方法
getDownloadFileName()
其中特殊的代码就是${downloadFileName},它的效果相当于运行的时候将action对象的属性的取值动态的填充在${}中间的部分,我们可以认为它等价于+action.
getDownloadFileName()。
-->
<param name="inputName">ioStream</param>
<param name="bufferSize">4096</param>
</result>
<interceptor-ref name="defaultStack" />
</action>
<!-- 返回Excel文件InputStream流 -->
<action name="file/saveExcel" class="com.chsoft.fbs.core.ufbp.action.FBSExcelFileAction">
<result name="success" type="stream">
<param name="contentType">application/vnd.ms-excel</param>
<param name="inputName">excelStream</param>
<param name="contentDisposition">filename="export.xls"</param>
<param name="bufferSize">1024</param>
</result>
</action>
<!-- 下载图片 -->
<action name="scan/fileDetail" class="com.chsoft.fbs.core.ufbp.action.FBSScannerAction"
method="execute">
<result name="success" type="stream">
<param name="contentType">image/jpeg</param>
<param name="inputName">imageStream</param>
<param name="bufferSize">1024</param>
</result>
<interceptor-ref name="defaultStack" />
</action>
<!-- 上传 -->
<action name="fileUpload" class="com.chsoft.fbs.core.ufbp.action.TJWUploadAction"
method="execute">
<!-- 动态设置savePath的属性值 -->
<param name="savePath">/images</param>
<result name="success" type="json">
<param name="root">result</param>
<param name="contentType">text/html</param>
</result>
<interceptor-ref name="fileUpload">
<!-- 文件过滤 -->
<!-- <param name="allowedTypes">image/bmp,image/png,image/gif,image/jpeg</param> -->
<!-- 文件大小, 以字节为单位 -->
<param name="maximumSize">30145728</param>
</interceptor-ref>
<!-- 默认拦截器必须放在fileUpload之后,否则无效 -->
<interceptor-ref name="defaultStack" />
<interceptor-ref name="sessionOut" />
</action>
<!-- 下载图片 -->
<action name="fileDown" class="com.chsoft.fbs.core.ufbp.action.TJWDownAction"
method="execute">
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="contentDisposition">attachment;filename=${filename}</param>
<param name="inputName">fileStream</param>
<param name="bufferSize">1024</param>
</result>
<interceptor-ref name="defaultStack" />
<interceptor-ref name="sessionOut" />
<result name="login" type="dispatcher">
/msg/login.jsp
</result>
</action>
</package>
</struts>
<constant name="struts.multipart.saveDir" value="/home/ch/tmp" />:因为项目部署在linux上,这里是上传的路径
<default-action-ref name="msg/index"> </default-action-ref>: (参考:)
<package name="support" extends="fbs-default">与这里异曲同工,下面的图是我练习的时候玩的,struts-default.xml这个也是个重要的文件。这个文件的详细说明()
我是真的没找到这个<package name="support" extends="fbs-default">这个鬼东西,我要去问问大佬再给大家解释,这里我们就当做struts2中的struts-defualt.xml来搞,我觉得应该是扩展了这个文件。后面的就是一些Action了。
现在清楚了些哈,一个请求经过struts2到达相应的页面的过程差不多就是这样玩的。我这里是一些大致的流程,详细还是要参考这里面的链接和自己百度一些不懂得地方,如果有什么错误或者我这有误解的话,请评论下哈。
补充来了,问了大佬。跟我猜的没错,就是躲在这里被我忽略了。这个fbs-default就是继承了struts-default这个东西。我写业务的时候直接在上面扩展而不影响到struts-defaul,基本都是封装扩展。