gpt4 book ai didi

java - Spring Boot中json转换的正确方式和位置

转载 作者:行者123 更新时间:2023-12-01 19:31:35 25 4
gpt4 key购买 nike

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

假设订单包含 ID、日期、客户名称、产品 ID。在此示例中,当要求输入特定名称时,我只需要前端的日期作为 order_date,产品 ID 作为 Product_id。

可能的方法:

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

@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);

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

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

Order findByName(String name);

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

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;

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

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

做这个相当标准的 Action 的专业方法是什么?在更大的企业应用程序中是如何完成的?大型企业应用程序是否使用 jpa crudrepository 之类的东西或如何与 java 中的数据库交互?

最佳答案

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

Controller

@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();
}
}

服务

@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);
}
}

存储库

public interface TheRepository extends JpaRepository<JpaEntity, UUID> { }

领域模型

@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();
}
}
@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 注解在序列化/反序列化发生时包含/排除一组成员/字段,例如:

// 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

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
}

然后,在“service”类中的某个位置,假设您正在处理两个不同的域模型,并希望将一些字段聚合到 JpaEntityResponse 中,那么您只需要选择成员/您感兴趣的字段,构建您的 JpaEntityResponse 并将其返回(还需要修改相关 Controller 的方法以返回此类型)。

关于java - Spring Boot中json转换的正确方式和位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59256232/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com