现在的位置: 首页 > 综合 > 正文

struts2 笔记

2017年10月24日 ⁄ 综合 ⁄ 共 17554字 ⁄ 字号 评论关闭

文档 --> google --> 老师
读书方法:记最常用的。 不常用的脑子里留印象,用到的时候再去查。不要在那边每个知识点来回扣。90%的书溜一遍,90%的书是用来查的(书是用来查的,不是用来扣的)。扣的书比如:数据结构,设计模式。
学了各种各样的方法,参加工作以后只要找到一种方法能解决它就行了,千万不要老钻牛角尖非要把那种特殊的方法研究出来。
    请大家不要去研究现在用不上对现在没有意义的东西,不要把你的精力放在将来才会用到的东西上,永远把你的精力用在java right now。
    不要用当前的时间去做以后的事,人没有这么多精力,也不一定记得住。因为你还没学会走呢,就逼着你去跑,你还没学会用呢,就逼着你去读源码。
一定要多多地关注在业务这个方面,而技术这方面要多多地学它的原理,弄明白原理,拿来用(除了业务方面,其他的全是copy改),原理在很多方面是相通的。

struts2核心:将请求与视图分开了。
让myeclipse在写struts时自动提示:打开preferences搜索catalog 打开xml子项中的 xml.catalog增加dtd文件
让struts开发者模式:sttuts.xml增加<constant name="struts.devMode" value="true" />
让myeclipse增加java文件的api关联,右键  properties编辑java source attachment
让myeclipse增加classs文件的反编译文件,右键  properties编辑resource
    设置Java Source Attachment:struts2源码目录:struts2根目录/src/core/src/main/java/
    设置Javadoc Location:URL:struts2根目录/doc/strut2-core/apidoc
namespace:默认为空
    一个url路径要是里面没有对应的<action>的name属性时,它会去上层目录的namespace里找<action>
        每个action不要和不同<package>里面的<action>相冲突,
