Struts2相关知识整合

来源:互联网 发布:ipad 下载软件 编辑:程序博客网 时间:2024/05/16 07:27

网站

Apache Struts 2 http://struts.apache.org/2.x/index.html

Opensymphony XWork http://www.opensymphony.com/xwork

Opensymphony WebWork http://www.opensymphony.com/webwork


Struts2是使用Filter作为控制器

Struts2AndStruts1  
Struts2和Struts1对比
Struts2,Struts

Struts 2 = WebWork 2.2

对比:

1.配置文件:Struts1配置文件放在WEB-INF/struts-config.xml(可定制)目录下;Struts2的配置文件要放在WEB-INF/classes目录下

2.控制器:Struts1的控制器是一个ActionServlet类;Struts2的控制器是一个过滤器。

3.动作表单:Struts1的HTML表单对应一个ActionForm类的实例,动作类可访问对应配置的ActionForm,操作ActionForm进行填充数据传输对象;Struts2的HTML表单直接映射成POJO,动作类中可直接访问POJO,操作对POJO的验证。

4.动作类:Struts1的动作类继承org.apache.struts.action.Action类;Struts2的动作类可以是任何一个POJO,但是最好是继承ActionSupport类?。

5.显示对象:在JSP中Struts2使用OGNL来显示各种对象模型,JSP自带的JSTL和EL中EL常用来补充使用。

6.标签库:Struts1常用HTML标签库、Bean标签库和Logic标签库;Struts2有通用标签库、表单标签库? 。


为什么最好是继承ActionSupport类 ?Struts2的标签具体有哪些


Action 跟 Actionsupport 的区别
 

   当我们在写action的时候,可以实现Action接口,也可以继承Actionsupport这个类.到底这两个有什么区别呢?

Action接口有:
public static final java.lang.String SUCCESS = "success";
public static final java.lang.String NONE = "none";
public static final java.lang.String ERROR = "error";
public static final java.lang.String INPUT = "input";
public static final java.lang.String LOGIN = "login";

public abstract java.lang.String execute() throws java.lang.Exception;

而Actionsupport这个工具类在实现了Action接口的基础上还定义了一个validate()方法,重写该方法,它会在execute()方法之前执行,如校验失败,会转入input处,必须在配置该Action时配置input属性。

另外,Actionsupport还提供了一个getText(String key)方法还实现国际化,该方法从资源文件上获取国际化信息.

这样在自定义标签时可以定义一个变量为new actionsupport对象实现国际化。 


    ActionSupport类的作用
    struts2不要求我们自己设计的action类继承任何的struts基类或struts接口,但是我们为了方便实现我们自己的action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类,并重写此类里的public String execute() throws Exception方法。因为此类中实现了很多的实用借口,提供了很多默认方法,这些默认方法包括国际化信息的方法、默认的处理用户请求的方法等,这样可以大大的简化Acion的开发。
    Struts2中通常直接使用Action来封装HTTP请求参数,因此,Action类里还应该包含与请求参数对应的属性,并且为属性提供对应的getter和setter方法。


 

 

2.8  增加数据校验
在上面应用中,即使浏览者输入任何用户名、密码,系统也会处理用户请求。在我们整个HelloWorld应用中,这种空用户名、空密码的情况不会引起太大的问题。但如果数据需要保存到数据库,或者需要根据用户输入的用户名、密码查询数据,这些空输入可能引起异常。
为了避免用户的输入引起底层异常,通常我们会在进行业务逻辑操作之前,先执行基本的数据校验。
2.8.1  继承ActionSupport
ActionSupport类是一个工具类,它已经实现了Action接口。除此之外,它还实现了Validateable接口,提供了数据校验功能。通过继承该ActionSupport类,可以简化Struts 2的Action开发。
在Validatable接口中定义了一个validate()方法,重写该方法,如果校验表单输入域出现错误,则将错误添加到ActionSupport类的fieldErrors域中,然后通过OGNL表达式负责输出。
为了让Struts 2增加输入数据校验的功能,改写程序中的LoginAction,增加重写validate方法。修改后的LoginAction类代码如下:

//Struts 2的Action类就是一个普通的Java类public class LoginAction{//下面是Action内用于封装用户请求参数的两个属性 private String username;private String password;//username属性对应的getter方法 public String getUsername(){ return username; }//username属性对应的setter方法 public void setUsername(String username){ this.username = username;}//password属性对应的getter方法 public String getPassword(){ return password; }//password属性对应的setter方法 public void setPassword(String password){ this.password = password; }//处理用户请求的execute方法public String execute() throws Exception{//当用户请求参数的username等于scott,密码请求参数为tiger时,返回success字符串//否则返回error的字符串 if (getUsername().equals("scott")&& getPassword().equals("tiger") ){ return "success"; }else{ return "error"; }//完成输入校验需要重写的validate方法public void validate(){//如果用户名为空,或者用户名为空字符串if (getUsername() == null || getUsername().trim().equals("")){//添加表单校验错误addFieldError("username", "user.required");}//当密码为空,或者密码为空字符串时,添加表单校验错误if (getPassword() == null || getPassword().trim().equals("")){addFieldError("password", "pass.required");}}}

上面的Action类重写了validate方法,该方法会在执行系统的execute方法之前执行,如果执行该方法之后,Action类的fieldErrors中已经包含了数据校验错误,请求将被转发到input逻辑视图处。
为了在校验失败后,系统能将视图转入input处,必须在配置该Action时配置input属性。下面是修改后login Action的配置片段:

<!-- 定义login的Action --><action name="Login" class="lee.LoginAction"><!-- 定义input的逻辑视图名,对应login.jsp页面 --><result name="input">/login.jsp</result><!-- 定义error的逻辑视图名,对应error.jsp页面 --> <result name=" success ">/error.jsp</result><!-- 定义welcome的逻辑视图名,对应welcome.jsp页面 --> <result name="success">/welcome.jsp</result>        </action>

对比上面的Action配置与前面的Action配置,我们发现该Action配置片段中增加了input逻辑视图的配置,该逻辑视图映射到login.jsp页面。
前面已经提到:当用户提交请求时,请求得到execute方法处理之前,先会被validate方法处理,如果该方法处理结束后,Action的fieldErrors里的校验错误不为空,请求将被转发给input逻辑视图。如果我们不输入用户名、密码而直接提交表单,将看到如图2.13所示的界面。

