簡體   English   中英

Spring 數據 JPA 更新使一些字段 null

[英]Spring Data JPA update makes some fields null

我有一個簡單的場景,其中有實體:

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Data
public abstract class AuditModel implements Serializable {

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_at", nullable = false, updatable = false)
    @CreatedDate
    private Date createdAt;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "updated_at", nullable = false)
    @LastModifiedDate
    private Date updatedAt;

    @Column(name = "created_by")
    @CreatedBy
    private String createdBy;

    @Column(name = "modified_by")
    @LastModifiedBy
    private String modifiedBy;

}

用戶.java

@Data
@Entity(name = "users")
@NoArgsConstructor
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class User extends AuditModel{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id", unique = true, nullable = false)
    private Integer userId;

    @NonNull
    private String userFirstName;

    @NonNull
    private String userLastName;

    @Email
    @NonNull
    private String userEmail;

    @NonNull
    private String userPassword;

    @Column(name = "enabled")
    private boolean userEnabled;

    @NonNull
    private String userFbLink;

    @NonNull
    private String userTwLink;

    @NonNull
    private String userLiLink;

    @NonNull
    @ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.MERGE)
    @JoinTable(
            name="user_role",
            joinColumns={@JoinColumn(name="USER_ID", referencedColumnName="ID")},
            inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="ID")})
    private List<Role> roles;

}

一個角色實體很簡單:Role.java

@Data
@Entity(name = "roles")
@NoArgsConstructor
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = false, exclude = {"userList"})
public class Role  extends AuditModel{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="id", unique = true, nullable = false)
    private Integer roleId;

    @NonNull
    @Column(nullable = false, unique = true)
    @NotEmpty
    private String roleName;

    @ManyToMany(mappedBy = "roles")
    private List<User> userList;

}

Spring 安全配置如下:

安全配置.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final UserDetailsServiceImpl userDetailsService;

    @Autowired
    public SecurityConfiguration(UserDetailsServiceImpl userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/assets/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        String [] permissibleResources = {"/register**", "/login**","/post_register", "/confirm**", "/reset", "/api/**"};
        http.csrf().disable()
                .authorizeRequests()
                    .antMatchers(permissibleResources).permitAll()
                        // START Add missing configs
                        .anyRequest()
                        .authenticated()
                        // END Add missing configs
                .and()
                    .formLogin()
                    .loginPage("/login")
                        // username password
                        .usernameParameter("username")
                        .passwordParameter("password")
                        // success and failure handlers
                    .successHandler(appAuthenticationSuccessHandler())
                    .failureHandler(appAuthenticationFailureHandler())
                    .permitAll()
                .and()
                    .logout()
                        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                        .logoutSuccessUrl("/login?logout")
                        .invalidateHttpSession(true)
                        .clearAuthentication(true)
                .permitAll()
                .and()
                    .exceptionHandling().accessDeniedHandler(accessDeniedHandler())
                .and()
                    .headers()
                    .defaultsDisabled()
                    .cacheControl()
        ;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .authenticationProvider(daoAuthenticationProvider());
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler(){
        return new AppAccessDeniedHandler();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider(){
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(bCryptPasswordEncoder());

        return provider;
    }

    @Bean
    public PasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder(5);
    }

    // Auth success handler
    @Bean
    public AuthenticationSuccessHandler appAuthenticationSuccessHandler(){
        return new AppAuthenticationSuccessHandler();
    }

    // Auth failure handler
    @Bean
    public AuthenticationFailureHandler appAuthenticationFailureHandler() {

        ExceptionMappingAuthenticationFailureHandler failureHandler = new ExceptionMappingAuthenticationFailureHandler();
        Map<String, String> failureUrlMap = new HashMap<>();
        failureUrlMap.put(BadCredentialsException.class.getName(), AppAuthenticationFailureHandler.BAD_CREDENTIALS_URL);
        failureUrlMap.put(AccountExpiredException.class.getName(), AppAuthenticationFailureHandler.EXPIRED_URL);
        failureUrlMap.put(LockedException.class.getName(), AppAuthenticationFailureHandler.LOCKED_URL);
        failureUrlMap.put(DisabledException.class.getName(), AppAuthenticationFailureHandler.DISABLED_URL);
        failureHandler.setExceptionMappings(failureUrlMap);

        return failureHandler;

    }

}

一切正常,但是我用以下形式更新了用戶實體的特定字段:

<form th:action="@{/user/__${user.userId}__/update}" th:object="${user}" method="post">
    <h5>Personal</h5>
    <hr>          
    <input type="hidden" th:value="${user.userId}" th:field="*{userId}" /> <br>       
    <input type="text" th:field="*{userFirstName}" th:value="${user.userFirstName}" required /> <br>
    <input type="text" th:field="*{userLastName}" th:value="${user.userLastName}" required /><br>
    <h5>Social</h5>
    <hr>
    <input type="url" th:field="*{userFbLink}" th:value="${user.userFbLink}" /><br>
    <input type="url" th:field="*{userTwLink}" th:value="${user.userTwLink}" /><br>        
    <input type="url" th:field="*{userLiLink}" th:value="${user.userLiLink}" /><br>
    <button name="save-user" type="submit">Save</button>
    </div>
</form>

通過 UserController.java 給出如下:

@Controller
@RequestMapping(value = "/user")
public class UserController {

    private final UserService userService;

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

    @PreAuthorize(value = "hasAuthority('USER')")
    @GetMapping(value = "/{id}/edit")
    public String editBio(
            @PathVariable("id") Integer id,
            Model model
    ){
        User user = userService.findById(id);
        String pageTitle = "Edit User " + user.getUserFirstName() ;
        model.addAttribute("pageTitle", pageTitle);
        model.addAttribute("user", user);
        return "edit_user";
    }

    @PreAuthorize(value = "hasAuthority('USER')")
    @PostMapping(value = "/{id}/update")
    public String updateBio(
            @PathVariable("id") Integer id,
            @ModelAttribute("user") @Valid User user,
            BindingResult result
    ){
        if (result.hasErrors()) {
            return "edit_user";
        }
        userService.save(user);
        return "redirect:/user/" + id;
    }
}

它執行查詢為:

Hibernate: update users set created_by=?, modified_by=?, user_first_name=?, user_last_name=?, updated_at=?, enabled=?, user_fb_link=?, user_li_link=?, user_password=?, user_tw_link=?, where id=?

Hibernate: delete from user_role where user_id=?

僅在更新表單中提到的字段中插入新數據,所有其他字段變為null ,甚至用戶密碼變為null並且啟用字段變為false 用戶角色也被刪除。 當我注銷並嘗試重新登錄時,我收到錯誤disabled 幾天前它工作正常,沒有任何奇怪的行為。 我搜索了很多,發現@DynamicUpdate 和 Spring Data JPA ,但它從來沒有幫助過我。 任何人,請在這種情況下幫助我。

當您保存User user時,當前user object 的所有數據都會更新。 如果任何數據不是更新形式,這意味着數據是 null 和boolean它是false 因此,使用 id 從數據庫中獲取數據,然后在 fetch user 中設置新值,然后保存。

@PostMapping(value = "/{id}/update")
public String updateBio(
        @PathVariable("id") Integer id,
        @ModelAttribute("user") @Valid User updatedUser,
        BindingResult result
){
    if (result.hasErrors()) {
        return "edit_user";
    }
    User user = userService.findById(updatedUser.getUserId());
    // Set the updated data from updatedUser to user 
    user.setUserFirstName(updatedUser.getUserFirstName()); // set other updated field like this
    // Now save
    userService.save(user);
    return "redirect:/user/" + id;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM