Struts2属于MVC框架

Struts2的优点:

1、侵入性低

2、提供了拦截器,可以利用拦截器进行AOP编程

3、提供了类型转换器

4、支持多种表示层技术:jsp,freeMarker,Veleocity

5、所有的请求都是使用拦截器处理

6、使用OGNL值栈

7、5和6也是缺点,导致执行效率低

Struts2的环境搭建:

1、创建web项目

2、放入struts2 的jar包(core:核心jar,ognl:值栈,xwork.jar)

3、在web.xml中配置过滤器(struts2定义的类 FilterDispatcher)

<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>

拦截所有请求 <url-pattern>/*</url-pattern>

4、执行过滤器的init方法,

5、Struts2的主配置文件放在src下

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>

<constant name="struts.devMode" value="true" />

<package name="myLogin" namespace="/test"           extends="struts-default">

<action name="login" class="com.asm.LoginAction">

//result标签相当于forward

<result name="loginSuccess">/success.jsp</result>

<result name="loginFailure">/failure.jsp</result>

</action>

</package>

</struts>

Struts2action收集表单数据,执行execute()方法,该方法没有参数,返回结果为String类型。

Struts2的执行流程:(执行环境 Tomcat6)

1、Tomcat一启动就创建filter对象,执行filter的init()

2、请求路径:项目名后+包下的命名空间名+访问的Action名,可以加上.action后缀,也可以不加。

http://127.0.0.1:8080/struts2/test/Login.action?message=first

3、如果需要添加参数,参数名要和Action类中的属性名一样

4、请求交给tomcat,tomcat创建request内置对象接收请求参数

5、Tomcat将请求交个Filter(filter发现是没有后缀或者是.action的请求,就把请求交给下一个拦截器,其余情况就不处理)

6、Filter会执到struts.xml中找到包(/test),在包下找到Action(Login)类

7、创建Action对象,将对象放到OGNL值栈中,通过拦截器设值(把表单中的参数名为message的值设到message属性中,如果类型不同可以自动转换),执行该对象的execute方法,根据返回值到主配置文件中找到对应的跳转路径,在jsp页面中共使用el表达式输出${message }

8、先到scope(request)中拿,发现没有就到值栈中拿,找到属性名为message的Action类,然后调用getMessage()方法输出

9、效率低

Struts2的流程

在web.xml中配置struts2

StrutsPrepareAndExecuteFilter(升级版的过滤器)

创建filter对象,执行init方法,读取struts2 的主配置文件

发送请求:

自动执行index.jsp

Login.jsp也会交给struts2的拦截器处理,因为配置的是拦截所有请求

但是拦截器拦截后判断如果不是.do,.action的请求就将请求交给Tomcat处理

请求路径:需要指定访问的包下的action

如果发现是.action结尾的请求,就会把请求交给另一个拦截器处理,找到对应的包名和action.通过命名空间找到包,通过action名字找到对应的action,然后马上创建action对象,自动把表单中的同名参数设到了action的同名属性,完成自动收集。

把封装用户信息的action,设到了值栈中

默认调用action的execute方法

返回字符串,字符串返回到action标签下的子标签 result,找到字符串对应的页面。

在jsp页面中首先通过EL表达式,找到属性名对应的属性值。到struts2的值栈中找到相应的值,如果没有就返回空串,如果有就返回其中一个。

值栈:

第一次接收请求会马上创建对象 ActionContext

该对象封装了action,数据结构为 最上部有个list集合,先入后出

有个map,以内置对象的属性名定义

一创建action,就放到值栈的list集合中(list集合中的值栈可以自动的设定,自动的获取)

valueStack,action

默认的配置:

Action标签中 默认调用的方法是 method=”execute”

没有指定class ,说明是ActionSupport

result标签中没有指定的result的name属性,默认值为success

包:struts2用包管理action,把一组相关业务的action放到一个包下

一个请求一个action,一个模块一个包(根据包分模块)

发请求时:指定包下的action路径(不同的包下的请求名可以相同)

Namespace可以不配置,默认的命名空间为:””

name:包名(必须唯一,是为了继承包而用的)

namespace:命名空间,直接体现在请求中(请求中通过命名空间找到对应的包)

extends 包中写了struts2的核心拦截器,继承后可以使用struts2的核心技术。(请求封装,拦截,国际化验证,上传等等)

<package name=” login”  namespace=”/” extends=”struts-default” >

extends=”struts-default”下的拦截器:

自动将默认包读到内存中,

包定义为抽象:包中不能提供action

为什么要配置extends=”struts-default”,因为这个包是个抽象包,只能被继承,该抽象包中封装了很多拦截器(struts2的核心技术)。

Struts2中拦截器处理请求

包的作用:

1. 模块化开发(一个项目可以有多个包,(几个模块几个包)

2. 通过包能够使用struts2的核心技术 拦截器

包的搜索顺序:

包名为 path1/path2/path3

先找到包名为 path1/path2/path3,

如果没找到就找到包名为:path1/path2

如果还是没有找到就找包名为 path1

如果还时没有就去默认的namespace的package中找到名字为test的action<默认的命名空间为””>

result(和struts1的forward标签类似)

对转向配置信息,通过转向信息觉得转到哪个页面

<result name=”success”>/WEB-INF/hello.jsp</result>

name:一定要和执行方法返回值相同

这边的跳转是服务端跳转

<result name=”success”type=”dispatcher”/>

默认使用转发(服务端)

如果需要变为客户端跳转就将type定义为 redirect

Type的取值:dispatcher,redirect,chain,redirectAction,plainText

redirectAction:后面跟的是转向路径的名字(转到下一个Action)

redirect重定向到另一个页面

<result type=”redirectAction”>helloword</result>//这里只能转到当前包下的action

如果需要转到别的包下的action:

<result type=”redirectAction”>

这里是找到/test包下的helloword的action

<param name=”actionName”>helloword</param>

<param name=”namespace”>/test</param>

</result>

在result中可以在转向页面路径上取id值

<result type=”redirectAction”>helloword.jsp?id=${id}</result>

result的作用:提供转向路径,在后端处理器调用

result的配置位置:配置在<action>标签的内部,表明是当前action提供的转向信息,转到某一个页面或者是转到另一个action

常量:一般在主配置文件struts.xml文件中定义

Struts2默认的扩展名是.action,或者是不写(没有扩展名)

//可以接收任何扩展名的请求(.do ,.go)根据value的配置而确定

<constant name="struts.action.extension" value="do,go"/>

//指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出

<constant name="struts.i18n.encoding" value="UTF-8"/>

//设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭

<constant name="struts.serve.static.browserCache" value="false"/>

开发模式下使用,这样可以打印出更详细的错误信息

<constant name=”struts.devMode" value="true" />

默认的视图主题

<constant name="struts.ui.theme" value="simple" />

与spring集成时,指定由spring负责action对象的创建

<constant name="struts.objectFactory" value="spring" />

该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false。

<constant name="struts.enable.DynamicMethodInvocation" value="false"/>

上传文件的大小限制

<constant name="struts.multipart.maxSize" value=“10701096"/>

常量的作用:设定编码方式,动态方法调用,设定上传文件的大小

Action:接收中央控制器的请求,并且把请求交给业务对象处理

收集表单参数的两种方式:从请求中取得,从配置中取得

需要调用请求中的另外的方法:三种实现方式

  1. 配置method = “other”,默认是execute方法
  2. 开启动态方法调用 : !+方法名

http://127.0.0.1/8080/strut2/test/helloword!other?id=1

前提是将常量设置为true,动态常量开启<constant name= "struts.enable.DynamicMethodInvocation" value= "false" />

  1. 请求通配符(helloword_other.action)other:是指定的方法名

<action name=”helloword_*”class=”…” method={1} >

Struts2的简单流程:

  1. 请求交给拦截器,拦截器处理指定的请求,如果不属于struts2指定处理的请求类型就将请求交给Tomcat处理
  2. 如果属于:拦截器对请求做处理,先截取分析(多个拦截器)
  3. 创建action对象放入值栈中
  4. 调用action对象的方法,返回字符串
  5. 到action标签中找到返回字符串对应的result标签,完成相应的跳转

Sturts2的拦截器

拦截器是struts2的核心

作用:完成解析请求参数,将请求参数赋值给Actio属性,执行数据校验,文件上传等。

拦截器定义在extends= struts-default包中,会自动使用该包下的所有拦截器,如果自己定义了拦截器就会覆盖其他的拦截器。需要重新引入才可以使用。

拦截器的自定义

方式一:实现Intercepter接口,实现intercept方法,在intercept方法中调用invocation.invoke();语句上面的是对请求拦截,下面的语句是对结果拦截。

String result = invocation.invoke();方法的返回值是String类型,intercept方法的返回值就是返回这个result,然后再判定是不是继续激活拦截器还是将请求下传。

方法二:继承抽象类AbstractIntercepter,复写intercept方法,和一类似

方法三: 继承,MethodFilterIntercepter类

复写 doIntercept方法,里面的内容和一类似

注册拦截器:

在struts.xml中,在定义包下添加<interceptors>标签,里面定义<interceptor name=”标识”class=”拦截器的全路径名”>标签

拦截器的使用:

在<action>标签中 配置<interceptor-ref=”标识”/>

一定要配置<interceptor-ref=” defaultStack”/>表示重新引入struts2默认的拦截器

拦截器的执行顺序和Spring的拦截器执行顺序类似。

利用struts2获取内置对象

获取内置对象的方法一:实现这三个接口: ServletResponseAware, ServletReqestAware , ServletContextAware(注入

实现相应的方法,设定实例全局变量。 注入属性到实例全局变量中,然后就可以直接使用(request,response,servletContext对象)

获取内置对象的方法二:通过ServletActionContext.类的静态方法 ServletActionContext.getRequest();(依赖查找

ServletActionContext.getResponse();

ServletActionContext.getServletContext();

得到request,response,servletContext内置对象,然后使用

 

获取内置对象的方法三:通过值栈ActionContext

ActionContext ac = ActionContext.getContext();

从ActionContext中拿到application的map,设值,然后往对应的application内置对象中设值,属性名为app,属性值为123

ac.getApplication().put(“app”,”aaplication123”);

ac.getSession().put(“session”,”session 123”);

ac.put(“req”,”request123‘’);//设值到request内置对象中

ActionContext本身是个Map,往ActionContext中设值就是往map中设值,然后在将值设到request内置对象中

类型转换:

int,double,boolean类型的数据会自动转换

struts2的转换器在一个文件下:xwork-message.properties

待转换的类型 = 类型转换器的全类名

java.util.Date = com.struts.DateConverter

处理出错信息流程:(Action类继承ActionSupport)

1、      表单中有String类型的数据

2、      创建action对象后把字符串封装到参数名对应的属性名上,但是属性名是Util类型

3、      在默认的文件中找不到把string类型的数据转换为util类下的数据的信息

4、      先到actionContext(值栈)中找一个map,名为fielderror,将转换出错信息设到该map中

5、      创建Action对象执行action对象的相应方法,发现map集合的长度大于0 就返回input。

6、      跳到result标签中input所标识的页面

7、      在jsp页面中通过<s:fielderror/>输出出错信息

如果Action没有继承ActionSupport类,就逆行转换,将action中的util类型的日期转换为String类型输出。(不继承ActionSupport就不找到转换器)表单中的参数值是什么就是输出什么。将属性转换为String类

转换器的编写

编写一个类继承DefaultTypeConverter

复写方法 convertValue方法

Public class DateConverter extends DafaultTypeConverter{

Public Object convertValue(Map context,Object value,Class toType){

SimpleDateFormat sdf=new SimpleDateFormat(“日期格式”);

If(toType == Date.class){

//request.getParameterValues(name),从表单中取出来的参数值

String[] params=(String[]) value;

return sdf.parse(param[0]);

} }}

转换器的注册

在src下写一个xwork-conversion.properties文件中写上:

java.util.Date = com.struts.DateConverter

局部类型的转换器:

将上面的类型转换器注册为局部类型转换器:

在Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassName是Action的类名,后面的-conversion.properties是固定写法,对于本例而言,文件的名称应为typeconvertAction-conversion.properties(typeconvertAction为类名)

在properties文件中的内容为:

属性名称=类型转换器的全类名

对于本例而言, typeconvertAction-conversion.properties文件中的内容为

utilDate= com.asm.DateConverter

如果全局转换器和局部转换器都写了,优先使用局部转换器。

Struts2的异常处理

在struts.xml中配置:

<action name="login" class="com.asm.LoginAction" method="add">

<exception-mapping result="usernameException"

exception="com.asm.UserNotFoundException">

</exception-mapping>

<result name="usernameException">/usernameexception.jsp

</result>

<exception-mapping result="PasswordException"

exception="com.asm.PasswordErrorException">

</exception-mapping>

<result name="PasswordException">/passwordexception.jsp</result>

<result name="loginSuccess">/success.jsp</result>

<result name="input">/validate.jsp</result>

</action>

在某个Action中出异常了。就到action中找到exception-mapping标签,找到具体的异常处理类。

1.局部异常处理仅在对应的action方法中有效

2. <exception-mapping>中的result属性的值

来源于<result>元素中的name属性的值

当action方法向struts2抛出异常对象时, struts2根

据struts.xml中的exception-mapping标签的result

属性找到result标签的name属性从而确定相应的转向页面。

定义全局异常:

<package name="ex" namespace="/" extends="def">

<action name="login" class="com.asm.LoginAction" method="add">

<exception-mapping result="usernameException"

exception="com.asm.UserNotFoundException">

</exception-mapping>

<result name="usernameException">/usernameexception.jsp

</result>

</action>

异常处理流程:

1、发请求login.jsp

2、请求给struts2,struts2发现请求是.jsp结尾就把请求交给tomcat处理

3、Tomcat拿到login.jsp,执行login.jsp

4、在login.jsp页面中提交错误的用户名和密码

5、将请求交给struts2

6、Struts2将请求下传,截取请求

7、找到对应的action,创建action对象,将表单中的参数收集过来

8、Action对象和参数都存到值栈中,然后执行action的对应的方法(add)

9、创建业务对象,对登录表单中的数据进行验证(验证方法中声明不处理异常,直接抛出异常) public void add()throws Exception{}

10、验证出错就产生异常 throw new UserNotFoundException();

11、到该action类对应的action标签中找到与异常对象类型相同的exception-mapping标签,

12、通过exception-mapping找到result属性

13、根据result属性找到对应的result所指的页面,对异常进行处理

如果在该action标签中找不到对应的异常,就会到当前包所继承的包下找到全局异常信息,在包下找到execption-mapping,然后找到全局的result,转到相应的页面。

1.全局异常处理对所有的action方法都有效

2.全局性的异常应放在一个抽象包中供其他包继承

3.在相应的包中我们继承了全局异常所在的包,该包中的所有action的方法均可进行全局异常处理,处理方法和局部异常处理相同。

Struts2对请求的验证:

Struts2对于输入校验的方法:

1、采用手工编写代码实现

2、基于XML配置方式实现

采用手工编写代码实现

1、action类必须继承ActionSupport类

2、复写validate()方法,在调用action的方法之前会先调用validate()方法

3、validateLogin()方法,只对访问当前action类的login方法做验证

通过validateXxx()方法实现, validateXxx()只会校验action中方法名为Xxx的方法。validateLogin()

验证流程:

1.类型转换器对请求参数执行类型转换,并把转换后的值赋给action中的属性。

2.如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContext,conversionError拦截器将异常信息添加到fieldErrors里。不管类型转换是否出现异常,都会进入第3步。

3.系统通过反射技术先调用action中的validateXxx()方法,Xxx为方法名。一旦出错就调用addFieldError()方法,将出错信息存到map中

4.再调用action中的validate()方法。一旦出错就调用addFieldError()方法 this.addFieldError("username", "用户名不能为空");

5.如果系统中的fieldErrors存在错误信息(即存放错误信息的集合的size大于0),系统自动将请求转发至名称为input的视图。在input指定的jsp页面中使用<s:fielderror/>显示失败信息。

6.如果系统中的fieldErrors没有任何错误信息,系统将执行action中的处理方法

验证方法的缺点:自己手动写验证规则代码

基于XML配置方式实现

使用基于XML配置方式实现输入校验时,Action也需要继承ActionSupport,并且提供校验文件,校验文件和action类放在同一个包下,文件的取名格式为:ActionClassName-validation.xml,其中ActionClassName为action的简单类名,-validation为固定写法。

如果Action类为com.asm.LoginAction,那么该文件的取名应为:LoginAction-validation.xml。

<!DOCTYPE validators PUBLIC

"-//Apache Struts//XWork Validator 1.0.2//EN"

"http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd">

<validators>

<field>指定action中要校验的属性,<field-validator>指定校验器,上面指定的校验器requiredstring是由系统提供的,系统提供了能满足大部分验证需求的校验器,这些校验器的定义可以在xwork-2.x.jar中

<field name="username">//指定action中验证的属性名

<field-validator type="requiredstring">

<param name="trim">true</param>

<message>为校验失败后的提示信息,如果需要国际化,可以为message指定key属性,key的值为资源文件中的key。

<message> 用户名不能为空!</message>

</field-validator>

</field>

</validators>

系统提供的校验器如下:

required (必填校验器,要求field的值不能为null)

requiredstring (必填字符串校验器,要求field的值不能为null,并且长度大于0,默认情况下会对字符串去前后空格)

stringlength(字符串长度校验器,要求field的值必须在指定的范围内,否则校验失败,minLength参数指定最小长度,maxLength参数指定最大长度,trim参数指定校验field之前是否去除字符串前后的空格)

regex(正则表达式校验器,检查被校验的field是否匹配一个正则表达式.expression参数指定正则表达式,caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true)

int(整数校验器,要求field的整数值必须在指定范围内,min指定最小值,max指定最大值)

double(双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值)

fieldexpression(字段OGNL表达式校验器,要求field满足一个ognl表达式,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过)

email(邮件地址校验器,要求如果field的值非空,则必须是合法的邮件地址)

url(网址校验器,要求如果field的值非空,则必须是合法的url地址)

date(日期校验器,要求field的日期值必须在指定范围内,min指定最小值,max指定最大值)

conversion(转换校验器,指定在类型转换失败时,提示的错误信息)

visitor(用于校验action中的复合属性,它指定一个校验文件用于校验复合属性中的属性)

expression(OGNL表达式校验器,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过,该校验器不可用在字段校验器风格的配置中)

防止用户重复提交请求:

 

发送请求的表单如下:

<%@ page language="java" pageEncoding="UTF-8"%>

<%@ taglib uri="/struts-tags" prefix="s" %>

<html>

<body>

<form action="<%=request.getContextPath()%>/login.action" >

姓名:<input type="text" name="username"><br>

密码:<input type="password" name="password"><br>

<input type="submit" value="登录">

<s:token></s:token>

</form>

</body>

</html>

<s:token></s:token>标签,它的作用就是在用户访问此页面时会生成一个sessionId,在提交时会服务器会据此验证表单是否已提交

我们必须要在提交的表单中使用这个token tag,这样提交到的Action便能配置TokenInterceptor拦截器验证表单是否重复提交。

<input type="hidden" name="struts.token.name" value="token" />

<input type="hidden" name="token" value="D3VI7HWCJ4PSOSYFZ6A1QIJT0J6VAHTT" />

struts.xml主要配置内容如下:

<struts>

<package name="tokenTest" extends="struts-default">

<action name="login" class="com.asm.LoginAction">

<result name="success">/success.jsp</result>

<result name="loginFailure">/failure.jsp</result>

//重复提交请求后跳转到subError.jsp页面

<result name="invalid.token">/subError.jsp</result>

<interceptor-ref name="token"></interceptor-ref>

<interceptor-ref name="defaultStack"></interceptor-ref>

</action>

</package>

</struts>

调用action的execute方法之前会调用拦截器,该拦截器定义在struts-default包下,但是需要人为的引用该拦截器。<s:token/>

如果是新的请求就可以再次提交了,因为token的value值(相当于sessionID)会重新生成。这里只是为了避免同一个请求重复提交。

Struts2的标签

1、引入标签库 <%@ taglib uri="/struts-tags" prefix="s" %>

基础表单标签

在html我们常用的基础表单标签主要有文本域、密码域、提交、重置四种。

<s:form action="login" method="post" namespace="/my">

required设为true,表示此表单项为必填内容以“*”提示

requiredposition="right":*显示在标识的右侧

<s:textfield label="用户名" name="username" required="true"                                requiredposition="right"/>

<s:password label="密码" name="password" required="true" /> 
       <s:reset value="重置" align="left"/>
       <s:submit value="注册" align="left"/>

</s:form>

<s:bean name=”cn.struts2.User”
id=”user”/ >该user对象存放在stackContext中,如果需要取出来就加 # 号

一个请求一个值栈,重新发请求后会创建新的值栈,销毁原来的值栈。

<s:set
name="name" value="'kk'" />把属性名为name的属性值kk设置到map中,(栈中)

<s:property value=”name”>先到值栈里面找name为name的value中,如果没有找到就到栈里面找。

<!--创建集合对象,然后把集合对象放到值栈中 -->

<s:set
var="list" value="{'第一个','第二个','第三个'}"/>

<!-- iterator迭代的特点:会把迭代的集合元素放到值栈的栈顶 -->

<s:iterator
value=“list”> <!--从值栈取出名字为list的集合并依次取出各个元素,把集合元素放到值栈的栈顶 -->

<s:property/>
<!--从值栈取出集合元素并显示出来-->

</s:iterator>

if/elseif/else标签

<s:set
name="age" value="21" /> :存放在栈空间

<s:if
test="#age==23">

23

</s:if>

<s:elseif
test="#age==21">

21

</s:elseif>

<s:else>

都不等

</s:else>

当标签的属性值作为字符串类型处理时, “%”符号的用途是计算OGNL表达式的值。

<s:set name="myurl"
value="'http://www.foshanshop.net'"/>

<s:url value="#myurl"
/><br>//s:url不支持栈输出,需要使用%

<s:url value="%{#myurl}" />

输出结果:

#myurl

http://www.foshanshop.net

说明:由于url标签的value属性默认不支持ognl,所以我们要使用%{}来表示{}中的#bdUrl是一个ognl表达式。

Struts2的文件上传

上传条件:

1、导入jar包(在WEB-INF/lib下加入commons-fileupload-1.2.2.jar、commons-io-2.0.1.jar。这两个文件可以从http://commons.apache.org/下载。)

2、在常量中设定上传文件的最大值

3、表单属性enctype设置为:“multipart/form-data“,如下:

<form
action="<%=request.getContextPath()%>/fileupload.action"                            method="post"    enctype="multipart/form-data">

标题:<input type="text"
name="title"><br>

文件:<input type="file"
name="myfile"><br>

<input type="submit" value="提交">

</form>

4、Action类的属性定义

public class fileuploadAction {

private String title;

private File myfile;//得到上传的文件(把表单里的文件收集到当前action的myfile属性

private String myfileContentType;//得到文件的类型(struts2通过文件自动识别文件类型设到myfileContentType属性上,后面一定是ContentType,前面一定是上传文件的参数名)

private String myfileFileName;//得到文件的名称struts2通过文件自动识别文件类型设到myfileFileName属性上,后面一定是FileName,前面一定是上传文件的参数名)

//这里略省了属性的getter/setter方法

}

创建Action对象后,将表单中的参数封装到Action中相应的属性上。

下载文件:(Action类中的一个方法)

public String
execute() throws Exception {

String realpath =
ServletActionContext.getServletContext(). getRealPath ("/images");//放到项目根路径下的images文件夹中

File file = new File(realpath);

if(!file.exists()) file.mkdirs();//如果images文件夹不存在就手动创建

FileUtils.copyFile(myfile, new
File(file,myfileFileName));//将上传myfile所指的文件对象拷贝到以myfileFileName命名的文件中

return
"fileuploadSuccess";

}

多文件上传:

1、导入jar包commons-fileupload-1.2.2.jar、commons-io-2.0.1.jar。这2、form表单

<form
action="<%=request.getContextPath()%>/mulfileupload.action"                    method="post"
enctype="multipart/form-data">

标题:<input type="text"
name="title"><br>

文件:<input type="file" name="myfile"><br>

文件:<input type="file"
name="myfile"><br>

<input type="submit"
value="提交">

</form>

3、Action类的属性定义

public class mulfileuploadAction implements
Action {

private String title;

private File[] myfile;//得到上传的文件数组

private String[] myfileContentType;//得到文件的类型数组

private String[] myfileFileName;//得到文件的名称数组

//这里略省了属性的getter/setter方法

}

4、文件下载

public String
execute() throws Exception {

String realpath =
ServletActionContext.getServletContext()

.getRealPath("/mulimages");

File file = new File(realpath);

if(!file.exists()) file.mkdirs();

for(int i=0 ;i<myfile.length; i++){ File
myfile1= myfile[i];

FileUtils.copyFile(myfile1, new
File(file,myfileFileName[i]));

}

return "mulfileuploadSuccess";

}

Struts2的国际化

1、在src下配置国际化资源文件

2、在struts.xml中通过常量指定国际化资源文件的基名

<constant
name="struts.custom.i18n.resources" value="myapp" />

myapp为资源文件的基本名。

资源文件的命名格式如下:

baseName_language_country.properties

baseName_language.properties

baseName.properties

其中baseName是资源文件的基本名,我们可以自定义,但language和country必须是java支持的语言和国家。如:

中国大陆: baseName_zh_CN.properties

美国: baseName_en_US.properties

使用浏览器默认的locale信息

1、Tomcat会把请求中的locale信息放到与该请求对应的session中,2、struts2的静态国际化标签,找到请求对应的locale信息决定调用哪个文件,<s:text name=”login_submit”/>name 指定国际化资源文件的key

如果国际化资源文件中没有该key,就会自动把当前页面的key作为value来显示。(原样显示chinese<s:text
name=”chinese”/>

3自动到struts2的struts.xml中通过常量找到基名。

4、通过基名+locale信息就能找到对应的国际化资源文件

通过action对象的方法完成不同语言的切换

在struts.xml中配置

<action
name="cl" class="com.asm.ChangeLangAction" method=
"changeLang">

<result>/login.jsp</result>

</action>

Action类中的方法

action对象的changeLang方法

public String
changeLang() throws Exception {

Locale locale = null;

if (lang.equals("zh")) {

locale = Locale.CHINA; //利用常量创建locale对象

} else {

locale = Locale.US;

}

ServletActionContext.getRequest().getSession().setAttribute("WW_TRANS_I18N_LOCALE",
locale);//将locale信息设置到session里面

return SUCCESS;

}

1、先到struts.xml的常量中找到基名

2、从请求中找到locale信息

3、通过基名和locale信息找到指定的国际化资源文件

4、从国际化资源文件中找到key对应的value进行显示

Struts2的动态国际化:

国际化资源文件中key使用占位符:login_fail=username error {0},and password error {1}

在页面中输出带占位符的国际化信息

<s:text
name="longin_fai">

        <s:param
value="%{username}"></s:param>

        <s:param
value="%{password}"></s:param>

</s:text>

表单中的输入用户名为:Tom,密码为123

<s:text>输出结果为 username error Tom ,and password error 123

国际化资源文件有全局国际化资源文件也有局部国际化资源文件:

包下的国际化资源文件:

package_language_country.properties资源文件,package为固定写法,处于该包及子包下的action都可以访问该资源。当查找指定key的消息时,系统会先从package资源文件查找,当找不到对应的key时,才会从常量struts.custom.i18n.resources指定的资源文件中寻找。

Action下的国际化资源文件:

ActionClassName_language_country.properties资源文件查找,如果没有找到对应的key,然后沿着当前包往上查找基本名为package 的资源文件,一直找到最顶层包。如果还没有找到对应的key,最后会从常量struts.custom.i18n.resources指定的资源文件中寻找。

局部的国际化资源文件不需要基名,全局的国际化资源文件都需要基名。

全局国际化资源文件拿到基名的方式:

1、通过标签拿到基名<s:i18n name=”myApp”>

2、没有标签就到struts.xml的常量中找到基名

Struts2的流程:

1、用户发请求先经过三个过滤器 ActionContextCleanUp,OtherFilters,(SiteMesh etc) FilterDispatcher(拦截器)

2、FilterDispatcher会将请求交给ActionMapper,ActionMapper判断是否处理当前请求

3、如果处理,FilterDispatcher就会创建ActionProxy代理对象,

4、ActionProxy代理对象创建ConfigurationManager对象,从struts.xml中读取配置信息

5、读取信息后会知道有哪些包,需要创建哪些Action对象,但是先不创建这些对象

6、创建ActionInvocation对象,

7、ActionInvocation对象根据请求找到对应包下的Action创建Action对象,调用拦截器把表单中的数据封装到action对象的属性中,然后将action对象封装到ognl值栈中

8、在封装表单参数的过程中,如果出现异常会调用处理异常的拦截器

9、在执行真正的方法之前会调用自己写的拦截器,以及格式验证的的拦截器

10、最后执行Action相应的方法 默认为execute

11、将执行结果  result返回给ActionInvocation

12、ActionInvocation拿到结果信息后,到struts.xml文件中转到相应的jsp页面。页面中处理结果信息,浏览器中显示结果信息。

OGNL值栈:

值栈的生存周期和request相同,请求一来就创建,请求结束就销毁。

OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts 2框架使用OGNL作为默认的表达式语言。

值栈的结构:

 

 

 

 

值栈的数据结构主要有stackvalueStack

值栈Valuestack中主要是list,存放Action对象

Stack中主要是map,存放对象

 

OGNL中常用的map

Parameters ,request,session,application,attribute

 

值栈的功能:

调用对象里的方法,属性

一个请求对应一个值栈,值栈中有个map,会把请求的参数名和参数值自动到封装到map中

创建Action对象后会自动的把action放到值栈中

调用静态方法

操作集合对象

Stack Context:

ValueStack:有个map集合parameters,封装表单中的参数名和参数值

Struts2重写了request,复写了getAttribute()方法

表单:<input type=”text” name=”user.username”>

Action类: 有个User user 属性,收集时会将user.username 设到Action类中的User对象的username 属性上。

创建Action对象时,会创建User对象,将表单中的数据封装到user对象中。

所有表单中提交的参数名和参数值都会进到值栈中 parameters Map

在Action类中创建的三个集合对象会放到值栈中的值栈 ValueStack中,因为这些集合对象属于Action对象。

值栈 list

栈是 map

Action对象存放在值栈(valueStack)中

使用#号,从栈中(Map)取出数据:

获取Request属性:<s:property
value="#request.req"/><br>

获取Session属性:<s:property
value="#session.ses"/><br>

获取parameters属性:<s:property value="#parameters.mes"/>

说明:我们获取这些对象都用了#,因为这些对象都是存在一般的Context Map中,而不是存在值栈中。

显示值栈的详细信息:

在jsp页面中使用 <s:debug></s:debug>

需要在struts.xml文件中配置 常量来struts.devMode,以及allowStaticMethodAccess(允许使用静态方法)

<s:property
value=”user.username”/>
到list集合的valueStack中看哪个Action对象包含User属性,调用user属性对应的user对象的getUsername()方法

${user.username}先通过EL表达式输出,发现没有就通过request getAttribute输出,发现还是没有就到list集合的valueStack中看哪个Action对象包含User属性,调用user属性对应的user对象的getUsername()方法

<s:property
value=”get()”/>
看那个Action包含get方法直接调用Action 对象的get方法

<s:property
value=”user.get()”/>
先到值栈中找到属性名为user的Action,然后调用user属性所指user对象的get方法

<s:property value=”@cn.struts2.LoginAction@getSta()”/>
到值栈中找到这个类LoginAction的getSta()静态方法,然后调用这个静态方法

<s:property
value=”map.m1”/>找到map集合中key= m1的value值

<s:property
value=”map.keys”/>找到map集合中所有key的值

<s:property
value=”map.values”/>找到map集合中所有value的值

使用#号,从栈中(Map)取出数据:

在Action类中:

ActionContext ctx
= ActionContext.getContext();//获取包含当前HttpServletRequest的属性(attribute)的Map

ctx.put("req",
"Req属性");//向包含当前HttpServletRequest的属性(attribute)的Map设值(栈里和request内置对象中设值)

ctx.getSession().put("ses",
"Ses属性");//拿到session表示的Map,将值设到map中(栈),然后设到session内置对象中

在jsp页面中:

获取Request属性:<s:property
value="#request.req"/><br>//到stackContext中找到request的map,然后找到map中 可以为req对应的value值。

${req} :从内置对象中取出值,因为往值栈中设值的时候也会在内置对象中设值。

获取Session属性:<s:property
value="#session.ses"/><br>

${session.ses}:如果在内置对象中没有找到keyses对应的value,就会输出空串,因为struts2只复写了request,并没有复写session。所以无法继续从值栈中找到对应的值。

获取parameters属性:<s:property value="#parameters.mes"/>

说明:我们获取这些对象都用了#,因为这些对象都是存在一般的Context Map中,而不是存在值栈中。

Struts2+Spring3.0+Hibernate3.x

1、搭建集成环境

2、导入jar包(struts2-spring-plugin.jar以及其他的jar包)

3、持久层:HIbernate完成,Spring替hibernate生成sessionFactory, hibernate配置hbm文件生成对应的表以及表的关系

4、视图层:struts2

5、控制层:Spring

6、业务层:

启动tomcat:

1、读取web.xml文件,创建了监听器对象,对application对象的创建和消耗做监听

2、监听器实现了ServletContextListener接口

3、读取全局初始化参数,创建application内置对象,将全局初始化参数放到application内置对象中

4、监听器监听到application内置对象的创建,调用contextInitialized 
方法,通过注入事件对象拿到application,取得application中的初始化信息,创建BeanFactory

5、读取数据源 dataSource(数据库基本信息)

6、通过注入数据源,以及hbm,是否建表和显示sql等信息来生成sessionFactory

7、通过sessionFactory注入session对象(HibernateTemplate和线程绑定)

8、通过sessionFactory工厂生成事务管理器 HiberanateTransactionManager(根据事务传播特性决定是否使用事务)

9、根据事务管理器配置事务传播特性(应用在方法上,决定什么样的方法怎么使用事务)

10、配置Aop,(指定事务边界)

11、以注入的方式,创建持久对象(把hibernateTemplate直接注入),从工厂中拿到的对象为目标对象,不是代理对象,因为持久层不符合pointcut

12、以注入的方式创建业务层对象(把持久层对象注入),工厂会为业务对象创建代理对象,因为它符合pointcut

<创建代理对象的目的是给方法织入advice,advice决定哪些方法怎么使用事务>

13、Struts2action交给beanFactory创建,并且指定为多例 scope=prototype并发性高,(注入业务层对象)

14、在web.xml文件中配置hibernate的懒加载过滤器OpenSessionInviewFilter(结果拦截时关闭session,使用cglib代理)

15、在web.xml中创建struts2拦截器 StrutsPrepareAndExecuteFilter

16、Struts.xml放在src下,配置常量,包,以及action ,result

Struts.xml中的配置信息

<?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>

标识action对象由bean工厂创建,不会再由struts2创建

<constant name="struts.objectFactory"
value="spring"></constant>

<package name="myLogin"
namespace="/" extends="struts-default">

testController:和beanFactory中配置Actionid相同

<action name="reg"
class="testController">

<result
name="loginSuccess">/success.jsp</result>

<result
name="loginFailure">/failure.jsp</result>

</action>

</package>

05-08 07:50