struts2 数据转换器
四、数据类型的转换(明白原理,实际开发中几乎不用)
1、开发中的情况:
实际开发中用户通过浏览器输入的数据都是String或者String[]。
String/String[]————填充模型(set方法)————>POJO(plain old java object) pojo中有java的数据类型。
POJO————————获取(get方法)————>页面展示:String
2、类型转换情况
写数据:(增,删,改)都是String或String[]数组转换为其他类型。
读数据:(查)其他类型转换为String。
3、Struts2提供的常用类型转换
a.基本数据类型自动转换。
b.日期类型:默认按照本地日期格式转换(yyyy-MM-dd)。
c.字符串数组:默认用逗号+空格,连接成一个字符串。
4、自定义类型转换器(知道)
示例:把日期格式按照 MM/dd/yyyy的格式转换
4.1、Struts2中的类型转换器结构:
1 /** 2 * Interface for accessing the type conversion facilities within a context. 3 * 4 * This interface was copied from OGNL's TypeConverter 5 * 6 * @author Luke Blanshard (blanshlu@netscape.net) 7 * @author Drew Davidson (drew@ognl.org) 8 */ 9 public interface TypeConverter 10 { 11 /** 12 * Converts the given value to a given type. The OGNL context, target, member and 13 * name of property being set are given. This method should be able to handle 14 * conversion in general without any context, target, member or property name specified. 15 * @param context context under which the conversion is being done 16 * @param target target object in which the property is being set 17 * @param member member (Constructor, Method or Field) being set 18 * @param propertyName property name being set 19 * @param value value to be converted 20 * @param toType type to which value is converted 21 * @return Converted value of type toType or TypeConverter.NoConversionPossible to indicate that the 22 conversion was not possible. 23 */ 24 public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType); 25 26 public static final Object NO_CONVERSION_POSSIBLE = "ognl.NoConversionPossible"; 27 28 public static final String TYPE_CONVERTER_CONTEXT_KEY = "_typeConverter"; 29 }
1 /** 2 * Default type conversion. Converts among numeric types and also strings. Contains the basic 3 * type mapping code from OGNL. 4 * 5 * @author Luke Blanshard (blanshlu@netscape.net) 6 * @author Drew Davidson (drew@ognl.org) 7 */ 8 public class DefaultTypeConverter implements TypeConverter { 9 10 protected static String MILLISECOND_FORMAT = ".SSS"; 11 12 private static final String NULL_STRING = "null"; 13 14 private final Map<Class, Object> primitiveDefaults; 15 16 public DefaultTypeConverter() { 17 Map<Class, Object> map = new HashMap<Class, Object>(); 18 map.put(Boolean.TYPE, Boolean.FALSE); 19 map.put(Byte.TYPE, Byte.valueOf((byte) 0)); 20 map.put(Short.TYPE, Short.valueOf((short) 0)); 21 map.put(Character.TYPE, new Character((char) 0)); 22 map.put(Integer.TYPE, Integer.valueOf(0)); 23 map.put(Long.TYPE, Long.valueOf(0L)); 24 map.put(Float.TYPE, new Float(0.0f)); 25 map.put(Double.TYPE, new Double(0.0)); 26 map.put(BigInteger.class, new BigInteger("0")); 27 map.put(BigDecimal.class, new BigDecimal(0.0)); 28 primitiveDefaults = Collections.unmodifiableMap(map); 29 } 30 31 public Object convertValue(Map<String, Object> context, Object value, Class toType) { 32 return convertValue(value, toType); 33 } 34 35 public Object convertValue(Map<String, Object> context, Object target, Member member, 36 String propertyName, Object value, Class toType) { 37 return convertValue(context, value, toType); 38 } 39
1 public abstract class StrutsTypeConverter extends DefaultTypeConverter { 2 public Object convertValue(Map context, Object o, Class toClass) { 3 if (toClass.equals(String.class)) { 4 return convertToString(context, o); 5 } else if (o instanceof String[]) { 6 return convertFromString(context, (String[]) o, toClass); 7 } else if (o instanceof String) { 8 return convertFromString(context, new String[]{(String) o}, toClass); 9 } else { 10 return performFallbackConversion(context, o, toClass); 11 } 12 } 13 14 /** 15 * Hook to perform a fallback conversion if every default options failed. By default 16 * this will ask Ognl's DefaultTypeConverter (of which this class extends) to 17 * perform the conversion. 18 * 19 * @param context 20 * @param o 21 * @param toClass 22 * @return The fallback conversion 23 */ 24 protected Object performFallbackConversion(Map context, Object o, Class toClass) { 25 return super.convertValue(context, o, toClass); 26 } 27 28 29 /** 30 * Converts one or more String values to the specified class. 31 * 32 * @param context the action context 33 * @param values the String values to be converted, such as those submitted from an HTML form 34 * @param toClass the class to convert to 35 * @return the converted object 36 */ 37 public abstract Object convertFromString(Map context, String[] values, Class toClass); 38 39 /** 40 * Converts the specified object to a String. 41 * 42 * @param context the action context 43 * @param o the object to be converted 44 * @return the converted String 45 */ 46 public abstract String convertToString(Map context, Object o); 47 }
DefaultTypeConverter 实现接口 TypeConverTer ;
Struts2TypeConverter 继承了DefaultTypeConverter
其它转换器都几乎继承自 Struts2TypeConverter
4.2、编写类型转换器(编写一个类继承StrutsTypeConverter,实现抽象方法)
1 /** 2 * 需求: 3 * 把表单中的MM/dd/yyyy格式的数据转成日期类型 4 * 把数据库中的本地日期格式,转成MM/dd/yyyy形式输出 5 * 6 * 自定义子类转换器: 7 * 第一步:编写一个类,继承自StrutsTypeConverter,实现convertFromString,convertToString抽象方法 8 * @author zhy 9 * 10 */ 11 public class MyTypeConvertor extends StrutsTypeConverter { 12 13 //定义一个类型转换器 14 private DateFormat format = new SimpleDateFormat("MM/dd/yyyy"); 15 16 /** 17 * 把字符串数组中的数据转成日期类型 18 * 19 * 方法参数详解: 20 * Map context:是OGNL的上下文对象,我们暂时不知道,所以暂时也不用 21 * String[] values:要转换的数据 22 * Class toClass:目标类型 23 */ 24 public Object convertFromString(Map context, String[] values, Class toClass) { 25 //1.先看看有没有数据 26 if(values == null || values.length == 0){ 27 return null; 28 } 29 //2.取出数组中的第一个元素 30 String date = values[0]; 31 //3.判断目标类型的字节码是不是日期类型 32 if(toClass == java.util.Date.class){ 33 try { 34 //4.使用DateFormat进行转换,并且返回转换后的结果 35 return format.parse(date); 36 } catch (ParseException e) { 37 e.printStackTrace(); 38 return null; 39 } 40 } 41 return null; 42 } 43 44 /** 45 * 把日期类型的数据转换成字符串 46 * 47 * 方法参数详解: 48 * Map context:是OGNL的上下文对象,我们暂时不知道,所以暂时也不用 49 * Object o:要转换的数据 50 */ 51 public String convertToString(Map context, Object o) { 52 //1.判断object是不是日期类型 53 if(o instanceof Date){ 54 Date date = (Date)o; 55 //2.是日期类型,使用转换器转成指定格式的字符串,并返回 56 return format.format(date); 57 } 58 return null; 59 } 60 61 }
4.3、注册类型转换器
局部类型转换器:只能指定javabean中的属性用
按照属性来注册。在属性所属的javabean的包下建立一个.properties文件。文件名称:javabean名称-conversion.properties
1 #局部类型转换器文件名的命名规范:javabean的名称-conversion.properties 2 #局部类型转换器声明,声明方式是以使用的属性名称作为key,以类型转换器的全类名作为value 3 birthday=com.itheima.web.converter.MyTypeConvertor
全局类型转换器:(推荐)
按照要转换的数据类型来注册。
at the top op classpath,建立一个固定名称xwork-conversion.properties的属性文件。
1 #全局类型转换器文件名的命名规范:xwork-conversion.properties。文件放到类路径的根路径 2 #全局类型转换器声明,声明方式是以使用的数据类型(全类名)作为key,以类型转换器的全类名作为value 3 java.util.Date=com.itheima.web.converter.MyTypeConvertor
5、转换失败后的处理(需要掌握)
当转换失败后,页面提示:
一串英文的错误提示
解决办法:配置回显结果视图
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE struts PUBLIC 3 "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 4 "http://struts.apache.org/dtds/struts-2.3.dtd"> 5 <struts> 6 <constant name="struts.devMode" value="true"/> 7 <package name="p1" extends="struts-default"> 8 <action name="register" class="com.itheima.web.action.UserAction" method="register" > 9 <result type="redirect">/success.jsp</result><!-- 当注册成功之后重定向的结果视图 --> 10 <result name="exists">/message.jsp</result><!-- 当用户名已经存在之后,转向的结果视图 --> 11 <!-- 当出现问题之后,需要从哪来回哪去 --> 12 <result name="input">/register1.jsp</result> 13 </action> 14 </package> 15 </struts>
问题:
配置了回显视图后,当转换失败时,可以回到请求页面,但是表单数据都没了?
显示错误提示:借助Struts2的标签库。
回显数据:使用struts2的标签库生成表单。(建议使用)
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%--导入struts2的标签库 --%> 3 <%@ taglib uri="/struts-tags" prefix="s" %> 4 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 5 <html> 6 <head> 7 <title>用户注册,使用的是struts2的标签</title> 8 <s:head></s:head> 9 </head> 10 <body> 11 <s:actionerror/><%-- 动作错误 --%> 12 <s:fielderror /><%-- 字段错误 --%> 13 <%--struts2的form标签,它提供了和原始html表单标签几乎一致的属性 14 action:请求的地址。直接写动作名称。不用写contextPaht 15 method:请求的方式。在这里不用写。struts2的form表单默认就是post 16 enctype:表单编码的MIME类型 17 --%> 18 <s:form action="register.action"> 19 <s:textfield name="username" label="用户名" requiredLabel="true" requiredPosition="left"/> 20 <s:password name="password" label="密码" showPassword="true"/> 21 <s:textfield name="birthday" label="生日"/> 22 <s:submit value="注册"/> 23 </s:form> 24 </body> 25 </html>
错误信息中文提示:使用的是struts2的国际化。
(在国际化中进行详解)
问题:
类型转换器当转换失败后,如何进入input视图的?
原因:
是由一个叫做conversionError的拦截器完成的。
注意:
要想使用类型转换中的错误处理,在定义Action时必须继承ActionSupport