目录 start
目录 end |2018-04-18| 码云 | CSDN | OSChina
<result-types>
	...
	<result-type name="myresult" class="com.foo.MyResult" />
</result-types>
1.浏览器的各种事件,发起一个URL的请求, 2.被项目的默认过滤器监听到了,调用对应的action,(需要配置好xml文件的package和action标签) 3.若action有绑定拦截器,就先执行拦截器里的方法 4.由action里运行方法(这里是真正的代码处理的地方)的return值来确定等会跳转的结果页面(配置xml文件的result标签)
(或者直接使用MyEclipse的快速搭建,struts2.1+Hibernate3.3.2+JSTL1.2.2(本机jdk7.45+tomcat7.08))
Struts2.3.3版本的开发必需JAR包:
	sm-3.3.jar
	sm-commons-3.3.jar
	sm-tree-3.3.jar
	ommons-fileupload-1.2.2.jar
	ommons-io-2.0.1.jar
	ommons-lang3-3.1.jar
	ommons-logging-1.1.1.jar
	reemarker-2.3.19.jar
	avassist-3.11.0.GA.jar
	gnl-3.0.5.jar
	truts2-core-2.3.3.jar
	work-core-2.3.3.jar
package的namespace加上Action的名字加上后缀
/a/b/c/d/df.action /a/df.action
struts.xml继承的struts-default.xml 中配置了一个默认的class,所以说不会报错
<default-class-ref name=""../../../../><default-action-ref name=""../../../../><constant name="struts.action.extension" value="myth"></constant>default.properties 里面只写需要修改的常量
struts.action.extension=myth若两者都修改了按以下顺序:
若有相同的常量配置好,后者覆盖前者 建议在struts.xml中配置
	<-- 配置URL后缀 默认是action或空-->
	<constant name="struts.action.extension" value="myth"></constant>
	<-- 配置国际化资源文件被修改时,是否重新加载 默认是false -->
	<constant name="struts.i18n.reload" value="true"></constant>
	<-- 配置struts2框架的配置文件修改时,是否重新加载 默认是false-->
	<constant name="struts.configuration.xml.reload" value="true"></constant> 
	<--
		配置struts2的模式 
		false 生产模式 默认是false
		true 开发模式 需要更多的调试信息 会自动将上面两个常量设置为true
	-->
	<constant name="struts.devMode" value="true"></constant>
