在带有 Spring REST JPA 的自定义 REST 控制器中使用链接资源
Using linked Resources in Custom REST Controller with Spring REST JPA
我正在数据库上开发一组休息资源,并使用 Spring 数据休息公开核心 CRUD 功能以直接与存储库交互。
在我的简化示例中,我有用户:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long id;
public String name;
@OneToMany(mappedBy = "user")
public Collection<Project> projects;
}
和用户自己的项目:
@Entity
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long id;
public String name;
public String oneOfManyComplexDerivedProperties;
@ManyToOne
public User user;
}
直接与存储库交互是可以的,因此对于创建用户(其他其他简单实体)来说,问题在于创建项目。项目有大量基于用户表单输入的服务器派生字段,因此我编写了一个自定义控制器来生成它们并保存结果。
为了保留结果,我需要将项目与其拥有的用户相关联。我希望我的客户能够为此使用用户 Link,就像通过直接转到存储库创建新实体时一样(直接转到存储库才有效):
@RepositoryRestController
public class CustomProjectController {
@Autowired
ProjectRepo projectRepo;
@RequestMapping(value = "/createProject", method = RequestMethod.POST)
public HttpEntity<Project> createProject(@RequestParam User userResource,
@RequestParam String formField1, // actually an uploaded file that gets processed, but i want simple for example purposes
@RequestParam String formfield2)
{
Project project = new Project();
/*
Actually a large amount of complex business logic to derive properties from users form fields, some of these results are binary.
*/
String result = "result";
project.oneOfManyComplexDerivedProperties = result;
project.user = userResource;
projectRepo.save(project);
// aware that this is more complex than I've written.
return ResponseEntity.ok(project);
}
}
当我打电话时:
<a href="http://localhost:9999/api/createProject?userResource=http://localhost:9999/api/users/1&formField1=data1&formField2=Otherdata" rel="nofollow noreferrer">http://localhost:9999/api/createProject?userResource=http://localhost:9999/api/users/1&formField1=data1&formField2=Otherdata</a>
我得到:
{
"timestamp": 1510588643801,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
"message": "Failed to convert value of type 'java.lang.String' to required type 'com.badger.User'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'http://localhost:9999/api/users/1'; nested exception is java.lang.NumberFormatException: For input string: \"http://localhost:9999/api/users/1\"",
"path": "/api/createProject"
}
如果我将 userResource 更改为键入 Resource
,则会出现不同的错误:
"Failed to convert value of type 'java.lang.String' to required type 'org.springframework.hateoas.Resource'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.hateoas.Resource': no matching editors or conversion strategy found"
我在文档中找不到任何关于在自定义控制器中使用存储库 URI 的参考,我找到的最接近的是 Resolving entity URI in custom controller (Spring HATEOAS),但是 API 自那以后已经改变了,我一直无法让它工作。
User userResource 需要的是一个 User 对象,你传入的是一个 String http://localhost:9999/api/users/1
所以我建议您将请求更改为 POST
请求并将您的用户对象作为该请求的主体传递。
请求正文将采用 JSON 格式:
{
id: 1,
name: "myName",
projects: []
}
然后您从 URL 中删除 userResource=http://localhost:9999/api/users/1
。
最后把@RequestParam User userResource
改成@RequestBody User userResource
编辑
由于您的请求中有用户 ID,因此您可以在控制器内进行调用以通过 ID 查找用户。因此,您可以将用户对象从 @RequestParam User userResource
更改为 @RequestParam long userId
,然后在您的方法
中调用以查找类似 findUserById(userId)
的用户
所以你 url 看起来会像 http://localhost:9999/api/createProject?userId=1&formField1=data1&formField2=Otherdata
如果您想坚持使用 url 参数,您可以将 @RequestParam User userResource
更改为 @RequestParam String userId
然后在你的 createProject 代码中有一些类似
的东西
User user = userRepo.findOne(userId);
project.user = user;
....
projectRepo.save(project);
如果是我,我会定义一个你传入的 CreateProjectRequest
对象,例如
{
"userId" : "1",
"formField1" : "whatever",
"formField2" : "whatever"
}
并将您的 createProject 更改为
createProject(@RequestBody CreateProjectRequest createProjectRequest)
...
project.setField1(createProjectRequest.getFormField1());
...
User user = userRepo.findOne(createProjectRequest.getUserId());
project.user = user;
....
projectRepo.save(project);
我建议你真正应该做的是:
http://localhost:9999/api/users/1/projects?formField1=data1&formField2=Otherdata
通过启用 Spring Data 的网络支持,您可以将路径变量自动绑定到实体实例。
@RequestMapping(value = "users/{id}/projects", method = RequestMethod.POST)
public HttpEntity<Project> createProject(
@PathVariable("id") User user,
@RequestParam String formField1,
@RequestParam String formfield2)
{
}
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.web
我正在数据库上开发一组休息资源,并使用 Spring 数据休息公开核心 CRUD 功能以直接与存储库交互。
在我的简化示例中,我有用户:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long id;
public String name;
@OneToMany(mappedBy = "user")
public Collection<Project> projects;
}
和用户自己的项目:
@Entity
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long id;
public String name;
public String oneOfManyComplexDerivedProperties;
@ManyToOne
public User user;
}
直接与存储库交互是可以的,因此对于创建用户(其他其他简单实体)来说,问题在于创建项目。项目有大量基于用户表单输入的服务器派生字段,因此我编写了一个自定义控制器来生成它们并保存结果。 为了保留结果,我需要将项目与其拥有的用户相关联。我希望我的客户能够为此使用用户 Link,就像通过直接转到存储库创建新实体时一样(直接转到存储库才有效):
@RepositoryRestController
public class CustomProjectController {
@Autowired
ProjectRepo projectRepo;
@RequestMapping(value = "/createProject", method = RequestMethod.POST)
public HttpEntity<Project> createProject(@RequestParam User userResource,
@RequestParam String formField1, // actually an uploaded file that gets processed, but i want simple for example purposes
@RequestParam String formfield2)
{
Project project = new Project();
/*
Actually a large amount of complex business logic to derive properties from users form fields, some of these results are binary.
*/
String result = "result";
project.oneOfManyComplexDerivedProperties = result;
project.user = userResource;
projectRepo.save(project);
// aware that this is more complex than I've written.
return ResponseEntity.ok(project);
}
}
当我打电话时:
<a href="http://localhost:9999/api/createProject?userResource=http://localhost:9999/api/users/1&formField1=data1&formField2=Otherdata" rel="nofollow noreferrer">http://localhost:9999/api/createProject?userResource=http://localhost:9999/api/users/1&formField1=data1&formField2=Otherdata</a>
我得到:
{
"timestamp": 1510588643801,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
"message": "Failed to convert value of type 'java.lang.String' to required type 'com.badger.User'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'http://localhost:9999/api/users/1'; nested exception is java.lang.NumberFormatException: For input string: \"http://localhost:9999/api/users/1\"",
"path": "/api/createProject"
}
如果我将 userResource 更改为键入 Resource
,则会出现不同的错误:
"Failed to convert value of type 'java.lang.String' to required type 'org.springframework.hateoas.Resource'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.hateoas.Resource': no matching editors or conversion strategy found"
我在文档中找不到任何关于在自定义控制器中使用存储库 URI 的参考,我找到的最接近的是 Resolving entity URI in custom controller (Spring HATEOAS),但是 API 自那以后已经改变了,我一直无法让它工作。
User userResource 需要的是一个 User 对象,你传入的是一个 String http://localhost:9999/api/users/1
所以我建议您将请求更改为 POST
请求并将您的用户对象作为该请求的主体传递。
请求正文将采用 JSON 格式:
{
id: 1,
name: "myName",
projects: []
}
然后您从 URL 中删除 userResource=http://localhost:9999/api/users/1
。
最后把@RequestParam User userResource
改成@RequestBody User userResource
编辑
由于您的请求中有用户 ID,因此您可以在控制器内进行调用以通过 ID 查找用户。因此,您可以将用户对象从 @RequestParam User userResource
更改为 @RequestParam long userId
,然后在您的方法
findUserById(userId)
的用户
所以你 url 看起来会像 http://localhost:9999/api/createProject?userId=1&formField1=data1&formField2=Otherdata
如果您想坚持使用 url 参数,您可以将 @RequestParam User userResource
更改为 @RequestParam String userId
然后在你的 createProject 代码中有一些类似
的东西User user = userRepo.findOne(userId);
project.user = user;
....
projectRepo.save(project);
如果是我,我会定义一个你传入的 CreateProjectRequest
对象,例如
{
"userId" : "1",
"formField1" : "whatever",
"formField2" : "whatever"
}
并将您的 createProject 更改为
createProject(@RequestBody CreateProjectRequest createProjectRequest)
...
project.setField1(createProjectRequest.getFormField1());
...
User user = userRepo.findOne(createProjectRequest.getUserId());
project.user = user;
....
projectRepo.save(project);
我建议你真正应该做的是:
http://localhost:9999/api/users/1/projects?formField1=data1&formField2=Otherdata
通过启用 Spring Data 的网络支持,您可以将路径变量自动绑定到实体实例。
@RequestMapping(value = "users/{id}/projects", method = RequestMethod.POST)
public HttpEntity<Project> createProject(
@PathVariable("id") User user,
@RequestParam String formField1,
@RequestParam String formfield2)
{
}
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#core.web