action:
    定义:只要是一个普通的class类,类中包含execute()方法,并且返回值为String时,这个类就可以被strut2当成action
          也可以是implements Action,是要实现String execute()
          也可以是extends ActionSupport。(只用这一种),封装了各种常用的方法,可以直接拿来使用。
    struts2每次访问必定new一个,strut1每次访问用的同一个
    如果不定义,默认new ActionSupport的一个实例,默认返回success。
    
    具体视图的返回可以由用户自己定义的Action来决定。
    具体的手段是根据返回的字符串找到对应的配置项,来决定视图的内容
    具体Action的实现可以是一个普通的java类,里面有public String execute方法即可或者实现Action接口,不过最常用的是ActionSupport继承,好处在于可以直接使用Strut2封装好的方法
    
    发来的请求首先交给struts.xml处理,如果没有在struts.xml里找到对应请求的namespace,则交给web.xml处理
    
    struts2中的路径问题是根据action的路径,即浏览器上显示的action的上下文路径。而不是jsp路径来确定,所以尽量不要使用相对路径,使用绝对路径
    虽然可以使用redirect方式解决,但redirect方式并非必要,不要使用它。
    解决办法非常简单,统一使用绝对路径(在jsp中用request.getContextRoot方式来拿到webapp的路径)或者使用myeclipse经常用的,指定basePath
    
    Action执行的时候并不一定要执行execute方法
    可以在配置文件中配置Action的时候用method=来指定执行哪个方法(可以忘了),也可以在url地址中动态指定(动态方法调用DMI(使用!调用需要使用的方法))(推荐),前者会产生太多的action,所以不推荐
    
    使用通配符,将配置降到最低
    *_* * {1} {2}...
    不过,一定要遵守“约定优于配置”原则
     只要包括(*)都是同一等级,哪个配置放前面调哪个,完全匹配高于带(*)的匹配
     
     接受参数:
         1 在action中定义成员变量,写上对应的getXxx(),和setXxx()方法,即可使用参数
         2 也可以使用域模型的概念(类似于javabean),只需要在域模型类中定义好接受参数成员变量的get/set方法,即可在action使用这个域模型的参数。(当然这个域模型成员变量(不用初始化new)和相应的get/set方法还需定义),url传递时也要使用对应的域模型对象进行设置,如:http://localhost:8080/BBS/action?user.setName("")
         参数传递过来的参数与后面的DomainModel 匹配不上,这时可以使用两种方式,1属性接收过来再给DomainModel。2用DTO接受参数然后 在action相应方法处理完了后(前台参数与DTO模型匹配,比如密码确认) 把DTO对象中取出参数的值再填充给DomainModel。
         3 url传递参数时,不用使用域模型对象。可以直接用 属性=值 的方式传递。action只需implements ModelDriven<域模型类>接口,域模型成员变量需要初始化才行。实现一个方法public 域模型类 getModel(){return 域模型类成员变量}
         中文问题:传递中文参数时,在struts.xml配置文件中加上:<constant name="struts.i18n.encoding" value="GBK" />
         
     数据校验:
         使用addFieldError方法(action)和s:fieldError标签(jsp)简单处理数据校验
             在action中:
             校验:有错误则:this.addFieldError("name","name is error!");
             在jsp中:
             <%@taglib uri="/struts-tags" prefix="s" %>
             <s:fielderror fieldName="name" theme="simple"/>
             <s:property value="error.name[0]"/>//从值栈取值
             <s:property value="#parameters.t" />//从ActionContext中取值,用#运算符
             <s:debug></s:debug>//打印值栈(保存Action的所有属性)和ActionContext(保存Action的上下文环境)的内容
             
     取得(Map类型):request,session,application,(真实类型):HttpServletRequest,HttpSession,HttpContext的引用:
     1前三者:依赖于容器
     2前三者:IOC
     3后三者:依赖于容器
     4后三者:IOC
     第一种方式(依赖于容器):
         在action中定义和初始化:
             如:private Map request;//在action中定义Map类型的变量
                 private Map session;
                 private Map application;
                 
                 public Action名字(){  //可以在构造方法里取值或者在execute()方法里取值。
                     request=(Map)ActionContext.getContext().get("request");//ActionContext即action的上下文环境。
                     session=ActionContext.getContext().getSession();
                     application=ActionContext.getContext().getApplication();
                 }
         存入属性值:(在action中的execute())
             如:request.put("r1","r1");
                 session.put("s1","s1");
                 application.put("a1","a1");
         在视图jsp中获取属性值:
             <s:property value="#request.r1"/>|<%=request.getAttribute("r1")%>
     第二种方式(常用,IOC)(主要使用这种方式中的session,其他方式基本不用):
         需要implements RequestAware,SessionAware,applicationAware接口
         在action中定义相应变量:
             private Map<String,Object> request;
             private Map<String,Object> session;
             private Map<String,Object> application;
         写上实现接口的方法:
             public void setRequest(Map<String,Object>,request)    {
                 this.request = request;
             }
     第三种方式(依赖于容器):
         定义:
             private HttpServletRequest request;
             private HttpSession session;
             private ServletContext application;
         构造方法:
             public action类(){
                 request = ServletActionContext.getRequest();
                 session = request.getSession();
                 application = session.getServletContext();
             }
         设置属性:request.setAttribute("r1","r1");
     第四种方式:(IOC)
         实现接口:implements ServletRequestAware
         定义:
             private HttpServletRequest request;
             private HttpSession session;
             private ServletContext application;
         实现方法:
             public void setServletRequest(HttpServletRequest request){
                 this.request = request;
                 this.session = request.getSession();
                 this.application = session.getServletContext();
             }
             
包含配置文件:
    在struts.xml文件中的<struts>标签中加入:<include file="login.xml">,login.xml同struts.xml,为了分模块

默认action(慎用):
    写在<package>标签里面<default-action-ref name="index"></default-action-ref>//如果在对应namespace找不到匹配的<action>,则交由默认<action>处理。
        注意:默认action只返回对应的<result>页面,并不执行相应的action类.
        

总结:将来开发主要就是:action类从ActionSupport继承,按照约定写好自己的各种方法add,delete...写完之后用DomainModel接受参数,如果需要访问Session,用IOC访问。

