最近,我开始了一份新工作(现在已经4个月了),我还有很多需要学习的东西。我们遇到的一个问题是,当我们从数据库中提取对象并将它们映射到(存储库 - >服务 - >控制器)JSON时,它会带来大量不必要的数据 - 例如(小例子):
我们有一个Employee类,它有一个Department对象,它带来以下内容:
{
'EmployeeId':1,
'Name':'John',
'Email':'email@moose.com'
'Department': {
'DepartmentId':1,
'name':'Development',
'location':'Somewhere',
}
}
课程详情:
@Entity
@Table(name = "Employees")
@NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employees e")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "EmployeeId")
private long EmployeeId;
@Column(name = "Email")
private String email;
@Column(name = "address")
private String address;
@ManyToOne
@JoinColumn(name = "DepartmentId")
@JsonBackReference(value = "department_employee")
private Departament departament;
// Other attributes, setters & getters
}
如果我想构建一个“自定义”映射器,这是最佳实践?或者我如何实现允许我创建一个JSON的东西,它带给我这样的东西:
{
'EmployeeId':'1',
'Name':'John',
'Email':'email@moose.com'
}
我一直在做一些研究,我偶然发现了以下例子:
Jackson's @JsonView, @JsonFilter and Spring
此外,我一直在考虑使用包含HashMap的通用对象,因此我可以在Controller上包含我想要或需要特定屏幕的数据。
我真的很感激任何帮助 - 希望问题很清楚。
答案 0 :(得分:1)
一个特别适合我的图书馆是Model Mapper。我使用它的方式是让你的Domain对象(就像你现在这样)和DTO。在您的情况下,Employee和EmployeeDTO。这样可以清楚地分离应用层,并且员工和employeeDto之间的映射非常简单,例如modelMapper(employee, EmployeeDTO.class)
。对于简单的情况,您只需要在域类和dto类中命名具有相同名称的属性,并且库将负责复制值。对于更复杂的情况,它有几个替代方案仍然可以使您的代码清洁。
答案 1 :(得分:0)
例如,假设您有一个JPA实体Comment(捕获用户发表的评论)并且您想要自定义 序列化(从对象转换 - > JSON)
定义实体
//Comment Entity Attributes (This is just an example make sure you properly annotate the entity etc...):
private String id;
private final String userId;
private String discussionId;
private final Date createdTime;
private final String comment;
创建自定义序列化程序
/*Serializer*/
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
@Component
@Slf4j
public class CommentSerializer extends JsonSerializer<Comment> {
@Override
public void serialize(Comment comment, JsonGenerator jgen, SerializerProvider provider)
throws IOException,
JsonProcessingException {
jgen.writeStartObject();
jgen.writeStringField("id", comment.getId());
jgen.writeStringField("userId", comment.getUserId());
jgen.writeStringField("firstName", redisRepo.getName(comment.getUserId(), false));
jgen.writeStringField("discussionId", comment.getDiscussionId());
jgen.writeStringField("createdTime", String.valueOf(comment.getCreatedTime().getTime()));
jgen.writeStringField("comment", comment.getComment());
jgen.writeEndObject();
}
}
配置序列化程序
/*Config*/
import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
@Autowired
private CommentSerializer commentSerializer;
@Bean
public HttpMessageConverters httpMessageConverters() {
return new HttpMessageConverters(mappingJackson2HttpMessageConverter());
}
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter mappingJackson2JsonView = new MappingJackson2HttpMessageConverter();
mappingJackson2JsonView.setObjectMapper(objectMapper());
return mappingJackson2JsonView;
}
@Bean
public ObjectMapper objectMapper() {
Map<Class<?>, JsonSerializer<?>> serializerMap = new HashMap<>();
serializerMap.put(Comment.class, commentSerializer);
Jackson2ObjectMapperFactoryBean objectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean();
objectMapperFactoryBean.setIndentOutput(true);
objectMapperFactoryBean.setSerializersByType(serializerMap);
objectMapperFactoryBean.afterPropertiesSet();
ObjectMapper objectMapper = objectMapperFactoryBean.getObject();
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.findAndRegisterModules();
objectMapper.addMixInAnnotations(OAuth2Exception.class, OAuth2ExceptionMixin.class);
return objectMapper;
}
现在每当调用相关的url / endpoint(如下所示)时,它总是按照CommentSerializer中的逻辑定义进行序列化。
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Comment findOne(@PathVariable("id") String id)
....
return comment;
}