DO、DTO、VOとは
JavaのVO、PO、DO、DTO、BO、QO、DAO、POJOの概念には、Javaのさまざまなモデル概念が導入されています。
ここに簡単な概要があります:
日々のプロジェクト開発において、VOはページに表示する必要があるデータ(フォーム)に対応し、DOはデータベース(データテーブル)に保存されているデータに対応し、DTOは2 つ以外の外部に転送する必要があるデータ。
多くの人は VO と DTO についてはあまり馴染みがないかもしれませんが、DO についてはよく知っています。それは、多くのプロジェクトではさまざまな理由から DO のみが使用されるためです。
1.小規模な企業エンティティの場合は、DO にカプセル化するだけで十分です。
2. DTO と VO の違いはおろか、よくわかりません。
3. DODTOVO の違いは知っていますが、使うのが面倒です。
それでは、ここでブロガーが、これほど多くの概念が導入されている理由と、プロジェクトでこれらのエンティティ オブジェクトを使用することをお勧めする理由を説明します。
なぜ 1 つの DO だけを使用できないのですか
そのような例を見てみましょう。プロジェクトに User のようなエンティティがあるとします。 User テーブルを作成するときは、通常、次の属性を含めます:
このエンティティの場合、通常、この User エンティティをカプセル化する DO クラスを作成する必要があります。
public class UserDO { private Integer id; //唯一主键 private Date createdTime; //创建时间 private Date updatedTime; //最后更新时间 private String name; //姓名 private Integer age; //年龄 private String gender; //性别 private String address; //住址 private String password; //密码 private String nickName; //昵称 private Date birthday; //生日 private String politicalStatus; //政治面貌,1表示群众,2表示团员,3表示党员,4表示其他,100表示未知 private Integer companyId; //公司的ID private Integer status; //数据状态,1表示可用,0表示不可用 //setter and getter }
次に、コード内で、DAO からフロントエンド ディスプレイまで、この UserDO クラスのオブジェクトを介してデータを送信します。これを行うことに問題はありますか?
不要なフィールドもフロントエンドページに渡されます。
パスワード、作成時刻、更新時刻、ステータスなどのフィールドについては、フロントエンドに表示する必要はまったくないかもしれませんが、これらのフィールドもフロントエンドに渡される可能性があります(SQL中に対応するフィールドをクエリしない限り)。クエリ)。これにより、送信されるデータ量が増加するだけでなく、セキュリティ上の問題が発生する可能性があります。
一部のフィールドは変換する必要がありますが、サポートできません。
上記の例の政治的外観フィールドでは、データベースに数値を保存していますが、フロントエンドページに表示したいのは中国語の説明です。この状況は、フロントエンドの if/else を通じてケースバイケースでのみ表示できます。
一部のフィールドは表示したいが、データベースには表示したくない
User テーブルには、このユーザーの companyId のみを保存し、それを確認するには、同時に company テーブルにクエリを実行する必要があります。会社に関するさらに詳しい情報。 User オブジェクトについて、その人物が所属する会社をフロントエンドに同時に表示し、1 つのクエリですべてを調べたい場合はどうすればよいでしょうか。いくつかの簡単な解決策があります。最初の解決策は、UserDO に Company クラスの属性を含めて、それをこの属性を通じて渡すことです。もう 1 つのオプションは、フロントエンドに渡したい Company 属性を UserDO に書き込むことです。しかし、これが本当に行われた場合、UserDO は引き続き DO と呼ばれるでしょうか?
まだ多くの質問があるため、ここでは詳しく説明しません。
最初から最後まで (データベースからフロントエンド ページまで) 1 つの DO を使用するのは良い設計ではないことがわかります。
DO、DTO、VOの正しい使い方
上記の例では、次のクラスに設計できます。モデルは複雑ではないので、ここではVOを導入するだけで済みます。
UserDO はすでにデータベース フィールドに 1 対 1 で対応しているため、ここでの変更は必要ありません。
public class UserDO { private Integer id; //唯一主键 private Date createdTime; //创建时间 private Date updatedTime; //最后更新时间 private String name; //姓名 private Integer age; //年龄 private String gender; //性别 private String address; //住址 private String password; //密码 private String nickName; //昵称 private Date birthday; //生日 private String education; //学历 private String politicalStatus; //政治面貌,1表示群众,2表示团员,3表示党员,4表示其他,100表示未知 private Integer companyId; //公司的ID private Integer status; //数据状态,1表示可用,0表示不可用 //setter and getter }
フロントエンドに表示する必要があるフィールドをカプセル化する UserVO を導入します。
public class UserVO { private Integer id; //唯一主键 private String name; //姓名 private Integer age; //年龄 private String gender; //性别 private String address; //住址 private String nickName; //昵称 private Date birthday; //生日 private String education; //学历 private String politicalStatus; //政治面貌,群众、团员、党员等 private Company company; //公司 //setter and getter }
UserVOには表示に必要なフィールドのみが含まれており、表示に必須でないフィールドはここに含める必要はありません。
このクラスを導入した後、データベース クエリを実行するときに UserDO を使用し、フロントエンドに渡す必要があるときに DO を VO に変換できます。
概要
これを見て、UserDO と UserVO に同じフィールドが多数含まれていることを発見したかもしれません。本当に別の VO を設計する必要があるのでしょうか?はっきりと言えるのは、システムがますます大きくなり、テーブル内のフィールドの数が増えると、階層処理に DODTOVO などの概念を使用することが絶対に有益であるということです。異なるエンティティクラス間で効率的に変換する方法については、次に紹介します。
DOをVOにエレガントに変換
Dozerはオブジェクト変換ツールです。
Dozer可以在JavaBean到JavaBean之间进行递归数据复制,并且这些JavaBean可以是不同的复杂的类型。
所有的mapping,Dozer将会很直接的将名称相同的fields进行复制,如果field名不同,或者有特别的对应要求,则可以在xml中进行定义。
前面我们介绍的DO\DTO\VO不就是JavaBean嘛。正好可以使用Dozer进行转换呀。
除了使用Dozer,当然你还由其他选择:
典型的解决方案就是手动拷贝,弊端很明显,代码中充斥大量Set 和Get方法,真正的业务被埋藏值与值的拷贝之中。
另一种方案就是使用BeanUtil,但BeanUtil不够很好的灵活性,又时候还不得不手动拷贝。Dozer可以灵活的对对象进行转换,且使用简单。
Dozer 支持的转换类型
Primitive 基本数据类型 , 后面带 Wrapper 是包装类 Complex Type 是复杂类型
• Primitive to Primitive Wrapper • Primitive to Custom Wrapper • Primitive Wrapper to Primitive Wrapper • Primitive to Primitive • Complex Type to Complex Type • String to Primitive • String to Primitive Wrapper • String to Complex Type if the Complex Type contains a String constructor • String 到复杂类型 , 如果复杂类型包含一个 String 类型的构造器 • String to Map • Collection to Collection • Collection to Array • Map to Complex Type • Map to Custom Map Type • Enum to Enum • Each of these can be mapped to one another: java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar • String to any of the supported Date/Calendar Objects. • Objects containing a toString() method that produces a long representing time in (ms) to any supported Date/Calendar object.
在普通Java项目中使用Dozer
在pom.xml中增加依赖
<dependency> <groupId>net.sf.dozer</groupId> <artifactId>dozer</artifactId> <version>5.5.1</version> </dependency>
使用Dozer进行类转换
public class Main { public static void main(String[] args) { DozerBeanMapper mapper = new DozerBeanMapper(); UserDO userDO = new UserDO(); userDO.setName("hollis"); userDO.setAddress("hz"); userDO.setAge(25); userDO.setCompanyId(1); userDO.setBirthday(new Date()); userDO.setGender("male"); userDO.setEducation("1"); userDO.setNickName("hollis"); userDO.setPoliticalStatus("3"); UserVO userVO = (UserVO) mapper.map(userDO, UserVO.class); System.out.println(userVO); } }
特殊的字段转换
在使用mapper进行转换前,设置一个或多个mapping文件
List myMappingFiles = new ArrayList(); myMappingFiles.add("dozer-mapping.xml"); mapper.setMappingFiles(myMappingFiles);
配置dozer-mapping.xml文件
数据类型不一致,或者名称不相同或者有级联关系等情况下,可以通过文件dozer-mapping.xml来进行定制Bean的转换
<?xml version="1.0" encoding="UTF-8"?> <mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dozer.sourceforge.net http://dozer.sourceforge.net/schema/beanmapping.xsd"> <mapping> <class-a>com.hollis.lab.UserDO</class-a> <class-b>com.hollis.lab.UserVO</class-b> </mapping> </mappings>
在JavaWeb项目中使用Dozer
在pom.xml中增加依赖
<dependency> <groupId>net.sf.dozer</groupId> <artifactId>dozer</artifactId> <version>5.5.1</version> </dependency>
使用Spring集成dozer
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <bean id="baseMapper" class="org.dozer.spring.DozerBeanMapperFactoryBean"> <property name="mappingFiles"> <list> <value>classpath:mapping/dozer-mapping.xml</value> </list> </property> </bean> </beans>
使用baseMapper进行Bean的转换
@Autowired private Mapper baseMapper; private UserVO doToVo(UserDO userDO){ if(userDO == null) return null; UserVO vo = baseMapper.map(userDO, UserVO.getClass()); if(userDO.getCompanyId != null) getCompany(vo); return vo; }
通过以上的代码加配置,我们就实现了从DO转换到VO的部分操作,之所以说是部分操作,是因为我们在dozer-mapping.xml并没有做多余的配置,只是使用dozer将DO中和VO中共有的属性转换了过来。对于其他的类型不同或者名称不同等的转换可以参考官网例子通过设置dozer-mapping.xml文件来实现。
上面还有一个getCompany()没有实现。这个方法其实就是通过companyId查询出company实体然后在赋值给UserVO中的company属性。
在使用了dozer之后,我们可以把UserDO中的部分属性赋值到UserVO中,其实,转化的过程是通过调用UserDO中的getter方法和UserVO中的setter方法来实现的。读者可以做个实验,对于UserVO中的部分属性不写Setter方法看看还能不能把属性值转换过来,博主已经测试过了,是不能的。