无法为 Spring JPA 从类型 [java.lang.String] 转换为类型 [java.lang.Long]?

Failed to convert from type [java.lang.String] to type [java.lang.Long] for Spring JPA?

我在 Spring JPA 中实现两个以国家和州命名的实体时遇到问题。

我写了一个代码来构成如下所示的国家和州实体。

国家实体

@Entity
@Table(name="COUNTRY",catalog ="SPRINGANGULAR")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"id","code","countryName"}, exclude = "states")
public class Country {

    @Id
    @SequenceGenerator(name="COUNTRY_SEQ", sequenceName="COUNTRY_SEQ", allocationSize=1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="COUNTRY_SEQ")
    @Column(name="ID", nullable = false)
    private long id;
    
    @Column(name="CODE")
    private String code;
    
    @Column(name="COUNTRY_NAME")
    private String countryName;
    
    @OneToMany(fetch=FetchType.LAZY,mappedBy="country",
            cascade= CascadeType.ALL)
    private Set<State> states = new HashSet<State>();

    public Country(String code, String countryName) {
        super();
        this.code = code;
        this.countryName = countryName;
    }
    
}

国家实体

@Entity
@Table(name="STATE",catalog ="SPRINGANGULAR")
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = {"id", "stateName"})
public class State {

    @Id
    @SequenceGenerator(name="STATE_SEQ", sequenceName="STATE_SEQ", allocationSize=1)
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="STATE_SEQ")
    @Column(name="ID", nullable = false)
    private long id;
    
    @Column(name="STATE_NAME")
    private String stateName;
    
    @ManyToOne(fetch=FetchType.LAZY,cascade= CascadeType.ALL)
    @JoinColumn(name = "COUNTRY_ID", nullable = false)
    private Country country;

    public State(String stateName, Country country) {
        super();
        this.stateName = stateName;
        this.country = country;
    }
    
}

然后我创建一个 State Reporistory 以按国家/地区代码获取州。

@CrossOrigin("http://localhost:4200")
@RepositoryRestResource(collectionResourceRel = "states", path = "states")
public interface StateRepository extends JpaRepository<State, Long>{

    @Query("SELECT s FROM State s \n" + 
           "LEFT JOIN Country c ON c.id = c.id \n" + 
           "WHERE c.code = :code \n" + 
           "ORDER BY s.id ASC")
    List<State> findByCountryCode(@RequestParam("code") String code);
}

然后我在Postman中写了一个连接url来检查它是否有效。

http://localhost:8080/api/states/findByCountryCode?code=BR

它抛出一个错误

Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'findByCountryCode'; nested exception is java.lang.NumberFormatException: For input string: "findByCountryCode"

我该如何解决这个问题?

您的查询混合了原生 SQL 和 JPQL,绝对无效。这是有效的:

@Query("SELECT s FROM State s \n" + 
           "WHERE s.country.code = :code \n" + 
           "ORDER BY s.id ASC")

不需要显式左连接,由s.country表达式完成。

此外,JPQL 中没有 LEFT JOIN ON 这样的东西。 Here 是一些连接示例

另外,URL 应该是这样的:

http://localhost:8080/states/search/findByCountryCode?code=BR

您缺少 search 作为路径元素。

在我看来 REST 控制器
有问题 我假设你在某处有 /api/states/{id} 的映射,如下所示:

@RestController
@RequestMapping(path = "api/states/")
public class StateController {

    @GetMapping("/{id}")
    public State getState(@PathVariable("id") long id) {
       ...
    }
}

当您调用 /api/states/findByCountryCode?code=BR 时,它会将 findByCountryCode 解释为 long 类型的路径变量 id,这将导致此异常:

NumberFormatException: For input string: "findByCountryCode"

解法:

  • 使用正则表达式模式(数字)限制 id 路径参数,或者
  • 使用不同的路径查询状态(例如/api/states?code=BR

后一种模式是列出和查找资源的通用标准:

  • 无查询参数:列出所有
  • 使用查询参数:列表匹配 -> 查找功能

所以像这样:

    @GetMapping("/")
    public List<State> find(@RequestParam(value = "code", required = false) String code) {
       if (code != null) {
           // find by code
       } 
       else {
           // list all
       }
    }

解决方法如下图

我用错了urlhttp://localhost:8080/api/states/findByCountryCode?code=BR

转换url

http://localhost:8080/api/states/findByCountryCode?code=BR`

http://localhost:8080/api/states?code=BR