基于class-transformer的对象与JSON相互转换
场景一:方法将普通javascript对象转换为特定类的实例
解决方案
首先我们先定义一个想要指定的特定的类如下:
User里面包含属性id,fistname,lastname,age,data和它的构造方法,还有特定的方法getName和isAdult。
class User {
id: number;
firstName: string;
lastName: string;
age: number;
date?: Date;
constructor() {
this.id = 0;
this.firstName = "";
this.lastName = "";
this.age = 0;
}
getName() {
return this.firstName + ' ' + this.lastName;
}
isAdult() {
return this.age > 18 && this.age < 60;
}
}
我们在前端处理后端传送过来的数据时,经过反序列化转换的对象全是plain(literal) object(普通(字面量)对象),如下,这里我们手动写一个待转换成特定对象的 JavaScript对象(JSON形式)。
interface UserJson {
id: number,
firstName: string,
lastName: string,
age: number,
date?: Date
}
const userJson:UserJson = {
id: 1,
firstName: "Johny",
lastName: "Cage",
age: 27,
date: new Date()
}
使用class-transform可以直接将收到的userJson字面量对象转换为User实例对象,进而可以使用其中的方法。
使用plainToInstance(将字面量转为类实例,支持数组转换)这个接口来进行转化对应实例。
plainToInstance第一个参数传入特定的实体类,第二个传入需要转换的js对象。
export function test1() {
// JSON转为对象
const user: User = plainToInstance(User,userJson);
log("JSON转对象后输出情况");
//输出class中的方法
log(user.getName());
log(user.isAdult() + "");
}
实现效果:
在项目中使用class-transformer例子
上面已经说明了class-transformer的最简单用法,现在说一个示例如何在项目中使用。
前端代码:
class User {
//实体类还是我们刚才的实体User(包含fistname,lastname,age,data,和它的构造方法还有特定的方法getName和isAdult) 这里省略重复代码
}
Request.get({
baseURL: 'http://xxxxx'
}).then((user: User) => {
console.log(user)
console.log(user.username)
console.log(user.getName())
console.log(user.isAdult())
})
后端代码:
@Get('/user')
findUser() {
const user = new User('coder', '12345', 18);
return user;
}
可以发现立马就报错了:
所以我们需要使用class-transformer的plainToInstance来做修改:
Request.get ({
baseURL : 'http://xxx'}).then((user : User) => {
const user1 = plainToInstance(User, user)
console.log(user1.username)
console.log(user1.getName())
console.log(user1.isAdult())
})
立马见效,并且还能调用其中的方法:
场景二:JSON转对象的时候,控制某些敏感字段不对外暴露
解决方案
使用exclude注解可以解决,还是使用User实体来做演示里面的password属性不想被传到JSON。
class User {
id: number;
@Exclude()
password: string;
constructor(id: number, password: string) {
this.id = id;
this.password = password;
}
}
手动写一个待转换成特定对象的 javascript对象(JSON形式)。
interface UserJson {
'id': number,
'password': string
}
如果是传入的字符串我们需要搭配JSON.parse来使用,将字符串转化成JSON格式的UserJson对象,使用plainToInstance来进行转换,由于使用了@Exclude()注解
转换成user对象后password属性也不会被输出。
export function SensitiveJsonToInstanceDemo() {
log('JSON转对象后输出情况');
let ss = '{"id":1,"password":"123456"}'
let oo: UserJson = JSON.parse(ss)
let user: User = plainToInstance(User,oo)
log('user_id=' + user.id)
log('user_password=' + user.password);
}
可见需要控制隐藏的password并不会被输出。
场景三:属性是一些复杂结构体时,实现json与对象的互转
解决方案
这里我们定义一个需要转换的User实体类,user的id,name 还有firstSonName,firstSonAge。
class User {
userId: number;
userName: string;
firstSonName: string;
firstSonAge: number;
constructor(userId: number, userName: string, firstSonName: string, firstSonAge: number) {
this.userId = userId;
this.userName = userName;
this.firstSonName = firstSonName;
this.firstSonAge = firstSonAge;
}
}
服务端传一个字符串。
{
'userId': 1,
'userName': 'abc',
'children': [
{
'username': 'son1',
'age': '18'
},
{
'username': 'son2',
'age': '28'
}
]
}
所以我们设计两个接口:
interface UserJson {
userId: number;
userName: string;
firstSonName: string;
firstSonAge: number;
}
interface FatherJson {
userId: number;
userName: string;
children: Record<string,string>[]
}
直接使用plainToInstance将fatherjson转换成user对象是获取不到firstSonName,与firstSonAge的属性的,所以我们需要进行一个属性拍平。
export function ComplexJsonToInstanceDemo() {
//服务器返回的字符串
let ss = '{"userId":1,"userName":"abc","children":[{"username":"son1","age":"18"},{"username":"son2","age":"28"}]}'
//将字符串转化成JSON
let fatherjson: FatherJson = JSON.parse(ss)
let fs: Record<string,string> = fatherjson.children[0]
//fatherjson转userjson
let userjson: UserJson = {
userId: fatherjson.userId,
userName: fatherjson.userName,
firstSonName: fs['username'],
firstSonAge: parseInt(fs['age'])
}
let user: User = plainToInstance(User,userjson)
log('user_firstSonName=' + user.firstSonName)
log('user_firstSonAge=' + user.firstSonAge)
}
实现效果,可看到firstSonName与firstSonAge,已经成功获取。
总结
使用三方库class-transformer搭配JSON的JSON.parse,可以满足类似gson/fastjson绝大部分的需求,更多用法可以参考https://github.com/typestack/class-transformer文档。
此外,建议审视设计的类和json是否合理,尽量避免使用复杂的转换。