java - 使用 Spring REST 更新一对多关系

标签 java hibernate rest spring-mvc jpa

我的问题是我在实体任务和实体用户(作者)之间有一个双向的 oneToMany 关系。这是在 Spring Boot 项目中使用 Spring Rest 和 Spring Data JPA 实现的。如果我通过 POST-Request 创建用户,它工作正常。如果我创建一个没有作者(用户)实例的任务,情况也是如此。我可以毫无困难地创建它。之后,我尝试通过执行 PUT 使用用户实例更新任务的作者。网络服务的答案是 200 好的。我还在数据库中找到了一个条目,其用户 ID 位于任务表的作者列中。但是,当我执行 GET-Request 来获取所有用户或任务时,一切都不起作用了。 Postman 仅显示诸如 Bad Array 之类的内容。我不知道为什么。如果我删除数据库中的任务,一切都会恢复正常。有谁知道为什么吗? 这里是类(class):

@Entity
@Table(name="User")
public class User {
@Id
@GeneratedValue
@Column(name="USER_ID")
private Long id;

@Column(name="CONFIRMATION")
private boolean confirmed;

@Column(name = "EMAIL",nullable = false)
private String email;

@Column(name = "USERNAME",nullable = false)
@NotNull
private String userName;

@Column(name="PASSWORD",nullable = false)
@NotNull
private String password;

@Column(name="TIMESTAMP")
private Long creationTime;

@OneToMany(cascade=CascadeType.ALL, mappedBy="author",fetch=FetchType.EAGER)
private Set<Task>assignedTasks;

@OneToMany(cascade=CascadeType.ALL, mappedBy="assignee",fetch=FetchType.EAGER) 
private Set<Task>createdTasks;


public User() {
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}



public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

public String getUserName() {
    return userName;
}

public void setUserName(String userName) {
    this.userName = userName;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public Long getCreationTime() {
    return creationTime;
}

public void setCreationTime(Long creationTime) {
    this.creationTime = creationTime;
}

public boolean isConfirmed() {
    return confirmed;
}

public void setConfirmed(boolean confirmed) {
    this.confirmed = confirmed;
}

public Set<Task> getAssignedTasks() {
    return assignedTasks;
}

public void setAssignedTasks(Set<Task> assignedTasks) {
    this.assignedTasks = assignedTasks;
}

public void addAssignedTasks(Task task){
    addAssignedTasks(task,true);
}

void addAssignedTasks(Task task, boolean set){
    if(task != null){
        getAssignedTasks().add(task);
        if(set){
            task.setAssignee(this);
        }
    }
}

public Set<Task> getCreatedTasks() {
    return createdTasks;
}

public void setCreatedTasks(Set<Task> createdTasks) {
    this.createdTasks = createdTasks;
}

public void addCreatedTask(Task task){
    addCreatedTask(task,true);
}

void addCreatedTask(Task task, boolean set){
    if(task != null){
        getCreatedTasks().add(task);
        if(set){
            task.setAuthor(this);
        }
    }
}

public void removeCreatedTask(Task task) {
    getCreatedTasks().remove(task);
    task.setAuthor(null);
}  

}

然后是任务实体:

@Entity
@Table(name="Task")
public class Task {


@Id
@GeneratedValue
@Column(name="TASK_ID")
private Long id;

@Transient
private List<String> possibleTaskTypes = TaskType.getTaskTypesAsString();

@Transient 
private List<String>possibleTaskContainer = TaskContainer.getTaskContainerAsString();

@Column(name="TASK_Container")
private String taskContainer;

@Column(name="TASK_TYPE")
private String taskType;

@Column(name="HEAD_LINE")
private String headLine;

@Column(name="TASK_TEXT")
private String taskText;

@Transient
private List<String> possibleworkFlowStati = WorkFlowStatus.getWorkFlowsStatiAsString();

@Column(name="WORKFLOW_STATUS")
private String status;

@ManyToOne(cascade=CascadeType.ALL)
private User author;

@ManyToOne(cascade=CascadeType.ALL)
private User assignee;

@Column(name="COMMENTS")
@ElementCollection(targetClass=String.class)
private List<String>comments;

@ManyToOne(cascade=CascadeType.ALL)
private Sprint sprint;

@Column(name="TIMESTAMP")
private Long creationTime;

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getHeadLine() {
    return headLine;
}

public void setHeadLine(String headLine) {
    this.headLine = headLine;
}

public String getTaskText() {
    return taskText;
}

public void setTaskText(String taskText) {
    this.taskText = taskText;
}

public User getAuthor() {
    return author;
}

public void setAuthor(User author) {
    setAuthor(author, true);
}

void setAuthor(User author, boolean add){
    this.author = author;
    if(author !=null&&add){
        author.addCreatedTask(this, false);
    }
}

public User getAssignee() {
    return assignee;
}

public void setAssignee(User assignee) {
    setAssignee(assignee,true);
}

void setAssignee(User assignee, boolean add){
    this.assignee = assignee;
    if(assignee != null && add){
        assignee.addAssignedTasks(this,false);
    }
}

public List<String> getComments() {
    return comments;
}

public void setComments(List<String> comments) {
    this.comments = comments;
}

public Sprint getSprint() {
    return sprint;
}

public void setSprint(Sprint sprint) {
    this.sprint = sprint;
}

public Long getCreationTime() {
    return creationTime;
}

public void setCreationTime(Long creationTime) {
    this.creationTime = creationTime;
}

public String getTaskType() {
    return taskType;
}

public void setTaskType(String taskType) {
    this.taskType = taskType;
}

public List<String> getPossibleTaskTypes() {
    return possibleTaskTypes;
}

public void setPossibleTaskTypes(List<String> possibleTaskTypes) {
    this.possibleTaskTypes = possibleTaskTypes;
}

public List<String> getPossibleworkFlowStati() {
    return possibleworkFlowStati;
}

public void setPossibleworkFlowStati(List<String> possibleworkFlowStati) {
    this.possibleworkFlowStati = possibleworkFlowStati;
}

public String getStatus() {
    return status;
}

public void setStatus(String status) {
    this.status = status;
}

public List<String> getPossibleTaskContainer() {
    return possibleTaskContainer;
}

public void setPossibleTaskContainer(List<String> possibleTaskContainer) {
    this.possibleTaskContainer = possibleTaskContainer;
}

public String getTaskContainer() {
    return taskContainer;
}

public void setTaskContainer(String taskContainer) {
    this.taskContainer = taskContainer;
}




}

现在是任务 Controller :

@RestController
@RequestMapping("/v1/")
@Api(value = "tasks", description = "V1 - Tasks API")
public class TaskController {

private final Logger logger = LoggerFactory.getLogger(TaskController.class);
private TaskRepository taskRepository;
private UserRepository userRepository;

@Autowired
public TaskController(TaskRepository taskRepository, UserRepository userRepository){
    this.taskRepository = taskRepository;
    this.userRepository = userRepository;

}

protected void verifyTaskById(Long id) throws ResourceNotFoundException{
    Task task = taskRepository.findOne(id);
    if(task == null){
        throw new ResourceNotFoundException("Task with ID:"+id+" not found."); 
    }
}
/**
 * <b>POST</b> v1/tasks/
 * @param task
 * @return
 */
@RequestMapping(value="tasks", method=RequestMethod.POST)
@ApiOperation(value = "Creates a new Task", notes="The newly created Task Id will be sent in the location response header", 
response = Void.class)
@ApiResponses(value = {@ApiResponse(code=201, message="Task Created Successfully", response=Void.class), @ApiResponse(code=500, message="Error creating Task", response=ErrorDetail.class) } )
public ResponseEntity<?> createTask(@Valid @RequestBody Task task){
    logger.info(task.toString());
    task.setCreationTime(new Date().getTime());

    task = taskRepository.save(task);
    HttpHeaders responseHeaders = new HttpHeaders();

    URI newTaskUri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(task.getId()).toUri();
    responseHeaders.setLocation(newTaskUri);

    return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED);
}

/**
 * <b>GET</b> v1/tasks/
 * @return
 */
@RequestMapping(value = "tasks", method = RequestMethod.GET )
@ApiOperation(value = "Retrieves all the tasks", response=Task.class, responseContainer="List")
public ResponseEntity<Page<Task>> listAllTasks(Pageable pageable){
    logger.info("Receiving get-Tasks Request..");
    Page<Task> allTasks = taskRepository.findAll(pageable);
    return new ResponseEntity<>(allTasks,HttpStatus.OK);
}

/**
 * <b>GET</b> v1/tasks/{id}
 * @param id
 * @return
 */
@RequestMapping(value = "tasks/{id}", method = RequestMethod.GET )
@ApiOperation(value = "Retrieves given Task", response=Task.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Task.class),  @ApiResponse(code=404, message="Unable to find Task", response=ErrorDetail.class) } )
public ResponseEntity<?> getSingleTask(@PathVariable(value="id") Long id){
    logger.info("Receiving get Task-Request for ID: "+ id);
    verifyTaskById(id);
    Task task = taskRepository.findOne(id);
    return new ResponseEntity<>(task,HttpStatus.OK);
}