<include file=""></include> file的路径都是以src为起点,注意把点换成 /    <struts>
	<package name="resulttype" namespace="../../../../resulttype" extends="struts-default">
	<!-- 这是action的执行入口,里面定义返回类型,或者转发重定向啥的 -->
	<action name="resulttypeAction" class="com.myth.resulttype.resulttypeAction">
		<!-- 默认是转发 type属性:是指定type类型-->
		<!-- <result name="success" type="dispatcher">/resulttype/success.jsp</result> -->
		<!--
		 	result标签的标准写法  验证了一个特性,可以在重定向后再重定向,这在原本的JSP中是不允许的
		 	 转发:dispatcher
		-->
		<result name="success" type="dispatcher">
			<param name="location">/resulttype/success.jsp</param>
		</result>
		<result name="jqgrid" type="dispatcher">
			<param name="location">/resulttype/Jqgrid.jsp</param>
		</result>
		<!-- 重定向到jsp 和后面的重定向action底层代码是一样的-->
		<!-- <result name="success" type="redirect">
			<param name="location">/resulttype/success.jsp</param>
		</result> -->
		
		<!-- 重定向到Action (可以是别的配置文件里的,只要引入到了主配置文件struts.xml就可以)-->
		<!-- <result name="success" type="redirectAction">
			
				actionName:指定的是struts.xml文件 中action标签中name属性的值
				namespace:指定的是struts.xml文件action对应的package的namespace值
			 
			<param name="actionName">helloWorldAction</param>
			<param name="namespace">/primer</param>
		</result> -->
	</action>
	<!-- 不写result就是默认返回文本 -->
	<action name="JSONAction" class="com.myth.resulttype.resulttypeAction" method="Json">
		<!-- <result type="json"../../../../> -->
	</action>
	</package> 
	</struts>
	<struts>
		<package name="pattern" namespace="../../../../pattern"  extends="struts-default">
			<!-- 全局result 之后的可以不用配置了相当于全局变量,如果之后的action配置了,那就是局部变量覆盖原理-->
			<!-- <global-result>
				<result name="success">/pattern/success.jsp</result>
			</global-result> -->
			
			<!-- 框架中默认是运行的execute,如果自定义就更改那个method属性 -->
			<action name="BookAction" class="com.myth.pattern.BookAction">
				<result name="success">/pattern/success.jsp</result>
				<result name="add">/pattern/BookAction.jsp</result>
			</action>
			<!-- 
				通配符的使用,可以匹配任意长字符 
			-->
			<!-- <action name="*_add" class="com.myth.pattern.BookAction" method="add">
				<result name="success">/pattern/success.jsp</result>
				<result name="add">/pattern/BookAction.jsp</result>
			</action> -->
			<!-- 问题出现了,如果没有下面两个action,访问的都会是bookaction没错
			可是有了上面的通配符的action,下面还能正常运行,这是因为覆盖? -->
			<!-- <action name="BookAction_add" class="com.myth.pattern.BookAction" method="add">
				<result name="success">/pattern/success.jsp</result>
				<result name="add">/pattern/BookAction.jsp</result>
			</action>
			<action name="UserAction_add" class="com.myth.pattern.UserAction" method="add">
				<result name="success">/pattern/success.jsp</result>
				<result name="add">/pattern/UserAction.jsp</result>
			</action> -->
			<!-- 
				上面两个可以改写 (1)匹配的是通配符的第一个子串
			 -->
			<!-- <action name="*_add" class="com.myth.pattern.{1}" method="add">
				<result name="success">/pattern/success.jsp</result>
				<result name="add">/pattern/{1}.jsp</result>
			</action> -->
			
			<!-- <action name="BookAction_add" class="com.myth.pattern.BookAction" method="add">
				<result name="add">/pattern/BookAction.jsp</result>
			</action>
			<action name="BookAction_delete" class="com.myth.pattern.BookAction" method="delete">
				<result name="success">/pattern/success.jsp</result>
			</action>
			<action name="UserAction_add" class="com.myth.pattern.UserAction" method="add">
				<result name="add">/pattern/UserAction.jsp</result>
			</action>
			<action name="UserAction_delete" class="com.myth.pattern.UserAction" method="delete">
				<result name="success">/pattern/success.jsp</result>
			</action> -->
			<!-- 
				改写: 
					{1}:通配符 * 的第一个子串
					{2}:通配符 * 的第二个子串
					{0}:通配符 * 的整个串
			-->
			<action name="*_*" class="com.myth.pattern.{1}" method="{2}">
				<result name="success">/pattern/success.jsp</result>
				<result name="add">/pattern/{1}.jsp</result>
			</action>
			<!-- 动态方法调用:(默认开启,已经配置关闭了)链接写法:namespace+actionname+!+方法名
					那么在配置中不用配置method方法,而是由页面的指定的方法名来调用相应的方法
				<a href="${pageContext.request.contextPath }/pattern/BookAction!add.action">添加图书</a>
				<a href="${pageContext.request.contextPath }/pattern/BookAction!delete.action">删除图书</a>
			 -->
			<!-- <action name="BookAction" class="com.myth.pattern.BookAction">
				<result name="success">/pattern/success.jsp</result>
				<result name="add">/pattern/BookAction.jsp</result>
			</action> -->
		</package>
	</struts>
2.3以上版本使用通配
	<action name="user_*"  class="userAction" method="{1}">                                  
	    <result name="success">/WEB-INF/jsp/login.jsp</result>                  
	    <allowed-methods>login</allowed-methods>                                      
	</action>
