1. 程式人生 > >李興華struts2學習筆記

李興華struts2學習筆記

跳轉型別

struts2有常用的三種跳轉型別:

1.伺服器跳轉,url地址不變。預設情況下就是此跳轉:

<result name="success" type="dispatcher">/test1.jsp</result>

2.客戶端跳轉,url地址改變:

<result name="success" type="redirect">/test1.jsp</result>

3. 由一個Action跳轉到另一個Action:

 

取得jsp內建物件

由於struts2的Action中並沒有像servlet或者filter那樣有引數為request和response的方法,所以需要藉助ServletActionContext類的方法取得request等物件。

 HttpServletRequest request= ServletActionContext.getRequest();
 HttpServletResponse response=ServletActionContext.getResponse();
 ServletContext context=ServletActionContext.getServletContext();

多人開發

可以建立多個struts的xml配置檔案,然後在struts.xml中include多個配置檔案,include順序越前面優先順序越高。

解決中文亂碼

如果專案統一使用utf-8,就不會有亂碼問題,如果使用的是gbk,那麼需要解決亂碼問題。

在src目錄下建立struts.properties檔案:

struts.i18n.encoding=utf-8
struts.locale=zh_Ch

配置資原始檔

三種級別的資原始檔:

1.全域性資原始檔:在src目錄下,可以有一個struts.properties,多個其他名稱的poperties(其他的全域性資原始檔命名規則與Java類名稱命名規則相同),並且在struts.properties中註冊其他的全域性資原始檔。(推薦使用)

struts.custom.i18n.resources=Hello,Message

2.包級別資原始檔:在某一包下,只能夠給該包使用,名稱為"package.properties"。

3.指定Acton的資原始檔:在該Action所在包下,只能夠給該Action使用,名稱為"(Action的名稱).properties"。

上面三種級別的優先順序為3>2>1 

在Action中讀取資原始檔:super.getText()方法。

示例:

EchoAction.properties:

msg=EchoAction.properties{0} {1} 嘻嘻{2} {3}

EchoAction:

System.out.println(super.getText("msg",new String[]{"one","two","three"}));

 執行結果:

EchoAction.propertiesone two 嘻嘻three {3}

資原始檔中有4個佔位符,但在Action中只傳了3個字串,這樣雖然不會報錯,但是最好我們編寫程式碼的時候,有幾個佔位符就傳幾個字串。 

結合VO輸入

java類:

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;

public class EchoAction extends ActionSupport {
    private City city=new City();

    public City getCity() {
        System.out.println("EchoAction的getCity()");
        return city;
    }

    public void setCity(City city) {
        System.out.println("EchoAction的setCity()");
        this.city = city;
    }

    public EchoAction(){
        System.out.println("EchoAction()構造方法");
    }

    @Override
    public String execute() throws Exception {

        System.out.println("EchoAction執行execute()");
        System.out.println("city:"+city);

        return Action.SUCCESS;
    }
}


import java.util.Date;
public class City {
    private int id;
    private double price;
    private String cityName;
    private Date date;
    private Province province;

    public City(){
        System.out.println("City()構造方法");
    }
    public String getCityName() {
        System.out.println("getCityName()");
        return cityName;
    }

    public void setCityName(String cityName) {
        System.out.println("setCityName()");
        this.cityName = cityName;
    }

    public Province getProvince() {
        System.out.println("getProvince()");
        return province;
    }

    public void setProvince(Province province) {
        System.out.println("setProvince()");
        this.province = province;
    }

    public int getId() {
        System.out.println("getId()");
        return id;
    }

    public void setId(int id) {
        System.out.println("setId()");
        this.id = id;
    }

    public Date getDate() {
        System.out.println("getDate()");
        return date;
    }

    public void setDate(Date date) {
        System.out.println("setDate()");
        this.date = date;
    }

    @Override
    public String toString() {
        return "City{" +
                "id=" + id +
                ", cityName='" + cityName + '\'' +
                ", province=" + province +
                ", date=" + date +
                '}';
    }
}


public class Province {
    private String provinceName;

    public Province(){
        System.out.println("Province()構造方法");
    }

    public String getProvinceName() {
        System.out.println("getProvinceName()");
        return provinceName;
    }

