跳转类型
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...
利用配置文件只是方便简单了一点,运行机制还是一样的。