result
类型:
    配置<action>时,指定其子元素<result>的type属性。(掌握前四种,重点是上面两种)
    dispatcher:服务器跳转,同forward(),只能跳转非action的视图页面(默认)
    redirect:客户端跳转到一个视图页面
    chain:forward到一个action
    redirectAction:重定向到一个action
    freemarker
    httpheader:http头信息
    stream:下载
    velocity:干不过freemarker
    xslt:和xml相关
    plaintext:将页面的源码显示出来,用于教学
    tiles:

全局Result:
    如果同一个<package>中的多个<action>共用一个结果,可以将它配置为共用结果。
    配置在<package>子元素下:<global-results>
                                <result name="mainpage">/mainpage.jsp    </result>
                            <global-results>
    如果不同的<package>想用,用<package>的extends属性继承一个包。

动态结果集:
    在<result>元素下可以使用${值栈中的名值对}这种方式去读取值栈中的内容(对于action它的任何一个属性都会放在值栈里面)。了解即可,用的并不多
    在action中可以用一个属性来保存一个具体结果(视图)的location,这个属性里面的结果可以由我们动态确定,在struts.xml用${}这种表达式访问属性
    一次request只有一个值栈,forward过程分享同一个值栈,redirect使用不同值栈,所以redirect要使用url?新参数名=${action属性名}
    
OGNL表达式:
    OGNL:Object Graph Navigation Language
    访问值栈中的action的普通属性:<s:property value="username" /> //value="username"这部分内容是OGNL表达式。
    访问值栈中对象的普通属性(get set方法):<s:property value="user.age" />
        url?user.age=9:只有url传递参数才会构造,或者手动new。如果Domain Model在action里没有手动new初始化,那么你想让struts2为你自己new出来的时候,你必须要给domain Model传值,而且你的domain Model必须有一个参数为空的构造方法,不然它不知道调用哪一个构造方法。
            想初始化domain model,可以自己new,也可以传递参数值,但这时候需要保持参数为空的构造方法。
        如果想访问对象的对象,只需要使用(.)操作符一层一层深入即可。    
    访问值栈中对象的普通方法:<s:property value="password.length()"/> //password为action的一个String属性,所以可以调用String的相关方法。也可以调用自定义对象的方法。
    访问值栈中action的普通方法:<s:property value="m()" />  //访问action的普通方法,即定义在action的普通方法。
    访问静态方法:<s:property value="@com.gmail.yangunilay.xxxAction@xxx()" /> //前面@跟类名,后面@跟静态方法名   
        需要在struts.xml中在struts中配置:<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
    访问静态属性:<s:property value="@com.gmail.yangunilay.xxxAction@STR"/>//前面@跟类名,后面@跟静态属性名
    访问Math类的静态方法:<s:property value="@@max(2,3)"    />  //@@只能访问Math类的静态方法。
    访问普通类的构造方法:<s:property value="new com.bjsxt.struts2.orgl.User(8)"/>//可以在value里面new对象
    数组的访问方式和List一模一样
    访问List:<s:property value="users" />//只需用对应的List对象即可   
    访问List中的某个元素:<s:property value="users[1]" />
    访问List中元素某个属性的集合:<s:property value="users.{age}" />//把users这个List中每个元素拿出来,然后把每个元素对象的age属性组合在一起成为一个新的 集合。
    访问List中元素某个属性的集合的特定值:<s:property value="users.{age}[0]"/>|<s:property value="users[0].age"/>
    访问Set和访问List一模一样,有一点不同:不能访问set的下标值,因为它是无序的。
    访问Map:<s:property value="dogMap" />
    访问Map中的某个元素:<s:property value="dogMap.key" /> |<s:property value="dogMap['dog101']"/>|<s:property value="dogMap[\"dog101\"]" />
    访问Map中所有的key:<s:property value="dogMap.keys" />
    访问Map中的所有value:<s:property value="dogMap.values" />
    访问容器的大小:<s:property value="dogMap.size()" /> |<s:property value="dogMap.size"/>
    投影(用正则表达式过滤):<s:property value="usesrs.{?#this.age==1}[0]" />//用?#开头表示是过滤条件
    投影:<s:property value="users.{^#this.age>1}.{age}" />
    投影:<s:property value="users.{$#this.age>1}.{age}" />
    投影:<s:property value="users.{$#this.age>1}.{age} == null" />
    用[]访问元素:<s:property value="[0]" /> //访问值栈对象
    什么时候在stack中会有两个Acton? chain
    其他参考orgl.jsp
    
    $:
        用于i18n(99%不用,除非你的网站面向国际化)或struts.xml配置文件里面来代表一个OGNL表达式
            struts.xml中应用OGNL表达式,在Resource.properties中放置将要在struts.xml引用的字段的值,然后在struts.xml中使用${}进行引用
    #:
        取得ActionContext的值,
            #parameters,代表request提交的所有参数,#parameters.id返回的是String[]类型,相当于JSP中的request.getParameterValues("id");一般使用#parameters.id[0]
            #request,代表request里的所有属性,#request.account相当于JSP中的request.getAttribute("account")
            #session,代表session里的所有参数,#session.account相当于JSP中的session.getAttribute("account")
            #application,代表ServletContext里的所有属性,#application.account相当于JSP中的application.getAttribute("account")
            #attr,代表request或session或application的所有属性,#attr.account相当于EL表达式中的${account}依次查找request,session,application的属性,找到为止。
        用于过滤或帅选集合:
            <struts:property value="magazineList.{?#this.name.contains('时代')}.size()"/>
        构造Map:
            如:#{'foo1':'bar1','foo2':'bar2'}
    %:将原本的文本属性解析为ognl,对于本来就是ognl属性不起作用。%{ }:把大括号里面的内容强制转换成OGNL表达式。
    
