【问题标题】:Java spring boot rest service struggleJava Spring Boot 休息服务之争
【发布时间】:2015-09-21 12:44:35
【问题描述】:

几年后,我回到 Java 尝试使用 Java 实现 RESTful WS。我找到了大量关于使用 Spring 实现它的教程和文章,它是 Maven 之上的 Spring boot 扩展。在设置完所有问题后,我终于有了一个正在运行且可访问的 WS(例如,从 CLI 使用 curl)。

不幸的是,我收到了java.lang.IllegalArgumentException 异常,并带有以下两条消息:

java.lang.IllegalArgumentException: 具有该位置 [1] 的参数不存在

java.lang.IllegalArgumentException:名称为 [cart_id] 的参数不存在

这是我缩短的Entity 课程:

@Entity
@Table(name = "cart", catalog = "table1", schema = "")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Cart.findAll", query = "SELECT c FROM Cart c"),
    @NamedQuery(name = "Cart.findByCartId", query = "SELECT c FROM Cart c WHERE c.cartId = :cartId"),
    @NamedQuery(name = "Cart.findByBarcode", query = "SELECT c FROM Cart c WHERE c.barcode = :barcode"),
    @NamedQuery(name = "Cart.findByCartTypeId", query = "SELECT c FROM Cart c WHERE c.cartTypeId = :cartTypeId"),
    @NamedQuery(name = "Cart.findByCartStyleId", query = "SELECT c FROM Cart c WHERE c.cartStyleId = :cartStyleId"),
    @NamedQuery(name = "Cart.findByCartName", query = "SELECT c FROM Cart c WHERE c.cartName = :cartName"),
    @NamedQuery(name = "Cart.findByNotificationId", query = "SELECT c FROM Cart c WHERE c.notificationId = :notificationId"),
    @NamedQuery(name = "Cart.findByCartContentId", query = "SELECT c FROM Cart c WHERE c.cartContentId = :cartContentId"),
    @NamedQuery(name = "Cart.findByStationId", query = "SELECT c FROM Cart c WHERE c.stationId = :stationId"),
    @NamedQuery(name = "Cart.findByUserId", query = "SELECT c FROM Cart c WHERE c.userId = :userId"),
    @NamedQuery(name = "Cart.findByStatus", query = "SELECT c FROM Cart c WHERE c.status = :status")})
public class Cart implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Basic(optional = false)
    @Column(name = "cart_id")
    private Long cartId;

    @Size(max = 50)
    private String barcode;

    @Column(name = "notification_id")
    private Integer notificationId;

    // other properties, getters and setters follow ...
}

这里是存储库:

@RepositoryRestResource
public interface CartDAO extends CrudRepository<Cart, Long> {

    /**
     * Returns cart by it's ID.
     * @param cartId
     * @return Cart
     */
    public Cart findByCartId(@Param("cart_id") Long cartId);

    /**
     * Returns cart by it's barcode (EAN).
     * @param barcode
     * @return Cart
     */
    public Cart findByBarcode(String barcode);

    /**
     * Returns all the carts belonging to notification (by notification ID).
     * @param notificationId
     * @return List of Carts
     */
    public List<Cart> findByNotificationId(@Param("notification_id") Integer notificationId);

}

这是控制器:

@RestController
@RequestMapping("/carts")
public class CartController {

    @Autowired
    private CartDAO cartDao;

    @RequestMapping(value="/id/{cartId}", method = RequestMethod.GET)
    public Cart getCartById(@PathVariable Long cartId) {
        return cartDao.findByCartId(cartId);
//        return cartDao.findOne(cartId);
    }

    @RequestMapping(value="/ean/{barcode}", method = RequestMethod.GET)
    public Cart getCartByBarcode(@PathVariable String barcode) {
        return cartDao.findByBarcode(barcode);
    }

    @RequestMapping(value="/notification/{notificationId}", method = RequestMethod.GET)
    public List<Cart> getCartByNotification(@PathVariable Integer notificationId) {
        return cartDao.findByNotificationId(notificationId);
    }
}

