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中提供的转换器更加适合于自己的标签输出;大部分情况下,如果没有特殊要求的数据,转换器使用意义不大,因为所有的框架都会提供有一些核心数据类型的转换操作.