Struts标签:
    1通用标签:
        property:
            输出变量值
            取值为字符串:<s:property value="'username'" />
            设定默认值:<s:property value="admin" default="管理员" /> //如果有一个值取不到,则使用这里设定的默认值。
            设定HTML:<s:property value="'<hr/>'" escape="false" /> //escape如果为false,则它就把它当成是一个html
        set(换名后放入ActionContext):
            设定adminName的值(默认为request和ActionContext):<s:set var="adminName" value="username" />//它会把adminName这个变量放在request和ActionContext里面
            从request取值:<s:property value="#request.adminName" />
            从ActionContext取值:<s:property value="#adminName" />
            设定范围:<s:set name="adminPassword" value="password" scope="page" />//scope属性设定有效的范围
            从相应的范围取值:<%=pageContext.getAttribute("adminPassword") %>
            设定var,默认范围为action(即request和ActionContext都有),如果设定scope,则就放在对应的scope范围内,ActionContext则没有了。
            使用#取值:<s:property value="#adminPassword" />
            从相应范围取值:<s:property value="#session.adminPassword" />
        bean(实例化一个bean类):
            在开始时它会new一个对象放在value stack contents里面,在结束时候它会把这个对象从value stack contents(栈)里拿出来,放入Stack Context(ActionContext)里面,名字为var设置的值。
            定义bean,并使用param来设定新的属性值
                <s:bean name="com.bjsxt.struts2.tags.Dog" var="myDog">
                    <s:param name="name" value="'oudy'"><s:param>//通过setter方法将字符串set到name属性上
                    <s:property value="sex"/>会调用sex属性的getter方法输出属性的值
                <s:bean>
        include
            可以用jsp包含代替,最好不要用,对中文支持有问题。
            <s:include value="/_include1.html"><s:include> //包含文件用 _ 开头。
        fielderror
            在execute() 方法内增加:this.addFieldError("fielderror.test","wrong!"); return ERROR;
            就可以在对应的错误页面:<s:fielderror fieldName="fielderror.test"     theme="simple"></s:fielderror>
        action
            用于访问某个acion,并将结果包含进来,相当于JSP中的include,ignoreContextParams表示是否将本页面的参数传递给被调用的Action
        date
            格式化日期时间输出,属性format设置日期时间格式字符串,如yyyy-MM-DD HH:mm:ss
        param
            传递参数
    2控制标签:
        if:具有test属性进行判断
            <s:if test="#parameters.age[0] < 0">wrong age!</s:if>
            <s:elseif test="#parameters.age[0] <20">too young!</s:elseif>
            <s:else>yeah!</s:else>
        iterator:可以使用OGNL对数据进行过滤
            可以遍历:collections map enumeration iterator array
            遍历集合:
                <s:iterator value="{1,2,3}">
                    <s:property />  //打印集合中的每个元素
                </s:iterator>
             自定义变量:
                 <s:iterator value="{'aaa','bbb','ccc'}" var="x">
                     <s:property value="#x.toUpperCase()" /> //x指循环变量
                 </s:iterator>
             使用status
                 <s:iterator value="{'aaa','bbb','ccc'}" status="status">
                     <s:property/>
                     遍历过的元素总数:<s:property value="#status.count"/>
                     遍历过的元素索引:<s:property value="#status.index"/>
                     当前是偶数?:<s:property value="#status.even"/>
                     当前是奇数?:<s:property value="#status.odd"/>
                     是第一个元素?:<s:property value="#status.first"/>
                     是最后一个元素?<s:property value="#status.last"/>
                 </s:iterator>
             定义map
                 <s:iterator value="#{1:'a',2:'b',3:'c'}" var="x"> //定义map需要加#
                     <s:property value="#x.key"/>
                     <s:property value="#x.value"/>
                     <s:property value="key"/>
                     <s:property value="value"/>
                 </s:iterator>
             遍历列表:
             <struts:iterator id="book" value="bookList"> <!--bookList为一个Book属性的列表,book为一个javabean-->
                <tr>
                    <td><struts:property value="name"/></td>
                    <td><struts:property value="author"/></td>
                    <td><struts:property value="publishedDate"/></td>
                </tr>
            </struts:iterator>
        append:连接多个List
            <s:append id="myAppendList"><!--在myAppendList后面追加数据-->
                <s:param value="%{maleList}"/><!--追加maleList(action中的两个List类型变量)-->
                <s:param value="%{femaleList}"/><!--追加femaleList-->
            <s:append>
        generator:将字符串转化为List,相当于java中的split
            <s:generator val="%{'李宁,安踏,双喜,阿达,耐克'}" separator=",">
                <s:iterator>
                    <s:property/>
                </s:iterator>
            <s:generator>
        merge:取集合的并集
            作用同append,只是增加数据的顺序不同,append是先增加一个集合的全部数据,再增加另一个集合的全部数据,merge是先增加一个集合的一个数据,再增加另一个集合的一个数据,交叠增加
        subset:过滤集合元素    
     3 UI标签
         theme
             simple xhtml(默认) css_xhtml ajax    
         基本不用,可以用其他框架替代,非要用的时候用simple(只有fielderror最麻烦)就够了
         定义自己的theme
             1 css(覆盖struts2原来的css)
             2 覆盖单个文件
             3 定义自己的theme
             4 实战
                 a 把所有的主题定义为simple
                 b fielderror特殊处理
                 c 自己控制其他标签的展现(当你改成simple后,它就恢复为最原始的html了)
     4 非表单UI标签
         debug
             输出调试信息
         fielderror,action,actionmessage
             fielderror用于显示数据校验错误信息,actionerror用于显示action中的错误信息,actionmessage用于显示action中的消息        
             action中使用方法增加消息:分别为:
                 fielderror:this.addFieldError("password","密码不能为空");
                 actionerror:this.addActionError("执行error()方法,抛出了第一个error消息")  
                 actionmessage:this.addActionMessage("执行message()方法,抛出第一个message消息");
                 
