问题描述
我遵循 Spring on Building REST 教程使用 HATEOAS:https://spring.io/guides/tutorials/rest/ 并将其与 JPA 和 MySQL DB (Maven) 混合。当我运行该应用程序时,我可以很好地看到 MySQL 工作台中最初的 2 个表(尽管有第三个突然出现?)。如果我执行 GET /players,它工作正常。当我在 Postman 中执行 POST 请求 (http://localhost:8080/players) 并将正文作为 JSON: { "playerName":"Pedro" }
时,我收到 500 状态,并且收到来自 Spring 的错误
没有足够的变量值可用于扩展 'id'] 的根本原因...
我想实现完整的 CRUD 操作。鉴于 playerId 是自动递增的,并且参数 registrariondate 是一个 TIMESTAMP,这里出现了很多疑问。这是次要的,因为我想这个问题来源于利用RepresentationModelAssembler在我的应用程序,但并不完全知道如何处理的响应和请愿。
这里是项目结构:
错误日志:
Hibernate:
insert
into
player
(player_name,registration_date)
values
(?,?)
2021-04-02 11:20:03.781 ERROR 2312 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: java.lang.IllegalArgumentException: Not enough variable values available to expand 'id'] with root cause
java.lang.IllegalArgumentException: Not enough variable values available to expand 'id'
at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:370) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:263) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.util.HierarchicalUriComponents$FullPathComponent.expand(HierarchicalUriComponents.java:917) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:434) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.util.HierarchicalUriComponents.expandInternal(HierarchicalUriComponents.java:52) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.util.UriComponents.expand(UriComponents.java:172) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.util.DefaultUriBuilderFactory$DefaultUriBuilder.build(DefaultUriBuilderFactory.java:403) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.hateoas.UriTemplate.expand(UriTemplate.java:272) ~[spring-hateoas-1.2.5.jar:1.2.5]
at org.springframework.hateoas.Link.expand(Link.java:361) ~[spring-hateoas-1.2.5.jar:1.2.5]
at org.springframework.hateoas.Link.toUri(Link.java:434) ~[spring-hateoas-1.2.5.jar:1.2.5]
at RESTApiJWTAuthMySQL.controllers.PlayerController.createNewPlayer(PlayerController.java:66) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.5.jar:5.3.5]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.5.jar:5.3.5]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.5.jar:5.3.5]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.5.jar:5.3.5]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060) ~[spring-webmvc-5.3.5.jar:5.3.5]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962) ~[spring-webmvc-5.3.5.jar:5.3.5]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.5.jar:5.3.5]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.5.jar:5.3.5]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652) ~[tomcat-embed-core-9.0.44.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.5.jar:5.3.5]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.44.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.44.jar:9.0.44]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.5.jar:5.3.5]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.5.jar:5.3.5]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.5.jar:5.3.5]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.3.5.jar:5.3.5]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630) ~[na:na]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
at java.base/java.lang.Thread.run(Thread.java:832) ~[na:na]
控制器类:
@RestController
//@RequestMapping("/")
public class PlayerController {
@Autowired
private final PlayerRepository repository;
@Autowired
private final PlayerModelAssembler assembler;
PlayerController(PlayerRepository repository,PlayerModelAssembler assembler) {
this.repository = repository;
this.assembler = assembler;
}
@GetMapping("/players/")
public CollectionModel<EntityModel<Player>> all() {
List<EntityModel<Player>> players = repository.findAll().stream().map
(assembler::toModel).collect(Collectors.toList());
return CollectionModel.of(players,linkTo(methodOn(PlayerController.class).all()).withSelfRel());
}
@GetMapping("/players/{id}")
public EntityModel<Player> one(@PathVariable Long playerId) {
Player player = repository.findById(playerId).orElseThrow(() -> new PlayerNotFoundException(playerId));
return assembler.toModel(player);
}
@PostMapping(path="/players",consumes="application/json")
public ResponseEntity<?> createNewPlayer(@RequestBody Player newPlayer) {
EntityModel<Player> entityModel = assembler.toModel(repository.save(newPlayer));
return ResponseEntity.created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()).body(entityModel);
}
@PutMapping("/players/{id}")
public ResponseEntity<?> replacePlayer(@RequestBody Player newPlayer,@PathVariable Long playerId) {
Player updatedPlayer = repository.findById(playerId) //
.map(player -> {
player.setPlayerName(newPlayer.getPlayerName());
return repository.save(player);
}) //
.orElseGet(() -> {
newPlayer.setPlayerId(playerId);
return repository.save(newPlayer);
});
EntityModel<Player> entityModel = assembler.toModel(updatedPlayer);
return ResponseEntity //
.created(entityModel.getRequiredLink(IanaLinkRelations.SELF).toUri()) //
.body(entityModel);
}
@DeleteMapping("/players/{id}")
public ResponseEntity<?> deleteEmployee(@PathVariable Long playerId) {
repository.deleteById(playerId);
return ResponseEntity.noContent().build();
}
}
PlayerModelAssembler
类:
@Component
public class PlayerModelAssembler implements RepresentationModelAssembler<Player,EntityModel<Player>> {
@Override
public EntityModel<Player> toModel(Player player) {
return EntityModel.of(player,//
linkTo(methodOn(PlayerController.class).one(player.getPlayerId())).withSelfRel(),linkTo(methodOn(PlayerController.class).all()).withRel("players"));
}
}
玩家实体类:
@Entity
@Table(name = "Player")
public class Player {
@Id
@GeneratedValue (strategy = GenerationType.IDENTITY)
private Long playerId;
@Column (name = "player_name")
private String playerName;
@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column (name = "registration_date",updatable = false)
private Date registrationDate;
@OneToMany (mappedBy="player",cascade = CascadeType.ALL,orphanRemoval=true)
private List<DiceRoll> diceRolls = new ArrayList<>();
public Player() {
}
public Player(Long playerId,String playerName,Date registrationDate) {
this.playerId=playerId;
this.playerName = playerName;
this.registrationDate = registrationDate;
}
//getter&setters//
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Player))
return false;
Player player = (Player) o;
return Objects.equals(this.playerId,player.playerId) && Objects.equals(this.playerName,player.playerName)
&& Objects.equals(this.registrationDate,player.registrationDate);
}
@Override
public int hashCode() {
return Objects.hash(this.playerId,this.playerName,this.registrationDate);
}
@Override
public String toString() {
return "Player{" + "id=" + this.playerId + ",name='" + this.playerName + '\'' + ",date of registration='" + this.registrationDate + '\'' + '}';
}
}
POM 文件:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.4.10.Final</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.hateoas</groupId>
<artifactId>spring-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Schema.sql:
USE `dicegame`;
DROP TABLE IF EXISTS `Player`;
CREATE TABLE IF NOT EXISTS `Player`
(
`player_id` BIGINT PRIMARY KEY AUTO_INCREMENT,`player_name` VARCHAR(45) NOT NULL,`registration_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
DROP TABLE IF EXISTS `DiceRoll`;
CREATE TABLE IF NOT EXISTS `DiceRoll`
(
`diceRoll_id` BIGINT PRIMARY KEY AUTO_INCREMENT,`d1` INT(55) NOT NULL,`d2` INT(55) NOT NULL,`result` VARCHAR(45) NOT NULL,`diceRoll_registration` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,`player_id` BIGINT NOT NULL
);
ALTER TABLE DiceRoll
ADD constraint FK_PLAYER_ID FOREIGN KEY (player_id)
REFERENCES Player (player_id);
任何帮助或指导将不胜感激。我在教程中看到他们使用 curl petiton 作为:
$ curl -v -X POST localhost:8080/players -H 'Content-Type:application/json' -d '{"playerName": "Pedro"}'
它应该可以工作。非常感谢。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)