1.转换器的主要使用以及作用;
2.实现自定义的转换器;
3.系统自带转换器;
具体内容
在使用Struts2.x接收参数的时候,可以发现,如果传递的是数字,可以自动的将参数的字符串内容变为数字,那么包括文件上传的时候,能接收的数据类型为File,那么这些实际上都是由转换器帮助我们用户自动完成的转换.
例如,如果要想实现字符串到"Locale"的转换,那么默认没有实现,必须自己手动实现
例如.在进行数据删除的时候往往都要传递"id|id|id|..",那么也可以利用转换器将其自动变为Set集合.
数组转换器
如果说现在要想进行参数的接收,默认情况下直接在Action里面设置一个与参数对应的名称即可,但是在进行参数接收的时候一定要记住,Struts 2.x里面可以接收数组.
<form action="InputAction!inst.action" method="post">
兴趣:<input type="checkbox" name="inst" id="inst" value="吃饭">吃饭
<input type="checkbox" name="inst" id="inst" value="睡觉">睡觉
<input type="checkbox" name="inst" id="inst" value="麻将">麻将
<input type="checkbox" name="inst" id="inst" value="纸牌">纸牌
<input type="submit" value="提交">
</form>
以上的带使用了对象数据,发现内容可以进行接收,但是Struts2.x的转换器功能远远不止这么点
范例:定义一个可以传递整数数组的表单
package cn.zwb.action;
import java.util.Arrays;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class InputAction extends ActionSupport{
private String inst[];
private Integer gid[];
public void setInst(String[] inst) {
this.inst = inst;
}
public void setGid(Integer[] gid) {
this.gid = gid;
}
public void inst(){
System.out.println("[参数内容]"+Arrays.toString(this.inst));
}
public void gid(){
System.out.println("[参数内容]"+Arrays.toString(this.gid));
}
}
<div>
<form action="InputAction!gid.action" method="post">
兴趣:<input type="checkbox" name="gid" id="gid" value="1">1
<input type="checkbox" name="gid" id="gid" value="2">2
<input type="checkbox" name="gid" id="gid" value="3">3
<input type="checkbox" name="gid" id="gid" value="4">4
<input type="submit" value="提交">
</form>
</div>
在Struts2.x里面针对于数据的转换操作也是自动完成的,但是在Struts2.x里面只一开数组接收没什么意义,它还可以使用集合接收.
范例:利用Set集合接收参数
package cn.zwb.action;
import java.util.Arrays;
import java.util.Set;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class InputAction extends ActionSupport{
private String inst[];
private Set<Integer> gid;
public void setInst(String[] inst) {
this.inst = inst;
}
public void setGid(Set<Integer> gid) {
this.gid = gid;
}
public void inst(){
System.out.println("[参数内容]"+Arrays.toString(this.inst));
}
public void gid(){
System.out.println("[参数内容]"+this.gid.toString());
}
}
此时数据可以接收到,但是属于无序的数据,一定可以想到,为Set接口实例化的一定是HashSet子类,此时即使是哦有那个了List集合也可以正常进行接收,这一切的操作支持都来源于Struts2.x的转换器
接收对象数组
在Sturts2.x中默认的转换器里面可以使用对象数组进行内容的接收,这一点非常的强大.
范例:定义一个对象--Member.java类
package cn.zwb.vo;
import java.io.Serializable;
import java.util.Date;
@SuppressWarnings("serial")
public class Member implements Serializable {
private Integer mid;
private String name;
private Double score;
private Date birthday;
public Integer getMid() {
return mid;
}
public void setMid(Integer mid) {
this.mid = mid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
随后如果要在Action里面接受一个对象数组的信息内容,那么必须设置一个List集合,而后泛型的类型是指定的Member类.
范例:定义MemberAction
package cn.zwb.action;
import java.util.List;
import com.opensymphony.xwork2.ActionSupport;
import cn.zwb.vo.Member;
@SuppressWarnings("serial")
public class MemberAction extends ActionSupport{
private List<Member> all;
public void setAll(List<Member> all) {
this.all = all;
}
public void insert(){
System.out.println("[参数内容]"+this.all.toString());
}
}
但是接下来的关键不服在于表单定义的格式上,表单提交的参数名称里面一定要包含有"allMembers"这个名称,否则无法正常接收到数据.
范例:定义member.jsp
<div>
<form action="MemberAction!insert.action" method="post">
成员A:编号:<input type="text" name="allMembers[0].mid" value="1" size="2">
姓名:<input type="text" name="allMembers[0].name" value="詹" size="5" maxlength="5">
成绩:<input type="text" name="allMembers[0].score" value="100.0" size="5" maxlength="5">
生日:成绩:<input type="text" name="allMembers[0].birthday" value="2018-06-11" size="5" maxlength="10"><br>
成员B:编号:<input type="text" name="allMembers[1].mid" value="1" size="2">
姓名:<input type="text" name="allMembers[1].name" value="闻博" size="5" maxlength="5">
成绩:<input type="text" name="allMembers[1].score" value="100.0" size="5" maxlength="5">
生日:成绩:<input type="text" name="allMembers[1].birthday" value="2018-06-17" size="5" maxlength="10"><br>
<input type="submit" value="提交">
</form>
</div>
虽然使用List集合可以进行结束,但是set却绝对无法接收,原因很简单,List实际上就是一个顺序式的结构,在List集合里面提供有get(),set()方法,都可以根据索引来操作.
自定义转换器
虽然系统提供了许多的转换器操作,但是在很多时候依然可能不够用户使用,例如:如果说现在用户希望可以将Spring类型变为Locale类型,那么这样的转换器,Struts2.x是不会提供的.
Locale主要用于国际化程序的操作实现上,那么在Locale类中定义了这样的构造方法:
●Locale类的构造方法
public Locale(String language,String country)
同时在Struts2.x的开发包里面提供有这样一个类:com.opensymphony.xwork2.util.LocalizedTextUtil
●读取资源:public static String findDefaultText(String aTextName,Locale locale);
如果想要使用国际化读取资源,那么应该根据语言和城市代码定义资源文件.
范例:定义Messages_zh_CN.properties文件
welcome=欢迎光临
范例:定义Messages_en_US.properties文件
welcome=WELCOME!!!!
范例:配置struts.properties
struts.i18n.enconding=UTF-8
struts.locale=zh_CN
struts.custom.i18n.resources=Messages_zh_CN,Messages_en_US
随后在Action中使用LocalizedTextUtil类,那么结合Locale对象就可以读取指定的资源文件中的内容
范例:读取资源
package cn.zwb.action;
import java.util.Locale;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
@SuppressWarnings("serial")
public class LocaleAction extends ActionSupport{
public void insert(){
Locale loc = new Locale("zh","CN");
String str = LocalizedTextUtil.findDefaultText("welcome", loc);
System.out.println(str);
}
}
现在的代码是固定完成的,那么现在希望可以通过外部传递参数来决定使用什么样的文字显示.
范例:定义一个表单
<form action="LocaleAction!inst.action" method="post">
选择信息语言:<select name="loc">
<option value="zh_CN">中文显示</option>
<option value="en_US">英文显示</option>
</select>
<input type="submit" value="提交">
</form>
如果表单一提交,提交到LocaleAction中的loc的是字符串,但是希望它可以变为Locale对象
范例:修改LocaleAction,让其接收loc数据,
package cn.zwb.action;
import java.util.Locale;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.LocalizedTextUtil;
@SuppressWarnings("serial")
public class LocaleAction extends ActionSupport{
private Locale loc;
public void setLoc(Locale loc) {
this.loc = loc;
}
public void insert(){
String str = LocalizedTextUtil.findDefaultText("welcome", this.loc);
System.out.println(str);
}
}
这个时候发现根本就不能实现转换处理的操作,因为在Struts2.x里面没有这种转换器,那么现在我们需要这种转换器,于是可以采用自定义转换器的方式完成.单独定义一个转换器的类,但是这个类在继承结构上是由明确要求的,要求其必须继承:"com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;"
此类定义如下:
public abstract class DefaultTypeConverter extends Object implements TypeConverter
可以发现此类是一个抽象类,如果是抽象类,那么使用原则就是必须有子类.但是这个类里面没有明确的定义抽象方法,它的存在意义就是:需要你去继承,不能够直接使用,做了一个父类,但是在子类中目的进行转换,那么要想转换子类则重写方法:
public Object convertValue(Map<String,Object> context, Object value, Class toType)
Map<String,Object> context 表示当前操作的上下文环境
Object value 描述的是接收到的请求参数
Class toType 要接收的数据类型,本次目标类型是Locale
范例:定义转换器
package cn.zeb.converter;
import java.util.Locale;
import java.util.Map;
import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;
public class StringToLocaleConverter extends DefaultTypeConverter{
@Override
public Object convertValue(Map<String, Object> context, Object value, Class toType) {
//主要实现数据转换的
//在Struts2.x里面所有的参数都是以String[]形式出现的
String result=((String[]) value)[0];
if(Locale.class.equals(toType)){ //要转换的目标类型为Locale
String str []=result.split("_");
Locale loc=new Locale(str[0],str[1]);
return loc;
}
return null;
}
}
虽然现在转换器开发完成了,但是依然不可以使用,因为如果要想使用转换器,则还需要配置一个专门的转换器操作属性,文件为--xwork-conversion.properties
范例:在src目录下建立xwork-conversion.properties文件
java.util.Locale=cm.zwb.converter.StringToLocaleConverter
以上的这种转换器实际上定义的是全局转换器,如果有需要也可以单独为某一个Action定义转换器
范例:在cn.mldn.action包中定义一个LocaleAction-convertion.properties
loc=cn.zwb.converter.StringToLocaleConverter
此处表示针对于LocaleAction中的loc属性使用的转换器.
转换器实际应用
如果说到转换器,可能大部分人会认为以上的操作意义不大,实际上以上只是给大家展示了一下转换器的基本结构,而如果结合到实际的开发中来讲,例如:有时候为了进行数据的批量删除,可能会传递一组的id谁,并且每一个ID之间使用了"丨"进行分割(2丨3丨3),所以在这种情况下就可以利用转换器,将这些字符串的数据转换为Set集合.
范例:定义一个转换器IntegerToSetConverter
package cn.zwb.converter;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;
public class IntegerToSetConverter extends DefaultTypeConverter {
@Override
public Object convertValue(Map<String, Object> context, Object value, Class toType) {
if(Set.class.equals(toType)){
Set<Integer> set=new HashSet<Integer>();
String val=((String[]) value)[0];
String result[]=val.split("\\丨");
for (int i = 0; i < result.length; i++) {
set.add(Integer.parseInt(result[i]));
}
return set;
}
return null;
}
}
那么随后编写一个Action,里面要求接收一组ID数据.
范例:定义NewsAction
package cn.zwb.action;
import java.util.Set;
import com.opensymphony.xwork2.ActionSupport;
@SuppressWarnings("serial")
public class NewsAction extends ActionSupport{
private Set<Integer> ids;
public void setIds(Set<Integer> ids) {
this.ids = ids;
}
public void insert(){
System.out.println("要删除的数据::"+this.ids);
}
}
<action name="NewsAction" class="cn.zwb.action.NewsAction"/>
随后浏览器的输入:"http://localhost:8080/ConverterProject/NewsAction!insert.action?ids=11|2"
但是有一个问题,可能很对时候的ID类型可能不是数字,而是字符串,所以如果要想接受字符串的话,那么就需要再次定义一个转换器.
范例:定义字符串转化为Set集合的转换器
package cn.zwb.converter;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;
private Set<String> nids;
public void setNids(Set<String> nids) {
this.nids = nids;
}
public class StringToSetConverter extends DefaultTypeConverter {@Overridepublic Object convertValue(Map<String, Object> context, Object value, Class toType) {if(Set.class.equals(toType)){Set<String> set=new HashSet<String>();System.out.println(value);String val=((String[]) value)[0];String result[]=val.split("-");for (int i = 0; i < result.length; i++) {set.add(result[i]);}return set;}return null;}}
随后在需要的NewsAction里面定义一个新的操作属性,例如,名称为nids.
范例:修改NewsAction.java类
private Set<String> nids;
public void setNids(Set<String> nids) {
this.nids = nids;
}
如果要转换器使用,还需要在转换器的配置文件上增加新的数据.
范例:修改NewsAction-converter.properties文件
nids=cn.zwb.converter.StringToSetConverter
此时的输入地址为:
http://localhost:8080/ConverterProject/NewsAction!insert.action?ids=11-2-3&nids=4564fewfwef-dwqdqw
如果真要强调转换器的作用,可能认为只有这样的形式才可以说它有用.
StrutsTypeConverter转换器
首先要明确一点,如果要定义转换器,那么肯定最大的父类使用的是"DefaultypeConverte"r,但是struts核心包里面又提供有一个转换器"org.apache.struts2.util.StrutsTypeConterver",这个转换器可以实现输入和输出的转换操作.此类定义结构如下:
public abstract class StrutsTypeConverter extends DefaultTypeConverter
但是这个类中定义有两个抽象方法
[接收数据]将接收的String参数变为指定对象:
public abstract Object convertFromString(Map context, String[] values, Class toClass)
[输出数据]将对象变为String:
public abstract String convertToString(Map context, Object o)
假设现在有一个表示坐标点的Point类, 里面可以接收的x坐标和y坐标的类型都是Double,如果说前端用户传递参数的时候可能给出的类型是"point=(1.1,2.5)",接收的时候需要将其利用转换器变为指定的Point类对象,但是如果输入的时候也可以将Point对象的内容转化为大家可以读懂的坐标点.
范例:定义一个Point类
package cn.zwb.vo;
public class Point {
private Double x;
private Double y;
public Double getX() {
return x;
}
public void setX(Double x) {
this.x = x;
}
public Double getY() {
return y;
}
public void setY(Double y) {
this.y = y;
}
}
范例:定义转换器
package cn.zwb.converter;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import cn.zwb.vo.Point;
public class PointConverter extends StrutsTypeConverter{
@Override
public Object convertFromString(Map context, String[] value, Class toClass) {
if(Point.class.equals(toClass)){
String result[]=value[0].split(",");
String xValue=result[0].substring(1);
String yValue=result[1].replace(")", "");
Point point=new Point();
point.setX(Double.parseDouble(xValue));
point.setY(Double.parseDouble(yValue));
return point;
}
return null;
}
@Override
public String convertToString(Map content, Object o) {
if(o instanceof Point){
Point point=(Point)o;
return "[坐标数据]("+point.getX()+","+point.getY()+")";
}
return null;
}
}
范例:定义PointAaction
package cn.zwb.action;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionSupport;
import cn.zwb.vo.Point;
public class PointAction extends ActionSupport {
private Point point;
public void setPoint(Point point) {
this.point = point;
}
public Point getPoint() {
return point;
}
public String insert(){
System.out.println("[参数内容]X坐标:"+this.point.getX()+",Y坐标:"+this.point.getY());
return Action.SUCCESS;
}
}
范例:定义show.jsp页面,这个页面使用标签输出
<%@taglib prefix="s" uri="/struts-tags" %>
<s:property value="point"/>
此处利用标签输出,而且输出的是point属性,完成之后通过浏览器输入如下路径信息
http://localhost:8080/ConverterProject/PointAction!insert.action?point=(12,24)
所以Struts中提供的转换器更加适合于自己的标签输出;大部分情况下,如果没有特殊要求的数据,转换器使用意义不大,因为所有的框架都会提供有一些核心数据类型的转换操作.