数据流系列-2-前后端数据传输技巧2

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/meiceatcsdn/article/details/88877498

各位小伙伴,晚上好!这里分享下后端定义前端需传入的参数:*Command的技巧之1:使用Map<>传参和返回给前端的DTO技巧之1:自定义反序列化。

目录


一、Command定义技巧(前端需传入的参数封装)
二、自定义反序列化
三、总结


一、Command定义技巧(前端需传入的参数封装)

在大专家,后端把前端需要传入的参数多封装成Command,返回给前端的封装成DTO。
Command多用动词表示。

比如:用户更新个人信息的时候,方法如下:

public void updateUserInfo(UpdateUserInfoCommand cmd){
    cmd.setUserId(getCurrentUserId());
    cmd.setOperatorId(getCurrentUserId);
    userInfoService.update(cmd)
}

Command命名要规范:明确是什么Command,这里是:UpdateUserInfoCommand,可能还有其他Command,不要笼统的命名为:
UserCommand.

和前端交互有传参有2种方式:

方式1:
一个Command,利用Map<String,Object>
场景:用户修改个人信息,包含各种各样的信息,各种数据格式:

"gender": "MALE",——枚举
"religiousFaith": "NOTHING", "BUDDHISM" ——字符串
"knownAllergyResource": ["鸡蛋"]——数组或容器

这么多的属性,一一封装嘛?那属性指定下来估计上百个。
用Map<>
来看一下UpdateUserInfoCommand

public class UpdateUserInfoCommand extends HashMap<String, Object> implements Serializable {

   private static final long serialVersionUID = 1L;

   private String userId;

   private String operatorId;
   
   private UpdateOptions options;
   
   public String getUserId() {
      return StringUtils.isNotEmpty(this.userId)?this.userId:(String) get("userId");
   }

   public void setUserId(String userId) {
      this.userId = userId;
   }

   public String getOperatorId() {
      return operatorId;
   }

   public void setOperatorId(String operatorId) {
      this.operatorId = operatorId;
   }

   public UpdateOptions getOptions() {
      return options;
   }

   public void setOptions(UpdateOptions options) {
      this.options = options;
   }

}

用Map<String,Object>传参:
优点:灵活,适合各种参数;一个接口可以搞定
缺点:前端不知道怎么传,传什么不明确,需要口头约定

方式2:
指定具体的参数,就是一个类,各种数据类型的指定即可。

方式1还存在一个问题,那就是查询返回给前端,数据怎么交互?
先来看一下返回给前端的DTO:

@JsonSerialize(using = UserDataJsonSerializer.class)
public class UserDataDTO implements Serializable {

   private static final long serialVersionUID = 1L;

   private String userId;

   private Map<String, Object> fields;

   public String getUserId() {
      return userId;
   }

   public void setUserId(String userId) {
      this.userId = userId;
   }

   public Map<String, Object> getFields() {
      return fields;
   }

   public void setFields(Map<String, Object> fields) {
      this.fields = fields;
   }

   public String getFieldAsString(String fieldName) {
      if (fields != null) {
         Object field = fields.get(fieldName);
         if (field != null) {
            return String.valueOf(field);
         }
      }
      return null;
   }
   }
   

会有什么问题?这个fields会明晃晃的作为一个key传给前端,语义一点也不明确。如下:

{
    "code": null,
    "message": null,
    "data": {
        "userId": "5c333cd684ae2c88b09b69a2",
        "fields": {
            "liveAddress": {
                "liveProvinceCode": 220000,
                "liveCityCode": 220100,
                "liveDistrictCode": 0,
                "liveStreetCode": null,
                "liveCommitteeCode": null
            }
        },
        "headImg": null
    }
}

我们要达到的效果如下:

{
    "code": null,
    "message": null,
    "data": {
    "userId": "5c333cd684ae2c88b09b69a2",
     "liveAddress": {
            "id": 897,
            "userId": "5bde896be4b0213186390386",
            "detailAddress": "上海****222",
            "provinceCode": 310000,
            "cityCode": 310100,
            "districtCode": 310117,
            "streetCode": 310117105,
            "streetName": "新桥镇",
            "committeeCode": 310117105002,
            "committeeName": "新育居委会",
        },
        "headImg": null
    }
}

看看这个fields,使我们想要传给前端的嘛?当然不是。我们只想给前端一个key为liveAddress,value为一个对象,该对象包含了:
liveProvinceCode等信息。怎么办?

反序列化的时候处理,不用默认的反序列化,用工具jackon。

二、自定义反序列化

import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonSerialize(using = UserDataJsonSerializer.class)
public class UserDataDTO implements Serializable {
    
}

该注解就重写了反序列化的过程,会把fields重新处理。

public class UserDataJsonSerializer extends JsonSerializer<UserDataDTO> {

   @Override
   public void serialize(UserDataDTO value, JsonGenerator gen, SerializerProvider serializers)
         throws IOException, JsonProcessingException {
      gen.writeStartObject();
      gen.writeStringField("userId", value.getUserId());
      Map<String, Object> fields = value.getFields();
      if (fields != null) {
         for (Entry<String, Object> entry : fields.entrySet()) {
            gen.writeFieldName(entry.getKey());
            gen.writeObject(entry.getValue());
         }
      }
      gen.writeEndObject();
   }

}

使用jackson步骤总结如下:


1、定义一个类,继承JsonSerializer
2、重写serialize()方法
3、在返回给前端的DTO上增加注解:@JsonSerialize(using = UserDataJsonSerializer.class)


为什么就避免了fields传给前端呢?因为用默认的Serializable,所有属性都会直接返回,自己重写serialize方法,就可以按照想要的来反序列化拉。

总结:


1、Command命名语义明确:eg:UpdateUserInfoCommand

2、Command里参数尽量少用Map<String,Object>.优点:简化传参、简化接口数量;缺点:传递给前端的参数语义非常模糊(需约定好)、反序列化需要干预,否则出现冗余字段类似fields

3、jackson的运用


猜你喜欢

转载自blog.csdn.net/meiceatcsdn/article/details/88877498