<allowed-methods>方法名1,方法名2…</allowed-methods>代码。1、从JSP页面上的输入框提交给action时,只要在action中声明同名变量,定义setget方法,那之后直接使用get方法就能获取到值。
2、当struts有些类型无法转换时,就需要自定义转换器
xwork.default.fieldvalue=无效的字段值 "{0}".<constant name="struts.custom.i18n.resources" 
	value="cn.itcast.converter.converter,
			cn.itcast.i18n.resources">
</constant>
xwork-conversion.properties文件java.util.Date=cn.itcast.convert.DataConverter<s:fielderror fieldName="createTime"../../../../>
invalid.fieldvalue.createTime=****####【注意】 JSP页面中引入struts标签 <%@ taglib uri="../../../../struts-tags" prefix="s" %>
struts2 对 HttpServletRequest HttpSession ServletContext进行了封装成了Map对象
	//分别三个属性的设置request session application
	HttpServletRequest request = ServletActionContext.getRequest();
		request.setAttribute("username", "username_request");
	Map sessionMap = ServletActionContext.getContext().getSession();
		sessionMap.put("username", "username_session");
	ServletContext sc = ServletActionContext.getServletContext();
		sc.setAttribute("username", "username_application");
JSP页面的获取:
    ${requestScope.username}<br>
    ${sessionScope.username}<br>
    ${applicationScope.username}<br>
	struts.messages.error.uploading=Error uploading: {0}
	struts.messages.error.file.too.large=File too large: {0} "{1}" "{2}" {3}
	struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
	struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
<!-- 配置拦截器的参数,这里是文件上传拦截器 -->
<interceptor-ref name="defaultStack">
	<!-- 
		配置文件上传拦截器的参数
			* 与定义参数的顺序无关
			* 允许的类型(allowedTypes)和允许的扩展名(allowedExtensions)必须保持一致
		-->
	<!-- 
		* 配置上传文件的大小
			* struts.xml文件中配置的是上传文件的总大小
			* 这里配置的是上传文件的单个大小
		-->
	<param name="fileUpload.maximumSize">20971520</param>
	<!-- 配置上传文件允许的类型,如果配置多个值的话,用","隔开 -->
	<param name="fileUpload.allowedTypes">text/plain,application/msword</param>
	<!-- 配置上传文件的扩展名,如果配置多个值的话,用","隔开 -->
	<param name="fileUpload.allowedExtensions">.txt</param>
</interceptor-ref>
	struts.messages.error.uploading=Error uploading: {0}
	struts.messages.error.file.too.large=File too large: {0} "{1}" "{2}" {3}
	struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3}
	struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3}
1、下载文件时 压入值栈的名字如果含中文需要转码:fileName = new String(filename.getBytes(),"ISO-8859-1"); 配置文件 filename=${filename}.xls
也就是说手动的是直接在action里,重写个validate方法就是了 方法里只要按需求写this.addFieldError( key, value);语句就行了,后续的由框架来处理
首先要从页面中获取对应的标签name属性的值,在动作类action中声明 同名的属性,提供get和set方法
要继承ActionSupport类或者实现Validateable接口
重写Validateable接口的validate()方法
如果登录失败,如何处理:
什么时候才是验证通过?
分析需求:
针对所有业务方法进行验证还是针对某个指定业务方法进行验证?
首先要从页面中获取对应的标签name属性的值,在动作类action中声明同名的属性,提供get和set方法
创建一个xml格式验证文件:
如果要对指定方法进行验证的话:
【拦截器 特性】:
拦截器一般是和对应的action绑定的,而原生的filter是对URL模式进行拦截的
	//cn.itcast.aop.UserAction @15b5783, 动作类的对象
System.out.println("invocation.getAction() : "+invocation.getAction());
	//cn.itcast.aop.UserAction @15b5783, 与invocation.getAction()方法获取的是同一的对象
