李興華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...
利用配置檔案只是方便簡單了一點,執行機制還是一樣的。