回忆一下,之前我们访问的spuList时候,返回的sku的json格式,并不能很好地被前端调用,我们需要进行改进。
这里的json格式分为单体json和数组型json。如何通过优化让前端更好调用呢?
- 单体Json对应的是map<string,Object>
- 数组型Json对应的是List<Map(string,Object)>或者List<类>
菜单
方法一:创建MapAndJson和ListAndJson并利用注解方式序列化
1、单体Json与Mpa的映射
1.1、在util中,创建一个MapAndJson的类,用于处理单体Json与Map的处理
package com.fcors.fcors.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fcors.fcors.exception.ServerErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.util.HashMap;
import java.util.Map;
@Converter
public class MapAndJson implements AttributeConverter<Map<String, Object>, String> {
@Autowired
private ObjectMapper mapper;
@Override
public String convertToDatabaseColumn(Map<String, Object> stringObjectMap) {
try {
return mapper.writeValueAsString(stringObjectMap);
} catch (Exception e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> convertToEntityAttribute(String s) {
Map<String,Object> t = new HashMap<String,Object>();
if(s==null){
return t;
}
try {
t = mapper.readValue(s, HashMap.class);
return t;
} catch (Exception e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
}
1.2、创建一个ServerErrorException
在execption下面创建一个ServerErrorException类
package com.fcors.fcors.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fcors.fcors.exception.ServerErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import javax.persistence.AttributeConverter;
import java.util.HashMap;
import java.util.Map;
public class MapAndJson implements AttributeConverter<Map<String, Object>, String> {
@Autowired
private ObjectMapper mapper;
@Override
public String convertToDatabaseColumn(Map<String, Object> stringObjectMap) {
try {
return mapper.writeValueAsString(stringObjectMap);
} catch (Exception e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> convertToEntityAttribute(String s) {
try {
Map<String, Object> t = mapper.readValue(s, HashMap.class);
return t;
} catch (Exception e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
}
1.3、添加错误码
在recources/config的exception-code.properties追加错误码
fcors.codes[9999]=服务器未知错误异常
1.4、修改Sku的model
package com.fcors.fcors.model;
import com.fcors.fcors.util.MapAndJson;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Map;
import java.util.Objects;
@Entity
@Getter
@Setter
@Table(name = "sku")
public class SkuEntity extends BaseEntity{
@Id
@Column(name = "id")
private Long id;
private BigDecimal price;
private BigDecimal discountPrice;
private byte online;
private String img;
private String title;
private Long spuId;
private String specs;
private String code;
private Long stock;
private Long categoryId;
private Long rootCategoryId;
// private String test;
/*把原来的String 改成 Map */
@Convert(converter= MapAndJson.class)
private Map<String,Object> test;
}
下面开始讲解数组型JSON与List的映射
2、数组型JSON与List的映射
1、在util下面创建ListAndJson类
package com.fcors.fcors.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fcors.fcors.exception.ServerErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.util.List;
@Converter
public class ListAndJson implements AttributeConverter<List<Object>, String> {
@Autowired
private ObjectMapper mapper;
@Override
public String convertToDatabaseColumn(List<Object> objects) {
try {
return mapper.writeValueAsString(objects);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
@Override
@SuppressWarnings("unchecked")
public List<Object> convertToEntityAttribute(String s) {
try {
if(s == null){
return null;
}
List<Object> t = mapper.readValue(s, List.class);
return t;
} catch (Exception e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
}
2.2 在model下创建一个Spec的类
List的话需要创建类,不然因为类型问题容易引起后面的错误。
因为没有数据表,所以不需要加入@Entity
package com.fcors.fcors.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.Table;
@Getter
@Setter
public class Spec {
@JsonProperty("keyId")
private Long key_id;
private String key;
@JsonProperty("valueId")
private Long value_id;
private String value;
}
2.3 修改Model下面的Sku
package com.fcors.fcors.model;
import com.fcors.fcors.util.ListAndJson;
import com.fcors.fcors.util.MapAndJson;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
@Entity
@Getter
@Setter
@Table(name = "sku")
public class SkuEntity extends BaseEntity{
@Id
@Column(name = "id")
private Long id;
private BigDecimal price;
private BigDecimal discountPrice;
private byte online;
private String img;
private String title;
private Long spuId;
/*把原来的String改成下面的*/
@Convert(converter = ListAndJson.class)
private List<Spec> specs;
// private String specs;
private String code;
private Long stock;
private Long categoryId;
private Long rootCategoryId;
// private String test;
@Convert(converter= MapAndJson.class)
private Map<String,Object> test;
}
完成序列化。
方法二:创建GenericAndJson公共方法类
1、在util处新增GenericAndJson类
package com.fcors.fcors.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fcors.fcors.exception.ServerErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class GenericAndJson {
private static ObjectMapper mapper;
@Autowired
public void setMapper(ObjectMapper mapper) {
GenericAndJson.mapper = mapper;
}
public static <T> String objectToJson(T o) {
String resp=null;
if(o ==null){
return null;
}
try {
resp=(String) (o.equals(String.class)?o:mapper.writerWithDefaultPrettyPrinter().writeValueAsString(o));
return resp;
} catch (Exception e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
public static <T> T jsonToObject(String s, TypeReference<T> tr) {
if (s == null) {
return null;
}
try {
T o = (T)GenericAndJson.mapper.readValue(s, tr);
return o;
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
}
2、修改model下的Sku类的代码
将单体Json或数组型Json的类型设置成String,然后重新设置Getter和Setter方法
package com.fcors.fcors.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fcors.fcors.util.GenericAndJson;
import com.fcors.fcors.util.ListAndJson;
import com.fcors.fcors.util.MapAndJson;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.*;
@Entity
@Getter
@Setter
@Table(name = "sku")
public class SkuEntity extends BaseEntity{
@Id
@Column(name = "id")
private Long id;
private BigDecimal price;
private BigDecimal discountPrice;
private byte online;
private String img;
private String title;
private Long spuId;
private String code;
private Long stock;
private Long categoryId;
private Long rootCategoryId;
/**方法一:数组型Json注解方式**/
// @Convert(converter = ListAndJson.class)
// private List<Spec> specs;
/**方法二:数组型JSON-GenericAndJson **/
private String specs;
public List<Map<String,Object>> getSpecs() {
List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
if (specs == null) return list;
list = GenericAndJson.jsonToObject(this.specs, new TypeReference<List<Map<String,Object>>>(){});
return list;
}
public void setSpecs(List<Spec> specs) {
if (specs.isEmpty()) return;
this.specs = GenericAndJson.objectToJson(specs);
}
/*方法一:单体Json注解方式*/
// @Convert(converter= MapAndJson.class)
// private Map<String,Object> test;
/** 方法二:单体JSON-GenericAndJson */
private String test;
public Map<String,Object> getTest() {
Map<String,Object> spec = new HashMap<String,Object>();;
if(this.test ==null){
return spec;
}
spec = GenericAndJson.jsonToObject(this.test, new TypeReference<HashMap<String, Object>>() {
});
return spec;
}
public void setTest(Spec test) {
if(test==null){
return;
}
this.test = GenericAndJson.objectToJson(test);
}
}
注意:如果没有使用Vo层的话,接口返回Json是不会报错的,但如果使用了Vo层需要Vo层的实体进行修改。
如图使用了Vo层过滤数据,我们需要在vo层重新定义一个“SkuEntityDTO”
切记添加上@Getter和@Setter
方法二完成。
方法三:实现AttributeConverter
1.1、在util下面创建一个SuperGenericAndJson类
package com.fcors.fcors.util;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fcors.fcors.exception.ServerErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class SuperGenericAndJson<T> implements AttributeConverter<T, String> {
@Autowired
private ObjectMapper mapper;
@Override
public String convertToDatabaseColumn(T t) {
if(t ==null){
return null;
}
try {
return mapper.writeValueAsString(t);
} catch (Exception e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
@Override
public T convertToEntityAttribute(String s) {
try {
if (s == null) {
return null;
}
T t = mapper.readValue(s, new TypeReference<T>() {
});
return t;
} catch (Exception e) {
e.printStackTrace();
throw new ServerErrorException(9999);
}
}
}
1.2、修改Model下面的Sku实体类
package com.fcors.fcors.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fcors.fcors.util.GenericAndJson;
import com.fcors.fcors.util.ListAndJson;
import com.fcors.fcors.util.MapAndJson;
import com.fcors.fcors.util.SuperGenericAndJson;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.*;
@Entity
@Getter
@Setter
@Table(name = "sku")
public class SkuEntity extends BaseEntity{
@Id
@Column(name = "id")
private Long id;
private BigDecimal price;
private BigDecimal discountPrice;
private byte online;
private String img;
private String title;
private Long spuId;
private String code;
private Long stock;
private Long categoryId;
private Long rootCategoryId;
/**方法一:数组型Json注解方式**/
// @Convert(converter = ListAndJson.class)
// private List<Spec> specs;
/**方法二:数组型JSON-GenericAndJson **/
// private String specs;
// public List<Map<String,Object>> getSpecs() {
// List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
// if (specs == null) return list;
// list = GenericAndJson.jsonToObject(this.specs, new TypeReference<List<Map<String,Object>>>(){});
// return list;
// }
// public void setSpecs(List<Spec> specs) {
// if (specs.isEmpty()) return;
// this.specs = GenericAndJson.objectToJson(specs);
// }
/**方法三:数组型JSON-SuperGenericAndJson **/
@Convert(converter = SuperGenericAndJson.class)
private List<Spec> specs;
/**方法一:单体Json注解方式**/
// @Convert(converter= MapAndJson.class)
// private Map<String,Object> test;
/** 方法二:单体JSON-GenericAndJson */
// private String test;
// public Map<String,Object> getTest() {
// Map<String,Object> spec = new HashMap<String,Object>();;
// if(this.test ==null){
// return spec;
// }
// spec = GenericAndJson.jsonToObject(this.test, new TypeReference<HashMap<String, Object>>() {
// });
// return spec;
//
// }
//
// public void setTest(Spec test) {
// if(test==null){
// return;
// }
// this.test = GenericAndJson.objectToJson(test);
// }
/**方法三:单体JSON-SuperGenericAndJson **/
@Convert(converter = SuperGenericAndJson.class)
private Map<String,Object> test;
}
方法三较方法二相比,即便使用了Vo层,也不需要创建Dto层。
扩展学习:如何在model下添加条件筛选
使用@Where注解
@Where(clause = "delete_time is null ")
完整代码
package com.fcors.fcors.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fcors.fcors.util.GenericAndJson;
import com.fcors.fcors.util.ListAndJson;
import com.fcors.fcors.util.MapAndJson;
import com.fcors.fcors.util.SuperGenericAndJson;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.Where;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.*;
@Entity
@Getter
@Setter
@Table(name = "sku")
@Where(clause = "delete_time is null ")
public class SkuEntity extends BaseEntity{
@Id
@Column(name = "id")
private Long id;
private BigDecimal price;
private BigDecimal discountPrice;
private byte online;
private String img;
private String title;
private Long spuId;
private String code;
private Long stock;
private Long categoryId;
private Long rootCategoryId;
/**方法一:数组型Json注解方式**/
// @Convert(converter = ListAndJson.class)
// private List<Spec> specs;
/**方法二:数组型JSON-GenericAndJson **/
// private String specs;
// public List<Map<String,Object>> getSpecs() {
// List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
// if (specs == null) return list;
// list = GenericAndJson.jsonToObject(this.specs, new TypeReference<List<Map<String,Object>>>(){});
// return list;
// }
// public void setSpecs(List<Spec> specs) {
// if (specs.isEmpty()) return;
// this.specs = GenericAndJson.objectToJson(specs);
// }
/**方法三:数组型JSON-SuperGenericAndJson **/
@Convert(converter = SuperGenericAndJson.class)
private List<Spec> specs;
/**方法一:单体Json注解方式**/
// @Convert(converter= MapAndJson.class)
// private Map<String,Object> test;
/** 方法二:单体JSON-GenericAndJson */
// private String test;
// public Map<String,Object> getTest() {
// Map<String,Object> spec = new HashMap<String,Object>();;
// if(this.test ==null){
// return spec;
// }
// spec = GenericAndJson.jsonToObject(this.test, new TypeReference<HashMap<String, Object>>() {
// });
// return spec;
//
// }
//
// public void setTest(Spec test) {
// if(test==null){
// return;
// }
// this.test = GenericAndJson.objectToJson(test);
// }
/**方法三:单体JSON-SuperGenericAndJson **/
@Convert(converter = SuperGenericAndJson.class)
private Map<String,Object> test;
}