/**
 * <b>PUT</b> v1/tasks/{id}
 * @param task
 * @param id
 * @return
 */
@RequestMapping(value = "tasks/{id}", method = RequestMethod.PUT)
@ApiOperation(value = "Updates given Task", response=Void.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Void.class),  
        @ApiResponse(code=404, message="Unable to find Task", response=ErrorDetail.class) } )
public ResponseEntity<?> updateTask(@RequestBody Task task, @PathVariable(value="id") Long id) {
    logger.info("Receiving put Task Request for "+id);
    verifyTaskById(id);
    if(!isIdInBodyCorrect(task, id)){
        task.setId(id);
    }

    if(task.getAuthor() != null)userRepository.save(task.getAuthor());
    if(task.getAssignee()!=null)userRepository.save(task.getAssignee());
    Task t = taskRepository.save(task);

    return new ResponseEntity<>(HttpStatus.OK);
}

/**
 * <b>DELETE</b> v1/tasks/{id}
 * 
 * @param id
 * @return
 */
@RequestMapping(value = "tasks/{id}", method = RequestMethod.DELETE)
@ApiOperation(value = "Deletes given Task", response=Void.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Void.class),  
        @ApiResponse(code=404, message="Unable to find Task", response=ErrorDetail.class) } )
public ResponseEntity<?> deleteTask(@PathVariable (value="id") Long id) {
    verifyTaskById(id);
    taskRepository.delete(id);
    return new ResponseEntity<>(HttpStatus.OK);
}

