【问题标题】:Spring Boot REST API - Type mismatch on field IDSpring Boot REST API - 字段 ID 的类型不匹配
【发布时间】:2021-11-17 11:07:44
【问题描述】:

我是使用 Kotlin 的 Spring Boot 的新手,我正在尝试在后台使用 MySQL 数据库实现一个简单的 REST API。我首先创建了一个带有“TestEntityRepository”、“TestEntityResource”和“TestEntityService”的“TestEntity”类。到目前为止一切正常。我能够通过 REST API 发布和获取数据。

之后,我创建了另一个实体“用户”,我想为它做与我的 TestEntity 相同的操作。我创建了包含更多字段的类,然后是 Repository、Resource 和 Service 类。现在,当我尝试向我的 UserResource REST 端点发布一个新条目时,我收到一个 400 Bad Request 错误,并显示以下消息:

字段“id”上的对象“用户”中的字段错误:拒绝值 [null];代码 [typeMismatch.user.id,typeMismatch.id,typeMismatch.long,typeMismatch];参数 [org.springframework.context.support.DefaultMessageSourceResolvable: 代码 [user.id,id];论据 [];默认消息 [id]];默认消息 [无法将“null”类型的值转换为所需的“long”类型;嵌套异常是 org.springframework.core.convert.ConversionFailedException: 无法从类型 [null] 转换为类型 [@javax.persistence.Id @javax.persistence.GeneratedValue long] 的值'null';嵌套异常是 java.lang.IllegalArgumentException: A null value cannot be assigned to an original type]]

我的用户类如下所示:

@Entity
class User(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    val id: Long,

    @Column(name = "login_id", unique = true, nullable = false)
    val loginId: String,

    @Column(name = "display_name")
    val displayName: String,

    @CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_date")
    val createdDate: Date,

    @UpdateTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "modify_date")
    val modifyDate: Date
)

存储库类如下所示:

@Repository
interface UserRepository: JpaRepository<User, Long>

这样的服务类:

@Service
class UserService(val repo: UserRepository) {

    fun findAll(): List<User> = repo.findAll()

    fun findById(userId: Long): User = repo.findById(userId)
        .orElseThrow { ResponseStatusException(HttpStatus.NOT_FOUND, "No user was found with this ID.") }

    fun post(user: User) {
        repo.save(user)
    }

    fun delete(user: User) {
        repo.delete(user)
    }
}

最后我的资源类(RestController)是这样的:

@RestController
class UserResource(val service: UserService) {

    @GetMapping("/user")
    fun get(): List<User> = service.findAll()

    @GetMapping("/user/{id}")
    fun get(@PathVariable(name = "id") id: Long): User = service.findById(id)

    @PostMapping("/user")
    fun post(user: User) {
        service.post(user)
    }

    @DeleteMapping("/user")
    fun delete(user: User) = service.delete(user)
}

有人可能知道出了什么问题吗?我只是发送一个包含“loginId”和“displayName”字段的 JSON 对象的 HTTP POST。 “id”字段应该自动填写,但它不起作用。此外,当我在我的 JSON 中添加一个名为“id”的字段时,请求将不会被接受。

谢谢!

【问题讨论】:

    标签: spring spring-boot rest kotlin


    【解决方案1】:
    1. 确保auto_increement 设置为表格中的id 列。
    2. 使用自动生成策略作为GenerationType.IDENTITY

    【讨论】:

    • 如何为我的表设置 auto_increment? Spring Framework 确实会自动创建它,所以我没有做任何事情来创建数据库。我只将连接参数写入了我的应用程序属性文件。
    • 然后尝试使用生成策略作为 GenerationType.SEQUENCE。我想这应该可行。
    • 很遗憾没有。我尝试了所有类型的 GenerationType。错误仍然发生...
    • 不确定这是否有效。创建单独的类 UserDTO。添加除 Id 字段外的所有字段,不添加任何注释。现在使用这个类来接受请求。然后通过单独设置用户字段手动将其转换为用户类。然后将用户对象传递给服务方法。并确保重新运行您的项目。
    【解决方案2】:

    好的,我找到了修复它的方法,但我不确定它是否是最好的方法。

    在我的实体类中,我必须将 createdDate 和 modifyDate 字段声明为可为空:

    @Entity
    class User(
        @Id
        @GeneratedValue
        var id: Long,
    
        @Column(name = "login_id", unique = true, nullable = false)
        var loginId: String,
    
        @GeneratedValue(generator = APITokenGenerator.GENERATOR_NAME)
        @GenericGenerator(name = APITokenGenerator.GENERATOR_NAME, strategy = "my.package.name.APITokenGenerator")
        @Column(name = "api_token")
        var apiToken: String? = null,
    
        @Column(name = "display_name")
        var displayName: String,
    
        @CreationTimestamp
        @Temporal(TemporalType.TIMESTAMP)
        @Column(name = "created_date")
        var createdDate: Date? = null,
    
        @UpdateTimestamp
        @Temporal(TemporalType.TIMESTAMP)
        @Column(name = "modify_date")
        var modifyDate: Date? = null
    )
    

    但我认为最重要的是将@RequestBody 注解添加到处理传入请求的 RestController 类中:

    @RestController
    @RequestMapping("/api/user")
    class UserResource(val service: UserService) {
    
        @GetMapping()
        fun get(): List<User> = service.findAll()
    
        @GetMapping("/{id}")
        fun get(@PathVariable(name = "id") id: Long): User = service.findById(id)
    
        @PostMapping()
        fun post(@RequestBody user: User) {
            service.post(user)
        }
    
        @DeleteMapping("")
        fun delete(@RequestBody user: User) = service.delete(user)
    }
    

    如果这是正确的解决方案或者有什么不正确的地方,如果有人能回答我,那就太好了:-)

    【讨论】:

      猜你喜欢
      • 2011-04-07
      • 2021-12-21
      • 2020-01-16
      • 2017-03-04
      • 2022-10-24
      • 2020-11-15
      • 2021-11-26
      • 1970-01-01
      • 2015-06-06
      相关资源
      最近更新 更多