SpringBoot开发课程加购接口时Swagger显示字段不符求助
我在实现课程加入购物车功能时,Swagger里显示的请求体不是预期的字段,而是:
{ "additionalProp1": "string", "additionalProp2": "string", "additionalProp3": "string" }以下是相关代码,帮忙排查问题:
CartController
@RestController public class AddToCartController { @Autowired CartService cartService; @PostMapping("/addToCart") public Cart addCartwithCourse(@RequestBody HashMap<String,String> addCartRequest) { try { // String keys[] = {"courseId","userId","qty","price"}; long courseId = Long.parseLong(addCartRequest.get("courseId")); long userId = Long.parseLong(addCartRequest.get("userId")); int qty = Integer.parseInt(addCartRequest.get("qty")); double price = Double.parseDouble(addCartRequest.get("price")); Cart obj = cartService.addCartbyUserIdAndCourseId(courseId,userId,qty,price); return obj; } catch (Exception e) { e.printStackTrace(); return null; } } }
Cart Model
package com.hashedin.hu22.entities; import org.springframework.data.annotation.CreatedDate; import javax.persistence.*; import java.time.Instant; @Entity public class Cart { @Id long id; int qty; double price; Long user_id; @CreatedDate private Instant createdDate; String CourseName; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="cr_fid", referencedColumnName = "id") Course course; public long getId() { return id; } public void setId(long id) { this.id = id; } public int getQty() { return qty; } public void setQty(int qty) { this.qty = qty; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public Long getUser_id() { return user_id; } public void setUser_id(Long user_id) { this.user_id = user_id; } public Instant getCreatedDate() { return createdDate; } public void setCreatedDate(Instant createdDate) { this.createdDate = createdDate; } public String getCourseName() { return CourseName; } public void setCourseName(String courseName) { CourseName = courseName; } public Course getCourse() { return course; } public void setCourse(Course course) { this.course = course; } }
AddToCartRepo
public interface AddToCartRepo extends JpaRepository<Cart, Long> { @Query("Select addCart FROM Cart addCart WHERE addCart.course.id= :course_id and addCart.user_id=:user_id") Optional<Cart> getCartByProductIdAnduserId(@Param("user_id")Long user_id, @Param("course_id")Long course_id); @Query("Select addCart FROM Cart addCart WHERE addCart.user_id=:user_id") List<Cart> getCartByuserId(@Param("user_id")Long user_id); }
CartService
@Service public class CartServiceImpl implements CartService { @Autowired AddToCartRepo addToCartRepo; @Autowired CourseSerivce courseSerivce; @Override public Cart addCartbyUserIdAndCourseId(long courseId, long userId, int qty, double price) throws Exception { try { if (addToCartRepo.getCartByProductIdAnduserId(userId, courseId).isPresent()) { throw new Exception("Product is Already Exist"); } Cart obj = new Cart(); obj.setQty(qty); obj.setUser_id(userId); Course course = courseSerivce.getCourseById(courseId); obj.setCourse(course); obj.setPrice(price); return addToCartRepo.save(obj); } catch(Exception e) { e.printStackTrace(); } return null; } @Override public List<Cart> getCartByUserId(long userId){ return addToCartRepo.getCartByuserId(userId); } }
问题根源
你在Controller的addCartwithCourse方法里用了HashMap<String,String>作为@RequestBody的参数类型。Swagger(以及Spring Doc/OpenAPI)无法识别HashMap的具体键值结构,只能默认显示通用的"additionalProp"占位符,这就是你看到的非预期内容。同时,手动解析HashMap的参数还容易出现类型转换错误、空指针问题,代码可读性也差。
修复步骤
1. 创建专用的请求DTO类
代替HashMap,定义一个明确的请求数据传输对象(DTO),让Swagger能识别具体字段:
import javax.validation.constraints.NotNull; public class AddCartRequestDTO { @NotNull(message = "课程ID不能为空") private Long courseId; @NotNull(message = "用户ID不能为空") private Long userId; @NotNull(message = "数量不能为空") private Integer qty; @NotNull(message = "价格不能为空") private Double price; // Getter和Setter方法 public Long getCourseId() { return courseId; } public void setCourseId(Long courseId) { this.courseId = courseId; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } public Integer getQty() { return qty; } public void setQty(Integer qty) { this.qty = qty; } public Double getPrice() { return price; } public void setPrice(Double price) { this.price = price; } }
2. 修改CartController的方法
把HashMap替换成刚才创建的DTO类,同时简化参数解析逻辑:
@RestController public class AddToCartController { @Autowired CartService cartService; @PostMapping("/addToCart") public ResponseEntity<Cart> addCartwithCourse(@Valid @RequestBody AddCartRequestDTO addCartRequest) { try { Cart obj = cartService.addCartbyUserIdAndCourseId( addCartRequest.getCourseId(), addCartRequest.getUserId(), addCartRequest.getQty(), addCartRequest.getPrice() ); return ResponseEntity.ok(obj); } catch (Exception e) { // 这里可以返回自定义错误响应,而不是打印堆栈后返回null return ResponseEntity.badRequest().body(null); } } }
注:这里用到了
@Valid注解来开启参数校验,需要确保你的项目里引入了spring-boot-starter-validation依赖。
3. 优化Cart实体的小问题
你的Cart实体里的@CreatedDate注解不会自动生效,需要在主启动类上添加@EnableJpaAuditing注解,同时给该字段加上@EntityListeners和@Column(updatable = false):
@Entity @EntityListeners(AuditingEntityListener.class) public class Cart { // ... 其他字段 ... @CreatedDate @Column(updatable = false) private Instant createdDate; // ... 其他Getter/Setter ... }
然后在主启动类添加:
@SpringBootApplication @EnableJpaAuditing public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
4. 优化Service层的异常处理
目前Service里的try-catch会捕获异常后打印堆栈再返回null,建议直接向上抛出异常,让Controller统一处理:
@Service public class CartServiceImpl implements CartService { @Autowired AddToCartRepo addToCartRepo; @Autowired CourseSerivce courseSerivce; @Override public Cart addCartbyUserIdAndCourseId(long courseId, long userId, int qty, double price) throws Exception { if (addToCartRepo.getCartByProductIdAnduserId(userId, courseId).isPresent()) { throw new Exception("商品已存在于购物车"); } Cart obj = new Cart(); obj.setQty(qty); obj.setUser_id(userId); Course course = courseSerivce.getCourseById(courseId); obj.setCourse(course); obj.setPrice(price); return addToCartRepo.save(obj); } @Override public List<Cart> getCartByUserId(long userId){ return addToCartRepo.getCartByuserId(userId); } }
修复后效果
修改完成后,Swagger会自动识别AddCartRequestDTO里的所有字段,显示出courseId、userId、qty、price这些你预期的请求参数,同时参数校验和代码可读性也会提升。
内容的提问来源于stack exchange,提问作者Nitin Saini

