I have a simple scenario where there are entities:
@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;
}
User.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;
}
A role entity is as simple as: 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 Security configuration is as:
SecurityConfiguration.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;
}
}
everything was working fine, but whine I update specific fields of the user entity with the following form:
<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>
through UserController.java given bellow:
@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;
}
}
it performs query as:
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=?
and
Hibernate: delete from user_role where user_id=?
Inserts new data only in the fields mentioned in the update form, all other fields become null
, even user password becomes null
and enabled field becomes false
. User role is also deleted. When I log out and try to log back in, I get error disabled
. A couple of days ago it was working fine without any weird behaviour. I searched a lot and found @DynamicUpdate with Spring Data JPA , but it never helped me. Anyone, please help me in this case.
When you are saving User user
all the data of the current user
object will update. If any data is not in update form that means that data is null and for boolean
it's false
. So fetch the data from the database using id then set the new value in fetch user then save.
@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;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.