使用REST API开发Spring简易市场应用,现有实体后续该如何推进?
开发推进步骤
第一步:修正现有实体类的错误
你当前写的实体类有几处影响功能的映射问题,先修改:
- User类的
@OneToMany映射错误,mappedBy要指向Item类中关联User的属性user,而非id,同时给account设置默认初始值0(你需求里的account自动递增大概率是笔误,id已经配置了自增,账户余额初始默认0即可,如有特殊自增需求再给account加@GeneratedValue) - Item类删除冗余的
ownerUsername持久化字段,该字段不需要存库,用户修改用户名时会出现数据不一致,直接通过关联的User对象动态返回即可,新增getOwnerId()方法适配接口返回的ownerId字段
修正后的核心代码示例:
// User类修正后的items关联 @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) public Set<Item> getItems() { return items; } // Item类新增方法 public Long getOwnerId() { return user.getId(); } // 删除ownerUsername的set方法,get方法保留动态取值即可
第二步:新增合约实体类Contract
按照需求定义合约字段,继承BaseEntity:
@Entity @Table(name = "contracts") public class Contract extends BaseEntity { private Long sellerId; private Long buyerId; private Long itemId; private Long price; private Boolean active; public Contract() {} @Column(nullable = false) public Long getSellerId() { return sellerId; } public void setSellerId(Long sellerId) { this.sellerId = sellerId; } public Long getBuyerId() { return buyerId; } public void setBuyerId(Long buyerId) { this.buyerId = buyerId; } @Column(nullable = false) public Long getItemId() { return itemId; } public void setItemId(Long itemId) { this.itemId = itemId; } @Column(nullable = false) public Long getPrice() { return price; } public void setPrice(Long price) { this.price = price; } @Column(nullable = false) public Boolean getActive() { return active; } public void setActive(Boolean active) { this.active = active; } }
第三步:编写DTO类适配入参出参
不要直接返回实体类给前端,单独定义入参和返回DTO:
- 入参DTO:创建商品DTO、创建合约DTO、更新合约价格DTO、关闭合约DTO
- 返回DTO:商品查询返回DTO、生效合约返回DTO、已关闭合约返回DTO
所有字段和你需求里的交互示例字段一一对应即可。
第四步:编写Repository层接口
三个实体分别对应一个Repository,都继承JpaRepository,同时按需求实现单条查询逻辑:
- ItemRepository:写单条JPQL/原生SQL,关联user表一次查出指定ownerId下所有商品的id、name、ownerId、ownerUsername,避免N+1查询
- ContractRepository:
- 写单条原生SQL查询所有生效中合约,关联user表查sellerUsername
- 写单条动态原生SQL,支持按itemId、sellerId、buyerId可选参数查询已关闭合约,同时关联两次user表分别查sellerUsername和buyerUsername
- 新增根据itemId查询生效中合约的方法,避免同一个商品重复创建售卖合约
第五步:编写Service层业务逻辑
所有业务规则都在Service层实现,加事务控制避免数据不一致:
- ItemService:创建商品前校验ownerId对应的用户存在,按ownerId查询商品直接调用Repository的单条查询方法
- ContractService:
- 创建合约:校验商品存在、操作人是商品所有者、该商品没有正在生效的售卖合约,保存合约时
sellerId取商品的ownerId,active设为true - 更新合约价格:校验合约存在、处于生效状态、操作人是合约卖家再更新价格
- 关闭合约(交易逻辑):校验合约生效、买家不是卖家、买家账户余额≥合约价格,事务内执行4个操作:扣减买家余额、增加卖家余额、修改商品所有者为买家、更新合约
active=false并填入buyerId
- 创建合约:校验商品存在、操作人是商品所有者、该商品没有正在生效的售卖合约,保存合约时
- 所有操作的异常情况都抛出对应的业务异常,方便上层统一处理
第六步:编写Controller层REST接口
按照需求暴露接口:
- 用户相关接口:用户增删改查
- 商品相关接口:创建商品、按ownerId查询商品
- 合约相关接口:创建合约、更新合约价格、查询所有生效中合约、关闭合约、按可选参数查询已关闭合约
入参做参数校验,出参统一封装响应格式。
第七步:配置与测试
- 配置数据库连接(测试可以先用H2内存数据库)、JPA参数(开启SQL打印、自动建表)
- 加全局异常处理器,统一捕获业务异常、参数校验异常返回错误信息
- 用Postman或者curl按照你给出的交互示例逐一测试接口,确认单条查询符合要求、事务正常回滚、业务规则全部满足(比如卖家不能买自己的商品、余额不足无法交易等)
内容的提问来源于stack exchange,提问作者georgik1_
相关产品推荐
相关产品推荐

