项目中Struts2的运用和理解

废话不多说,直接贴图(开发工具: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说明:《https://blog.csdn.net/a915800048/article/details/70260205

可以看出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>:  (参考:https://blog.csdn.net/chen_jp/article/details/7893432)

<package name="support" extends="fbs-default">与这里异曲同工,下面的图是我练习的时候玩的,struts-default.xml这个也是个重要的文件。这个文件的详细说明(https://blog.csdn.net/com_ma/article/details/73692269

我是真的没找到这个<package name="support" extends="fbs-default">这个鬼东西,我要去问问大佬再给大家解释,这里我们就当做struts2中的struts-defualt.xml来搞,我觉得应该是扩展了这个文件。后面的就是一些Action了。

现在清楚了些哈,一个请求经过struts2到达相应的页面的过程差不多就是这样玩的。我这里是一些大致的流程,详细还是要参考这里面的链接和自己百度一些不懂得地方,如果有什么错误或者我这有误解的话,请评论下哈。

 

补充来了,问了大佬。跟我猜的没错,就是躲在这里被我忽略了。这个fbs-default就是继承了struts-default这个东西。我写业务的时候直接在上面扩展而不影响到struts-defaul,基本都是封装扩展。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值