图2.13  输入校验的界面

看到这里也许读者觉得非常神奇:我们仅仅在Action添加了数据校验错误,并未在输入页面输出这些校验错误信息,但图2.13所示的页面,却可以看到页面已经输出了这些校验信息——这是因为Struts 2的标签,上面的JSP页面中表单使用的并不是HTML表单,而是用了<s:form .../>标签,Struts 2的<s:form ... />标签已经具备了输出校验错误的能力。
提示  Struts 2的<s:form .../>默认已经提供了输出校验错误的能力。
但上面的程序还存在一个问题:校验信息的国际化。查看上面的Action类代码发现:重写validate方法时,如果发生校验失败的问题,校验错误的提示信息是以硬编码方式写死了——这就失去了国际化的能力。
实际上,ActionSupport类已经提供了国际化信息的能力,它提供了一个getText(String key)方法,该方法用于从资源文件中获取国际化信息。为了让校验信息支持国际化,再次改写Action里的validate方法,改写后的validate方法代码如下:

//执行数据校验的validate方法public void validate(){//如果用户名为空,或者为空字符串if (getUsername() == null || getUsername().trim().equals("")){//添加校验错误提示,使用getText方法来使提示信息国际化addFieldError("username", getText("user.required"));}if (getPassword() == null || getPassword().trim().equals("")){addFieldError("password", getText("pass.required"));}}

在上面的validate方法中,添加校验错误提示时,并不是直接给出了错误提示的字符串,而是调用了getText方法来获取错误提示。因为在Action中,使用getText方法来获取了两个国际化提示:user.required和pass.required,因此应该在国际化资源文件中添加这两条提示信息。
提示  ActionSupport增加了让提示信息国际化的能力,ActionSupport提供的getText方法可以根据资源文件加载获得国际化提示信息。
此时,如果没有任何输出,直接提交登录表单,将看到如图2.14所示的界面。

图2.14  国际化数据校验的错误提示     

Struts2Request  
Struts2在Action 中访问request,session,application

只需用到attribute

//获取requestActionContext ctx = ActionContext.getContext();ctx.put("request", "request");//获取SessionMap<String,Object> session = ctx.getSession();session.put("session", "session");//获取ServletContextMap<String,Object> appliction = ctx.getApplication();appliction.put("appliction", "appliction");

获得HttpServletRequest

代码获得

HttpServletRequest request = ServletActionContext.getRequest();HttpServletResponse response = ServletActionContext.getResponse();HttpSession session = request.getSession();//不要在Action构造器里调用,可能还没初始化好ServletContext servletContext = ServletActionContext.getServletContext();

接口获得

如果有多个Action需要用到request,可以写个Action继承接口,使用request的Action继承再它.

