简体   繁体   English

Spring boot 3 问题:为什么不能用Postman和Frontend调用API调用API然后得到空数组?

[英]Spring boot 3 Questions: Why it can't to call API with Postman and Frontend call API then get empty array?

I created an API, it's called search stores feature.我创建了一个 API,它被称为搜索商店功能。 . .

MySql Script MySql 脚本

When I Use this SQL Script runs in MySql.当我使用此 SQL 脚本在 MySql 中运行时。 It will show the valid result它将显示有效结果

SET @productName = null;
SET @BranchName = null;
SET @minPrice = 0;
SET @maxPrice = 10000;
SET @quantity = 1000;

SELECT * FROM stores s 
INNER JOIN products p 
ON p.id = s.product_id 
INNER JOIN branches b 
ON b.id = s.branch_id 
WHERE (p.name LIKE CONCAT('%', @productName , '%') OR @productName IS NULL) 
  AND (b.name LIKE  CONCAT('%', @branchName , '%')  OR @branchName IS NULL) 
  AND (@minPrice <= p.price AND p.price <= @maxPrice) 
  AND s.quantity <= @quantity 
ORDER BY p.name, b.name, quantity;

. .

Click image to see the result of MySQL点击图片查看MySQL运行结果

MySQL and valid result image MySQL 和有效的结果图像

Log from StoreService.java and Hibernate从 StoreService.java 和 Hibernate 登录

Click to see Postman before call API调用API前点击查看Postman

When I call it by Frontend it happens the log in StoreService.java is...当我通过前端调用它时, StoreService.java 中的日志是...

productName: null, minPrice: 0.0, maxPrice: 15000.0, branchName: null, 1000
Hibernate: SELECT * FROM stores s INNER JOIN products p ON p.id = s.product_id INNER JOIN branches b ON b.id = s.branch_id WHERE (p.name LIKE CONCAT('%', ? , '%') OR ? IS NULL)  AND (b.name LIKE  CONCAT('%', ? , '%')  OR ? IS NULL)  AND (? <= p.price AND p.price <= ?)  AND s.quantity <= ?  ORDER BY p.name
Stores: []

. .

Error Log when I call API by Postman Postman 调用 API 时的错误日志

Postman Params image邮递员参数图像
When call it by Postman will get当邮递员调用它时会得到

java.lang.StackOverflowError: null
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:944) ~[mysql-connector-java-8.0.19.jar:8.0.19]
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003) ~[mysql-connector-java-8.0.19.jar:8.0.19]
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52) ~[HikariCP-3.4.2.jar:na]
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java) ~[HikariCP-3.4.2.jar:na]
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:390) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:163) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:104) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:707) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:108) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2145) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at com.g_able.back_g_exam.entity.Product.hashCode(Product.java:12) ~[classes/:na]
    at com.g_able.back_g_exam.entity.Store.hashCode(Store.java:13) ~[classes/:na]
    at java.util.HashMap.hash(HashMap.java:339) ~[na:1.8.0_172]
    at java.util.HashMap.put(HashMap.java:612) ~[na:1.8.0_172]
    at java.util.HashSet.add(HashSet.java:220) ~[na:1.8.0_172]
    at java.util.AbstractCollection.addAll(AbstractCollection.java:344) ~[na:1.8.0_172]
    at org.hibernate.collection.internal.PersistentSet.endRead(PersistentSet.java:355) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollection(CollectionLoadContext.java:239) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:224) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.engine.loading.internal.CollectionLoadContext.endLoadingCollections(CollectionLoadContext.java:198) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl.endLoading(CollectionReferenceInitializerImpl.java:154) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishLoadingCollections(AbstractRowReader.java:267) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]
    at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:218) ~[hibernate-core-5.4.10.Final.jar:5.4.10.Final]

. .

My Springboot code:我的 Springboot 代码:

StoreController.java存储控制器.java

@GetMapping("/api/v1/stores/advance-search")
  public List<Store> findStoresByFilter(
      @RequestParam(required = false) String productName, @RequestParam(required = false) String branchName,
      @RequestParam(required = false, defaultValue = "0") Integer minPrice,
      @RequestParam(required = false, defaultValue = "999999") Integer maxPrice,
      @RequestParam(required = false, defaultValue = "3000") Integer quantity) {

    ProductParams productParams = ProductParams.builder().name(productName).minPrice(minPrice).maxPrice(maxPrice).build();
    Branch branch = Branch.builder().name(branchName).build();

    List<Store> stores = storeService.findStoresByFilter(productParams, branch, quantity);
    System.out.println("Stores: " + stores);
    return stores;

}

. .

StoreService.java商店服务.java

public List<Store> findStoresByFilter(ProductParams productParams, Branch branch, int quantity) {
    System.out.println("productName: " + productParams.getName() + ", minPrice: " + productParams.getMinPrice() + ", maxPrice: "
        + productParams.getMaxPrice() + ", branchName: " + branch.getName() + ", " + quantity);
    return storeRepository.searchStoresByFilter(productParams.getName(), branch.getName(),
        productParams.getMinPrice(), productParams.getMaxPrice(), quantity);
}

. .

StoreRepository.java存储库.java

@Query(nativeQuery = true,
      value = "SELECT * " +
          "FROM stores s " +
          "INNER JOIN products p " +
          "ON p.id = s.product_id " +
          "INNER JOIN branches b " +
          "ON b.id = s.branch_id " +
          "WHERE (p.name LIKE CONCAT('%', :productName , '%') OR :productName IS NULL) " +
          " AND (b.name LIKE  CONCAT('%', :branchName , '%')  OR :branchName IS NULL) " +
          " AND (:minPrice <= p.price AND p.price <= :maxPrice) " +
          " AND s.quantity <= :quantity " +
          " ORDER BY p.name")
  List<Store> searchStoresByFilter(@Param("productName") String productName, @Param("branchName") String branchName,
                                 @Param("minPrice") double minPrice, @Param("maxPrice") double maxPrice, @Param("quantity") int quantity);