    public void setProvinceName(String provinceName) {
        System.out.println("setProvinceName()");
        this.provinceName = provinceName;
    }

    @Override
    public String toString() {
        return "Province{" +
                "provinceName='" + provinceName + '\'' +
                '}';
    }
}

jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>echo</title>
  </head>
  <body>
 <form action="echo">
     cityName:<input name="city.cityName"><br/>
     id:<input name="city.id"/><br/>
     price:<input name="city.price"><br/>
     date: <input name="city.date"><br/>
     province:<input name="city.province.provinceName"><br/>
   <input type="submit">
 </form>
  </body>
</html>

 struts.xml:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>

    <!--根名稱空間-->
    <package name="test"  namespace="/" extends="struts-default">
        <action name="echo" class="struts2.EchoAction">
            <result name="success">echo.jsp</result>
        </action>

    </package>

</struts>

訪問echo並填寫表單提交後控制檯輸出:

City()構造方法
EchoAction()構造方法
EchoAction執行execute()
city:City{id=0, cityName='null', province=null, date=null}
City()構造方法
EchoAction()構造方法
EchoAction的getCity()
setCityName()
EchoAction的getCity()
setDate()
EchoAction的getCity()
setId()
EchoAction的getCity()
EchoAction的getCity()
getProvince()
Province()構造方法
setProvince()
setProvinceName
EchoAction執行execute()
city:City{id=1, cityName='寧波', province=Province{provinceName='浙江'}, date=Fri Dec 12 00:00:00 CST 2014}

(我已被自己繞暈)

標籤與屬性範圍 

在action中request.setAttribute("msg","msg"),轉發的頁面可以用#request.msg取出。

非UI標籤

1.日期格式化標籤

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

2.資原始檔輸出標籤

  <%--name=資原始檔的名稱--%>
  <s:i18n name="Hello">
      <%--name=資原始檔中的key--%>
      <s:text name="msg">
          <%--給資原始檔中key=msg的值傳遞引數給佔位符--%>
          <s:param>小魚仙倌</s:param>
          <s:param>錦覓</s:param>
      </s:text>
  </s:i18n>

3.判斷與迭代標籤

  <s:if test="cities!=null">
      <s:iterator value="cities" var="c">
          <%--id的獲取利用了JSTL,這裡是想說明可以用JSTL,也可以用struts標籤--%>
          <li>城市名稱:<s:property value="cityName"/>城市編號:${c.id} </li>
      </s:iterator>
  </s:if>

完整示例程式碼:

echo.jsp:

<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>echo</title>
  </head>
  <body>
  <h><s:property value="date"/> </h><br/>
  <s:date name="date" format="yyyy-MM-dd HH:mm:ss"/><br/>

  <%--name=資原始檔的名稱--%>
  <s:i18n name="Hello">
      <%--name=資原始檔中的key--%>
      <s:text name="msg">
          <%--給資原始檔中key=msg的值傳遞引數給佔位符--%>
          <s:param>小魚仙倌</s:param>
          <s:param>錦覓</s:param>
      </s:text>
  </s:i18n><br/>

  <s:if test="cities!=null">
      <s:iterator value="cities" var="c">
          <%--id的獲取利用了JSTL,這裡是想說明可以用JSTL,也可以用struts標籤--%>
          <li>城市名稱:<s:property value="cityName"/>城市編號:${c.id} </li>
      </s:iterator>
  </s:if>
  </body>
</html>

UI標籤

EchoAction:傳遞cities給echo.jsp。

List<City> cities=new ArrayList<>();
        for (int i=0;i<5;i++){
            City c=new City();
            c.setCityName("城市"+i);
            c.setId(i);
            cities.add(c);
        }
 ServletActionContext.getRequest().setAttribute("cities",cities);

echo.jsp:

  <s:form action="test" method="POST">
      <%--<s:select list="#request.cities" name="city" listKey="id" listValue="cityName" 
      id="city"></s:select>--%>
      <s:checkboxlist list="#request.cities" listKey="id" listValue="cityName" name="c" 
      id="c"></s:checkboxlist>
      <s:submit ></s:submit>
  </s:form

TestAcion:接收echo.jsp設定的引數

public class TestAction extends ActionSupport {
    private Object[] c;

    public void setC(Object[] c) {
        System.out.println(c[0].getClass());
        this.c = c;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(Arrays.toString(c));
        return "test";
    }
}

多業務處理

學到多業務處理了,我只想感嘆,struts2是什麼鬼,太麻煩了吧,各種配置問題,這是要死記硬背麼?

吐槽完畢,迴歸正題。

介紹兩種method分發:

1.利用萬用字元*:

struts.xml配置:

<action name="*echo" class="struts2.EchoAction" method="{1}">
       <allowed-methods>update,delete</allowed-methods>
</action>

一開始,總是執行不了Action裡的update方法,後來加上<allowed-method>就可以了,原因好像是struts2的版本關係,我是2.5版本的。

EchoAction:

import com.opensymphony.xwork2.ActionSupport;

public class EchoAction extends ActionSupport {
    private String msg;

    public String getMsg() {
        System.out.println("getMsg...");
        return msg;
    }

    public void setMsg(String msg) {
        System.out.println("setMsg...");
        this.msg = msg;
    }



    public String update(){
        System.out.println("list...+msg="+msg);
        return null;
    }

    public void delete() {
        System.out.println("delete...msg="+msg);
    }


    @Override
    public String execute() throws Exception {
        System.out.println(this);
        return "echo";
    }
}

然後就可以訪問:

http://localhost:8080/struts2/updateecho?msg=hello

http://localhost:8080/struts2/deleteecho?msg=world

注意,要訪問的方法返回值只能是null或者是String,比如返回值是int,將會報錯:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

而且方法必須是無參的。

2.動態方法

在struts.xml的<struts>標籤里加上:

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

另外:

<action name="test" class="struts2.TestAction">
         <result name="test">test.jsp</result>
         <allowed-methods>fun</allowed-methods>
</action>

TestAction中的fun()方法我就不貼了。

然後就可以訪問:

http://localhost:8080/struts2/test!fun

struts2與Ajax

雖說是struts2與Ajax,但好像並沒有涉及到struts2的知識,仍舊是jsp頁面利用jquery非同步請求,只不過這回請求的不是一個servlet,而是一個action,訪問路徑變了而已,其他沒什麼變化。

jsp頁面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>echo</title>
    <script src="http://apps.bdimg.com/libs/jquery/1.6.4/jquery.js"></script>

  </head>
  <body>
    <script>
      $(function () {
          $.get(
              "updateecho",
              function (result) {
                  for (var i=0;i<result.cities.length;i++){

                      $("#city").append("<tr><td>"+result.cities[i].name+"</td><td>"+result.cities[i].id+"</td></tr>")
                  }

              },
              "json"
          )
      })
    </script>
  <table id="city">
      <tr>
          <td>城市名稱</td>
          <td>城市編號</td>
      </tr>
  </table>
  </body>

</html>

 EchoAction中的update方法:

