springboot2.x 如何優(yōu)雅的實現(xiàn) API 輸出?

前言

很多同學(xué)在 API 接口開發(fā)過程中肯定遇到過這樣的問題:如果 API 輸出的內(nèi)容直接使用 DB 表實體類,可能實際需求還得附帶更多的其他業(yè)務(wù)字段信息。如果新建一個類,包含 DB 表實體類字段信息,并帶上其他業(yè)務(wù)信息,是不是感覺又很累贅,字段屬性拷貝更是令人頭疼。因此,很有必要考慮用統(tǒng)一的一套方案,來優(yōu)雅的解決這個困擾。

DO、VO 實體類定義

DO 定義,沒什么好說的,跟 DB 表字段一一對應(yīng)。

package com.yb.demo.pojo.model.db1;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import javax.validation.constraints.Min;
import javax.validation.constraints.Size;

/**
 * @author daoshenzzg@163.com
 * @date 2019-08-05 17:58
 */
@Data
@TableName("student")
public class Student1DO {
    private Long id;
    @Size(max = 8, message = "studName長度不能超過8")
    private String studName;
    @Min(value = 12, message = "年齡不能低于12歲")
    private Integer studAge;
    private String studSex;
    @TableField(fill = FieldFill.INSERT)
    private Integer createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateTime;
}

VO 就比較有意思了,只需要多定一個 teacherName,表示我們要多輸出一個字段信息,然后再繼承Student1DO的所有屬性。

package com.yb.demo.pojo.response;

import com.yb.demo.pojo.model.db1.Student1DO;
import lombok.Data;

/**
 * @author daoshenzzg@163.com
 * @date 2019-10-29 11:07
 */
@Data
public class StudentVO extends Student1DO {
    private String teacherName;
}

類型轉(zhuǎn)換器定義

二話不說,先定一個類型轉(zhuǎn)換器接口

package com.yb.demo.converter;

import com.yb.demo.common.exception.ConverterException;

import java.util.List;

/**
 * 對象轉(zhuǎn)換器
 *
 * @author daoshenzzg@163.com
 * @date 2019-09-09 10:20
 */
public interface Converter<DO, VO> {

    /**
     * 對象轉(zhuǎn)換
     *
     * @param from
     * @param clazz
     * @return
     */
    VO convert(DO from, Class<VO> clazz) throws ConverterException;

    /**
     * 對象批量轉(zhuǎn)換
     *
     * @param fromList
     * @param clazz
     * @return
     */
    List<VO> convert(List<DO> fromList, Class<VO> clazz) throws ConverterException;
}

然后定一個基礎(chǔ)的轉(zhuǎn)換器來實現(xiàn)它。這里的默認實現(xiàn)是使用BeanUtils.copyProperties方式。

package com.yb.demo.converter;

import com.yb.demo.common.exception.ConverterException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 默認基礎(chǔ)對象轉(zhuǎn)換器
 *
 * @author daoshenzzg@163.com
 * @date 2019-09-09 10:26
 */
@Slf4j
public abstract class BaseConverter<DO, VO> implements Converter<DO, VO> {

    @Override
    public VO convert(DO from, Class<VO> clazz) throws ConverterException {
        if (from == null) {
            return null;
        }
        try {
            VO to = clazz.newInstance();
            BeanUtils.copyProperties(from, to);
            return to;
        } catch (Exception ex) {
            throw new ConverterException(ex);
        }
    }

    @Override
    public List<VO> convert(List<DO> fromList, Class<VO> clazz) throws ConverterException {
        if (CollectionUtils.isEmpty(fromList)) {
            return null;
        }
        List<VO> toList = new ArrayList<>(fromList.size());
        for (DO from : fromList) {
            toList.add(convert(from, clazz));
        }
        return toList;
    }
}

定義一個 StudentConverter 業(yè)務(wù)自定義來繼承 BaseConverter 。然后在使用super的默認轉(zhuǎn)換器實現(xiàn)拷貝bean屬性,再把 teacherName 批量賦值。就達到我們的目的。

package com.yb.demo.converter;

import com.yb.demo.common.exception.ConverterException;
import com.yb.demo.pojo.model.db1.Student1DO;
import com.yb.demo.pojo.response.StudentVO;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * 可以自定義轉(zhuǎn)換,也可以直接用BaseConverter的默認實現(xiàn)
 *
 * @author daoshenzzg@163.com
 * @date 2019-10-29 11:12
 */
@Component
public class StudentConverter extends BaseConverter<Student1DO, StudentVO> {

   /*
    @Autowired
    private TeacherService teacherService;
    */

    @Override
    public StudentVO convert(Student1DO from, Class<StudentVO> clazz) throws ConverterException {
        return super.convert(from, clazz);
    }

    @Override
    public List<StudentVO> convert(List<Student1DO> fromList, Class<StudentVO> clazz) throws ConverterException {
        List<StudentVO> voList = super.convert(fromList, clazz);
        // 模擬批量通過學(xué)生ID找到對應(yīng)的老師
        if (!CollectionUtils.isEmpty(voList)) {
            voList.forEach(entry -> entry.setTeacherName("莫言"));
        }
        return voList;
    }
}

StudentConverter 轉(zhuǎn)換器定義完了,然后在業(yè)務(wù)代碼中使用

@Autowired
private StudentConverter studentConverter;

/**
 * 學(xué)生列表
 *
 * @return
 */
public List<StudentVO> listStudent(String studName) {
    QueryWrapper<Student1DO> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("stud_name", studName);
    List<Student1DO> students = super.list(queryWrapper);
    return studentConverter.convert(students, StudentVO.class);
}

最終效果如下:

{
    "code": 200,
    "msg": "OK",
    "data": [
        {
            "id": 1,
            "studName": "張三-修改",
            "studAge": 23,
            "studSex": "男",
            "createTime": 1559724842,
            "updateTime": 1559724842,
            "teacherName": "莫言"
        }
    ],
    "ttl": 74
}

建議:如果有同學(xué)是做 API 輸出,需要追求極致的性能,可以自己在業(yè)務(wù)converter自己去實現(xiàn)拷貝方式。但,像一些管理后臺,也不太追求性能,完全可以直接使用BaseConverter的屬性拷貝方式。

結(jié)束語

這樣去定義,不僅代碼耦合度低,你會發(fā)現(xiàn),大伙都會使用這種方式去實現(xiàn)。代碼高度統(tǒng)一。

本系列文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 去年有段時間得空,就把谷歌GAE的API權(quán)威指南看了一遍,收獲頗豐,特別是在自己幾乎獨立開發(fā)了公司的云數(shù)據(jù)中心之后...
    騎單車的勛爵閱讀 21,135評論 0 41
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,694評論 1 32
  • 點擊查看原文 Web SDK 開發(fā)手冊 SDK 概述 網(wǎng)易云信 SDK 為 Web 應(yīng)用提供一個完善的 IM 系統(tǒng)...
    layjoy閱讀 14,495評論 0 15
  • 不可或缺的心理營養(yǎng) 父母都希望自己的孩子能夠健康成長。可是,我們也許不知道,就像需要身體營養(yǎng)一樣,孩子在不同的年齡...
    心創(chuàng)社閱讀 3,050評論 3 9
  • 這個周末回家鄉(xiāng)武漢看看小寶。算算一月余未見,骨子里都是想念,雖然每天視頻也不足以解思念之情。一月未見對一歲多的小寶...
    金艷時光閱讀 266評論 0 1

友情鏈接更多精彩內(nèi)容