Notice:注意:

I am being flagged in my POJO classes that they have warnings about @Table and @JoinColumn from javax.persistence package我在我的POJO 类中被标记,他们对javax.persistence包中的@Table@JoinColumn发出警告

Cannot resolve table 'table_name' in @Table and Cannot resolve column 'product_id' Cannot resolve table 'table_name' @Table 中的Cannot resolve table 'table_name'并且Cannot resolve column 'product_id'
Cannot resolve column 'branch_id' in @JoinColumn Cannot resolve column 'branch_id'@JoinColumn

Store.java (Pojo) Store.java (Pojo)

Product.java (Pojo) Product.java (Pojo)

Branch.java (Pojo) Branch.java (Pojo)

I want to know the root causes我想知道根本原因

  1. Why can I not get a valid result when I call API from Frontend?为什么从前端调用 API 时得不到有效结果?
  2. Why can I not call API from Postman?为什么我不能从 Postman 调用 API?
  3. Why Annotation from javax.persistenct cannot resolve table_name and column_name ?为什么来自javax.persistenct 的注解无法解析table_namecolumn_name

Finally I need solutions to fix these problems最后我需要解决这些问题的解决方案

Thanks a lot for all your help非常感谢您的帮助

I am being flagged in my Entity classes that they have warnings about @Table from javax.persistence Cannot resolve table 'table_name' in @Table and Cannot resolve column 'product_id' Cannot resolve column 'branch_id' in @JoinColumn我在我的实体类中被标记,他们有来自 javax.persistence 的关于 @Table 的警告无法解析 @Table 中的表 'table_name' 并且无法解析列 'product_id' 无法解析 @JoinColumn 中的列 'branch_id'

That's the reason hibernate cannot actually map table, you need to fix mapping before anything else, so hibernate knows which table to use.这就是 hibernate 不能真正映射表的原因,你需要先修复映射,所以 hibernate 知道要使用哪个表。 Currently its looking for 'table_name' in sql which is not your store or product table.目前它在 sql 中寻找“table_name”,这不是您的商店或产品表。 We do not know if your mappings are correct as your entity class code is not shared here, but it's likely that annotation or xml file has wrong mapping name from the error itself, ultimately crashing whole request.我们不知道您的映射是否正确,因为您的实体类代码未在此处共享,但注释或 xml 文件可能具有错误本身的错误映射名称,最终导致整个请求崩溃。

Edit: kindly check if these libraries are included in your classpath : hibernate-annotations.jar lib/hibernate-comons-annotations.jar lib/ejb3-persistence.jar编辑:请检查这些库是否包含在您的类路径中:hibernate-annotations.jar lib/hibernate-comons-annotations.jar lib/ejb3-persistence.jar

Also I'd suggest you to use hibernate query language instead of native queries as they are much more extensible when you want to switch underlying database.此外,我建议您使用休眠查询语言而不是本机查询,因为当您想要切换基础数据库时,它们的可扩展性要高得多。

Root cause is, hibernate is database abstraction layer aka DBAL, whole purpose of this library is to build queries on behalf of your code and execute them.根本原因是,hibernate 是数据库抽象层又名 DBAL,该库的全部目的是代表您的代码构建查询并执行它们。 You are trying to use it as native sql wrapper, and sql queries would give result to hibernate but since mapping is wrong it cannot parse and store data in your Entities, while it's useful in some cases, hibernate itself provides much more roburst functionalities such as lazy loading, entity relations to name a few.您正在尝试将其用作本机 sql 包装器,并且 sql 查询会将结果提供给 hibernate,但由于映射错误,因此无法在实体中解析和存储数据,虽然它在某些情况下很有用,但 hibernate 本身提供了更强大的功能,例如延迟加载、实体关系等等。

You can read full documentation here to use such functionalities.您可以在此处阅读完整文档以使用此类功能。 Getting started guide 入门指南

Hibernate Query Language Refrence Hibernate 查询语言参考

I already found how to fixed Postman cannot finish this API and Frontend get an empty array.我已经找到了如何修复 Postman 无法完成此 API 并且前端获得空数组的方法。

I just add @ToString(exclude = "stores") and @EqualsAndHashCode(exclude = "stores") into Entity who have association as Many to Many .我只是将@ToString(exclude = "stores")@EqualsAndHashCode(exclude = "stores")到具有多对多关联的实体中。

The current code in entities are:实体中的当前代码是:

Product.java产品.java

@Data
@ToString(exclude = "stores")
@EqualsAndHashCode(exclude = "stores")
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "products")
@Builder(toBuilder = true)
public class Product {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(nullable = false, length = 50)
  private String name;

  private String detail;

  private double price;

  @JsonIgnore
  @OneToMany(mappedBy = "product")
  private Set<Store> stores;

}

Branch.java分支.java

@Data
@ToString(exclude = "stores")
@EqualsAndHashCode(exclude = "stores")
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "branches")
@Builder(toBuilder = true)
public class Branch {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(nullable = false, length = 60)
  private String name;

  @JsonIgnore
  @OneToMany(mappedBy = "branch")
  private Set<Store> stores;
}

But I don't understand why it errors yet.但我不明白为什么它会出错。 Could you explain it ?你能解释一下吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM