JSON对象映射 - Spring Data

时间:2016-08-11 20:42:18

标签: java json spring spring-mvc spring-data

最近,我开始了一份新工作(现在已经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 JSON Views

Jackson's @JsonView, @JsonFilter and Spring

此外,我一直在考虑使用包含HashMap的通用对象,因此我可以在Controller上包含我想要或需要特定屏幕的数据。

我真的很感激任何帮助 - 希望问题很清楚。

2 个答案:

答案 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;
}