• struts总结


    struts总结

    1.为什么学习Struts框架

       a.Struts框架好处

    struts2是主流的开发技术,大多数公司在使用,struts把相关的servlet组件的各种操作都进行了相应的封装,这样就可以轻松地完成复杂的操作。Struts2是基于MVC模式开发的,MVC结构是一个优秀的设计思想,可以提高程序结构的灵活性,便于日后的维护和扩展。

     --简化开发工作量,提高开发效率

         --采用了优秀的设计思想(MVC)

      b.Struts框架作用

    struts充当控制器,接收请求,分发处理,

      c.如何学习Struts框架

         先重点掌握框架使用,原理性有余力可以多了解些。

     

    注:我们目前使用的Struts版本为struts2 2.1.8。(2.1.6版本bug较多)

      d.学校struts要掌握的重点:

    valuestack

    action

    result

    拦截器

    标记库

    2.MVC模式在JavaWeb中的应用

       *a.什么是MVC

         是一种软件架构的思想,将一个软件的组成部分划分成三种不同类型的 模块,分别是:

    模型(用于封装业务逻辑,包括业务数据和业务处理逻辑,由JavaBean组件   (比如实体类,DAO,Service)实现),

    视图(负责显示界面与用户交互,处理表示逻辑,一种是展示数据,另一种      是接受数据,由jsp组件实现),

    控制器(用于控制流程,协调模型与视图,由Servlet、Filter组件(比如之 前的ActionServlet)实现)。

    使用mvc的最主要的原因是为了实现模型的复用:即模型只需要开发 一次, 模型不关心处理的结果如何展现,模型将结果交给不同的视 图,由视图来展 现这些数据;另外,可以利用不同的视图来访问 同一个模型。  

     

    MVC:基于面向对象的一种常见的体系架构

    Model:

    封装数据以及对数据操作的方法(相当于饭店中做菜的材料(数据)和做菜的厨师(方法)

    一个流程用一个方法

    View:

    封装的是用户界面,接收用户请求,负责输入和输出(和用户打交道)(相当于服务员)

    Controller:

    封装的是业务流程,控制业务流程(相当于饭店中的管理者)(如果程序比较简单,可以把Controller写在Model里面)

     

       b.为什么使用MVC

         企业程序更强调结构灵活,易于扩展和升级。所以广泛选用MVC模式开发。

       *c.JavaWeb中如何实现MVC结构

        JavaWeb技术主要有:Servlet,JSP,JavaBean,Filter,Listener等

        V部分:JSP组件 (cart.jsp)

        M部分:JavaBean组件(entity,dao)

        C部分:Servlet,Filter组件 (ShoppingCartServlet)

     *d.MVC处理流程

       --首先浏览器发出请求

       --请求进入C控制器

       --C控制器调用M模型组件处理

       --M模型组件处理后返回处理结果

       -- C控制器调用V视图组件生成响应信息

     

     *e.Struts框架的MVC实现

        原有ShoppingCart程序,虽然符合MVC结构,但不适合大型项目开发,因为请求一多,ShoppingCartServlet会出现大量的if..else... ,可以进行以下方式的改造:

    为ShoppingCartServlet配置一个XML文件,该文件定义不同请求和不同Action组件的对应关系,将原有if..else..分支处理用Action组件封装。   

      **f.Struts框架的处理流程

        --浏览器发出struts请求

        --请求进入struts控制器

        --struts控制器解析xml配置文件(xml定义了请求和Action对应关系)

        --控制器根据不同请求,调用不同的Action

        --Action调用DAO处理请求,之后返回结果

        --控制器根据结果调用视图组件为用户响应

     struts总结

     

    3.了解Struts历史

       Struts框架分成Struts1和Struts2.Struts2和Struts1没有必然联系。Struts2是以WebWork框架核心(xwork)为基础构建起来

    最早出现的Struts1是一个非常著名的框架,它实现了MVC模式。Struts1简单小巧,其中最成熟的版本是Struts1.2。之后出现了WebWork框架,其实现技术比Struts1先进,但影响力不如Struts1。在框架技术不断发展过程中,有人在WebWork核心XWork的基础上包装了Struts1(算是两种框架的整合),由此,结合了Struts1的影响力和WebWork的先进技术,Struts 2诞生了。所以说,Struts2不是Struts1的升级,它更像是WebWork的升级版本。

    *4.Struts基本使用

       a.引入struts2核心开发包(5个) 

    (1).struts2-core-2.1.8.1.jar

    Struts2核心包,是Struts框架的“外衣。

    (2).xwork-core-2.1.6.jar

    Struts2核心包,是WebWork内核。

    (3).ognl-2.7.3.jar

    用来支持ognl表达式的,类似于EL表达式,功能比EL表达式强大的

    多。

    (4).freemarker-2.3.15.jar

    freemarker是比jsp更简单好用,功能更加强大的表现层技术,用来 替代jsp的。在Struts2中提倡使用freemarker模板,但实际项目中使 用jsp也很多。

    (5).commons-fileupload-1.2.1.jar

    用于实现文件上传功能的jar包。

    b.在web.xml中配置下struts控制器

       c.根据请求编写Action,JSP

       d.在struts.xml定义Action和请求对应关系

    5.HelloWord入门实例

    welcome.action-->Struts控制器-->struts.xml-->WelcomeAction

    -->welcome.jsp

    (Action请求可以是/welcome.action或者/welcome两种写法)

    7、struts.xml基本配置

    struts.xml放在src根目录下。

    a) <struts>

    根元素,可以包含多个<package>元素

    b)<package>

    <package name="***" namespace="/默认" extends="struts-default">

    元素主要用于将Action分组定义。name属性用于指定包名;extends一般指 定为struts-default。struts-default这个包在struts-default.xml中定义,其中 包含了struts2运行所需的必要组件。

    添加namespace属性的主要作用是避免在大项目中出现的命名冲突问题。

    注意:

    http://localhost:8080/struts01/netctoss/welcome

    <package name="demo1" namespace="/netctosss" 

    extends="struts-default">

    <action name="welcome" class="action.WelcomeAction">

         <result name="success">/WEB-INF/jsp/Welcome.jsp</result>

     </action>

    namespace属性默认为“/”(即从应用名后的第一个"/"开始到最后一个“/”结束)。

    eg:对于http://localhost:8080/struts01/netctoss/cost/showList.action

    其中的namespace属性值应为”/netctoss/cost”。

    eg:

    如果不加namespace="/netctoss"那么

    http://localhost:8080/struts01/netctoss/list.action便不会得到正确的匹配

    一个<package>元素可以包含多个<action>..</action>主要用于定义请求

    和Action组件的对应关系。name属性指定请求名;class属性指定Action的包

    名.类名

    c)<action>

    <action name="***" method="execute默认" class="***">

    一个<action>元素可以包含多个<result>...<result>主要用于定义视图响 应。name属性与Action.execute()返回值一致。

    其中

    (1).method属性可以省略,如果省略则默认调用Action中的execute()方法

    (2.)如果不指定class属性,Struts会默认调用框架底层的ActionSupport

          类处理(见下面:)。框架会默认为该<action>添加一个class,作用是

          转发到对应

          的<result  name="success">中指定的页面。当有nameform请求发

          来时,struts不会调 用action(找不到)而是直接调用result中name属

          性为success对应的页面。

    注:name=”success”可以省略

    <action name="nameform">

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

           <result>/WEB-INF/jsp/Welcome.jsp</result>

    </action>

      struts总结

    --------ActionSupport类:---------

     public String execute(){

         return “success”;

    }

      

    d)<result>

    <result name="success默认" type="dispatcher默认">

    e:注意:

    1.对于package、action、result,如果使用默认属性值,则可以省略属性名。

    eg:<result name=”sucess” type=”dispatcher”>****</sesult>

      如果使用默认属性值:则可以写成:

      <result >****</sesult>

     

    对于重复使用的result可以写成全局的result

    <!-- 定义全局result -->

    <global-results>

    <!-- 错误处理 -->

    <result name="error">/WEB-INF/jsp/error.html</result>

    <!-- 拦截器登录处理 -->

    <result name="login" type="redirectAction">showLogin</result>

    </global-results>

     

    2.page包中的各组件的放置顺序:

    具体见struts-2.1.7dtd

    package (result-types——> interceptors——>default-interceptor-ref——> 

    default-action-ref——> default-class-ref——> global-results——> 

    global-exception-mappings——> action*)>

    拦截器配置放在global-results之前

     

    3.当项目业务处理较多时如果将所有的配置都写在struts.xml一个文件中将很不方便,所以可以将不同的处理模块分别写在不同的xml文件中,最后在struts.xml中加载和模块配置文件,过程如下:

    struts.xml:

    <struts>

    <!-- 加载各模块配置文件 -->

    <include file="struts-cost.xml"/>

    <include file="struts-account.xml"/>

    ...........

    <package name="netctoss-default" extends="json-default">

    <!-- 追加共通的Action,Interceptor组件 -->

    拦截器、全局results....

    </package>

    </struts>

    struts-cost.xml:

    <!-- 资费模块配置文件 -->

    <struts>

    <package name="cost" extends="netctoss-default">

    ........

    </package>

    </struts>

    struts-account.xml:

    <!-- 资费模块配置文件 -->

    <struts>

    <package name="account" extends="netctoss-default">

    ........

    </package>

    </struts>

    .............................

    浏览器访问地址:

    http://localhost:8080/应用名/namespace/action

    http://localhost:8080/struts03_2/list/costList.action?page=4

    以上的namespace默认为’’/’,本例为list

    8、如何解决用户绕过ActionServlet,直接访问jsp文件的问题。

    将所有jsp文件拷贝到WEB-INF目录下。因为WEB-INF目录中的内容不能直接访问,但能转发过来。

    当然也可以用之前的session技术(太麻烦)。

    对于struts中WebRoot文件夹下的.jsp页面仍可以直接输入地址访问。

    9、Struts2提供的方便之处:

    a.数据的自动的封装

    根据页面组件的name属性,自动封装到Action中对应的name属性中。

    在Jsp页面<input name=”name” type=”text”/>

    在action中会自动给属性private String name 赋值。但是注意要有name对应的getter和setter方法。

    b.数据的自动的传递

    Action中的属性在jsp页面可以直接用EL表达式拿到

    eg:

    Action中属性private String name;

    在jsp页面上可以直接${name}的到对应的值

    按理说,EL表达式取数据的对象只有pageContext,request,session,application四类,不应该从Action对象中取name属性值,但struts框架重新包装了request,getAttribute()方法被改写(request的其他方法没被改写),如果从request对象中调用getAttribute()方法没获取到值(null),那么会自动从action中取,这样,struts中EL表达式就可以直接获取到Action属性中的值了。

    上面介绍的采用了包装模式:(相当于手机加壳案例和线程池案例(其中的close方法特殊)。参考如下:

    public class StrutsRequestWrapper extends HttpServletRequestWrapper{

         //重写

         public Object getAttribute(String key){

               //寻找原request信息

               Object obj = super.getAttribute(key);

               if(obj == null){

                  //寻找valuestack信息

                   obj = valuestack.findValue(key);

                  //Ognl.getValue(key,context,root);

               } struts总结

               return obj;

         }

    }

    ${name} -->request.getAttribute("name")

    -->Ognl.getValue("name",context,root)

     

    10.项目示例(资费列表显示)

    a.显示默认主页面

     index.action-->struts控制器-->index.html

    b.资费列表显示

    feeList.action-->struts控制器

    -->FeeListAction-->FeeDAO-->COST

    -->fee_list.jsp

      1)编写COST对应的Entity实体类

      2)编写DAO,DBUtil

         --引入oracle驱动包

      3)编写Action

      4)配置Action

      5)编写JSP

        --引入jstl.jar,standard.jar

    11.OGNL技术的使用

      1)什么是OGNL

    OGNL是Object-Graphic Navigation Language(对象图导航语言)的缩写,

    是一种功能强大的表达式语言(与EL表达式类似)。OGNL可以让我们用非常

    简单的表达式访问对象层(访问对象的数据和方法),它用一个独立的lib形

    式出现(封装于ognl.jar工具包中),方便我们使用或者构建自己的框架。 

     

    OGNL区别于EL表达式,OGNL可以在.java文件中通过getValue()方法访问对

    象,而EL表达式不可以在.java文件中使用;EL表达式在.jsp文件中可以直接

    输出数据,而OGNL不可以,OGNL在.jsp文件中只能当做struts标签中的属性

    值,通过struts标签访问数据。

      2)OGNL基本原理

        OGNL工具主要由3部分构成,具体如下

        a.OGNL引擎

            负责解析ONGL表达式,定位数据

        b.Root根存储区(Object类型)

            负责存储要访问的目标对象(一个)。

        c.Context变量存储区(Map类型)

            负责存放多个要访问的目标对象。


      *3)OGNL基本语法

        a.访问Root区域对象基本语法

           Ognl.getValue("OGNL表达式""Map存储器内容","根存储器内容");

    Ognl.getValue("OGNL表达式""根存储器内容");

    --访问简单数据:"属性" 例如"name"

    int id = (Integer)Ognl.getValue("id", foo);

    String name = (String)Ognl.getValue("name", foo);

           --访问数组或List集合:"属性[0]" 

               例如"arr[1]"

    String arrVal = (String)Ognl.getValue("arr[1]", foo);

    String  listVal = (String)Ognl.getValue("list[2]", foo);

           --访问map集合元素:"属性['key']"或"属性.key"

         例如"map.c"或"map[‘two’]"  

              注:”map[‘a’]”不可用(‘a’结果为整数)

    String mapVal = (String)Ognl.getValue("map.b", foo);

    String mapval2 = (String)Ognl.getValue("map['user.name']",foo);

     --访问方法:"属性值.方法()",

        例如"list.size()"

    System.out.println(Ognl.getValue("map['two'].toUpperCase()", foo));

    System.out.println(Ognl.getValue("list.size()", foo));

     --访问构造方法:"new 包名.构造方法"

        例如"new java.util.Date()"

    Object obj = 

    Ognl.getValue("new org.tarena.entity.Foo('TOM')", foo);

     --访问静态成员:"@包名.类名@成员"

        例如"@java.lang.Math@PI"

    Ognl.getValue("@java.lang.Math@abs(-1)", foo);

    Ognl.getValue("@java.lang.Math@PI", foo);

     --创建List对象:"{元素1,元素2}"

    Object obj1 = Ognl.getValue("{'struts','hibernate','spring'}",foo);

     --创建Map对象

        "#{key1:value1,key2:value2}"

    Object obj2 = Ognl.getValue("#{1:'tom',2:'jack',3:'rose'}", foo);

     

    public static void main(String[] args) throws Exception {

    Foo foo = new Foo();

    foo.setId(100);

    foo.setName("张三");

    foo.setArr(new String[] { "A""B""C" });

    foo.setList(Arrays.asList("芙蓉""凤姐""春哥"));

    Map<String, String> map = new HashMap<String, String>();

    map.put("one""Java");

    map.put("two""JavaWeb");

    map.put("three""Struts2");

    map.put("user.name""Scott");

    foo.setMap(map);

    //测试OGNL访问foo目标对象

    //Ognl.getValue("OGNL表达式", "Map存储器内容","根存储器内容");

    //Ognl.getValue(expression, root);

    Map context = new HashMap();

    //访问root基本的属性值

    int id = (Integer)Ognl.getValue("id", foo);

    System.out.println(id);

    String name = (String)Ognl.getValue("name", foo);

    System.out.println(name);

    System.out.println(Ognl.getValue("user.name", foo));

    //访问root数组和集合元素

    String arrVal = (String)Ognl.getValue("arr[1]", foo);

    System.out.println(arrVal);

    String  listVal = (String)Ognl.getValue("list[2]", foo);

    System.out.println(listVal);

    //访问root对象的map集合元素

    String mapVal = (String)Ognl.getValue("map.b", foo);

    System.out.println(mapVal);

    String mapval2 = (String)Ognl.getValue("map['user.name']",foo);

    System.out.println(mapval2);

    //支持运算符

    System.out.println(Ognl.getValue("id+1",foo));

    //System.out.println((Integer)Ognl.getValue("id",foo)+1);

    System.out.println(Ognl.getValue(""姓名:"+name", foo));

    System.out.println(Ognl.getValue("id > 200",foo));

    //方法调用

    System.out.println(Ognl.getValue("map['two'].toUpperCase()", foo));

    System.out.println(Ognl.getValue("list.size()", foo));

    //构造方法的调用

    Object obj = Ognl.getValue("new org.tarena.entity.Foo('TOM')", foo);

    System.out.println(obj);

    System.out.println(Ognl.getValue("name", obj));

    //静态方法和常量的调用

    System.out.println(Ognl.getValue("@java.lang.Math@abs(-1)", foo));

    System.out.println(Ognl.getValue("@java.lang.Math@PI", foo));

    //创建一个list集合

    Object obj1 = Ognl.getValue("{'struts','hibernate','spring'}",foo);

    System.out.println(obj1.getClass().getName());

    //创建一个map集合

    Object obj2 = Ognl.getValue("#{1:'tom',2:'jack',3:'rose'}", foo);

    System.out.println(obj2.getClass().getName());

    }

    12、OGNL技术在Struts的使用

    在Struts2中有一个ValueStack(本质就是存放数据的集合)数据对象,该对象存储了请求相关的所有数据信息。例如request,session,application,action等.

      Struts2采用OGNL工具对ValueStack进行操作。

      1)xwork对OGNL进行了部分改造

        在xwork中将原来OGNL标准结构中的Root存储区改造成了一个栈结构

        (CompoundRoot)以前只能存放一个对象,现在进行了扩容,可以存放

        多个对象

        当利用"属性"表达式访问时,优先去栈顶对象寻找,没有再去次栈顶寻找。

    2)ValueStack结构(OgnlValueStack)

        ValueStack就是一个容器(Map集合)(存放东西的不是Tomcat容器)

    (参考valuestack.jpg)

     

    3)Struts2标签的使用

      在JSP中,利用Struts2标签显示数据,需要为标签指定OGNL表达式,标签利用表达式定位ValueStack中的数据,进行相应操作。

      a) debug标签:显示valuestack状态

    <s:debug></s:debug>

      b) iterator标签:循环集合元素

        value属性:指定ognl

        var属性:指定循环变量,会被存放到ValueStack的context区域。

        status属性:指定循环状态变量,会被存放到ValueStack的context区域.该

                     变量有count属性表示一共循环了多少个元素。

        index属性表示当前循环元素的索引。

    <s:iterator value="new int[totalPages]" status="i">

           <s:if test="#i.count==page">

              <a class="current_page"href="costList.action?page=${i.count }">

                  <s:property value="#i.count"/>

               </a>

            </s:if>

             <s:else>

              <a href="costList.action?page=${i.count }">

               <s:property value="#i.count"/>

              </a>

            </s:else>

     </s:iterator>          

      c) if...else...标签:判断分支

           test属性:指定ognl判断表达式

    <s:if test="page < totalPages>                  

              <a href="costList?page=${page+1 }">下一页</a>

            </s:if>

            <s:else>

               下一页 

     </s:else>

      d) property标签:显示数据

           value属性:指定ognl表达式

    <s:iterator value="costList" var="cost">

      <tr><td><s:property value="#cost.id"/></td></tr>

    </s:iterator>

      e) date标签:将date数据格式化输出

           name属性:指定ognl表达式

           format属性:指定日期模板

    <td>

    <s:date name="#cost.createTime" format="yyyy-MM-dd HH:mm:ss"/>

    </td> 

    13、Action组件的相关使用

       1)Action组件的原理

           --客户发出action请求给struts控制器

    --前端控制器截获请求并根据配置信息调用对应的action

           --struts控制器会创建valuestack对象

           --struts控制器根据请求创建Action对象并将Action压入valuestack的root

             栈顶(Action线性安全,不用考虑并发问题,struts会为每一个请求 创

             建一个Action对象,区别于Servlet)

           --struts控制器调用一系列拦截器做一些辅助性的工作(一般都是

             valuestack的操作),如通过parmaeterInterceptor将表单中的数据赋值

              给action中的对象;还有将请求相关request,session对象放入到

              valuestack的context区域,同时将ValueStack对象存入到request中。

              存储的key为”struts.valueStack”。(这样,当一次请求结束后,容器

              会销毁request,request销毁了,其中的valuestack对象也就销毁了)

           --控制器调用Action,执行业务方法处理(根据输入算输出并返回结果)

           --控制器根据Action返回值调用result视图组件处理。

           --请求处理完毕,销毁valuestack和Action对象。

           一次请求,一个valuestack和action对象

     2Struts中写Action过程

    定输入、定输出、根据输入算输出、返回结果

       *3)Action中如何使用session,request

            (1).利用ActionContext和ServletActionContext工具类(不推荐)

             a.ActionContext返回是Struts框架封装成Map之后的

      request,session,application.

    eg:

    //将用户信息写入Session

    ActionContext ac = ActionContext.getContext();

    Map<String,Object> session = ac.getSession();

    session.put("user", adminCode);

    Map<String,Object> application = ac.getApplication();

    Map<String,Object> request = (Map)ac.get("request");

             b.ServletActionContext返回的是Servlet中使用的request, session,

               application原有类型。

            (使用建议:存值取值建议用Map结构API,如果有特殊需求再采用

              Servlet原有类型(如获取客户端IP))

    eg:

    HttpServletRequest request = ServletActionContext.getRequest();

    HttpSession session = httpRequest.getSession();

    HttpServletResponse response = ServletActionContext.getResponse();

    ServletContext application = ServletActionContext.getServletContext()

     

    ActionContext工具类中的方法getSession()如何将HttpSession对

    象封装成Map对象的说明:

          Map----impements--->AbstructMap---extends-->SessionMap(重

                                                写了Map中的put和get方法)

    ----如何将原有HttpSession封装成Map------

    public class SessionMap extends AbstractMap{

        private HttpSession session;   

         public SessionMap(HttpSession session){

              this.session = session;

        }

          public void put(Object key,Object val){

              session.setAttribute(key,val);

         }

         public Object get(Object key){

             session.getAttribute(key);

         }

    }

    不推荐使用ActionContext访问Session的方式,因为这种方式的“侵入性”较强。ActionContext是Struts2的API, 如果使用其他框架代替目前的Struts2框架,而我们实际项目中的Action的数量非常庞大,每个类都修改的话,会非常麻烦。

       (2).利用Aware接口方式注入(推荐)

    将Action实现Aware接口,由框架底层将对象注入给Action中相应的变量

    当action实例化时候,struts框架就会自动将session对象(在valuestack中)赋值给实现了SessionAware接口的类中的变量(就是注入)。

    (即session,ruquest,response,application) 

    RequestAware 对应的是Map结构的Request

      SessionAware 对应的是Map结构的Session

      ApplicationAware 对应的是Map结构的Application

               ServletRequestAware对应的HttpServletRequest

    ServletResponseAware对应的HttpServeltResponse

    ServletContextAware对应的ServletContext

    eg:

    public class LoginAction implements SessionAware{

    protected Map<String,Object> session;

        ...............

    public void setSession(Map<String, Object> session) {

    this.session = session;

    }

    public String execute(){

    if(("admin".equals(adminCode)) && ("1234".equals(passWord))){

    session.put("user"adminCode);

    return "success";

    }else{

    return "error";

    }

    }

    }

    (3)、使用工具类(ActionContext、ServletActionContext)还是

    Aware接口?

    Action组件内部用Aware接口、Action组件之外(比如后面的拦截器)用ActionContext、ServletActionContext

       4)Action属性注入

      作用:在创建Action对象时指定属性值

      在<action>配置中为Action组件的属性指定一个初始值,该值在创建

           Action对象时注入。可以将一些变化的参数值,利用该方法指定。例如

           pageSize,管理员用户名,dir存储路径等。

    在<action>配置中,为Action对象的属性指定初始值。使用格式如下:

    <action name="feeList" class="org.action.FeeListAction">

            <!--创建Action对象时给属性指定一个值-->

            <param name="属性名">属性值</param>

            <result></result>

          </action>

    eg:

    public class ListAction{

        private Stirng param1;

        private String param2;

        .....

    public String getParam1(){

    return param1;

    }

    ..... struts总结

    public setParam1(Stirng param1){

    this.param1 = param1;

    }

    .......

     }

           struts.xml:

           <action name="feeList" class="org.action.FeeListAction">

            <param name="param1">admin</param>

            <param name="param2">1234</param>

            <result>........</result>

          </action>

       5)Action通配符配置

           Action通配符可以将多个具有相同属性的Action整合为一个Action。

    在<action>配置时,name请求名可以使用若干个*符号。然后再其他属

           性中通过使用{1},{2}引用第一个*号,第二个*号所代表的字符串。

    <!-- 通配符配置 -->

    <action name="*_*" method="{2}"class="com.tarena.action.{1}">

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

        </action>

     

      eg:

               CostAction.java:

    public class CostAction {

    //属性定义--省略

    public String add(){

    System.out.println("资费添加操作");

    return "success";

    }

    public String update(){

    System.out.println("资费更新操作");

    return "success";

    }

    }

    struts.xml:

    <action name="cost_*" method="{1}"

    class="com.tarena.action.CostAction">

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

    </action>

     

    14、Result组件的相关使用

      1)Result组件原理

        a.Result组件的作用

         Result组件负责生成响应视图内容。将ValueStack中的数据做不同形式

         的输出。

         Struts2框架提供了多种不同的Result组件类型,用于做不同形式响应。

          例如json数据响应,流数据响应,jsp响应等。

        b.Result组件相关配置

           --Result声明定义

             <package>

                  <result-types>

                    <result-type name="result类型" class="Result组件实现类"/>

                  </result-types>

             </package>

            --Result使用定义

            <action>

              <result name="标示符" type="result类型"></result>

            </action>

    c.编写一个转发功能的Result组件

    定义的类类必须实现Result接口(Result组件),并且将约定的execute方法实现在该方法中编写了生成响应输出的逻辑代码。

    public class MyDispatcherResult implements Result{

         private String location;

         //setter和getter方法

    ................

         //约定方法

      public void execute(){

                HttpServletRequest request = ServletActionContext.getRequest();

             HttpServletResponse response =ServletActionContext.getResponse();

              RequestDispatcher rd = request.getRequestDispatcher(location);

                 rd.forward(request,response);

          }

    }

      *2)掌握经常使用的Result组件

          a. JSP视图

           --dispatcher(默认):以转发方式调用JSP

           --redirect:以重定向方式调用JSP

            <result name="" type="dispatcher(默认)/redirect">

              jsp页面

           </result>

          b.Action视图

           --chain:以转发方式调用下一个Action

           --redirectAction:以重定向方式调用下一个Action

        c:

    stream:以字节流方式响应,Action中的InputStream类型的属性以

             字节流方式输出。

    eg:由服务器端生成验证码图片并以流的方式发送给浏览器。

     

    在struts.xml端的配置如下:

     <!--验证码处理 -->

        <action name="image" class="org.tarena.netctoss.action.ImageAction">

           <result type="stream"  name="success">

           <param name="inputName">imageStream</param>

           </result>

           <result name="fail">/WEB-INF/jsp/login.jsp</result>

       </action>

    注:其中的<param name="inputName">imageStream</param>区别于Action

        属性注入,其作用为:给result对象指定参数值

         d:

    json:以json字符串响应,将Action中指定的属性拼成一个json字符串输

    出。

         注:

    其中,a、b、c中的result组件在’struts-defaulg”包下,d中的result组件

         在”json-default”,struts-core.jar中的默认包

    <package name="struts-default" abstract="true">如下:

     

    <package name="struts-default" abstract="true">

    <result-types>

                <result-type name="chain" class="*****"/>

                <result-type name="dispatcher" class="*****"/>

                <result-type name="freemarker" class="*****"/>

                <result-type name="httpheader" class="*****"/>

                <result-type name="redirect" class="*****"/>

                <result-type name="redirectAction" class="*****"/>

                <result-type name="stream" class="class="*****"/>

                <result-type name="velocity" class="class="*****"/>

                <result-type name="xslt" class="*****"/>

                <result-type name="plainText" class="*****"/>

            </result-types>

    </package>

        相同命名空间调用:

      <result type="redirectAction">

          请求名

      </result>

        跨命名空间调用

      <result type="redirectAction">

          <param name="actionName">请求名</param>

          <param name="namespace">/</param>

      </result>

        ======资费删除流程=====

    fee_delete.action-->FeeDeleteAction-->FeeDAO

    -->FeeListAction-->fee_list.jsp

    ============练习=============

    完成课上项目任务。

    扩展任务:完成资费的添加,更新处理,查看,启用等。

     

    16、json Result组件

       主要负责将Action的属性以json字符串格式输出。

       json Result的使用步骤:

       a.引入struts2-json-plugin.jar

       b.将<package>元素的extends属性改为继承"json-default"(json-default包

         的范围比原struts-default包大,所以更改后仍可以使用以前包中的组件)

       c.<result>使用配置

         //只返回Action中一个属性值

      <result type="json">

           <param name="root">属性名</param>

      </result>

        //返回Action中多个属性值

      <result type="json">

           <param name="includeProperties">

           属性名1,属性名2,属性名3

          </param>

      </result>

       //返回Action中所有属性值

      <result type="json">

      </result>

     

       因为使用name属性默认值,所以name=”success”可以省略。

     

    17、Struts2表单标签

      1.什么是标签

    struts标签封装了界面显示逻辑,用于简化JSP。

    jstl标签用来代替jsp页面中的java代码,struts标签不但可以代替jsp页面中的

    java代码,还可以代替jsp页面中html标记

      2.struts常用标签:

    textfield,password,hidden,textarea

    radio,checkboxlist,select

    checkbox,form

    a) textfield 

       以输入框方式显示属性值.

       name属性指定ognl表达式,表示输入框中的值

    <input type="text" class="readonly" name=cost.id value=${cost.id

     readonly />

    相当于:

      <s:textfield name="cost.id" cssClass="readonly" readonly="true">

    </s:textfield>

    规定输入字段为只读(内容不可被更改)。在html中input标签readonly属性

         直接写,在struts标签中要写成:readonly=”true”。类似的的还有disabled要写成

         disabled=”true”

    b) textarea 

       以文本域方式显示属性值.

       name属性指定ognl表达式,表示文本域中的值

     <textarea class="width300 height70">${cost.descr}</textarea>

    <s:textarea name="cost.descr" cssClass="width300 height70"></s:textarea>

    c)password:

     以文本框方式显示密码

     name属性指定ognl表达式,,表示输入框中的值

    注:默认情况下,文本框内不会显示密码,如果要显示密码则需要设置showPassword属性。

    密码:<s:password name="password" showPassword="true"></s:password>

    d) radio: 

        以一组单选框方式显示,并可以根据属性值决定哪个选项选中。

     list属性指定集合ognl,用于生成若干radio选项。

     name属性指定ognl,用于决定哪个raido选中。

    <s:radio name="cost.costType" list="#{'1':'包月','2':'套餐','3':'计时'}">

    </s:radio>

    e)checkbox:

    以单选框方式显示选中状态

    name属性指定ognl表达式,name属性值为true时,单选框默认会被选中

    eg:

    婚姻状况:<s:checkbox name="marry""></s:checkbox>已婚

    f)checkboxlist:

    以复选框方式显示选中状态

    name属性指定ognl表达式,用来决定哪些复选框默认被选中。

    list属性为map<key,value>集合

    listKey属性为map集合中的key

    listValue属性为map集合中的value,为在界面显示的内容

    参考struts05_1中的form.jsp

    eg1:

    爱好:<s:checkboxlist name="chk" list="#session.favors" listKey="id" 

           listValue="name"></s:checkboxlist>

    eg2:

        <s:checkboxlist name=”” list=”costList’” listKey="id" 

           listValue="name"></s:checkboxlist>

     

    g)select:

     以下拉列表的方式显示数据:

         name属性指定ognl表达式,用来决定哪个option默认被选中。

    eg1:

    <s:select name="status" cssClass="select_search"

             list="#{0:暂停,'1':'开通','2':'暂停','3':'删除'}">

              </s:select>

    相当于

     <select class="select_search" >

                         <option value="2">全部</option>

                         <option value="1">开通</option>

                         <option value="0">暂停</option>

                         <option value="-1">删除</option>

         </select>

       eg2:

       <s:select list=costList name=”” listKey=id listValue=name></s:select>

    注:对于上面的struts标签中的name属性,不但可以指定ognl表达式获取相关的数据,还可以将action中的属性名设置为name的属性值,这样就可以实现表单数据的自动提交。

    h)form:

    theme属性:表示主题,可选项有xhtml和simple;如果不写,默认为xhtml 。

      theme属性如果为默认值(xhtml),那么在使用struts表单标

        签时候会自动添加样式(自动添加tr、tr,让显示更美观),

        这样就会破坏当前页面的布局和样式。

        如果在用struts表单标签时,没有用struts中的form标签而是

        使用html中的form标签,那么在使用struts表单标签时候也

        会自动添加样式

    <s:form action="update" namespace="/" theme="simple">

       .............

    </s:form>

     通用属性(所有标记都具备的属性):

    label

    labelpostion

    required

    tooltip

    tooltipIconPath

    cssClass(html中的class)

    cssStyle(html中的style)

    name

    value

     

    18、拦截器组件

    2)什么是拦截器:

      一般利用拦截器封装一些通用性处理功能,便于重复利用。例如请求参

        数给action属性赋值、日志记录、权限检查、文件上传、事务处理等。拦截

        器通过配置方式调用,因此使用方法比较灵活,便于维护或扩展。

    Struts2框架提供了大量的拦截器组件,如果不能满足开发者需要,可以

     进行自定义。

    eg:

    <interceptor name="params" 

    class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>

    其中ParametersInterceptor类用于在创建Action对象时将表单中的参数

    赋值给Action中的相关属性。

    具体见:

    ReferencedLibraries/struts2-core-2.1.8.jar/struts-default.xml

     /<interceptors>标记

     

    2)拦截器完整工作流程:

     

    上图中的FilterDispatcher为前端控制器

    a.客户发送一个Action请求,请求交给控制器

    b.控制器创建一个ValueStack、Action对象,并将Action压入ValueStack栈顶

    c.控制器调用ActionInvocation组件执行请求处理

    d.ActionInvocation组件调用请求相关的拦截器组件--前部分处理.

    e.然后再调用Action组件业务方法

    f.然后再调用Result组件处理方法

    g.最后执行拦截器组件--后部分处理.

    h.将响应信息输出,为客户端响应

     3)拦截器作用

        拦截器可以在Action和Result组件调用之前执行,也可以在Action和Result

        组件之后执行。

     4)自定义拦截器

        a.编写拦截器组件实现类(两种方法):

         1.编写拦截器组件实现类实现Interceptor接口的interceptor方法。

       public class MyInterceptor implements Interceptor{

          public String intercept (ActionInvocation in){

               //拦截器的前期处理逻辑

               in.invoke();//执行Action和Result

              //in.invokeActionOnly();//仅执行Action

               //拦截器的后期处理逻辑

           }

    }

    eg:

    public class CheckLoginInterceptor implements Interceptor{

    public void destroy() {

    // TODO Auto-generated method stub

    }

    public void init() {

    // TODO Auto-generated method stub

    }

    public String intercept(ActionInvocation in) throws Exception {

    System.out.println("(前期处理)自定义拦截器被调用。。。");

    ActionContext ac = ActionContext.getContext();

    //ActionContext ac = in.getInvocationContext();

    Map<String,Object> session = ac.getSession();

    //登录检查

    if(session.get("user") == null){

    //为登录

    return "login";//进入登录页面

    }

    in.invoke();//执行ActionDAO和Result--->jsp

        System.out.println("(后期处理)自定义拦截器被调用。。。");

    return null;//invoke()方法执行之后,后面的返回值都无效即不会返回),因为执行in.invoke(),也即执行Action和Result调用Jsp后,返回的值没有任何意义。

    }

               }

      2.所有拦截器组件实现类也可以通过继承AbstractInterceptor类并实现

       inteceptor方法。

    eg:

    public class Interceptor2 extends AbstractInterceptor {

    public String intercept(ActionInvocation in) throws Exception {

    System.out.println("(前期处理)自定义拦截器被调用。。。");

    // ActionContext ac = ActionContext.getContext();

    ActionContext ac = in.getInvocationContext();

    Map<String, Object> session = ac.getSession();

    // 登录检查

    if (session.get("user") == null) {

    // 未登录

    return "login";// 进入登录页面

    }

    in.invoke();// 执行Action和Result

                  System.out.println("(后期处理)自定义拦截器被调用。。。");

    return null;//invoke()方法执行之后,后面的返回值都无效(即不会返回),写着只是好看一点

    }

           }

       注意:当执行了invoke()方法后,invoke()方法后面的返回值无效(即不会返回),写着只是好看一点。如果没有执行invoke(),返回值有效。控制器会根据该返回值调用一个Result生成响应信息

     b.注册拦截器(将拦截器注册给struts2框架)

    (1).方法一:

    <package>

       <interceptors>

           <interceptor name="拦截器名"class="拦截器实现类"/>

           <interceptor name="" class=""/>

       </interceptors>

    </package>

    eg:

     <!-- 定义拦截器 -->

    <interceptors>

      <interceptor name="checklogin" 

            class="org.tarena.netctoss.interceptor.CheckLoginInterceptor2"/>

     </interceptors>

     <!-- 使用拦截器 -->

    <action name="costDelete" class=org.tarena.netctos.CostDeleteAction>

          <interceptor-ref name="checklogin"/>

        <interceptor-ref name="defaultStack"/>//调用默认拦截器栈中的拦截器

      <result name=cuccess>/WEB-INF/jsp/cost/cost_delete.jsp</result>

    </action>

      struts总结

    (1).方法二

    创建拦截器栈(<interceptor-stack name="loginStack">),将多个拦截器放在拦截器栈中,这样就可以在需要的地方直接引入拦截器栈就行了(<interceptor-ref name="loginStack"/>

    eg:

    <!-- 定义拦截器 -->

    <interceptors>

      <interceptor name="checklogin" 

            class="org.tarena.netctoss.interceptor.CheckLoginInterceptor2"/>

    <interceptor-stack name="loginStack">

    <interceptor-ref name="checklogin"/>

    <interceptor-ref name="defaultStack"/>

     </interceptor-stack>

    </interceptors>

        <!-- 使用拦截器 -->

    <action name="costDelete" class=org.tarena.netctos.CostDeleteAction>  

    <interceptor-ref name="loginStack"/>   

    <result name=cuccess>/WEB-INF/jsp/cost/cost_delete.jsp</result>

    </action>

    方法二中的定义拦截器的方法实际上是先定义一个checklogin拦截器,然后定义一个拦截器栈(用于存放多个拦截器),把定义的checklogin拦截器和struts默认的拦截器放在拦截器栈里面。在使用拦截器时候,直接引入拦截器栈就可以了(相当于引入了checklogin拦截器和struts默认拦截器)。

     

      c.使用拦截器组件

        (1).为所有Action指定默认使用配置,这样,拦截器便对该包中的所有Action

           起拦截作用

       <package ******>

            <default-interceptor-ref  name="拦截器名"/>

       </package>

       --(2).为某一个Action指定使用配置

       <action>

          <interceptor-ref name="拦截器名"/>

       </action>

    eg:

    <action name="showAddCost">

           <interceptor-ref name="loginStack"/>

    <interceptor-ref name="defaultStack"/>

    <result>/WEB-INF/jsp/cost/cost_add.jsp</result>

    </action>

       注意:如果为某个Action指定了拦截器配置,不会再调用指定的默认拦截器.所以一般会加上<interceptor-ref name="defaultStack"/>

     

    5)fileUpload内置拦截器的使用

       a)fileUpload拦截器功能

           用于实现文件上传功能。

    fileUpload拦截器处理流程:

      客户端发送上传文件请求

    首先,struts控制器收到请求后调用fileUpload拦截器,fileUpload拦截器调用commons-file-upload.jar上传组件对请求提交

    的表单信息进行解析。

    然后将解析后的文件保存到服务器临时目录下,并将临时目录下的文件

       对象赋值给Action的File属性。

    执行Action,在Actin业务中,需要做文件复制,将临时文件转移到目标

       目录中。

    当Action和Result调用完毕后,清除临时目录下的文件,因此在Actin业务中,需要做文件复制,将临时文件转移到目标目录中。

       b)上传示例

         注意事项:

          --需要引入commons-io.jar)

          --form表单method必须为post;enctype必须为multipart/form-data

          --Action组件按下面规则接收表单信息

              <input type="file" name="xxx">

            Action属性如下:

              private File xxx;// 临时目录下的文件

              private String xxxFileName;// 源文件名

              private String xxxContentType;// 源文件类型

         ---struts默认允许上传的文件所占最大内存为2097152字节(不同计算机可

            能略有不同)。如果要更改默认设置,可以参考如下“更改struts中的默

            认设置”

    更改struts中的默认设置(即修改如下配置文件):

    ReferencedLibraries/struts2-core-2.1.8.jar/org-apache.struts2/default.properties

     

    18、更改strts中的默认配置:

    1.更改对客服端发送过来的参数进行解码的方式:

    <constant name="struts.i18n.encoding" value="gbk"/>(默认为utf-8)

    2.更该允许客户端上传的最大文件大小值:

    <constant name=struts.multipart.maxSize value=100000000/>

    (默认大小为:2097152字节,约2M)

     

    19、全局异常处理:

    <!--全局的异常处理,当异常从Action中抛出时,会自动进入全局异常处理模块-->

       <global-results>

          <!-- 错误处理 -->

        <result name="error">/WEB-INF/jsp/error.html</result>

         </global-results>

     

     <global-exception-mappings>

    <exception-mapping exception="java.lang.Exception" result="error">

           </exception-mapping>

     </global-exception-mappings>

     

    20、用户输入不存在请求资源路径(及action不存在)处理:

    <!-- 指定一个默认响应的Action,当遇到例外的action请求,该项配置启作用 -->

    <default-action-ref name="defaultAction"/>

    <!-- 采用重定向方式调用toLogin -->

    <action name="defaultAction">

    <result type="redirectAction">

    <param name="namespace">/</param>

    <param name="actionName">toLogin</param>

    </result>

    </action>

        <!-- 显示登录页面 -->

        <action name="toLogin">

    <result>/WEB-INF/jsp/login.jsp</result>

     </action>

    通过此配置后,用户输入非法请求资源路径时便不会出现“404”错误提示了,而是友好地跳转到登录页面。

    ======NETCTOSS项目========

    1)项目描述(一期工程)

      实现电信计费系统的账号管理,业务管理,资费管理,管理员和角色管理的功能。

    2)项目技术架构

      主要采用Struts2,JDBC,Ajax,jQuery技术。

       采用MVC结构分层思想开发。

       表现层(V):JSP,Ajax,jQuery

       控制层(C):Struts2控制器Filter+Action

       业务层(M):JavaBean,Bean组件

       数据访问层(M):DAO+JDBC

    3)项目工程结构

      a.开发包引入

        --Struts2开发包(5个核心+1个json响应包)

        --Oracle驱动包

      b.src源码

        org.tarena.netctoss.action

        org.tarena.netctoss.action.fee

        org.tarena.netctoss.action.account

        org.tarena.netctoss.service

        org.tarena.netctoss.dao

        org.tarena.netctoss.pojo

        org.tarena.netctoss.util

        org.tarena.netctoss.test

      c.配置文件

        web.xml : 配置struts2控制器

        struts.xml:struts2框架主配置

         --struts-fee.xml : 资费模块配置

         --struts-account.xml:账号模块配置

      d.WebRoot

         WebRoot/WEB-INFO/jsp/fee/资费页面

         WebRoot/styles/样式文件

         WebRoot/js/脚本文件

         WebRoot/images/页面图片

      

    =========记录检索=========

    search.action-->SearchAction-->DAO

     

     

     

    1.项目评审

      1)自我简介,项目需求描述,功能演示

      2)典型功能实现讲解

    2.共通问题处理

      1)表单校验处理(参考“jQuery表单校验插件”目录的资料)

         可以利用jQuery编写校验函数,

         也可以基于现有的jQuery扩展插件来实现

         例如validate和formvalidate等插件都可以

       2)Struts2全局异常处理

           当异常抛出Action的业务方法时,可以利用全局异常处理方式解决(在struts.xml追加配置)。

       3)将页眉导航部分提取成一个head.jsp,

     通过include方式引入各个页面。

       4)设置一个默认响应Action。

      遇到不能识别的Action请求,或找不到请求对应的Action时,调用该默认Action做响应

    以上的“struts总结“是本人在学习期间自己总结出来的,今天,把她晒出来,希望能够和大家分享下!


  • 相关阅读:
    JAVA语言中冒号的用法
    Tamper Data 安装与使用
    HTTP协议缓存策略深入详解之ETAG妙用
    HTTP协议
    HTTP协议----ETag
    super 使用以及原理
    __slots__用法以及优化
    归并排序详解(Python | Java实现)
    周刷题第二期总结(Longest Substring Without Repeating Characters and Median of Two Sorted Arrays)
    周刷题第一期总结(two sum and two numbers)
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3436947.html
Copyright © 2020-2023  润新知