首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >SpringBoot中json转换的正确方式和位置

SpringBoot中json转换的正确方式和位置
EN

Stack Overflow用户
提问于 2019-12-10 04:38:38
回答 2查看 1.8K关注 0票数 0

我正在做一个小的SpringBoot项目。将订单数据存储在postgres数据库中。我有一个API,它为我的前端返回json。我在问自己到底应该在哪个地方将我的数据转换为实际的json。我知道有几种方法可以做到这一点,但我想学习专业的方法。

假设订单包含id、date、customername、productid。在这个例子中,当我的前端被要求输入一个特定的名字时,我只需要order_date形式的date和product_id形式的productid。

可能的方式:

1)在我的CrudRepository中使用原生postgres查询:

代码语言:javascript
运行
复制
@Query(value="SELECT json_build_object('order_date', o.date, 'product_id', productid) 
       from order where name=:name", nativeQuery = true)
List<Object> getOrderByName(@Param("name") String name);

然后只需在控制器方法中调用此存储库方法。考虑到性能,转换成json可能是最快的方式。我现在面临的最大缺点是,你不能对crudrepository方法的返回值进行任何计算,因为它是一个特殊的postgres对象。例如,在测试中模拟这一点似乎很复杂。

2)选择crudrepository中的整个对象,然后在控制器中创建json:

代码语言:javascript
运行
复制
Order findByName(String name);

在控制器中,假设我的方法有一个返回类型ResponseEntity>,我将创建一个HashMap并返回它。

代码语言:javascript
运行
复制
Order order = orderRepository.findByName("John Doe");
HashMap<String, String> jsonResult = new HashMap<>();
jsonResult.put("order_date", order.getName());
jsonResult.put("product_id", order.getProductId());
return jsonResult;

这样做的好处是,我可以对从数据库中获得的order对象进行计算。我不必使用丑陋的sql查询,并且可以利用我的ORM系统的优点。最大的缺点是,我总是必须在每个控制器方法的末尾创建这个自定义的json,这感觉是错误的。

3)使用JPA投影。我没有尝试过,但我读到过(https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections)

做这个相当标准的动作的专业方法是什么?在更大的企业应用程序中是如何实现的?大型企业应用程序是否使用jpa crudrepository或如何在java中与数据库进行交互?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-10 23:21:37

假设您有一个“标准”项目结构:控制器、服务、存储库和域模型-为简洁起见,省略了import

控制器

代码语言:javascript
运行
复制
@Controller
@RequestMapping("/entities")
public final class TheController {
  private static final Logger log = LoggerFactory.getLogger(TheController.class);

  private final TheService service;

  public TheController(final TheService service) {
    this.service = service;
  }

  @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<Collection<JpaEntity>> getAll(final HttpServletRequest request) {
    log.info("{} {}", request.getMethod(), request.getRequestURI());
    return ResponseEntity.ok(service.searchAll());
  }

  @GetMapping(path = "{entity-id}", produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<?> getById(final @PathVariable("entity-id") String id, final HttpServletRequest request) {
    log.info("{} {}", request.getMethod(), request.getRequestURI());
    final Optional<JpaEntity> result = service.searchById(UUID.fromString(id));
    if (result.isPresent()) {
      return ResponseEntity.ok(result.get());
    }
    return ResponseEntity.notFound().build();
  }

  @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<?> post(@RequestBody @Valid final JpaEntity body, final HttpServletRequest request) {
    log.info("{} {}", request.getMethod(), request.getRequestURI());
    final URI uri = URI.create(String.format("%s/%s", request.getRequestURI(), service.save(body).getId())).normalize();
    return ResponseEntity.created(uri).build();
  }
}

服务

代码语言:javascript
运行
复制
@Service
@Transactional
public class TheService {
  private static final Logger log = LoggerFactory.getLogger(TheService.class);

  private TheRepository repository;

  public TheService(final TheRepository repository) {
    this.repository = repository;
  }

  @Transactional(readOnly = true)
  public Collection<JpaEntity> searchAll() {
    log.info("Retrieving all records...");
    return repository.findAll();
  }

  @Transactional(readOnly = true)
  public Optional<JpaEntity> searchById(final UUID id) {
    log.info("Retrieving record with ID [{}]", id);
    return repository.findById(id);
  }

  public JpaEntity save(final JpaEntity entity) {
    log.info("Persisting record [{}]", entity);
    return repository.save(entity);
  }
}

存储库

代码语言:javascript
运行
复制
public interface TheRepository extends JpaRepository<JpaEntity, UUID> { }

域模型

代码语言:javascript
运行
复制
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
abstract class AbstractPersistable<T> implements Serializable {
  private static final long serialVersionUID = -537959523291969928L;

  @Id
  @JsonProperty("_id")
  @GeneratedValue(generator = "uuid2")
  @GenericGenerator(name = "uuid2", strategy = "uuid2")
  @Column(name = "id", nullable = false, updatable = false, unique = true)
  private T id;

  @CreatedDate
  @Column(name = "created_on", nullable = false, updatable = false)
  private Instant createdOn;

