假设您有一个“标准”项目结构:控制器、服务、存储库和域模型 — 为简洁起见,省略了 imports。
控制器
@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
}
然后,在“服务”类的某个地方,假设您正在处理两个不同的域模型并希望将一些字段聚合到JpaEntityResponse,那么您只需要选择您所在的成员/字段有兴趣,构建您的JpaEntityResponse 并将其返回(也需要修改控制器的方法以返回此类型)。