目录 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>
能查看值栈状态