1、struts2环境的简单搭建
- 必须的jar包有
- 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> </struts>
- web.xml文件的格式
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <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> </web-app>
以上为简单配置,然后部署启动如果在控制台没有发现错误则环境OK,此处使用的版本是struts-2.3.24,上面的jar包经测试都是必须的jar包。
知识点:
struts.xml文件:
- 使用package对Action进行管理
- package的name必须唯一,继承时有用
- namespace作为路径的一部分
- 自定义的package必须extends="struts-default",否则struts2的强大的拦截器功能将不会使用到
- 如果package 的 abstract="true"则该package将不能在其中定义action,该package只能被集成
- action 的class指定action是哪个类,method指定方法名称
- struts.xml文件struts在启动时只会加载一次,后面如果有改动,需重新部署启动服务器
action类:
- action中被调用的方法返回的是String类型,不许继承任何类
- action中的属性在页面可直接通过EL表达式访问,不许指定访问范围
浏览器访问Action的方法如下:
- http://主机名(或IP):8080(端口号)/struts2(应用的名称)/test(package的namespace)/test(action 的name)
- struts2的默认访问后缀是.action,如果不加.action也是可以的
struts2路径寻找规则:
假如路径是:http://localhost:8080/app/path1/path2/path3/action.action
- 首先,struts2会在namespace为/path1/path2/path3的package下寻找名称为action的Action,如果找到则返回,否则进入2
- 然后,struts2会在namespace为/path1/path2的package下寻找名称为action的Action,如果找到则返回,否则进入3
- 然后,struts2会在namespace为/path1的package下寻找名称为action的Action,如果找到则返回,否则进入4
- 然后,struts2会在namespace为/的package下寻找名称为action的Action,如果找到则返回,否则进入5
- 最后,struts2会在默认的命名空间下寻找名称为action的Action,如果找到则返回,否则返回404
struts2中Action中的默认值
- 如果class没有指定,则默认值是ActionSupport类
- 如果method没有指定,则默认值是execute方法
- 如果result节点的name属性没有指定,则默认值是success
struts2中result的类型:
其中比较常用的有:dispatcher、redirect、redirectAction、plainText
- dispatcher:默认的方式,代表请求转发
- redirect:重定向,注意不能重定向到WEB-INFO下面的页面
- redirectAction:重定向到Action,同一个包时不必指定namespace,但是必须指定actionName,不在同一个包时namespace和actionName都要指定
例如:
<result type="redirectAction"> <param name="actionName">dashboard</param> <param name="namespace">/secure</param> <result> <result name="error" type="redirectAction">error</result>
- plainText: 文本显示,如果乱码需要指定编码,如上通过param标签传递编码参数和资源路径即可PlainTextResult
全局视图:
- 包全局视图:通过<global-results></global-results>直接在包中定义即可
- 全局全局视图:包和包都可以访问的全局视图,可通过包的继承实现,定义一个包,包中通过<global-results></global-results>定义全局视图,然后其他的包继承该包即可实现
在视图中的资源文件后可以通过${属性名称}带上Action的属性的值,注意如果是URL要对属性值进行URL编码。
struts.xml中可以通过<param name=""></param>为Action注入数据:
<action name="" type=""> <param name="name">张三</param> </action>
struts2可以配置常量的地方:
- struts-default.xml(struts2-core-2.3.24.jar)
- struts-plugin.xml(struts2-convention-plugin-2.3.24.jar)
- struts.xml (src/)
- struts.properties (src/)
- web.xml
如果在上面的文件中都配置了同一个常量的值,那么后面的值会覆盖掉前面配置的值。
sturts2的常量:
默认常量的位置:struts2-core-2.3.24.jar(org.apache.struts2/default.properties)
常见常量的含义:
struts.i18n.encoding:这个常量会作用于setCharacterEncoding方法和freemarker,velocity(这两种为模板技术)的输出,POST方式提交的数据,可以交由这个常量去设置它的编码格式。
struts.configuration.xml.reload:当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false,开发阶段最好打开,开发完后再关闭。
struts.serve.static.browserCache:设置浏览器是否缓存,默认值为true,开发阶段最好关闭。
struts.devMode:打印出更详细的错误信息,用于排错,主要用于开发模式,做好了再关闭,在copy sturts-blank中的stuts.xml中,里面有这常量。
struts.ui.theme:标签所使用的额外的自定义样式,不太实用,最好设置成simple,且一般都不用到struts 2的标签库。
struts.objectFactory:与spring继承时,指定由spring负责action对象的创建,在继承spring时,会用到这个常量.
struts.enable.DynamicMethodInvocation:该属性设置struts2是否支持动态方法调用,该属性的默认值是true,如果需要关闭动态方法调用,则可设置该属性为false,
注意:DMI的调用方式Struts2的文档不建议使用,且下载的struts2-2-X.jar中,它的sturts-blank中sturts.xml有这常量,并设其值为false。
struts.multipart.maxSize:设置上传文件的总大小限制
<constant name="struts.multipart.maxSize" value="20971520" />
struts.action.extension:修改后缀名,默认是action,可以修改。若值有多个,可用逗号隔开,这对于常量的值都通用。
struts.custom.i18n.resources:用于配置国际化全局XML资源文件,须在指明该全局资源文件的基础名。
struts.ognl.allowStaticMethodAccess:如其名,用于设置OGNL是否允许静态方法访问,默认为false。
struts2流程图(官网的一张)
struts2的简单流程:
客户端请求来临时,StrutsPrepareAndExecuteFilter进行处理,如果请求是以.action或者为空则转给Intecepter(准确的说是一系列拦截器,这些拦截器都是struts2的核心连接器),拦截器处理完成后交由Action进行处理,Action处理结束后返回result视图的名称,最后把视图返回给客户端。值得注意的是struts2的Action是线程安全的,因为struts2会对每一个请求实例化一个Action进行对请求的处理。
为struts2指定多个配置文件:
<?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> <include file="default.xml"></include> <include file="other.xml"></include> </struts>
struts2的动态方法调用:
- 感叹号的形式
假如Action中有两个方法,一个方法使add另一个方法使delete,Action的名称为xxxAction,应用名称为test,action的命名空间为test,则感叹的动态方法调用如下:
htttp://localhost:8080/test/test/xxxAction!add.action
struts2官方不建议使用这种形式的动态方法调用,可以通过下面的常量配置是否支持动态方法调用
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
- 通配符的形式
假如Action中有两个方法,一个方法使add另一个方法使delete,Action的名称为xxxAction,应用名称为test,struts.xml配置文件如下:
<package name="test" namespace="/test" extends="struts-default"> <action name="test_*" class="xxxAction" method="{1}"> <result name="success" >/WEB-INF/jsp/hello.jsp</result> </action> </package>
则客户端的调用形式如下
http://localhost:8080/struts2/test/test/test_add
注意:一个*好就代表一个通配符,{1}代表action name中的第一个*,如果有多个直接修改{}中的数值即可。通配符的位置可以出现在很多地方,不仅仅是上面的例子看到的那样。
struts2 Action对请求参数的接收:
- 基本类型的接收
Action属性的名称和页面表单的字段的名称一致,且Action中属性必须存在set方法
- 复合类型的接收
复合类型在Action中必须存在set方法,页面使用复合类型属性.复合类型内部的属性传递参数
如 Person有个name属性,那么 在页面访问时可以通过person.name
struts2类型转换器:
- 局部类型转换器
- 定义类型转换器:该转换器集成com.opensymphony.xwork2.conversion.implDefaultTypeConverter并重写convertValue(Map<String, Object> context, Object value, Class toType)
- 注册类型转换器:在Action所在的包下创建actionName-conversion.properties(actionName:Action的简单类名,也就是不带包的类型)文件,文件的内容为Action中需要转换的属性=类型转换器的全名称
- 全局类型转换器
- 定义类型转换器:该转换器集成com.opensymphony.xwork2.conversion.implDefaultTypeConverter并重写convertValue(Map<String, Object> context, Object value, Class toType)
- 注册类型转换器:在类路径下创建xwork-conversion.properties文件,文件的内容为需要转换的数据类型(全名称)=类型转换器的全名称
struts2向request、session、application范围存放数据:
ActionContext act = ActionContext.getContext(); act.getApplication().put(key, value)// application范围存放数据 act.getSession().put(key, value)// session范围内存放数据 act.put(key, value) // request范围内存放数据
struts2获取request、session、application等对象
ServletActionContext.getRequest()
ServletActionContext.getServletContext()
另外一种获取request、session、application等对象的方法使实现相应的接口,由容器自动注入这些对象,例如:ServletRequestAware,其他的接口与该接口类似
struts2文件上传
- 页面表单的method="post" enctype="multipart/form-data"
- Action中通过如下的字段接收客户端传递的文件资源
private File image; // 与file表单的name一致 private String imageFileName; // 文件名称 private String imageContentType; // 文件的类型
服务端可通过FileUtils 对文件进行保存。
多文件上传:
只需将接收的参数设置问数组形式的就OK了。
private File image[]; // 与file表单的name一致 private String imageFileName[]; // 文件名称 private String imageContentType[]; // 文件的类型
struts2拦截器:
拦截器的定义:拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口,并实现intercept(ActionInvocation invocation)方法,
如果在intercept方法中不调用invocation.invoke()方法则Action中的方法将得不到执行的机会。
拦截器在Action中的使用:
struts.xml中拦截器的配置:
<package name="test" namespace="/test" extends="struts-default"> <interceptors> <interceptor name="permisson" class="xxx.PermissionInterceptor"> </interceptor> </interceptors> </package>
Action中拦截器的使用:
<package name="test" namespace="/test" extends="struts-default"> <interceptors> <interceptor name="permisson" class="xxx.PermissionInterceptor"></interceptor> </interceptors> <action name=" " class=" " method=" "> <interceptor-ref name="permisson"></interceptor-ref> <result name="success" ></result> </action> </package>
注意:如果Action中指定了拦截器那么系统默认的拦截器将不会被使用,系统默认的拦截器在文件struts-default.xml中,如下:
<interceptor-stack name="defaultStack"> <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="i18n"/> <interceptor-ref name="prepare"/> <interceptor-ref name="chain"/> <interceptor-ref name="scopedModelDriven"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="datetime"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionError"/> <interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="workflow"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="debugging"/> <interceptor-ref name="deprecation"/>
</interceptor-stack>
那么我们应该在package中定义一个拦截器栈,然后在给Action使用
<interceptors> <interceptor name="permisson" class="xxx.PermissionInterceptor"></interceptor> <interceptor-stack name="permissonStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="permisson"></interceptor-ref> </interceptor-stack> </interceptors>
注意系统默认的拦截器应该在我们自定义的拦截器前面,因为拦截器的调用时按照在文件中的配置顺序执行的。
然后在对我们的Action应用这个拦截器栈。
对package中所有的Action都应用同一个拦截器,如下配置即可对package下的所有Action都使用了拦截器permissonStack:
<default-interceptor-ref name="permissonStack"></default-interceptor-ref>
如果Action一次要使用多个拦截器,那么可以在Action通过多个<interceptor-ref name=""></interceptor-ref>指定拦截器。
值得注意的是,如果Action中指定了拦截器,那么默认的拦截器和package内默认的拦截器将都不会被使用到。
struts2的输入校验
- 编码校验
- xml配置文件校验
- 编码校验
- 所有方法校验
- 指定方法校验
所有方法校验,类必须继承ActionSupport类,然后重写validate()方法,在该方法中对数据进行验证,如果存在问题则调用addFieldError(String fieldName, String errorMessage)方法,如果校验出现不通过的情况,那么就会返回input视图。
针对Action中的某个方法进行校验,只需要在Action中实现validateXxx方法,Xxx为方法的签名,其他的和所有方法校验一致。
当类型转换异常或者校验失败时,fieldErrors不为空,则会进入input视图。
基于XML文件的输入校验:
- Action也必须继承ActionSupport
- 编写校验文件
基于XML所有方法校验:
编写XML文件,文件的命名格式为ActionClassName-validation-xml,ActionClassName为Action的简单类名。该文件应该与Action在同一个包中。
校验文件格式如下:
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> <validators> <field name="username"> <field-validator type="requiredstring"> <message key="requiredstring"/> </field-validator> </field> </validators>
filed节点的name为Action中属性的名称,field-validator的type属性指定了校验器,message为校验不通过的提示信息(注意Action应该配置input视图)。
所有的校验器我们可以在work-core-2.3.24.jar jar包下 com/opensymphony/xwork2/validator/validators/default.xml找到,如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator Definition 1.0//EN" "http://struts.apache.org/dtds/xwork-validator-definition-1.0.dtd"> <!-- START SNIPPET: validators-default --> <validators> <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/> <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/> <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/> <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/> <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/> <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/> <validator name="date" class="com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator"/> <validator name="expression" class="com.opensymphony.xwork2.validator.validators.ExpressionValidator"/> <validator name="fieldexpression" class="com.opensymphony.xwork2.validator.validators.FieldExpressionValidator"/> <validator name="email" class="com.opensymphony.xwork2.validator.validators.EmailValidator"/> <validator name="url" class="com.opensymphony.xwork2.validator.validators.URLValidator"/> <validator name="visitor" class="com.opensymphony.xwork2.validator.validators.VisitorFieldValidator"/> <validator name="conversion" class="com.opensymphony.xwork2.validator.validators.ConversionErrorFieldValidator"/> <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/> <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/> <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/> </validators> <!-- END SNIPPET: validators-default -->
假如我们的Action为UserAction,那么校验文件的命名应该为:UserAction-validation.xml。
基于XML对Action中的指定方法进行校验,大体上和对所有方法校验一样,只是校验文件的命名有所变化。文件命名的格式是:ActionClassName-actionName-validation.xml,其中actionName为struts.xml中Action的配置名称。例如:
假如我们的Action为UserAction,在UserAction中有两个方法,分别为add、delete,UserAction的配置如下:
<package name="user" namespace="/user" extends="struts-default"> <action name="user_*" class="com.xxx.UserAction" method="{1}"> <result name="input">/WEB-INFO/page/input.jsp</result> </action> </package>
那么如果我们需要对add方法校验,那么校验文件的命名应该为UserAction-user_add-validation.xml,该文件与Action在同一个包下。
如果一个Action既有所有方法校验配置文件也有方法校验配置文件,那么struts2会搜索所有的检验文件,对于方法校验以方法校验文件为准。
struts2国际化:
全局范围的国际化、包范围的国际化、action范围的国际化。
国际化资源文件的命名规则:
baseName_language_country.properties
baseName_language.properties
baseName.properties
其中baseName可为任意值
比如汉语国际化资源文件命名:resources_zh_CN.properties,美国英语资源文件为:resources_en_US.properties
全局资源文件应该放在src目录下。
struts.xml中可通过常量引入全局资源文件:
<constant name="struts.custom.i18n.resources" value="baseName" />
jsp页面访问国际化资源:
<s:text name="key" />
key为国际化资源文件中的key。
Action中访问国际化资源文件需要继承ActionSupport,通过getText()方法获取。
带占位符的国际化资源的访问:
name={0}你好,{1}
<s:text name="key" > <s:param> </s:param> <s:param> </s:param> </s:text>
包范围的国际化资源的命名格式package_language_country.properties,package为固定写法。包范围的国际化资源可以被该包和子包进行访问,访问格式和访问全局国际化资源文件一样。如果在包范围内找不到,则会去全局范围内找。
Action范围的国际化资源文件的命名格式ActionClassName_language_country.properties,ActionClassName为Action的简单类名称。
OGNL表达式:Object Graphic Navigation Language(对象图导航语言)的缩写,struts2框架默认使用OGNL做为表达式语言。
OGNL有一个上下文的概念,在struts2中上下文的实现时ActionContext。结构图如下:
当struts2接收到一个请求时,会迅速的创建ActionContext、ValueStack、action,然后把action存放进ValueStack中,所以action中的实例变量可以被OGNL访问。
访问上下文(Context)中的对象需要使用#标注命名空间,如#application、#session
另外OGNL会设定一个根对象(root对象),在struts2中根对象就是ValueStack(值栈),如果需要访问根对象中的对象属性,则可以不加#命名空间,直接访问该对象的属性即可。
在struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象可以存放一组对象,在OgnlValueStack类里有一个List类型的root变量,就是使用它存放一组对象。
在root变量中处于第一位的对象叫栈顶对象,通常我们在ONGL表达式里直接写上属性名即可访问root变量里对象的属性。搜索顺序是从栈顶开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到,则从第三个对象寻找,知道找到为止。
值得注意的是,OGNL表达式需要配合struts2的标签才可以使用。
由于ValueStack是struts2中OGNL的根对象,那么可以直接使用EL表达式直接访问值栈中的对象的属性。
如果是其他的Context中的对象,由于他们不是根对象,所以访问时需要添加#前缀。
application对象:用于访问ServletContext,例如#application.userName或者#application["userName"]相当于调用ServletContext的getAttribute("userName");
session对象:用于访问HttpSession对象,例如:#session.userName或者#session["userName"]相当于调用seesion.getAttibute("userName")
request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request["userName"],相当于调用requset.getAttribute("userName")
parameters对象:用于访问HTTP的请求参数,例如#parameters.userName或者#parameters["userName"]相当于调用request.getParameter("userName")
attr对象:用于按page->request->session->application顺序访问其属性
OGNL表达式创建List/Map集合对象
使用如下代码创建一个List集合对象:
<s:set name="list" value="{'a', 'b', 'c'}"/>
遍历List集合:
<s:iterator value="#list"> <s:property/><br/> </s:iterator>
Set标签用于将某个值存放在指定的范围内
scope:指定变量被存放的范围,该属性可接受application、seesion、request、page、action,如果没有设置该属性,则默认放置在OGNL Context中。
value:赋给变量的值,如果没有设置该属性,则将ValueStatck栈顶的值赋给变量
生成Map集合:
<s:set name="map" value="#{'key1':'value1', 'key2':'value2'}"/>
遍历Map集合
<s:iterator value="#map"> <s:property value="key"/> <s:property value="value"/> </s:iterator >
iterator标签的特点:该标签会把当前遍历的元素放置在值栈的栈顶。
property标签的特定,如果value没有指定,则表示输出值栈栈顶的元素。
OGNL表达式可以判断对象是否存在于某个集合中:
in:表示对象在集合中
not in: 表示对象不在集合中
<s:if test="'a' in {'a','b'}"> 在 </s:if> <s:else> 不在 </s:else> <s:if test="'a' not in {'a','b'}"> 在 </s:if> <s:else> 不在 </s:else>
OGNL表达式的投影功能
常用的有以下几个:
?:获取所有符合逻辑的元素
^:获取符合逻辑的第一个元素
$:获取符合逻辑的最后一个元素
使用方式:
<s:iterator value="books.{?#this.price>35}"> <s:property value="title"/> <s:property value="price"/> </s:iterator>
上面代码直接在集合后面紧跟 .{} 运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,this指的是为了从大集合中筛选元素到小集合中,需要对大集合进行迭代,this代表当前迭代的元素。
OGNL栈顶的元素可以直接使用EL表达式访问。