public void update(){
        ServletActionContext.getResponse().setCharacterEncoding("utf-8");

        JSONObject jsonObject=new JSONObject();
        jsonObject.put("name","浙江");
        jsonObject.put("cityCount",2);

        JSONArray jsonArray=new JSONArray();
        JSONObject c1=new JSONObject();
        c1.put("name","寧波");
        c1.put("id",1);
        JSONObject c2=new JSONObject();
        c2.put("name","杭州");
        c2.put("id",2);

        jsonArray.add(c1);
        jsonArray.add(c2);
        jsonObject.put("cities",jsonArray);

        try {
            ServletActionContext.getResponse().getWriter().print(jsonObject);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

struts.xml中的action配置:

<action name="*echo" class="struts2.EchoAction" method="{1}">
            <allowed-methods>update</allowed-methods>
</action>

訪問:

http://localhost:8080/struts2/echo.jsp

執行結果:


城市名稱	城市編號
寧波	1
杭州	2

資料驗證及錯誤顯示

題外話:之前聽李興華的課程裡說struts2自定義的過濾器無用,但是剛剛自己定義了一個,發現當我直接訪問jsp頁面的時候是有被我定義的過濾器給攔截的。於是我又試了一下,直接訪問Action是否會被攔截,發現不會。百度了一下,得知如果要想訪問Action也經過自定義的過濾器,必須在web.xml中配置<filter-mapping>的順序為自定義過濾器在struts2帶的過濾器之前。

ActionSupport有一個方法validate()是資料驗證方法,作用是驗證頁面提交過來的資料是否符合要求。

在自定義的Action中重寫validate()就能呼叫此方法,此方法會在資料賦值之後,Action的execute()方法(或者其他定義的方法)之前執行。

接著我們就要在validate()中編寫驗證資料的程式碼了。

在AcitonSupport中有一個增加錯誤資訊的方法:

public void addFieldError(String fieldName,String errorMessage)

這個方法是往一個Map集合——fieldErrors中增加錯誤資訊,這個Map集合可以通過ActionSupport提供的以下方法取得:

public Map<String,List<String>> getFieldErrors()

每次執行完validate()之後,如果fieldErrors為空,那麼繼續執行Action的其他方法,如果不為空,說明有錯誤資訊,那麼將直接跳轉到result name="input"配置的跳轉頁去,不再執行Action的其他方法。

示例:

echo.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>echo</title>
  </head>
  <body>
    <form action="updateecho" method="post">
        <input type="text" name="msg">${fieldErrors['msg'][0]}
        <input type="submit">
    </form>
  </body>

</html>

EchoAction:

package struts2;

import com.opensymphony.xwork2.ActionSupport;

public class EchoAction extends ActionSupport {
    private String msg;

    public String getMsg() {
        System.out.println("getMsg...");
        return msg;
    }

    public void setMsg(String msg) {
        System.out.println("setMsg...");
        this.msg = msg;
    }

    public String update(){
        System.out.println("update...+msg="+msg);
        return "show";
    }

    @Override
    public String execute() throws Exception {
        System.out.println("execute...");
        return "echo";
    }

    @Override
    public void validate() {
        System.out.println("validate...");
        if (this.msg==null||"".equals(this.msg)){
            super.addFieldError("msg","msg不能為空");
        }else if (this.msg.length()<5){
            super.addFieldError("msg","msg必須超過5個字元");
        }
    }
}

show.jsp:

<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>show</title>
</head>
<body>
    <s:property value="msg"></s:property>
</body>
</html>

 

struts.xml :

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
        "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>

    <package name="test"  extends="struts-default">
        <action name="*echo" class="struts2.EchoAction" method="{1}">
            <result name="input">echo.jsp</result>
            <result name="show">show.jsp</result>
            <allowed-methods>update</allowed-methods>
        </action>
    </package>

</struts>

1.訪問:http://localhost:8080/struts2/echo.jsp

2.不填寫任何內容,點選提交:

頁面顯示:

控制檯輸出:

setMsg...
validate...

3.填寫hi,點選提交:

頁面顯示:

控制檯輸出:

setMsg...
validate...

4.填寫hello world,點選提交:

頁面成功跳轉,顯示:

控制檯輸出:

setMsg...
validate...
update...+msg=hello world
getMsg...

需要注意到的是,validate都是在setMsg也就是賦值之後才執行的,所以假設填寫的內容不符合要求,validate也沒能阻攔你賦值。

驗證框架基礎

之前是在Action裡面重寫validate方法來驗證資料,還可以用配置檔案的方式來驗證。

在EchoAction的包目錄下建立一個名為EchoAction-validation的xml檔案:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE validators PUBLIC
        "-//Apache Struts//XWork Validator 1.0.3//EN"
        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
    <field name="msg">
        <field-validator type="requiredstring" >
            <message>msg不能為空</message>
        </field-validator>
    </field>
</validators>

然後將之前EchoAction中的validate方法註釋掉。

執行專案……

效果會和之前一樣:

1.訪問:http://localhost:8080/struts2/echo.jsp

2.不填寫任何內容,點選提交:

頁面顯示:

控制檯輸出:

setMsg...
getMsg...

這裡比上面多執行了多輸出了一行getMsg...,我想應該是利用配合利用配置檔案檢驗資料會先自動呼叫get方法獲取資料。

3.填寫hello world,點選提交:

頁面成功跳轉,顯示:

控制檯輸出:

setMsg...
getMsg...
update...+msg=hello world
getMsg...

利用配置檔案只是方便簡單了一點,執行機制還是一樣的。