You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot多对多双向关联中,POST书籍时无法更新关联表的问题求助

Spring Boot多对多双向关联中,POST书籍时无法更新关联表的问题求助

我是Spring Boot新手,最近在做一个书籍和作者的项目,需要实现一个作者可以有多本书,一本书也可以由多个作者合著的多对多关联功能。目前POST作者可以正常工作,但POST书籍的时候,虽然用户表和书籍表都能更新,但中间的关联表(USERS_BOOKS)没有同步更新,数据库用的是PostgreSQL。

下面是我的实现细节:

实体类代码

Users类

@Entity
@Table
@Getter
@Setter
@NoArgsConstructor
public class Users {

    @Id
    @SequenceGenerator(
        name = "user_sequence",
        sequenceName = "user_sequence",
        allocationSize = 1
    )
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "user_sequence"
    )
    
    private Long userId;
    private String password;
    private LocalDate dateOfBirth;
    private String fullName;
    private String email;

    @Enumerated(EnumType.STRING)
    private Roles role;

    @ManyToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "USERS_BOOKS", joinColumns = {
        @JoinColumn (name = "User_id", referencedColumnName = "userId")
    }, 
    inverseJoinColumns = {
        @JoinColumn(name = "BookId", referencedColumnName = "bookId")
    })
    private Set<Book> books;


    public Users(String password, LocalDate dateOfBirth, String fullName, String email, Roles role){
        this.password = password;
        this.dateOfBirth = dateOfBirth;
        this.fullName = fullName;
        this.email = email;
        this.role = role; 
    }

    public Users(String password, LocalDate dateOfBirth, String fullName, String email, Set<Book> books){
        this.password = password;
        this.dateOfBirth = dateOfBirth;
        this.fullName = fullName;
        this.email = email;
        this.books = books;
    }

    public void addBooks(Set<Book> books){
        if(this.role == Roles.AUTHOR){
            for(Book book : books)
                try{
                    this.books.add(book);
                    book.addAuthors(Set.of(this));
                } catch(Exception e){
                    System.out.println("Wrong type of object for a List of Book");
                    continue;
                }
        } else {
        throw new IllegalArgumentException("Non author users cannot hold books");
        }
    }


    public void removeBooks(Set<Book> books){
        for(Book book : books)
            for(Book user : this.books){
                if (user.equals(book)) {
                    this.books.remove(user);
                }
                else{
                    System.out.println("Book: "+book.getTitle()+ " is already not in set.");
                }
            }
        }
    
}

Book类

@Table(name = "Books")
@Entity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor

public class Book {
    @Id
    @SequenceGenerator(
        name = "book_sequence",
        sequenceName = "book_sequence",
        allocationSize = 1
    )
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = "book_sequence"
    )
    private Long bookId;
    private String title;
    private LocalDate releaseDate;
    private String genresStr;
    @Column(columnDefinition = "text")
    private String content;

    @ManyToMany(mappedBy="books", fetch=FetchType.LAZY, cascade = CascadeType.ALL)
    
    private Set<Users> authors;


    public Book(String title, LocalDate releaseDate, String content, String genresStr){
        this.genresStr = genresStr;
        this.title= title;
        this.releaseDate = releaseDate;
        this.content = content;
    }

    public Book(String title, LocalDate releaseDate, String content, String genresStr, Set<Users> authors){
        this.genresStr = genresStr;
        this.title= title;
        this.releaseDate = releaseDate;
        this.content = content;
        this.authors = authors;
    }

    public void addAuthors(Set<Users> authors){
        System.out.println("addAuthorsCalled");
        for(Users author : authors)
        try{
            this.authors.add(author);
            author.addBooks(Set.of(this));
            author.setRole(Roles.AUTHOR);
        } catch(Exception e){
            System.out.println("Wrong type of object for a List of Users");
        }
    }

    public void removeAuthors(Set<Users> authors){
        if(authors.size() == 1){
            System.out.println("Can't delete all authors for certain book");
            return;
        }
        for(Users author : authors)
            for(Users user : this.authors){
                if (user.equals(author)) {
                    this.authors.remove(user);
                }
                else{
                    System.out.println("User: "+author.getFullName()+ " is already not in set.");
                }
            }
    }
}

