DTO:数据传输对象
好处,给被调用方包装数据,有些数据你希望开发者可以看到的数据,可控数据,总结为数据隐藏和数据封装
比如做AA模块的只可以看到那些,而且bean的属性甚至可以与ORM中的对象不同名称(一般都是相同的),AA前台模块只可以看到要查询的数据,不会把不该看到的数据提供过去,如审核人,审核内容等。对于后台管理模块可以看到,这样的DTO的作用就可以明显看到了。另外如果一个table要显示数据很复杂,可能来自不同的Hessian调用,这样DTO 可以满足需求,DTO可以给开发提供比普通Bean更多的数据,同时DTO也可以对开发者隐藏数据。
DTO的不好,先看:
原文链接是 http://www.iteye.com/topic/1013803
我也纠结DTO和POJO之间的转换。服务端是纯粹的做数据调用服务,从客户端项目请求,到服务端项目接受请求并操作,但是在服务端项目中remoting service层传递过来的是DTO对象,而要保存的是POJO对象。
DTO和POJO唯一的区别是类型不一样,DTO是序列化的,而POJO不是。这样转换有几个地方我觉得不可忍的:第一要写很多的转换代码,第二要生成很多的对象,第三如果表结构变了,POJO,DTO和转换的代码都得进行修改。多N的对象可以不考虑,性能可以不考虑,作为开发,不想麻烦,set一大堆,如果表结构中N多的属性那何时了,虽然有现成的工具可用,像BeanUtil,但是加上这个东西,又对性能是一个挑战。
Martin Flower和Spring作者对次有相反的看法。真的没好的办法解决这个问题吗?
在每个Remoting Service中写这样的代码不是很蛋疼吗?
public XXX dtoToDomain(XXXDto xdto){
XXX x= new XXX ();
x.setId(xdto.getId());
// 等等
return x;
}
然后还有对客户端提供数据的时候还要domainToDto操作。
static String dtoPath = "com.xxx.remoting.dto.AADto";
static String domainPath = "com.xxx.domain.AA";
public static void main(String[] args) {
try {
String[] dtoNames = dtoPath.split("\\.");
String dtoName = dtoNames[dtoNames.length - 1];
String smallDtoName = toHeadLow(dtoName);
String[] damainNames = domainPath.split("\\.");
String domainName = damainNames[damainNames.length - 1];
String smallDamainName = toHeadLow(domainName);
Class dtoClass = Class.forName(dtoPath);
/**
* dto转domain
* @param memberAddressDto
* @return
*/
System.out.printf("/**\r\n");
System.out.printf(" * dto转domain\r\n");
System.out.printf(" * @param " + smallDtoName +"\r\n");
System.out.printf(" * @return\r\n");
System.out.printf("*/\r\n");
System.out.printf("public " + domainName + " " + smallDtoName + "To" + domainName + "(" + dtoName + " " + smallDtoName + ") {\r\n");
System.out.printf("\tif (" + smallDtoName + " == null)\r\n");
System.out.printf("\t\treturn null;\r\n");
System.out.printf( "\t" + domainName + " " + smallDamainName + " = new " + domainName + "();\r\n");
for (Method method : dtoClass.getMethods()) {
String name = method.getName();
if (name.equals("getClass"))
continue;
if (name.startsWith("get")) {
String property = name.substring(3);
System.out.printf("\t" + smallDamainName + ".set" + property + "(" + smallDtoName + "." + name + "());\r\n");
}
}
System.out.printf("\treturn " + smallDamainName + ";\r\n");
System.out.printf("} \r\n\r\n");
System.out.printf("/**\r\n");
System.out.printf(" * domain转dto\r\n");
System.out.printf(" * @param " + smallDamainName +"\r\n");
System.out.printf(" * @return\r\n");
System.out.printf("*/\r\n");
System.out.printf("public " + dtoName + " " + smallDamainName + "To" + dtoName + "(" + domainName + " " + smallDamainName + ") {\r\n");
System.out.printf("\tif (" + smallDamainName + " == null)\r\n");
System.out.printf("\t\treturn null;\r\n");
System.out.printf("\t" + dtoName + " " + smallDtoName + " = new " + dtoName + "();\r\n");
for (Method method : dtoClass.getMethods()) {
String name = method.getName();
if (name.equals("getClass"))
continue;
if (name.startsWith("get")) {
String property = name.substring(3);
System.out.printf("\t" + smallDtoName + ".set" + property + "(" + smallDamainName + "." + name + "());\r\n");
}
}
System.out.printf("\treturn " + smallDtoName + ";\r\n");
System.out.printf("} \r\n");
}
catch (Exception e) {
e.printStackTrace();
}
}
public static String toHeadLow(String data) {
return String.valueOf(Character.toLowerCase(data.charAt(0))) + data.substring(1);
}
我的想法是让POJO实现序列化,这样就没必要用POJO对象了 直接保存DTO对象。对象转换也不需要了。
为了接着这样一个频繁的操作我们可以自己写一个类路劲做为参数通过反射机制,生成这些代码。
今天遇到一个诧异的问题,客户端项目的DTO传递到服务端项目的时候就Decimal类型的的属性值都变为了0了,郁闷我!
问题在BigDecimal类型的应该使用BigDecimalDeserializer,
在basic没有BigDecimal的deserializer,需要使用customer根据类名查找
public Deserializer getCustomDeserializer(Class cl)
Class serClass = Class.forName(cl.getName() + "HessianDeserializer",
false, cl.getClassLoader());
结果类名错误拼错导致找不到相应的反序列化类
我准备在公共项目中的DTO的BigDecimal中改为String类型,到了服务端就进行类型转换,这样就解决问题了,但是是投机取巧,不可取。
这是hessian的一个bug,解决此bug的方法:
在 hessian.jar 的 META-INF/hessian 目录下加入 serializers 和 deserializers 这两个文件, 两个文件的内容如下:
serializers
--------------------------
java.math.BigDecimal=com.caucho.hessian.io.StringValueSerializer
deserializers
--------------------------
java.math.BigDecimal=com.caucho.hessian.io.BigDecimalDeserializer
解决办法原文链接 (原文把引用的序列化和反序列化写反了)