  @CreatedBy
  @Column(name = "created_by", nullable = false)
  private String createdBy;

  @LastModifiedDate
  @Column(name = "modified_on", nullable = false)
  private Instant modifiedOn;

  @LastModifiedBy
  @Column(name = "modified_by", nullable = false)
  private String modifiedBy;

  @Version
  @JsonProperty("_version")
  private Integer version;

  AbstractPersistable() { } // No-args constructor required by JPA spec

  public T getId() { return id; }

  public Instant getCreatedOn() { return createdOn; }

  public String getCreatedBy() { return createdBy; }

  public Instant getModifiedOn() { return modifiedOn; }

  public String getModifiedBy() { return modifiedBy; }

  public Integer getVersion() { return version; }

  @Override
  public String toString() {
    return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
        .append("id", id)
        .append("createdOn", createdOn)
        .append("createdBy", createdBy)
        .append("modifiedOn", modifiedOn)
        .append("modifiedBy", modifiedBy)
        .append("version", version)
        .toString();
  }
}
代码语言:javascript
运行
复制
@Entity
@Immutable
@Table(name = "tb_name")
public final class JpaEntity extends AbstractPersistable<UUID> {
  private static final long serialVersionUID = -1352464759104643303L;

  @Column(name = "column1", length = 128, nullable = false)
  private String one;

  @Column(name = "column2", length = 128, nullable = false)
  private String two;

  private JpaEntity() { } // No-args constructor required by JPA spec

  public JpaEntity(final String one, final String two) {
    this.one = one;
    this.two = two;
  }

  public String getOne() { return one; }

  public String getTwo() { return two; }

  @Override
  public int hashCode() {
    return Objects.hash(one, two);
  }

  @Override
  public boolean equals(final Object obj) {
    if (this == obj) { return true; }
    if (!(obj instanceof JpaEntity)) { return false; }
    final JpaEntity entity = (JpaEntity) obj;
    return Objects.equals(one, entity.one) &&
        Objects.equals(two, entity.two);
  }

  @Override
  public String toString() {
    return new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE)
        .appendSuper(super.toString())
        .append("one", one)
        .append("two", two)
        .toString();
  }
}

在向用户代理发送响应时,Spring Boot将为JpaEntity生成适当的JSON表示。

如果您希望控制哪些字段被序列化,则可以利用@JsonView注释在序列化/反序列化发生时包括/排除一组成员/字段,例如:

代码语言:javascript
运行
复制
// CustomView.java
public interface CustomView { }

// JpaEntity.java
@JsonView(CustomView.class)
@Column(name = "column1", length = 128, nullable = false)
private String one;

// TheController.java
// When CustomView is used you are only going to get back what's annotated
// with CustomView in the given response type (JpaEntity on this case)
@JsonView(CustomView.class)
@GetMapping(path = "{entity-id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> getById(final @PathVariable("entity-id") String id, final HttpServletRequest request) {
  log.info("{} {}", request.getMethod(), request.getRequestURI());
  final Optional<JpaEntity> result = service.searchById(UUID.fromString(id));
  if (result.isPresent()) {
    return ResponseEntity.ok(result.get());
  }
  return ResponseEntity.notFound().build();
}

或者,您可以使用另一种返回类型,例如:JpaEntityResponse

代码语言:javascript
运行
复制
public final class JpaEntityResponse {
  private String one;

  private String three;

  private String andFour;

  private JpaEntityResponse() { } // No-args constructor required by JPA spec

  public JpaEntityResponse(final String one, final String two, final String andFour) {
    this.one = one;
    this.three = three;
    this.andFour = andFour;
  }

  // ...getters
}

然后,在“服务”类中的某个地方,假设您正在处理两个不同的域模型,并希望将一些字段聚合到JpaEntityResponse中,那么您只需要从中挑选感兴趣的成员/字段,构建JpaEntityResponse并返回它(同时还需要修改控制器的方法以返回此类型)。

票数 0
EN

Stack Overflow用户

发布于 2019-12-10 05:57:10

您首先需要一个可以映射到您的表的实体,以及该实体的crud/JPA存储库。您可以查询存储库(在控制器中),并控制API要发回的字段(映射到表的列)。

下面是一个示例(您需要包含spring web依赖项才能启用自动Jackson配置)。在@JsonIgnore注释中,忽略JSON响应字段。但它将在java对象中可用。

代码语言:javascript
运行
复制
@Entity
public class Order {

    @Column(name = "product_id")
    protected Long productId;

    @Column(name = "order_date")
    protected Date orderDate;

    @JsonIgnore
    @Column(name = "order_number")
    protected Date orderNumber;

    //setters and getters

}

@Transactional
public interface OrderRepo extends JpaRepository<Order, Long>{
}

@Controller
public class OrderController
{

  public OrderController(){}

  @Autowired
  OrderRepo orderRepo;

  @GetMapping(/orders/{id})
  public Order findOrder(@PathVariable("id")long id)
  {
   return orderRepo.findById(id);
  }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59256232

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档