控制器代码

BookController

@RestController
@RequestMapping(path = "api/books")
public class BookController {
    
    private final BookService bookService;
    private UserService userService;


    public BookController(@Autowired BookService bookService, UserService userService){
        this.bookService = bookService;
        this.userService = userService;
    }


    @GetMapping
    public List<Book> getBooks(){
        return bookService.getBooks();
    }

    @PostMapping
    public void addBook(@RequestBody Book book){
        if(!book.getAuthors().isEmpty()){
            for(Users author :  book.getAuthors()){
                author.setRole(Roles.AUTHOR);
                userService.saveUser(author);
            }
        }
        bookService.saveBook(book);
    }

    @DeleteMapping(path="{bookId}")
    public void deleteBook(@PathVariable ("bookId") Long bookId){
        bookService.deleteBook(bookId);
    }

    @PutMapping(path="{bookId}")
    public void updateBook(
        @PathVariable("bookId") Long bookId,
        @RequestParam(required = false) String title,
        @RequestParam(required = false) LocalDate releaseDate, 
        @RequestParam(required = false) String content,
        @RequestParam(required = false) Set<Long> userIds

    ){
        Set<Users> usersToAdd = null;
        if(userIds!=null){
            usersToAdd = userService.getUsersById(userIds);
        }
        bookService.updateBook(bookId, title, releaseDate, content, usersToAdd);
    }

    @PutMapping(path = "/{bookId}/delAuthor")
    public void putMethodName(
        @PathVariable Long bookId,
        @RequestParam(required = true) Set<Long> userIds
    ){
        Set<Users> usersToRemove = userService.getUsersById(userIds);
        bookService.removeAuthors(bookId, usersToRemove);

    }
}

UserController

@RestController
@RequestMapping(path = "api/users")
public class UserController {
    
    private final UserService userService;

    public UserController(@Autowired UserService userService){
        this.userService = userService;
    }

    @GetMapping
    public List<Users> getAllUsers() {
        return userService.getUsers();
    }

    @PostMapping
    public void addNewUser(@RequestBody Users user) {
        userService.saveUser(user);
        
    }

    @DeleteMapping(path="{userId}")
    void deleteUser(@PathVariable ("userId") Long userId){
        userService.deleteUser(userId);
    }

    @PutMapping(path="{userId}")
    void updateUser(@PathVariable ("userId") Long userId,
        @RequestParam(required = false) String fullName,
        @RequestParam(required = false) String password,
        @RequestParam(required = false) LocalDate dateOfBirth,
        @RequestParam(required = false) String email,
        @RequestParam(required = false) Set<Long> bookIds
    ){
        userService.updateUser(userId, password, dateOfBirth, fullName, email, bookIds);
    }
}

UserService代码

@Service
public class UserService {

    private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

    private final UserRepository userRepository;
    private BookRepository bookRepository;

    public UserService(@Autowired UserRepository userRepository, BookRepository bookRepository){
        this.userRepository = userRepository;
        this.bookRepository = bookRepository;
    }

    public Users getUser(Long id){
        return this.userRepository.getReferenceById(id);
    }

    public List<Users> getUsers(){
        return this.userRepository.findAll();
    }

    public Set<Users> getUsersById(Set<Long> userIds){
        Set<Users> users = new HashSet<>();
        for(Long userId : userIds)
            if(userId != null){
                users.add(this.getUser(userId));
            }
        return users;
    }

    public void saveUser(Users user){
        Optional<Users> userEmailOptional = userRepository.findUserByEmail(user.getEmail());
        if(userEmailOptional.isPresent()){
            throw new IllegalStateException("This email already exists in database");
        }

        if(user.getRole() == Roles.AUTHOR){
            Optional<Users> authorByFullName = userRepository.findUserByFullName(user.getFullName());
            if(authorByFullName.isPresent()){
                throw new IllegalStateException("Authors cannot have the same name");
            }
        }

        user.setPassword(encoder.encode(user.getPassword()));
        userRepository.save(user);
    }

    // 剩余代码省略(原内容截断)
}

备注:内容来源于stack exchange,提问作者marioszap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 11:07:57