protected boolean isIdInBodyCorrect(Task task, Long id){
    if(task.getId() != id){
        logger.warn("Id in Body wasn't defined or wrong. ");  //TODO Exception werfen. 
        return false;
    }else{
        return true;
    }
}

}

最后但并非最不重要的用户 Controller :

@RestController
@RequestMapping("/v1/")
@Api(value = "users", description = "V1 - Users API")
public class UserController {

private final Logger logger = LoggerFactory.getLogger(UserController.class);

private UserRepository userRepository;

@Autowired
public UserController(UserRepository userRepository ){
    this.userRepository = userRepository;
}
/**
 * Checks wether the user exists. If not it throws a {@link ResourceNotFoundException}.
 * @param id
 * @throws ResourceNotFoundException
 */
protected void verifyUserById(Long id) throws ResourceNotFoundException{
    User user = userRepository.findOne(id);
    if(user==null){
        throw new ResourceNotFoundException("User with ID:"+id+" not found.");
    }
}
/**
 * <b>POST</b> v1/users/
 * @param user
 * @return
 */
@RequestMapping(value="users", method=RequestMethod.POST)
@ApiOperation(value = "Creates a new User", notes="The newly created user Id will be sent in the location response header", 
response = Void.class)
@ApiResponses(value = {@ApiResponse(code=201, message="User Created Successfully", response=Void.class), @ApiResponse(code=500, message="Error creating User", response=ErrorDetail.class) } )
public ResponseEntity<?> createUser(@Valid @RequestBody User user) {
    user.setCreationTime(new Date().getTime());
    user = userRepository.save(user);

    // Set the location header for the newly created resource
    HttpHeaders responseHeaders = new HttpHeaders();
    URI newUserUri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(user.getId()).toUri();
    responseHeaders.setLocation(newUserUri);

    return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED);
}
/**
 * <b>GET</b> v1/users/
 * @return
 */
