1.基本概念
VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。简称为页面对象。
DTO(Data Transfer Object):数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。
DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。
PO(Persistent Object):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应PO的一个(或若干个)属性。
模型:
用户发出请求(可能是填写表单),表单的数据在展示层被匹配为VO。
展示层把VO转换为服务层对应方法所要求的DTO,传送给服务层。
服务层首先根据DTO的数据构造(或重建)一个DO,调用DO的业务方法完成具体业务。
服务层把DO转换为持久层对应的PO(可以使用ORM工具,也可以不用),调用持久层的持久化方法,把PO传递给它,完成持久化操作。
对于一个逆向操作,如读取数据,也是用类似的方式转换和传递,略。
2.基于DDD模型的微服务分层架构图
3.dto的应用实例
3.1 需求分析
现有学生表,课程表,分数表,这三张表,要求通过学号查询出学生信息,包含课程和分数,这里我们采用dto思想进行操作。
3.2 代码实现
编写转换器,将实体类换成dto对象
package com.gh.blog.dto; import com.github.pagehelper.PageInfo; import org.springframework.beans.BeanUtils; import java.util.ArrayList; import java.util.List; public interface Convert<DTO, ENTITY> { /** * 把ENTITY转换为DTO * @param entity * @return */ default DTO convertFrom(ENTITY entity) { try { BeanUtils.copyProperties(entity, this); return (DTO)this; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("系统异常"); } } /** * 把List<ENTITY>转换为List<DTO> * @param entities * @return */ default List<DTO> convertFrom(List<ENTITY> entities) { List dtoList = new ArrayList(); for (ENTITY entity : entities) { try { // 反射当前对象,Obj就是指的当前对象,也就是ArticleDTO Object dto = this.getClass().newInstance(); // 拷贝参数,把entity中的参数数据,拷贝到obj BeanUtils.copyProperties(entity, dto); dtoList.add(dto); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("系统异常"); } } return dtoList; } /** * 把page<ENTITY>转换为page<DTO> * @param page * @return */ default PageInfo<DTO> convertFrom(PageInfo page) { // 把page<Article>的list取出,进行转换 List<ENTITY> entities = page.getList(); // 把Article的list转换为ArticleDTO的list List<DTO> dtos = convertFrom(entities); // 更换page的内容 page.setList(dtos); return page; } }
我们这里返回给页面的一个dto对象
@Getter @Setter public class StudentDetailDTO implements Convert<StudentDetailDTO, Student> { private String no; private String name; private Boolean sex; private Date birthday; private Date inSchoolDay; private String classCode; private String phone; private String homeAddress; private List<ScoreDTO> scores; }
这里的dto包含了ScoreDTO进一步进行封装
@Getter @Setter public class ScoreDTO implements Convert<ScoreDTO, Score> { private Double score; private Course course; }
controller的实现
@GetMapping("detail") public StudentDetailDTO studentDetail(String no) { StudentDetailDTO studentDetail = stuService.findDetail(no); return studentDetail; }
service实现类
@Override public StudentDetailDTO findDetail(String no) { // 查询学生信息并转换为dto StudentDetailDTO studentDetail = new StudentDetailDTO().convertFrom(stuMapper.findByNo(no)); // 查询学生全部成绩 List<ScoreDTO> scores = new ArrayList<>(); //根据学号查成绩,然后拿到该学生的所有成绩,进行遍历 for (Score item : scoreMapper.listByStudentNo(no)) { //把学生成绩用dto封装 ScoreDTO score = new ScoreDTO().convertFrom(item); // 查询成绩对应课程 Course course = courseMapper.getByCode(item.getCourseNo()); score.setCourse(course); scores.add(score); } studentDetail.setScores(scores); return studentDetail; }
dao是简单的单表查询操作,省略不写