如果您升级到 Spring Boot 3,Spring Hateoas 似乎不提供对 HAL-FORMS 中模板可供性属性验证的支持。似乎 Spring Boot 正在迁移到更新版本的休眠和 jakarta 验证 api,而 Spring Hateoas PropertyUtils 没有尚不支持。它的主要分支仍然导入javax.validation.constraints.NotNull,并且它的hibernate版本与Spring boot 3冲突。
这是一个只有 1 个文件(& pom)的非常简单的示例,它演示了它适用于 Spring boot 2.7.6(请参阅我们稍后将使用的注释掉的 spring-boot-starter-parent 版本。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
<!-- <version>3.0.5</version> -->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-hateoas-affordance-sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-hateoas-affordance-sample</name>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.example.demo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
import org.hibernate.validator.constraints.Length;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.hateoas.RepresentationModel;
import org.springframework.hateoas.config.EnableHypermediaSupport;
import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotNull;
//import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Value;
@SpringBootApplication
@EnableHypermediaSupport(type = HypermediaType.HAL_FORMS)
public class SpringHateoasAffordanceSampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringHateoasAffordanceSampleApplication.class, args);
}
@RestController
class FooController {
private static final String TEMPLATE = "Hello, %s!";
@GetMapping("/")
public HttpEntity<FooRepresentation> get(
@RequestParam(value = "name", defaultValue = "foo") String name) {
var controller = methodOn(FooController.class);
return new ResponseEntity<>(
new FooRepresentation(String.format(TEMPLATE, name))
.add(linkTo(controller.get(name)).withSelfRel())
.add(linkTo(controller.post(new FooModel("foo"))).withRel("foo"))
, HttpStatus.OK);
}
@PostMapping("/foo")
public HttpEntity<FooModel> post(@RequestBody FooModel fooModel) {
return new ResponseEntity<>(fooModel, HttpStatus.OK);
}
}
@Value
@EqualsAndHashCode(callSuper=false)
class FooRepresentation extends RepresentationModel<FooRepresentation> {
private final String name;
}
@Data
@AllArgsConstructor
public class FooModel {
@NotNull
@Length(min = 2, max = 10)
private String name;
}
}
如果我运行上面的命令并将我的浏览器指向 http://localhost:8080,我会得到 'required=true' 以及我期望的 FooModel.name 属性的最小长度和最大长度。我不得不调整网址,因为堆栈溢出认为它们是垃圾邮件
{
"name": "Hello, foo!",
"_links": {
"self": {
"href": "/?name=foo"
},
"foo": {
"href": "/foo"
}
},
"_templates": {
"default": {
"method": "POST",
"properties": [
{
"name": "name",
"required": true,
"minLength": 2,
"maxLength": 10,
"type": "text"
}
],
"target": "/foo"
}
}
}
但是如果我升级到 Spring 3.0.5(请参阅 pom 中的注释行)我必须将导入更改为 jakarta.validation.constraints.NotNull 而不是 javax.validation.constraints.NotNull 但是当我重复我的测试时我得到缺少注释驱动提示的响应。
{
"name": "Hello, foo!",
"_links": {
"self": {
"href": "/?name=foo"
},
"foo": {
"href": "/foo"
}
},
"_templates": {
"default": {
"method": "POST",
"properties": [
{
"name": "name",
"type": "text"
}
],
"target": "/foo"
}
}
}
虽然它不是很明显来自休眠的@Length(导入包没有改变)我怀疑版本冲突也是原因。
是否有一些我可以用来变通的配置,或者是否计划在 spring boot 3 中支持它?