异常处理:
    声明式异常处理:你要是有异常了,你尽管往外抛,到最后我会给你一个统一的接口,然后让你在特殊的页面做出处理。
        在catch中捕获的异常往外抛:throw(e);
        在try catch的方法声明抛出特定的异常:throws SQLException
        在使用这个方法的Action继续往外把异常的父类抛给struts.xml处理:throws Exception
        异常处理:
            特定的<action>异常处理: 然后在<action>里关联特定的页面处理异常:
                <exception-mappng result="error" exception="java.sql.SQLException" />//当这个action遇到特定的异常时,交给<result>为error的页面处理
                <result name="error">/error.jsp</result>
            也可以写一个异常处理器包:
                <package name="" extends="struts-default">
                    <global-results>
                        <result name="error">/error.jsp</result>
                    </global-results>
                    <global-exception-mappings>
                        <exception-mapping result="error" exception="java.lang.Exception"></exception-mapping>
                    </global-exception-mappings>    
                </package>
                //其他包只要 extends 这个包就可以使用了,        
    总结:
        1在action标签中进行异常映射
        2在package标签中进行全局异常映射
        3使用继承共用异常映射
        4struts2中异常由拦截器实现(观察struts-default.xml)
            实际上struts2的大多数功能都由拦截器实现

i18N:
    i18N原理:
        a ResourceBundle和Locale的概念
        b 资源文件
        c native2ascii
    Struts 的资源文件
        a Action-Package-App级
            一般只用App级别
                配置:struts.xml struts.custom.i18n.resources=资源文件开头的部分
                    要把资源文件放在classes目录下
                    资源文件的命名:
                        bbs2009_en_US.properties
                        bbs2009_CN_CN.properties
                使用:对应在jsp页面使用struts2标签:<s:property value="getText('对应配置文件中的属性名')"/>
        动态语言切换:只需在请求url跟上参数:request_locale=en_US即可    
        b PropertiesEditor插件
            解压
            features plugin覆盖到myeclipse中的eclipse目录下