如果我使用 cmd curl -g localhost:8080/carts/id/1curl -g localhost:8080/carts/notification/1 调用 WS,我会收到第二个 msg 的异常(对于名称 [cart_id][notification_id])。如果我调用 cmd curl -g localhost:8080/carts/ean/2550000017884 我得到了第一个 msg 的异常(对于 position [1])。

数据库表如下所示:

cart
===========================================
cart_id            INT (PK, auto_increment)
notification_id    INT (FK)
barcode            VARCHAR(13) (NOT NULL, UNIQUE)
...

但是,如果我为CartController.getCartById() 中的两行切换注释(即让return cartDao.findOne(cartId); 被调用而不是return cartDao.findByCartId(cartId);),那么我终于可以毫无例外地看到一个有效的响应。

但是我在这里做错了什么?显然我遗漏了一些东西(以及所有的教程)。

PS:我已经使用persistance unit 创建了所有实体 - 我让 PU 连接到我的数据库并为我创建所有实体。过去我喜欢以这种方式工作,因为 PU 可以非常快速地处理两侧的变化并将它们镜像到另一侧。在 PU 的帮助下,我还有很多 @NamedQueries 可能会有所帮助,但由于所有 spring-boot 教程都在使用 JPA 存储库 我不知道如何从 Persistence...

调用那些命名查询

编辑:添加我的 pom.xml 的依赖项部分:

<dependencies>
    <!-- Get the dependencies of a web application -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- DB -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-commons</artifactId>
        <type>jar</type>
    </dependency>
</dependencies>

【问题讨论】:

  • 从查询方法中删除@Param,仅当您使用@Query 时才需要(如参考指南中所述)。此外,您的 findByCartId 与默认的 findOne 相同,因此恕我直言,它毫无用处。
  • @M.Deinum 谢谢,这有助于摆脱 parameter name 异常消息,现在我只得到 Parameter with that position [1] did not exist; 三个方法...
  • 我会首先删除 findByCartId ,这可以将您的问题减少 33% :) (它也没有增加 findOne 方法。你能添加完整的堆栈跟踪,也许你的 pom (至少 pom 的依赖部分)。
  • @M.Deinum 我首先实现了findByCartId,因为我的@IdInteger 类型。然后我发现有本地存储库的方法findById 正在接受Long 所以我在我的实体中将它更改为Long 来尝试一下......如果我发现findByCartId 因为Integer 正在工作,我会把我的@Id 还给Integer...
  • 添加了来自pom.xml 的@M.Deinum 依赖项。

标签: java spring spring-boot


【解决方案1】:

@Param 工作(并且没有给出错误)的事实表明执行了预定义的查询。如果没有查询,@Param 将失败。

Spring Data 使用一种策略来确定默认执行哪个查询,它使用CREATE_IF_NOT_FOUNDlookup strategy。它首先尝试找到一个预定义的查询,这可以是方法上的 @Query 或 JPA 的 @NamedQuery(在后一种情况下,它正在寻找 &lt;entity-name&gt;.&lt;method-name&gt; 命名查询)。如果这些都不适用,它将基于该方法创建一个查询。

在您的情况下,您有一个名为 Cart.findByCartId 的命名查询(同样适用于其他方法)。 Spring Data 检测到这个查询并将执行它。由于您的@Param,它会尝试查找名为cart_id 的参数,但名称实际上是cartId(请参阅命名查询)。

为了解决您的问题 1.修复你方法中的@Param注解指向正确的参数名 2.删除@Param@NamedQuerys 3. 将 Spring Data JPA 切换到 CREATE 查找策略并删除 @Param

【讨论】:

  • 我选择了第一个解决方案。这使我有可能使用查找策略来创建新查询(如果缺少)并使用命名查询以及我在使用 Persistence 时就已经喜欢的。再次感谢您!
猜你喜欢
  • 2021-02-11
  • 2018-12-09
  • 1970-01-01
  • 2016-04-02
  • 2015-04-25
  • 1970-01-01
  • 1970-01-01
  • 2016-09-27
  • 2017-10-27
相关资源
最近更新 更多