@RequestMapping(value = "users", method = RequestMethod.GET )
@ApiOperation(value = "Retrieves all the users", response=User.class, responseContainer="List")
public ResponseEntity<Page<User>> listAllUsers(Pageable pageable){
    Page<User> allUsers = userRepository.findAll(pageable);
    return new ResponseEntity<>(allUsers,HttpStatus.OK);
}

/**
 * <b>GET</b> v1/users/{id}
 * @param id
 * @return
 */
@RequestMapping(value = "users/{id}", method = RequestMethod.GET )
@ApiOperation(value = "Retrieves given User", response=User.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=User.class),  @ApiResponse(code=404, message="Unable to find User", response=ErrorDetail.class) } )
public ResponseEntity<?> getSingleUser(@PathVariable(value="id") Long id){
    verifyUserById(id);
    User user = userRepository.findOne(id);
    return new ResponseEntity<>(user,HttpStatus.OK);
}
/**
 * <b>PUT</b> v1/users/{id}
 * @param user
 * @param id
 * @return
 */
@RequestMapping(value = "users/{id}", method = RequestMethod.PUT)
@ApiOperation(value = "Updates given User", response=Void.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Void.class),  
        @ApiResponse(code=404, message="Unable to find User", response=ErrorDetail.class) } )
public ResponseEntity<?> updateUser(@RequestBody User user, @PathVariable (value="id") Long id) {
    verifyUserById(id);
    // Save the entity
    if(!isIdInBodyCorrect(user,id)){
        user.setId(id);
    }
    User u = userRepository.findOne(id);
    userRepository.save(user);
    return new ResponseEntity<>(HttpStatus.OK);
}

/**
 * <b>DELETE</b> v1/users/{id}
 * @param id
 * @return
 */
@RequestMapping(value="users/{id}", method=RequestMethod.DELETE)
@ApiOperation(value = "Deletes given User", response=Void.class)
@ApiResponses(value = {@ApiResponse(code=200, message="", response=Void.class),  
        @ApiResponse(code=404, message="Unable to find User", response=ErrorDetail.class) } )
public ResponseEntity<?> deleteUser(@PathVariable (value="id") Long id) {
    verifyUserById(id);
    userRepository.delete(id);
    return new ResponseEntity<>(HttpStatus.OK);
}

protected boolean isIdInBodyCorrect(User user, Long id){
    if(user.getId() != id){
        logger.warn("Id in Body wasn't defined or wrong. ");  //TODO Exception werfen. 
        return false;
    }else{
        return true;
    }
}



}

最佳答案

如果您有双向关系,则必须使用 @JsonIdentityInfo 注释。

让我们看看如何使用 @JsonIdentityInfo 帮助序列化具有双向关系的实体。

@Entity
@Table(name = "TABLENAME")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class ... {

关于java - 使用 Spring REST 更新一对多关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37986928/

相关文章:

java - Hibernate:如果参与者之一只有最终字符串字段(类似于无状态),则一二一和多二一相等

spring - 如何使用 Thymeleaf 模板从 Json 加载数据

angularjs - 如何正确调用外部 api 以在express应用程序中使用来构建我自己的restful api?

.net - 南希 : use array of data from POST request

java - 是否可以使用相同的方法返回一个字符串然后清除它?

java - Autowiring 依赖项注入(inject)失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException : Could not autowire field:

java - 如何像Java一样在Javascript中创建Bean类?

hibernate - JBoss 在开发环境中找不到 PostgreSQL 的 JDBC 驱动程序

java - 为什么 OutputStream.write() 关闭套接字连接?

java - MySQL 的 Hibernate 类中出现未知实体错误