/*继承ServletRequestAware(获得request),ServletResponseAware(获得response),ServletContextAware(获得ServletContext),SessionAware(获得Session)接口*/public class FormAction implements ServletRequestAware,ServletResponseAware{                   private HttpServletRequest request;             private HttpServletResponse response;                   //拦截器会把request注入到变量中   public void setServletRequest(HttpServletRequest req) {      this.request = req;   }           public void setServletResponse(HttpServletResponse res) {      this.response = res;   }}

Struts2ActionMethod  
Struts2Action中方法的访问
Updated May 10, 2010 by cm2...@gmail.com

默认方法

//Struts2中默认访问的是Action中execute方法//url:http://127.0.0.1:8080/Struts2Pro/hello.action(访问hello指定的Action中的execute方法)public String execute() {   return "success";}

访问Action中多个方法

动态方法调用

只要在url中指定方法名称就可以了. 如:要访问HelloAction中的add()方法 url:http://127.0.0.1:8080/Struts2Pro/hello!add.action (加!和方法名字)

<!-- 在struts.xml中配置可以关闭动态方法(默认是激活,可能会让用户方法没有公开的方法,最好不用) --><constant name="struts.enable.DynamicMethodInvocation" value="false" />

配置文件中多个方法

配置多个方法

<!-- url:http://127.0.0.1:8080/Struts2Pro/userActionAdd.action 访问FormAction中的add方法 --><action name="userActionAdd" class="com.struts2.form.FormAction" method="add"><!-- url:http://127.0.0.1:8080/Struts2Pro/userActionUpdate.action 访问FormAction中的update方法 --><action name="userActionUpdate" class="com.struts2.form.FormAction" method="update">

使用通配符调用多个方法

<!-- name="*_*" class="com.struts2.form.{1}Action" method="{2}" url:user_list.action 就是调用userAction中list方法.                        name="*_*_*"url:user_list_abd.actionmethod="{1}"->user(第一个*对应的字符串)method="{2}"->list(第二个*对应的字符串)method="{3}"->abd(第三个*对应的字符串)--><action name="userAction_*" class="com.struts2.form.FormAction" method="{1}">


Struts2OGNL  
Struts2_OGNL表达式
Updated May 10, 2010 by cm2...@gmail.com

Struts2标签不支持el表达式,只能使用OGNL.

1.OGNL分为Object StackContext Map.   把动作和相关对象压入Object Stack.   把各种映射关系(一些Map类型的对象)压入Context Map.(parameters,request,session,application,attr)                          OGNL表达式加上一个前缀"#",访问Context Map.  没加访问Object Stack.                        2.OGNL访问数组   //String[] colors = {"blue","green","red"};   colors[0]//访问第一个元素   colors.length//访问长度                        3.OGNL访问List   countries[0]//访问第一个元素   countries.size//访问countries.size()   countries.isEmpty//访问countries.isEmpty()   创建List   {"a","b","c"}//创建一个由3个String构成的List                4.OGNL访问Map   cities["CA"]或者cities['CA']//访问cities中key为CA的元素   cities.size//访问cities.size()   cities.isEmpty//访问cities.isEmpty()   创建Map   {"CA":"S","WA":"O","UT":"ST"}                        %{}里面的表达式会被求值(%{#request.user.age>40}->true or false,%{1+6}->7)



Struts2ResultType  
Struts2返回类型
Updated May 10, 2010 by cm2...@gmail.com

类型对应的类

Chain(chain)                    构成一条动作链Dispatcher(dispatcher)          默认类型,转发FreeMarker(freemarker)          用于与FreeMarker的集成HttpHeader(httpheader)          HTTP标头发送回用户Redirect(redurect)              重定向到另一个URLRedirectAction(redirectAction)  重定向到另一个ActionStream(stream)                  把一个InputStream流发送给浏览器(下载用)Velocity(Velocity)              用于与Velocity技术的集成XSLT(xslt)                      用于与XML/XSLT技术的集成PlainText(plaintext)            发送普通文本,通常用来显示JSP页面的源代码

Chain

<!--Chain用途是构成一条动作链:前一个动作把控制权转交给后一个动作,而前一个动作的状态在后一个动作里仍保持着.动作链能不用就不用, 有可能把一套连续动作弄成一团乱.--><package name="package1" extends="struts-default">   <action name="action1" class="...">     <result type="chain">action2</result>   </action>   <action name="action2" class="...">     <result type="chain">        <param name="actionName">action3</param>        <param name="namespace">/namespace2</param>     </result>   </action></package><package name="package2" namespace="/namespace2" extends="struts-default">  <action name="action3" class="...">     <result>/view.jsp</result>  </action></package>

Dispatcher

<!-- 转发到JSP,result默认类型 --><result name="...">/view.jsp</result><!--或者--><result name="...">  <param name="location">/view.jsp</param></result>

HttpHeader

<!-- 把一个HTTP状态发送给浏览器 --><action name="CatchAll">  <result type="httpheader">    <param name="status">404</param>  </result></action>

Redirect

<!-- 重定向 参数:location:重定向的目的地     parse:   表明是否把location参数的值视为一个OGNL表达式来解释,默认值为true--><action name="..." class="...">  <result name="success" type="redirect">    <!-- 内部资源 -->    /jsp/Product.jsp    <!-- Action带动态参数(${userName}值为本Action中的userName属性值) -->    UserAction.action?userName=${userName}    <!--      外部资源(如果需要使用&和+之类的特殊字符必须使用转义序列.如:&改成&amp;)      http://www.google.com?user=1&site=4     转成:http://www.google.com?user=1&amp;site=4    -->    http://www.google.com  </result></action>

RedirectAction

<!-- 重定向到一个Action 参数:actionName:指定重定向Action的名字     namespace: 指定重定向Action的命名空间(没有此参数,与本action同一个命名空间)--><result type="redirectAction">UserAction</result><!-- 或者 --><result type="redirectAction">  <param name="actionName">UserAction</param>  <!-- 参数 -->  <param name="userId">xyz</param>  <param name="area">ga</param><result><!-- 生成URL:UserAction.action?userId=xyz&area=ga -->

PlainText

<!-- 通常被用来发送JSP页面的源代码 --><action name="source_show" class="...">   <result name="success" type="plaintext">/jsp/Menu.jsp</result></action>



Struts2Staglib  
Struts2的S标签
Updated May 10, 2010 by cm2...@gmail.com
        <!-- 访问request必须要加# -->        <p>赋值,取值</p>                <!-- 页面定义变量(本页赋值用name要加#取值),default默认值.-->                 <!-- 赋值字符串要加'',不然是去Action中找对应的变量.value="test"->在Action中找test变量 -->                <s:set id="test1" value="'test1'"></s:set>                 <!-- #request.get('javax.servlet.forward.context_path')必须经过Action转发到jsp才有值,直接访问jsp无值 -->                <s:set id="msg" value="#request.get('javax.servlet.forward.context_path')"/>                s:<s:property value="#msg" default="Struts2"/><br/>                el:${msg}<br/>                                <!-- 取Action中变量的值不用加# -->                <s:property value="user.name"/><br/>                                <!-- Action中的变量放在request中 -->                --${requestScope.user}||<br/>                        <p><b>if标签:</b> If标签用来控制基本的条件处理流程,通常和else标签或者elseif标签连用。(%{}可加可不加)</p>                <!-- test必须,支持表达式(不支持el表达式) -->                                        <s:if test="#request.user!=null">                                        <div>user!=null</div>                        <s:if test="%{#request.user.age>40}">                            <div>中年人</div>                        </s:if>                        <s:elseif test="%{#request.user.age>20}">                            <div>年轻人</div>                        </s:elseif>                        <s:else>                            <div>小孩</div>                        </s:else>                                        </s:if>                <s:else>                        <div>user==null</div>                </s:else>        <p><b>iterator标签:</b> 对集合迭代 </p>                迭代List<br/>                <!-- 判断是否为空 -->                <s:if test="(userList!=null)&&(!userList.isEmpty())">                        <div>userList</div>                                                <s:iterator value="#request.userList" id="u" status="st">                                index:<s:property value="#st.index+1"/>&nbsp;                                是否第一个:<s:property value="#st.first"/>&nbsp;                                是否最后一个:<s:property value="#st.last"/>&nbsp;                                是否偶数:<s:property value="#st.even"/>&nbsp;                                是否奇数:<s:property value="#st.odd"/>&nbsp;                                <br/>                                   <s:property value="#u.name"/>&nbsp;                                <s:property value="#u.age"/>&nbsp;                                <!-- 格式化日期 -->                                <s:date name="#u.birthday" format="yyyy-MM-dd HH:mm:ss" />&nbsp;                                <br/>                        </s:iterator>                </s:if>                <s:else>                        <div>null</div>                </s:else>                迭代Map<br/>                <s:if test="(userMap!=null)&&(!userMap.isEmpty())">                        <div>userMap</div>                                                <s:iterator value="#request.userMap" id="map" status="st">                                index:<s:property value="#st.index+1"/>&nbsp;                                是否第一个:<s:property value="#st.first"/>&nbsp;                                是否最后一个:<s:property value="#st.last"/>&nbsp;                                是否偶数:<s:property value="#st.even"/>&nbsp;                                是否奇数:<s:property value="#st.odd"/>&nbsp;                                <br/>                                   <s:property value="#map.key"/>&nbsp;                                <s:property value="#map.value.name"/>&nbsp;                                <s:property value="#map.value.age"/>&nbsp;                                <!-- 格式化日期 -->                                <s:date name="#map.value.birthday" format="yyyy-MM-dd HH:mm:ss" />&nbsp;                                <br/>                        </s:iterator>                </s:if>                <s:else>                        <div>null</div>                </s:else>                                <p><b>append标签:</b> 对多个集合进行合并 </p>                <br/>                                合并List <br/>                <s:append id="newList">                        <s:param value="#request.userList"></s:param>                        <s:param value="#request.userList"></s:param>                </s:append>                <s:iterator value="#newList" id="u" status="st">                        index:<s:property value="#st.index+1"/>&nbsp;                        是否第一个:<s:property value="#st.first"/>&nbsp;                        是否最后一个:<s:property value="#st.last"/>&nbsp;                        是否偶数:<s:property value="#st.even"/>&nbsp;                        是否奇数:<s:property value="#st.odd"/>&nbsp;                        <br/>                           <s:property value="#u.name"/>&nbsp;                        <s:property value="#u.age"/>&nbsp;                        <!-- 格式化日期 -->                        <s:date name="#u.birthday" format="yyyy-MM-dd HH:mm:ss" />&nbsp;                        <br/>                </s:iterator>                           <br/>                                List和Map合并,结果为Map <br/>                <s:append id="newListMap">                        <s:param value="#request.userList"></s:param>                        <s:param value="#request.userMap"></s:param>                </s:append>                                <s:iterator value="#newListMap" id="map" status="st">                        index:<s:property value="#st.index+1"/>&nbsp;                        是否第一个:<s:property value="#st.first"/>&nbsp;                        是否最后一个:<s:property value="#st.last"/>&nbsp;                        是否偶数:<s:property value="#st.even"/>&nbsp;                        是否奇数:<s:property value="#st.odd"/>&nbsp;                        <br/>                           <s:property value="#map.key"/>&nbsp;                        <s:property value="#map.value.name"/>&nbsp;                        <s:property value="#map.value.age"/>&nbsp;                        <!-- 格式化日期 -->                        <s:date name="#map.value.birthday" format="yyyy-MM-dd HH:mm:ss" />&nbsp;                        <br/>                </s:iterator>                                <!-- 显示栈里的参数信息 -->                <s:debug></s:debug>


Struts2FormTaglib  
Struts2表单标签
Updated May 10, 2010 by cm2...@gmail.com
        <!--          action="userAction!%{tip}"动态方法tip为Action中的变量 submit不加method        -->        <s:form action="userAction" namespace="/form" method="POST">                <!-- userBean.id为Action中属性userBean中id的值 -->                <s:hidden name="userBean.id"></s:hidden>                <s:textfield name="userBean.name" label="用户名" ></s:textfield>                <s:textfield name="userBean.age" label="年龄" ></s:textfield>                <s:textfield name="userBean.birthday" label="生日" >                        <!-- 格式化日期 -->                        <s:param name="value">                            <s:date name="userBean.birthday" format="yyyy-MM-dd" />                        </s:param>                </s:textfield>                <!-- 密码不能回填 -->                <s:password name="userBean.password" label="密码" ></s:password>                <s:textarea name="userBean.des" label="描述" cols="35" rows="8"></s:textarea>                                <!-- 这种checkbox显示出来是一行只有一个checkbox                <s:iterator value="likeList">                        <s:checkbox name="userBean.likes" label="%{name}" fieldValue="%{id}"></s:checkbox>                </s:iterator>                -->                <!-- 这种是一行多个 -->                <s:checkboxlist list="likeList" name="userBean.likes" listKey="id" listValue="name" label="爱好"></s:checkboxlist>                                <!-- 下拉框                <s:select list="likeList" listKey="id" listValue="name" headerKey="-1" headerValue="请选择爱好"></s:select>                -->                <!-- value="1" 设置默认,但是好像设置了不能回填 -->                <s:radio list="#{'1':'男','2':'女'}" label="性别"  name="userBean.sex"></s:radio>                 <!-- value显示值,method调用方法 -->                <s:submit value="%{tip}" id="submitBut" method="%{tip}"></s:submit>        </s:form>



Struts2FileUpload  
Struts2文件上传下载
Struts2
Updated Apr 26, 2010 by coderro...@gmail.com

文件上传

1.jsp页面

<s:form action="fileAction" namespace="/file" method="POST" enctype="multipart/form-data">    <!-- name为后台对应的参数名称 -->    <s:file name="files" label="file1"></s:file>    <s:file name="files" label="file2"></s:file>    <s:file name="files" label="file3"></s:file>    <s:submit value="提交" id="submitBut"></s:submit></s:form>

2.Action

//单个文件上传可以用 File files,String filesFileName,String filesContentType//名称要与jsp中的name相同(三个变量都要生成get,set)private File[] files;// 要以File[]变量名开头private String[] filesFileName;// 要以File[]变量名开头private String[] filesContentType;private ServletContext servletContext;//Action调用的上传文件方法public String execute() {      ServletContext servletContext = ServletActionContext.getServletContext();      String dataDir = servletContext.getRealPath("/file/upload");      System.out.println(dataDir);      for (int i = 0; i < files.length; i++) {            File saveFile = new File(dataDir, filesFileName[i]);            files[i].renameTo(saveFile);      }      return "success";}

3.配置上传文件临时文件夹(在struts.xml中配置)

<constant name="struts.multipart.saveDir" value="c:/temp"/>

文件下载

1.下载的url(到Action)

<a href="${pageContext.request.contextPath}/file/fileAction!down.action">下载</a>

2.struts.xml配置

    <package name="file" namespace="/file" extends="struts-default">        <action name="fileAction" class="com.struts2.file.FileAction">               <!-- 下载文件配置 -->            <!--type 为 stream 应用 StreamResult 处理-->            <result name="down" type="stream">                <!--                        不管实际类型,待下载文件 ContentType 统一指定为 application/octet-stream                         默认为 text/plain                -->                <param name="contentType">application/octet-stream</param>                <!--                         默认就是 inputStream,它将会指示 StreamResult 通过 inputName 属性值的 getter 方法,                                      比如这里就是 getInputStream() 来获取下载文件的内容,意味着你的 Action 要有这个方法                 -->                             <param name="inputName">inputStream</param>                <!--                         默认为 inline(在线打开),设置为 attachment 将会告诉浏览器下载该文件,filename 指定下载文                         件保有存时的文件名,若未指定将会是以浏览的页面名作为文件名,如以 download.action 作为文件名,                                      这里使用的是动态文件名,${fileName}, 它将通过 Action 的 getFileName() 获得文件名                 -->                             <param name="contentDisposition">attachment;filename="${fileName}"</param>                <!-- 输出时缓冲区的大小 -->                <param name="bufferSize">4096</param>            </result>                    </action>    </package>

3.Action

        //Action调用的下载文件方法        public String down() {                return "down";        }                //获得下载文件的内容,可以直接读入一个物理文件或从数据库中获取内容        public InputStream getInputStream() throws Exception {                String dir = servletContext.getRealPath("/file/upload");                File file = new File(dir, "icon.png");                if (file.exists()) {                        //下载文件                        return new FileInputStream(file);                                                //和 Servlet 中不一样,这里我们不需对输出的中文转码为 ISO8859-1                        //将内容(Struts2 文件下载测试)直接写入文件,下载的文件名必须是文本(txt)类型                        //return new ByteArrayInputStream("Struts2 文件下载测试".getBytes());                }                return null;        }        // 对于配置中的 ${fileName}, 获得下载保存时的文件名        public String getFileName() {                String fileName ="图标.png";                try {                        // 中文文件名也是需要转码为 ISO8859-1,否则乱码                        return new String(fileName.getBytes(), "ISO8859-1");                } catch (UnsupportedEncodingException e) {                        return "icon.png";                }        }







Struts2JSON  
Struts2返回JSON
Updated May 10, 2010 by cm2...@gmail.com

1.导入jsonplugin包

Struts2.16:导入jsonplugin-0.34.jar包(下载包)和commons-logging-1.0.4.jar(Struts2 lib下有)

Struts2.18导入struts2-json-plugin-2.1.8.1.jar(Struts2 lib下有)

2.struts.xml中package 中extends="json-default"

<package name="json" namespace="/json" extends="json-default">

3.result 中type="json"

<!-- 封装所以的get开头的方法 --><result type="json" name="user"></result><!-- 只包含user.id属性 --><result type="json" name="user">    <param name="includeProperties">                       user\.id    </param></result><!-- 不包含user属性 --><result type="json" name="list">    <param name="excludeProperties">                       user    </param></result><!-- 根对象只包含user --><result type="json">      <param name="root">          user    </param>  </result> <!-- "root"对象中父类的field(属性)不会(会?) 默认存放到 JSON数据中,如果不想这样做,需要在配置时指定 ignoreHierarchy 为 false:  --><result type="json">      <param name="ignoreHierarchy">false</param>  </result> 

4.避免使用get开头的action方法

在属性get方法上面加@JSON(name="newName")json中的名称@JSON(serialize=false) 属性不被加入json@JSON(format="yyyy-MM-dd") 格式化日期

5.在action中赋值,返回对应的result字符串


Struts2XML  
Struts2返回XML
Updated May 10, 2010 by cm2...@gmail.com

使用response

        //直接调用responseOut方法        public void responseOut() throws Exception {                StringBuilder sb = new StringBuilder();                sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");                sb.append("<users>");                sb.append("     <user id=\"50\">");                sb.append("             <userName>abc</userName>");                sb.append("     </user>");                sb.append("</users>");                                //得到response                HttpServletResponse response = ServletActionContext.getResponse();                //设置编码                response.setCharacterEncoding("UTF-8");                response.setContentType("text/xml;charset=utf-8");                response.setHeader("Cache-Control", "no-cache");                PrintWriter out = response.getWriter();                out.write(sb.toString());                out.flush();                out.close();        }



Struts2CRUD  
Struts2增删改查例子
Updated May 10, 2010 by cm2...@gmail.com

UserBean

//要添加set,getpublic class UserBean {         private Long id;        private String name;            private String password;                private int age;                private Date birthday;          private Long sex;               private Set<Long> likes;                private String des;//描述}public class LikeBean {         private Long id;        private String name;}

FormAction

   public class FormAction{        //属性要生成get,set        //标记(添加,修改)        private String tip;             private UserBean userBean;              private List<LikeBean> likeList;                private List<UserBean> userList;        //到列表页面         public String list(){                userList = new ArrayList<UserBean>();                userList.add(new UserBean("abc",19,new Date()));                userList.add(new UserBean("def",70,new Date()));                userList.add(new UserBean("ghi",40,new Date()));                return "list";        }        //到添加页面        public String toAdd(){                likeList = new ArrayList<LikeBean>();                likeList.add(new LikeBean(new Long(1),"上网"));                likeList.add(new LikeBean(new Long(2),"读书"));                likeList.add(new LikeBean(new Long(3),"游戏"));                                tip = "add";                return "info";        }        //添加方法,Struts2会自动把对应的值赋值给userBean        public String add(){                System.out.println(userBean);                return "toList";        }        //到更新页面,取出值,设置标记        public String toUpdate(){                likeList = new ArrayList<LikeBean>();                likeList.add(new LikeBean(new Long(1),"上网"));                likeList.add(new LikeBean(new Long(2),"读书"));                likeList.add(new LikeBean(new Long(3),"游戏"));                                tip = "update";                System.out.println("update name:"+userBean.getName());                userBean = new UserBean("update",100,new Date());                userBean.setId(new Long(101));                userBean.setSex(new Long(2));                userBean.setDes("Struts2用户");                Set<Long> likes = new HashSet<Long>();                likes.add(new Long(2));                likes.add(new Long(3));                userBean.setLikes(likes);                return "info";        }        //更新方法        public String update(){                System.out.println(userBean);                return "toList";        }        //删除方法        public String delete(){                System.out.println("del name:"+userBean.getName());                return "toList";        }   }

struts.xml配置

<struts>    <package name="form" namespace="/form" extends="struts-default">        <!-- 使用通配符调用多个方法,method为*对应的字符串 -->        <action name="userAction_*" class="com.struts2.form.FormAction" method="{1}">            <!-- 方法返回的字符串对应name,再转发到页面 -->            <result name="list">/form/list.jsp</result>            <result name="info">/form/info.jsp</result>            <!-- 重定向Action,可以有Action名字和空间,参数 -->            <result name="toList" type="redirectAction">                <!-- 空间参数,不写代表和当前Action同一个空间                <param name="namespace">form</param>                 -->                <!-- 重定向Action的名称 -->                <param name="actionName">userAction_list</param>                <!-- url带的参数,${userBean.name}是动态参数,值为Action的属性userBean中name的值 -->                <param name="userName">${userBean.name}</param>                <param name="userAge">${userBean.age}</param>            </result>                    </action>    </package></struts>

jsp页面

1.list(列表页面)

<!-- 添加标签 --><%@ taglib prefix="s" uri="/struts-tags" %>        <div><a href="${pageContext.request.contextPath}/form/userAction_toAdd.action">添加</a></div>        <div>                <!-- 判断用户是否为空 -->                <s:if test="(userList!=null)&&(!userList.isEmpty())">                        <div>用户列表</div>                        <!-- 遍历用户 -->                        <s:iterator value="#request.userList" id="u" status="st">                                <s:property value="#st.index+1"/>&nbsp;                                <s:property value="#u.name"/>&nbsp;                                <s:property value="#u.age"/>&nbsp;                                <!-- 格式化日期 -->                                <s:date name="#u.birthday" format="yyyy-MM-dd HH:mm:ss" />&nbsp;&nbsp;&nbsp;&nbsp;                                <a href="${pageContext.request.contextPath}/form/userAction_toUpdate.action?userBean.name=${u.name}">修改</a>&nbsp;&nbsp;&nbsp;&nbsp;                                <a href="${pageContext.request.contextPath}/form/userAction_delete.action?userBean.name=${u.name}">删除</a>                                <br/>                        </s:iterator>                </s:if>                <s:else>                        <div>无用户</div>                </s:else>        </div>

2.info.jsp(添加和修改页面)

<!-- 添加标签 --><%@ taglib prefix="s" uri="/struts-tags" %>        <!-- 显示标记(添加/修改) -->        <s:property value="tip"/>        <!-- action="userAction_%{tip}"tip为Action中的标记变量 submit不加method -->        <s:form action="userAction" namespace="/form" method="POST">                <!-- userBean.id为Action中属性userBean中id的值 -->                <s:hidden name="userBean.id"></s:hidden>                <s:textfield name="userBean.name" label="用户名" ></s:textfield>                <s:textfield name="userBean.age" label="年龄" ></s:textfield>                <s:textfield name="userBean.birthday" label="生日" >                        <!-- 格式化日期 -->                        <s:param name="value"><s:date name="userBean.birthday" format="yyyy-MM-dd" /></s:param>                </s:textfield>                <!-- 密码不能回填 -->                <s:password name="userBean.password" label="密码" ></s:password>                <s:textarea name="userBean.des" label="描述" cols="35" rows="8"></s:textarea>                                <!-- 这种checkbox显示出来是一行只有一个checkbox                 <s:iterator value="likeList">                        <s:checkbox name="userBean.likes" label="%{name}" fieldValue="%{id}"></s:checkbox>                </s:iterator>                -->                <!-- 这种是一行多个 -->                 <s:checkboxlist list="likeList" name="userBean.likes" listKey="id" listValue="name" label="爱好"></s:checkboxlist>                                <!-- 下拉框                <s:select list="likeList" listKey="id" listValue="name" headerKey="-1" headerValue="请选择爱好"></s:select>                -->                <!-- value="1" 设置默认,但是好像设置了不能回填 -->                <s:radio list="#{'1':'男','2':'女'}" label="性别"  name="userBean.sex"></s:radio>                <s:submit value="%{tip}" id="submitBut" method="%{tip}"></s:submit>        </s:form>



Struts2I18n  
Struts2国际化
Updated May 10, 2010 by cm2...@gmail.com

1.定义properties文件

资源文件查找顺序

JAVA国际化如果系统同时存在资源文件、类文件,系统将以类文件为主,而不会调用资源文件。对于简体中文的LocaleResourceBundle搜索资源的顺序是:(1)baseName_zh_CN.class(2)baseName_zh_CN.properties(3)baseName_zh.class(4)baseName_zh.properties(5)baseName.class(6)baseName.properties/* Struts2找不到对应语言的配置文件时,会先找系统语言对应的配置文件,再找不到才使用baseName.properties */

国际化分为三类:全局的,包级别的,类级别的

  全局的:   1.struts.xml中的<constant name="struts.custom.i18n.resources" value="message"></constant>指定baseName   国际化文件名为:baseName_语言名_国家名.properties(如:message_zh_CN.properties   2.全局的国际化资源文件放在src下面  包级别的:   1.包级别的国际化资源文件放在该包下面   2.命名规则为:package_语言名_国家名.properties(如:package_zh_CN.properties)      其中package不变,不是指的是包名,每个包的国际化文件命名都这样    类级别的:   1.与该类放在同一目录中   2.命名规则为:类名_语言名_国家名.properties(如:RegisterAction_zh_CN.properties     若同一key 在上面三个国际化文件中都为value值则:(优先级)类级别的>包级别的>全局的

2.在jsp中访问国际化资源文件

  <!-- 输出国际化 -->  <!-- name为国际化文件中的key -->  <s:text name="hello">                <!-- 若该国际化文件的value中有{0}则可用下面的标签把参数传进去 -->                <s:param>mengya</s:param>                <s:param><s:property value="firstName"/></s:param>  </s:text>    <s:property value="%{getText('customer.contact')}"/>  传参数  <s:property value="%{getText('customer.contact','sh')}"/>    定义变量,加var属性  <s:text name="greetings" var="msg"/>  <s:property value="#msg"/>    <!-- 指定特定的国际化文件,name为全局国际化文件的baseName -->  <s:i18n name="temp">   <!-- 下面的<s:text>标签与上面的用法一样 -->   <s:text name="hello">    <s:param>mengya</s:param>   </s:text>  </s:i18n>    表单国际化:   1.theme不能为simple如:<s:form action="register">(默认的theme不是simple)   2.使用key如:<s:textfield name="username" key="" id="usernameId"></s:textfield>   3.或者使用getText方法<s:textfield name="username" label="%{getText('customer.name')}"/>

3.在Action中访问国际化资源文件,该Action继承了ActionSupport类

  this.getText("username.invalid")  若该key对应的value需要参数则:  this.getText("username.invalid",new String[]{username})    List list = new ArrayList();  list.add(username);  this.getText("username.invalid",list)  如:  if (null == username || username.length() < 6 || username.length() > 10)  {   List list = new ArrayList();   list.add(username);   this.addActionError(this.getText("username.invalid",new String[]{username}));  }  该国际化资源文件中的keyvalue为:  username.invalid = \u7528\u6237\u540d "{0}" \u586b\u5199\u4e0d\u6b63\u786e

4.在输入验证框架访问国际化资源文件

  <!-- 使用<message key="..."></message> ->  <field-validator type="requiredstring">           <param name="trim">true</param>           <message key="username.invalid"></message>  </field-validator>

5.动态改变语言

只有在url传入request_locale=en_US就可以指定为en_US的语言

1.如果配置文件是en_US结尾,传入en,en_US都可以找到

2.如果配置文件是en结尾,只能传入en,传入en_US会找不到,从而找默认的配置文件(en的范围>en_US,使用英语的国家不止美国一个)

<a  href="${pageContext.request.contextPath}/i18n/i18nAction?request_locale=en_US">English</a>

6.使用类来代替properties文件

//继承ListResourceBundle实现getContents方法public class MyCustomResourceBundle extends ListResourceBundle {    public Object[][] getContents() {        if (Calendar.getInstance().get(Calendar.HOUR_OF_DAY) < 12) {            return contents1;        } else {            return contents2;        }    }    static final Object[][] contents1 = {             { "greetings", "中午好 {0}" },            { "farewell", "再见" } };    static final Object[][] contents2 = {             { "greetings", "你好 {0}" },            { "farewell", "再见" } };}//en对应的字符串public class MyCustomResourceBundle_en extends ListResourceBundle {    public Object[][] getContents() {        if (Calendar.getInstance().get(Calendar.HOUR_OF_DAY) < 12) {            return contents1;        } else {            return contents2;        }    }    static final Object[][] contents1 = {             { "greetings", "Good morning {0}" },            { "farewell", "Good bye" } };    static final Object[][] contents2 = {             { "greetings", "Hello {0}" },            { "farewell", "Good bye" } };}//jsp中使用<s:i18n name="com.resourcebundle.MyCustomResourceBundle">    <s:text name="greetings">        <s:param>Jon</s:param>    </s:text>.    <s:text name="farewell"/></s:i18n>




Struts2Validator  
Struts2验证框架
Updated Jun 18, 2010 by cm2...@gmail.com

Action配置中一定要设置input返回页面

添加验证只要创建验证的xml文件

1.创建xml文件名

验证Action中全部方法

在Action同包下,创建:Action类名-validation.xml
如:ValidateAction创建ValidateAction-validation.xml

验证Action中单个方法

<!-- 每个方法单独配置一个Action --><!-- 在Action同包下,创建:Action类名-action方法配置名称-validation.xml --><action name="validateAdd" class="com.struts2.validator.ValidateAction" method="add"><!-- 要创建ValidateAction-validateAdd-validation.xml --><!-- 使用通配符配置 --><!-- 在Action同包下,创建:Action类名-action方法对应的名称-validation.xml --><action name="validate_*" class="com.struts2.validator.ValidateAction" method="{1}"><!-- 要创建ValidateAction-validate_add-validation.xml,validate_add为访问这个action方法的路径 -->

注意事项

注意:1.要验证的方法不能叫input.2.这样配置在form表单中要在<s:form action="validate_add">中action写好名称,不能写action="validate_",然后<s:submit value="提交"method="add" /> 这样会找不到对应的配置文件,跳过验证.3.如果验证出错,返回input页面时,那些存在ValueStack中的值会丢失,可以将Action实现Preparable接口,然后prepare()方法里初始化添加页面需要的值.4.如果使用Preparable接口,必须在action配置中添加<interceptor-ref name="paramsPrepareParamsStack" />.这样prepare()才能得到form提交的参数.

2.创建xml内容

<!DOCTYPE validators PUBLIC  "-//OpenSymphony Group//XWork Validator 1.0.2//EN"  "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"><validators>         <!-- 要验证的字段名称 -->        <!-- 要验证Action中UserBean的id字段,name="userBean.id"(userBean为Action中的变量名) -->    <field name="mail">        <!-- type要验证的类型,short-circuit(默认false),true含义,如果当前验证失败了,下面的验证就不执行了.如requiredstring失败了,email就不验证了. -->        <!-- field-validator下面可以有多个param元素,但是最多只能有一个message -->        <field-validator type="requiredstring">            <param name="trim">true</param>            <message>Please enter a mail</message>        </field-validator>        <field-validator type="email">                <message>                        Invalid MAIL                </message>        </field-validator>    </field></validators>

Struts内建验证程序(type的值)

required

保证字段的值不是空值null.空字符串不是空值null.

<field name="userName">    <field-validator type="required">        <message>Please enter a user name</message>    </field-validator></field>

requiredstring

保证字段不是空值null,也不是空白(empty).
param:trim(boolean) ->true->去除前后空格

<field name="userName">    <field-validator type="requiredstring">        <param name="trim">true</param>        <message>Please enter a user name</message>    </field-validator></field><field name="password">    <field-validator type="requiredstring">        <param name="trim">false</param>        <message>Please enter a password</message>    </field-validator></field>

int

验证字段值是否可以转换为一个整数.
param: min(int);max(int)

 <field name="yeaar">        <field-validator type="int">            <param name="min">1999</param>             <param name="max">2010</param>            <message>year:1999-2010</message>        </field-validator></field>

date

验证给定日期字段的值是否在一个给定的范围内.
param:max(date);min(date)

 <field name="borthday">        <field-validator type="int">            <!-- 格式取决于当前地理时区 -->            <param name="min">1999-01-01</param>             <param name="max">2010-01-01</param>            <message>birthday:1999-2010</message>        </field-validator></field>

email

给定的String值是否是一个电子邮件地址

<field name="email">    <field-validator type="email">        <message>Invalid email</message>    </field-validator></field>

url

给定的String值是否是一个合法的URL(要有前缀)

<field name="url">    <field-validator type="url">        <message>Invalid URL</message>    </field-validator></field>

expression,fieldexpression

验证给定字段是否满足一个OGNL表达式.
区别:expression 不是一个字段验证程序,失败时将生成一个动作错误.(JSP中调用

<actionerror>
</actionerror>
才显示出错信息)
fieldexpression 是一个字段验证程序,失败时将抛出一个字段错误.(对字段验证)
param:expression(String)OGNL表达式

expression:

public class ExpressionTestAction {        //属性生成get,set    private int min;    private int max;}<validator type="expression">    <param name="expression">        max > min    </param>    <message>        Maximum temperature must be greater than Minimum temperature    </message></validator><!-- jsp --><s:actionerror/>

fieldexpression:

public class FieldExpressionTestAction {        //属性生成get,set    private int min;    private int max;}<!-- 对字段验证 --><field name="max">    <field-validator type="fieldexpression">        <param name="expression">            max > min        </param>        <message>            Maximum temperature must be greater than Minimum temperature        </message>    </field-validator></field>

visitor

把同一个验证程序配置文件用于多个动作(对一个Bean写验证文件,每个使用的Action只要引用)

//UserBeanpublic class UserBean {        //属性get,set        private String name;        private int age;}//UserBean-validation.xml(和UserBean放在同一个包中)<field name="name">    <field-validator type="requiredstring">        <message>用户名必须</message>    </field-validator></field><field name="age">    <field-validator type="int">        <param name="min">18</param>        <param name="max">99</param>        <message>Age must be between 18 and 99</message>    </field-validator></field>//Actionvalidation.xml<!-- userBean变量名 --><field name="userBean">    <field-validator type="visitor">        <!-- message会和UserBean验证中的message一起显示 -->        <message>用户: </message>    </field-validator></field>

如果另一个Action对UserBean使用另一个标准的验证,可以创建新的验证文件

//UserBean-specific-validation.xml<!-- 和之前的验证不同 --><field name="age">    <field-validator type="int">        <param name="min">30</param>        <param name="max">50</param>        <message>Age must be between 30 and 50</message>    </field-validator></field>//另一个Actionvalidation.xml<field name="userBean">    <field-validator type="visitor">        <!-- xml中扩展的名字,执行UserBean-specific-validation.xml的验证 -->        <param name="context">specific</param>        <message>用户1: </message>    </field-validator></field>

conversion

检查对某个属性进行类型转换是否会导致一个转换错误

<field name="age">    <field-validator type="conversion">        <message>            An age must be an integer.        </message>    </field-validator></field>

stringlength

验证一个非空的字段值是不是足够的长度
param:minLength(int);maxLength(int);trim(boolean)

 <field name="password">        <field-validator type="requiredstring">            <param name="minLength">6</param>             <param name="maxLength">14</param>            <message>length:6-14</message>        </field-validator></field>

regex

给定的值是否与一个给定的正则表达式匹配
param:expression(String)正则表达式;caseSensitive(boolean)是否区别大小写,默认为true;trim(boolean)是否去除前后空格

<field name="phone">    <field-validator type="regex">        <param name="expression">            <![CDATA[\d\d\d\-\d\d\d\-\d\d\d\d]]>        </param>        <message>            Invalid phone number or invalid format        </message>    </field-validator></field>

3.在action中验证

利用Validateable接口实现验证,实现void validate()方法.
ActionSupport类已经实现了这个接口

//继承ActionSupportpublic class User extends ActionSupport {    //属性get,set    private String userName;    private String password;    private static List<String> userNames = new ArrayList<String>();    static {        userNames.add("harry");        userNames.add("sally");    }    //验证方法    public void validate() {        if (userNames.contains(userName)) {                        //添加出错信息            addFieldError("userName",  "'" + userName + "' has been taken.");        }    }}

4.自定义验证类

要创建一个普通的验证程序(非字段验证程序),扩展ValidatorSupport类.验证失败要从validate方法调用addActionError方法.
要创建一个字段验证程序,扩展FieldValidatorSupport类.验证失败要从validate方法调用addFieldError方法.
如果要能接受参数,要在类中定义一个相应的属性,并生成get,set.

编写类

public class StrongPasswordValidator extends FieldValidatorSupport {        //属性    private int minLength = -1;    public void setMinLength(int minLength) {        this.minLength = minLength;    }    public int getMinLength() {        return minLength;    }        //验证方法    public void validate(Object object) throws ValidationException {        String fieldName = getFieldName();        String value = (String) getFieldValue(fieldName, object);        if (value == null || value.length() <= 0) {            // use a required validator for these            return;        }        if ((minLength > -1) && (value.length() < minLength)) {            addFieldError(fieldName, object);        } else if (!isPasswordStrong(value)) {            addFieldError(fieldName, object);        }    }        private static final String GROUP_1 = "abcdefghijklmnopqrstuvwxyz";    private static final String GROUP_2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";    private static final String GROUP_3 = "0123456789";    protected boolean isPasswordStrong(String password) {        boolean ok1 = false;        boolean ok2 = false;        boolean ok3 = false;        int length = password.length();        for (int i = 0; i < length; i++) {            if (ok1 && ok2 && ok3) {                break;            }            String character = password.substring(i, i + 1);            System.out.println("character:" + character);            if (GROUP_1.contains(character)) {                ok1 = true;                continue;            }            if (GROUP_2.contains(character)) {                ok2 = true;                continue;            }            if (GROUP_3.contains(character)) {                ok3 = true;            }        }        return (ok1 && ok2 && ok3);    }    }

注册xml

在src下创建validators.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC  "-//OpenSymphony Group//XWork Validator Config 1.0//EN"  "http://www.opensymphony.com/xwork/xwork-validator-config-1.0.dtd"><validators>        <!-- 名称(type对应值),类路径 -->    <validator name="strongpassword"  class="com.validator.StrongPasswordValidator"/></validators>

使用验证

<field name="password">    <field-validator type="strongpassword">        <param name="minLength">8</param>        <message>            Password must be at least 8 characters long            and contains at least one lower case character,            one upper case character, and a digit.        </message>    </field-validator></field>


0 0
原创粉丝点击