System.out.println("invocation.getProxy().getAction() : "+invocation.getProxy().getAction());
	//userAction_save,自定义配置文件中的action标签的name属性的值
System.out.println("invocation.getProxy().getActionName() : "+invocation.getProxy().getActionName());
	//save,对应动作类指定要执行的方法名
System.out.println("invocation.getProxy().getMethod() : "+invocation.getProxy().getMethod());
	//	/aop,自定义配置文件中的package标签的namespace属性的值
System.out.println("invocation.getProxy().getNamespace() : "+invocation.getProxy().getNamespace());
#####3、 在struts.xml配置文件中,进行注册
<interceptors>
	<!-- 声明自定义的拦截器 -->
	<interceptor name="expessionInterceptor" class="cn.itcast.aop.ExpessionInterceptor" />
	<!-- 声明自定义拦截器栈 -->
	<interceptor-stack name="expessionStack">
			<interceptor-ref name="defaultStack"../../../../>
			<!-- 配置使用自定义拦截器 -->
			<interceptor-ref name="expessionInterceptor"../../../../>
	</interceptor-stack>
</interceptors>
<!-- 配置修改struts2框架运行时,默认执行的是自定义拦截器栈 -->
<default-interceptor-ref name="expessionStack" />
后面跟着的就是action的配置了
ValueStack实际上是一个接口,在struts2中利用OGNL时,实际上是哦那个的是实现了该接口的OgnlValueStack类,这个类是利用OGNL的基础 贯穿整个action生命周期,每个action类的对象都有一个valueStack对象,相当于一个数据的中转站,在其中保存了当前action对象和其他相关对象 struts框架把valueStack对象保存在名为 “struts.valueStack”的请求属性中(request中)
	ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");
	vs.set("key","value");//实际上是放在了Map集合里再放在栈里的
	vs.getRoot().add(0,new Person());//把person对象压入List集合的0位置(栈顶)
public class OgnlValueStack implements ValueStack {
		CompoundRoot root;    ---  list集合
	transient Map<String, Object> context;  --- map集合
}
实际操作的不是值栈,而是值栈的属性:Context的上下文(就是一个Map集合)
${requestScope.username}<br>
${sessionScope.username}<br>
${applicationScope.username}<br><br><br><br>
<s:property value="#request.username"../../../../><br>
<s:property value="#session.username"../../../../><br>
<s:property value="#application.username"../../../../><br><br>
<s:property value="#request['username']"../../../../><br>
<s:property value="#parameters.cid[0]"../../../../><br>
<s:property value="#attr.username"../../../../><br><br>
访问对象栈中对象可不加#
<s:property value="msg"../../../../><br><br>
<s:property value="name"../../../../><br> 
<s:property value="sex"../../../../><br>
<s:property value="age"../../../../><br>
<s:property value="salary"../../../../><br><br>
// 深入理解值栈中的 ObjectStack
// 【后台代码:】 
vs.getRoot().add(0,new Person()); 
【若有多个name属性名】只取出栈中第一个
<s:radio list="#{'01':'男','02':'女'}"></s:radio><br><br><br><br>
<s:property value="#request.username"../../../../><br>
<s:property value="%{#request.username}"../../../../>
%的用法:“%”符号的用途是在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式。 %{}是万能用法,无论里面的表达式是不是ognl表达式,都会强制理解为ognl表达式
1 * 用于在国际化资源文件中,引用OGNL表达式
 <s:text name="ognl" /><br><br> 在properties文件中配置:ognl=${error} ognl 取的是值栈中的error属性 代码:valueStack1.set("error", "error_valueStack");
2 * 在Struts 2配置文件中,引用OGNL表达式
 <s:property value="#parameters.msg[0]"../../../../><br><br> <result name="s" >ognl/ognl.jsp?msg=${msg}</result> 这里的msg是request的param 使用 ${} 访问的都是值栈里的
<s:debug></s:debug> 能查看值栈状态