Struts2学习笔记

来源:互联网 发布:2016高校网络舆情事件 编辑:程序博客网 时间:2024/06/04 20:05

Struts2简介:
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构差别巨大。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts 2可以理解为WebWork的更新产品。虽然从Struts 1到Struts 2有着太大的变化,但是相对于WebWork,Struts 2的变化很小。

struts2开发环境搭建 2.1.7版本需要以下几个jar包:
1.引入struts2需要的jar文件
struts2-core.jar 核心jar包
xwork-core.jar xwork核心jar包
ognl.jar ognl表达式
freemarker.jar FreeMarker模板
commons-logging.jar 日志
commons-fileupload.jar 文件上传
commons-io.jar 文件上传依赖的包
可以从struts2自带的示例项目中拷贝,粘贴到WebRoot/WEB-INF/lib下面)
2.编写struts2的配置文件(可以从struts2自带的示例项目中拷贝struts.xml,粘贴到src目录下,然后在这个基础上按照自己的需要来更改)
3.在web.xml中加入struts2框架启动配置,具体的方法是在web.xml中加入如下的代码:

<filter>      <filter-name>struts2</filter-name>      <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>  </filter>  <filter-mapping>      <filter-name>struts2</filter-name>      <url-pattern>/*</url-pattern>  </filter-mapping>  

struts.xml 属性介绍

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"    "http://struts.apache.org/dtds/struts-2.3.dtd"><struts>    <constant name="struts.enable.DynamicMethodInvocation" value="false" />    <constant name="struts.devMode" value="true" />    <package name="default" namespace="/" extends="struts-default">        <action name="hello" class="cn.xia.struts2.action.HelloAction" method="execute">            <result name="success">/hello.jsp</result>        </action>    </package></struts>

struts2中使用包来管理action。包的作用和java中类包是非常类似的,它主要用于管理一组业务功能相关的action。在实际应用中,应该把一组业务功能相关的action放在同一个包下面。
配置包是必须指定name属性,该name可以随意取名,但是必须唯一,它不对应java的类包,如果其他类要继承该包,必须使用该属性进行使用。包的namespace属性用于定义包的命名空间,命名空间作为该action路径的一部分,如访问上面的例子中的action的路径为:/upload/upload.action。namespace属性可以不用配置,如果不指定该属性,默认的命名空间为“”(空字符串)。
通常每个包都必须继承struts-default包,因为struts很多核心的功能都是在这个包中定义的拦截器实现的,如:从请求中把请求参数封装到action、文件上传和数据验证等功能搜是通过拦截器实现的。struts-default包中定义了这些拦截器和result类型。换句话说,当包继承了strtus-default包才能使用struts提供的核心功能。struts-default包是在struts2-core-2.x.x.x.jar文件中的struts-default.xml中定义的。struts-default.xml是struts2的默认配置文件,struts2每次都会自动加载struts-default.xml文件。
包还可以通过abstract=“true”定义为抽象包,抽象包中不能包含action。
注意,在配置文件struts.xml中没有提示的解决办法:window->preference->xml catalog中添加struts-2.3.dtd文件,key type为URI,key为“-//Apache Software Foundation//DTD Struts Configuration 2.3//EN”
struts-2.3.dtd文件在哪里找?
打开struts2的集合包–>src–>core–>src–>main–>resources目录下找。

action名称的搜索顺序
1.获得请求的URI,例如uri是:http://server/struts2/path1/path2/path3/test.action
2.首先寻找namesp为/path1/path2/path3的package,如果不存在这个package,就转第三步,如果存在这个package,则在这个package中寻找名字为test的action,当在该package中找不到action时就到默认namespace的package中寻找(默认package的命名空间为空字符串“”),如果在默认的package中还找不到该action,页面提示找不到action。
3.寻找namespace为/path1/path2的package,如果不存在这个package,则转第四步,如果存在这个package,则在这个package中寻找名字为test的action,当在该package中找不到action时就到默认namespace的package中寻找(默认package的命名空间为空字符串“”),如果在默认的package中还找不到该action,页面提示找不到action。
4.寻找namespace为/path1的package,如果不存在这个package,则转第五步,如果存在这个package,则在这个package中寻找名字为test的action,当在该package中找不到action时就到默认namespace的package中寻找(默认package的命名空间为空字符串“”),如果在默认的package中还找不到该action,页面提示找不到action。
5.寻找namespace为/的package,如果存在这个package,则在这个package中寻找名字为test的action,当在该package中找不到action或不存在这个package时就到默认namespace的package中寻找(默认package的命名空间为空字符串“”),如果在默认的package中还找不到该action,页面提示找不到action。

action配置中的默认值:
如果没有为action指定class,默认的class是ActionSupport。
如果没有为action指定method,默认执行action中的execute方法。
如果没有为result指定name属性,默认值为success

为应用指定多个struts配置文件
在大部分应用里,随着应用规模的增加,系统中action的数量也会大量增加,导致struts.xml配置文件变的非常臃肿。为避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,可以将一个struts.xml文件分解成过个配置文件,然后在struts.xml文件中包含其他的配置文件。下面的struts.xml文件通过include元素指定多个配置文件:

<?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>    <include file="department.xml"></include>    <include file="employee.xml"></include>    <include file="upload.xml"></include>    <include file="interceptor.xml"></include></struts>

动态方法调用
在配置文件的action中不指定method,而是在访问的时候通过actionname!methodname这种方式来访问,前提是struts.enable.DynamicMethodInvocation要设置为true。

使用通配符的定义action

<package name="employee" namespace="/employee" extends="struts-default">    <action name="helloworld_*" class="zhchljr.action.HelloWorldAction" method="{1}">        <param name="savepath">employee</param>        <result name="success">/employeeAdd.jsp?username=${username}</result>    </action></package>

为action的属性注入值
struts2为action的属性提供了依赖注入功能,在struts2的配置文件中,可以很方便的为action中的属性值注入值。注意,属性必须有setter方法。

<action name="helloworld_*" class="zhchljr.action.HelloWorldAction" method="{1}">    <param name="savepath">/upload</param>    <result name="success">/employeeAdd.jsp?username=${username}</result></action>

action中result的各种转发类型
result配置类似于struts1中的forward,但struts2提供了多种结果类型,常用的类型有dispatcher(默认值)、redirect、redirectAction、plainText。
result中还可以使用${属性名}表达式来访问action中的属性,表达式中的属性名为action中的属性名,如下:

<result type="redirect">/employeeAdd.jsp?id=4{id}</result>

下面是结果类型为redirectAction的例子:
重定向到同一个包中的action:

<result type="redirectAction">add</result>

重定向到别的namespace中的action:

<result type="redirectAction">    <param name="actionName">xxx</param>    <param name="namespace">/redirectAction</param></result>

plainText:显示原始文件内容,例如:当需要原样显示jsp文件源代码的时候,就可以使用此类型。

<action name="source">    <result type="plainText">        <param name="location">/index.jsp</param>        <param name="charSet">UTF-8</param> <!--指定读取文件的编码方式-->     </result></action>

struts2.1.6接收中文请求参数乱码的问题是个bug,原因是在获取并使用了请求参数后才调用HttpServletRequest的setCharacterEncoding()方法进行编码设置,导致应用使用的就是乱码参数。这个bug在struts2.1.8中已经被解决,如果使用的是struts2.1.6,要解决这个问题,可以采用下面的方法:
新建一个filter,把这个filter放在struts2的filter前面,然后在doFilter()方法里添加如下的代码:

public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws java.io.IOException,ServletException {    HttpServletRequest req = (HttpServletRequest)request;    req.setCharacterEncoding("UTF-8");//根据实际使用的编码替换    chain.doFilter(request,response);}

文件上传

文件上传在项目中经常会用到,下面就来说说struts2中怎么上传文件的:
1.引入相应的jar包(commons-fileupload-1.2.1.jar和commons-io-1.3.2.jar)
2.把form的enctype设置为”multipart/form-data”,如下所示:

<form action="<%=basePath%>upload/upload.action" method="post" name="form" enctype="multipart/form-data">    文件1:<input type="file" name="upload"/><br/>    <input type="submit" value="上传" /></form>

3.在action类中添加如下代码中注释的几个属性。

public class HelloWorldAction {    private File upload;//得到上传的文件    private String uploadContentType;//得到上传文件的扩展名    private String uploadFileName;//得到上传文件的名称    public File getUpload() {        return upload;    }    public void setUpload(File upload) {        this.upload = upload;    }    public String getUploadContentType() {        return uploadContentType;    }    public void setUploadContentType(String uploadContentType) {        this.uploadContentType = uploadContentType;    }    public String getUploadFileName() {        return uploadFileName;    }    public void setUploadFileName(String uploadFileName) {        this.uploadFileName = uploadFileName;    }    public String upload() throws IOException {        String realpath = ServletActionContext.getServletContext().getRealPath("/upload");        if(upload != null) {            File savefile = new File(realpath,uploadFileName);            if(!savefile.getParentFile().exists()) {                savefile.getParentFile().mkdirs();            }            FileUtils.copyFile(upload, savefile);            ActionContext.getContext().put("msg", "文件上传成功!");        }        return "success";    }}

注意,如果在上传的过程中文件的大小超过了struts2默认的文件大小的话,就会上传失败,这时候,可以根据具体的情况设置struts.multipart.maxSize的值来满足上传的需求。

多文件上传

在实际的项目中,有时候可能会要求上传多个文件的情况,下面就来说说上传多个文件的情况。
1.同上。
2.form如下所示:

<form action="<%=basePath%>upload/upload" method="post" name="form" enctype="multipart/form-data">    文件1:<input type="file" name="upload"/><br/>    文件2:<input type="file" name="upload"/><br/>    文件3:<input type="file" name="upload"/><br/>    <input type="submit" value="上传" /></form>

3.action中添加的几个属性都是数组形式的。

public class HelloWorldAction {    private File[] upload;//得到上传的文件    private String[] uploadContentType;//得到上传文件的扩展名    private String[] uploadFileName;//得到上传文件的名称    public File[] getUpload() {        return upload;    }    public void setUpload(File[] upload) {        this.upload = upload;    }    public String[] getUploadContentType() {        return uploadContentType;    }    public void setUploadContentType(String[] uploadContentType) {        this.uploadContentType = uploadContentType;    }    public String[] getUploadFileName() {        return uploadFileName;    }    public void setUploadFileName(String[] uploadFileName) {        this.uploadFileName = uploadFileName;    }    public String upload() throws IOException {        String realpath = ServletActionContext.getServletContext().getRealPath("/upload");        if(upload != null) {            for(int i=0; i<upload.length; i++) {                File savefile = new File(realpath,uploadFileName[i]);                if(!savefile.getParentFile().exists()) {                    savefile.getParentFile().mkdirs();                }                FileUtils.copyFile(upload[i], savefile);            }            ActionContext.getContext().put("msg", "文件上传成功!");        }        return "success";    }}

自定义拦截器
自定义拦截器要实现com.opensymphony.xwork2.interceptor.Interceptor接口。下面是一个自定义拦截器的例子:

public class PermissionInterceptor implements Interceptor {    public void destroy() {    }    public void init() {    }    public String intercept(ActionInvocation invocation) throws Exception {        Object user = ActionContext.getContext().getSession().get("user");        if(user != null) {            return invocation.invoke();        } else {            ActionContext.getContext().put("message", "你没有执行权限!");        }        return "success";    }}

接下来,就要在配置文件中注册拦截器,具体的做法是:

<interceptors>    <interceptor name="permission" class="zhchljr.interceptor.PermissionInterceptor"></interceptor></interceptors>

为action指定拦截器,具体的做法是:

<action name="interceptor" class="zhchljr.action.HelloWorldAction" method="interceptor">    <interceptor-ref name="permission"></interceptor-ref></action>

但是这样做了以后,就会出现一个问题,struts2中为一个action指定拦截器后,默认的defaultStack中的拦截器就不起作用了,也就是说struts2的众多核心功能都使用不了了(struts2的许多核心功能都是通过拦截器实现的),为了解决这个问题,引入拦截器栈,先使用系统默认的拦截器,然后再来使用自定义的拦截器,具体的做法是:

<interceptors>    <interceptor name="permission" class="zhchljr.interceptor.PermissionInterceptor"></interceptor>    <interceptor-stack name="permissionStack">        <interceptor-ref name="defaultStack"></interceptor-ref>        <interceptor-ref name="permission"></interceptor-ref>    </interceptor-stack></interceptors>

如果希望包下的所有action都使用自定义的拦截器,可以把拦截器设置为默认拦截器,具体的实现方式是:

<default-interceptor-ref name="permissionStack"></default-interceptor-ref>

注意:每个包中只能有一个默认的拦截器;一旦为包中的某个action指定了拦截器,则默认的拦截器就不起作用了。

输入校验
struts2中可以实现对action中的所有方法进行校验,也可以实现对指定的方法进行校验。可以用如下两种方式来实现输入校验。

1.采用手工编写代码实现:
<1>手工编写代码实现对action中的所有方法进行校验:通过编写validate()方法实现,validate()会校验action中所有与execute方法签名相同的方法。当某个数据校验失败时,应该采用addFieldError()方法往系统的filedErrors添加校验失败信息(为了使用该方法,action可以继承ActionSupport),如果系统的filedErrors包含失败信息,struts2会将请求发到名为input的result,在input视图中可以通过<s:fielderror/>显示失败信息。具体的参见下面的例子:

<s:fielderror></s:fielderror><form method="post" action="<%=basePath%>person/manage_save.action">       用户名:<input type="text" name="username"/>不能为空<br/>       手机号:<input type="text" name="mobile"/>不能为空,并且要符合手机号的格式,1,3/5/8,后面是9个数字<br/>       <input type="submit" value="提交"/></form>

页面中使用<s:fielderror></s:fielderror>来显示失败信息

public void validate() {//会对action中的所有方法进行校验    if(this.username == null || this.username.trim().equals("")) {        this.addFieldError("username", "用户名不能为空!");    }    if(this.mobile == null || this.mobile.trim().equals("")) {        this.addFieldError("mobile", "手机号不能为空!");    } else {        if(!Pattern.compile("^1[358]\\d{9}{1}quot;).matcher(this.mobile).matches()) {            this.addFieldError("mobile", "手机号格式不正确!");        }    }}

<2>手工编写代码实现对action中的指定方法进行校验:通过编写validateXxx()方法实现,validateXxx()会校验action中方法名为xxx的方法。当某个数据校验失败时,应该采用addFieldError()方法往系统的filedErrors添加校验失败信息(为了使用该方法,action可以继承ActionSupport),如果系统的filedErrors包含失败信息,struts2会将请求发到名为input的result,在input视图中可以通过<s:fielderror/>显示失败信息。该校验方法示例如下:

public void validateUpdate() {//会对action中的update方法进行校验    if(this.username == null || this.username.trim().equals("")) {        this.addFieldError("username", "用户名不能为空!");    }    if(this.mobile == null || this.mobile.trim().equals("")) {        this.addFieldError("mobile", "手机号不能为空!");    } else {        if(!Pattern.compile("^1[358]\\d{9}{1}quot;).matcher(this.mobile).matches()) {            this.addFieldError("mobile", "手机号格式不正确!");        }    }}

*.输入校验的流程:
(1)类型转换器对请求参数进行执行类型转换,并把转换后的值赋给action中的属性。
(2)如果在执行转换的过程中出现异常,系统会将异常信息保存到ActionContext中,conversionError拦截器将异常信息封装到fieldErrors中。不管类型转换是否异常,都会转入第3步。
(3)系统通过放射技术先调用action中的validateXxx()方法,xxx为方法名。
(4)再调用action的validate()方法。
(5)经过上面四步,如果系统中的fieldErrors存在错误信息(即存放错误信息的集合的size大于0),系统会将请求转发至名为input的视图。如果系统中的filedErrors中没有错误信息,系统将执行action中的处理方法。
2.基于xml配置方式来实现:
<1>基于xml配置方式实现对action中的所有方法进行校验:Action要继承ActionSupport,并且提供校验文件,校验文件和action类在同一个包下,文件的命名规则是:ActionClassName-validation.xml,其中的ActionClassName为action的简单类名,-validation为固定写法。下面是一个校验文件(PersonAction-validation.xml)的例子:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.3//EN"       "http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd"><validators>    <field name="username">        <field-validator type="requiredstring">            <param name="trim">true</param><!-- 默认为true -->            <message>用户名不能为空!</message>        </field-validator>    </field>    <field name="mobile">        <field-validator type="requiredstring">            <param name="trim">true</param><!-- 默认为true -->            <message>手机号不能为空!</message>        </field-validator>        <field-validator type="regex">             <param name="expression"><![CDATA[^1[358]\d{9}$]]></param>            <message>手机格式不正确!</message>        </field-validator>    </field></validators>

说明:<field>指定action中要校验的属性,<field-validator>指定校验器,上面指定的requiredstring校验器是由系统提供的,系统提供了能满足大部分验证需求的校验器,这些校验器可以在文件xwork-core-2.X.X.jar中的com.opensymphony.xwork2.validator.validators下的default.xml中找到。<message>为校验失败后的提示信息,如果需要国际化,可以为message指定key属性,key的值为资源文件中的key。在这个配置文件中,对action中字符串类型的username属性进行验证,首先要求调用trim()去掉空格,然后判断用户名是否为空。对string类型的mobile字段的校验使用了regex这个校验器。

<2>基于xml配置方式实现对action中指定的方法进行校验:当校验文件名为ActionClassName-validation.xml时,会对action中的所有方法进行校验。如果要对action中的某一个方法进行校验,那么校验文件的名称为:ActionClassName-ActionName-validation.xml。其中ActionName为struts.xml中的action的名称。配置文件如下:

<package name="person" namespace="/person" extends="struts-default">    <action name="manage_*" class="zhchljr.action.PersonAction" method="{1}">        <result name="message">/WEB-INF/page/message.jsp</result>        <result name="input">/index.jsp</result>    </action></package>

假设PersonAction中有save()和update()两个方法。对save方法进行校验的文件名为PersonAction-manage_save-validation.xml,对update方法进行校验的文件名位PersonAction-manage_update-validation.xml。

*.基于xml校验的一些特点:
当为某个action提供了ActionClassName-validation.xml和ActionClassName-ActionName-validation.xml两种规则的校验文件时,系统按下面的顺序寻找校验文件:
(1)ActionClassName-validation.xml
(2)ActionclassName-ActionName-validation.xml
系统搜索到第一个校验文件时,还会继续搜索后面的校验文件,当搜索到所有校验文件时,会把校验文件里的所有校验规则汇总,然后全部应用于action方法的校验。如果两个文件指定的校验规则冲突,则只使用后面文件中的校验规则。

当action继承了另一个action时,父类action的校验文件会被先搜索到。还是按照上面的顺序,校验规则为四个文件的总和。

0 0
原创粉丝点击