Was sind DO, DTO und VO?
Verschiedene Modellkonzepte in Java wurden in den Konzepten VO, PO, DO, DTO, BO, QO, DAO und POJO in Java eingeführt.
Eine kurze Zusammenfassung hier:
In der täglichen Projektentwicklung entspricht VO den Daten (Formular), die auf der Seite angezeigt werden müssen, DO entspricht den in der Datenbank (Datentabelle) gespeicherten Daten. und DTO Entspricht den Daten, die zusätzlich zu den beiden übertragen werden müssen.
Viele Menschen kennen sich vielleicht nicht so gut mit VO und DTO aus, sind aber mit DO besser vertraut. Das liegt daran, dass wir aus verschiedenen Gründen nur DO verwenden:
1. Das Projekt ist zu klein. Für ein Unternehmen reicht es aus, es in ein DO zu kapseln.
2. Ich kenne DTO und VO nicht, geschweige denn den Unterschied zwischen ihnen.
3. Ich kenne den Unterschied zwischen DODTOVO, bin aber zu faul, ihn zu benutzen.
Hier wird der Blogger darüber sprechen, warum so viele Konzepte eingeführt werden und warum ich jedem empfehle, diese Entitätsobjekte in seinen eigenen Projekten zu verwenden.
Warum nicht einfach ein DO verwenden?
Schauen wir uns ein solches Beispiel an. Angenommen, in unserem Projekt gibt es eine Entität wie „Benutzer“. Wenn wir die Benutzertabelle erstellen, schließen wir im Allgemeinen die folgenden Attribute ein:
Für diese Entität müssen wir normalerweise eine DO-Klasse erstellen, um die Benutzerentität zu kapseln.
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 }
Dann übertragen wir im Code vom DAO zur Front-End-Anzeige Daten über das Objekt dieser UserDO-Klasse. Gibt es dabei irgendwelche Probleme?
Unnötige Felder werden ebenfalls an die Frontend-Seite übergeben.
Felder wie Passwort, erstellte Zeit, aktualisierte Zeit und Status müssen möglicherweise überhaupt nicht im Frontend angezeigt werden, aber diese Felder können auch an das Frontend übergeben werden (es sei denn, wir fragen die entsprechenden Felder währenddessen nicht ab). SQL-Abfragefelder). Dies erhöht nicht nur die Menge der übertragenen Daten, sondern kann auch zu Sicherheitsproblemen führen.
Einige Felder müssen konvertiert werden, können aber nicht unterstützt werden.
Für das Feld „Politisches Erscheinungsbild“ im obigen Beispiel speichern wir Zahlen in der Datenbank, aber was ich auf der Startseite anzeigen möchte, ist eine chinesische Beschreibung. Diese Situation kann nur im Einzelfall über if/else im Frontend angezeigt werden.
Einige Felder müssen angezeigt werden, möchten aber nicht in der Datenbank angezeigt werden
In der Benutzertabelle speichern wir nur die Firmen-ID dieses Benutzers und müssen das Unternehmen abfragen Tabelle gleichzeitig, um weitere Details des Unternehmens abzufragen. Was wäre, wenn wir für das Benutzerobjekt gleichzeitig die Firma, zu der er gehört, im Frontend anzeigen und alle durch eine Abfrage herausfinden möchten? Es gibt mehrere einfache Lösungen. Die erste besteht darin, UserDO ein Attribut der Company-Klasse enthalten zu lassen und es über dieses Attribut zu übergeben. Eine andere Möglichkeit besteht darin, die Unternehmensattribute, die wir an das Frontend übergeben möchten, in UserDO zu schreiben. Wenn dies jedoch wirklich geschehen ist, kann UserDO dann immer noch DO heißen?
Es gibt noch viele Fragen, daher werde ich hier nicht näher darauf eingehen.
Es ist ersichtlich, dass die Verwendung eines DO von Anfang bis Ende (von der Datenbank bis zur Front-End-Seite) kein gutes Design ist.
Wie man DO, DTO und VO richtig verwendet
Für das obige Beispiel können wir es in die folgende Klasse entwerfen. Da das Modell nicht kompliziert ist, müssen wir hier nur VO einführen.
UserDO entspricht bereits eins zu eins den Datenbankfeldern, hier sind keine Änderungen erforderlich.
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 }
Führt UserVO ein, um die Felder zu kapseln, die angezeigt werden müssen, wenn sie an das Frontend übergeben werden.
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 enthält nur die für die Anzeige erforderlichen Felder. Felder, die für die Anzeige nicht erforderlich sind, müssen hier nicht enthalten sein.
Nach der Einführung dieser Klasse können wir UserDO verwenden, wenn wir Datenbankabfragen durchführen, und dann DO in VO konvertieren, wenn wir es an das Frontend übergeben müssen.
Zusammenfassung
Wenn Sie dies sehen, haben Sie möglicherweise festgestellt, dass UserDO und UserVO eine große Anzahl derselben Felder enthalten. Ist es wirklich notwendig, eine separate VO zu entwerfen? Was ich Ihnen klar sagen kann: Wenn Ihr System immer größer wird und immer mehr Felder in der Tabelle vorhanden sind, ist es absolut vorteilhaft, Konzepte wie DODTOVO für die hierarchische Verarbeitung zu verwenden. Wie man effektiv zwischen verschiedenen Entitätsklassen konvertiert, werde ich als Nächstes vorstellen.
DO auf elegante Weise in VO umwandeln
Dozer ist ein Objektkonvertierungstool.
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方法看看还能不能把属性值转换过来,博主已经测试过了,是不能的。