拦截器以及源码解析:
    1 struts架构图
        见文档
    2 struts执行过程分析
    3 interceptor拦截器过程模拟
    4 定义自己的拦截器(很少用,大部分拦截图都已经定义了,也可以用其他方法替代)
        acegi-spring security
    5 使用token拦截器控制重复提交(很少用)
    6 类型转换
        默认转换
            日期转换
        写自己的转换器
            1 public class MyPointConverter extends DefaultTypeConverter{
                  public Object convertValue(Object value,Class toType){
                      if(toType == Point.class){
                          Point p = new Point();
                          String [] strs = (String[]) value;
                          String [] xy = strs[0].split(",");
                          p.x = Integer.parseInt(xy[0]);
                          p.y = Integer.parseInt(xy[1]);
                          return p;
                      }
                  }
              }
    ————————————————————————————————————————————————————————————————
         2 public class MyPointConverter extends StrutsTypeConverter{
              public Object convertFromString(Map context,String[] values,Class toClass){
                    Point p =  new Point();
                    String[] strs = (String[])values;
                    String[] xy = strs[0].split(",");
                    p.x = Integer.parseInt(xy[0]);
                    p.y = Integer.parseInt(xy[1]);
                    return p;
              }
              public String convertToString(Map context,Object o){
                    return o.toString();
              }
          }
      三种注册方式
          局部:XXXAction-conversion.properties
              p(属性名称) = converter
          全局:xwork-conversion.properties
              com.xxx.xxx(类名) = converter
          Annotation
      如果遇到非常麻烦的映射转换
          request.setAttribute();
          session
          
          
Struts总结
    1 Action
        namespace(掌握)
        path(掌握)
        DMI(掌握    )
        wildcard(掌握)
        接受参数(掌握前两种)
        访问request等(掌握Map IOC方式)
        简单数据验证(掌握addFieldError和<s:fieldError>)
    2 Result
        结果类型(掌握四种,重点两种)
        全局结果(掌握)
        动态结果(了解)
    3 OGNL表达式(精通)
        # % $
    4 Struts标签
        掌握常用的
    5 声明式异常处理(了解)
    6 i18N(了解)
    7 CRUD的过程(最重要是设计与规划)(精通)
    8 Interceptor的原理(掌握)
    9 类型转换(掌握默认,了解自定义)

抱歉!评论已关闭.