后台系统的前后端字段不一样,前端用的是小驼峰,后端用的是下划线分隔,每次转起来特别烦,所以想着写个简单的 dto 来转换一下。同时还可以用自定义的规则来判断字段的过滤,不通过就不传给后端。
export class AdvancedDtoManager {
constructor(source = {}, validationRules = {}, mappingRules = {}) {
this.source = source;
this.validationRules = validationRules;
this.mappingRules = mappingRules;
}
validate(key, value) {
const rule = this.validationRules[key];
if (!rule) {
return true;
}
return rule(value);
}
toDto() {
const dto = {};
for (const key in this.source) {
if (this.validate(key, this.source[key])) {
const mappedKey = this.mappingRules[key] || key;
dto[mappedKey] = this.source[key];
}
}
return dto;
}
fromDto(dto) {
const source = {};
for (const key in dto) {
const reverseMapping = Object.entries(this.mappingRules).find(
([, v]) => v === key
)?.[0] || key;
if (this.validate(reverseMapping, dto[key])) {
source[reverseMapping] = dto[key];
}
}
return source;
}
}
function isDefined(v) {
return v !== undefined && v !== null;
}
function notEmptyArr(v) {
return v && v.length > 0;
}
function isNumber(v) {
return (typeof v === 'number' || v) && !isNaN(v);
}
function isValidNumber(v) {
return isNumber(v) && v > 0;
}
function isString(v) {
return typeof v === 'string';
}
export const rules = {
name: isDefined,
groupId: isDefined,
tags: notEmptyArr,
coverUrl: isDefined,
id: isString,
};
export const mapping = {
'name': 'name',
'groupId': 'group_id',
'assetType': 'asset_type',
'coverUrl': 'cover_url',
'id': 'asset_id',
'tags': 'tags'
};
业务层使用方式如下
const manager = new AdvancedDtoManager(data, rules, mapping);
const Dto = manager.toDto();