【问题标题】:JSON Object mapping - Spring DataJSON 对象映射 - Spring Data
【发布时间】:2016-12-18 17:56:24
【问题描述】:

最近,我开始了一份新工作(现在已经 4 个月了),我还有很多东西要向 Spring 学习。我们遇到的问题之一是,当我们从数据库中获取对象并将它们映射到(存储库 -> 服务 -> 控制器)一个 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 的通用对象,这样我就可以在控制器上包含特定屏幕所需或需要的数据。

非常感谢任何帮助 - 希望问题足够清楚。

【问题讨论】:

  • 顺便说一句,问题也发布在:coderanch.com/t/669152/Spring/Spring-Mapping-Objects#3124303
  • 如果不想序列化部门可以使用@JsonIgnoreProperties注解。
  • 抱歉,如果我没有在问题上指定这一点 - 在某些屏幕上,我需要部门,例如当我需要更新员工时。但是,如果我只需要显示姓名、电子邮件和一些特定数据,那么哪种方式更合适呢? @JsonIgnoreProperties 完全忽略该字段。
  • 也许我对类似问题的旧回答会有所帮助stackoverflow.com/a/30645468/1847202

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


【解决方案1】:

一个特别适合我的库是Model Mapper。我使用它的方式是拥有你的 Domain 对象(就像你现在做的那样)和一个 DTO。因此,在您的情况下,Employee 和 EmployeeDTO。这允许在应用程序的层之间进行清晰的分离,并且使用模型映射器在员工和员工Dto 之间进行映射非常容易,例如 modelMapper(employee, EmployeeDTO.class)。对于简单的情况,您所要做的就是在域类和 dto 类中命名具有相同名称的属性,并且库将负责复制这些值。对于更复杂的情况,它有几个替代方案仍然可以使您的代码干净。

【讨论】:

  • 谢谢@Ulises,我会试一试,看看它是如何工作的。
【解决方案2】:

例如,假设您有一个 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-19
    • 2021-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 2023-03-07
    相关资源
    最近更新 更多