• Struts2的基础知识


    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>

  • 相关阅读:
    JAVA日报
    JAVA日报
    JAVA日报
    JAVA日报
    JAVA日报
    JAVA日报
    JAVA日报
    剑指 Offer 20. 表示数值的字符串
    剑指 Offer 51. 数组中的逆序对
    剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
  • 原文地址:https://www.cnblogs.com/DFX339/p/8535233.html
Copyright © 2020-2023  润新知