I have the following classes. I wonder if this structure makes sense in any terms especially the usage of the UserDetails
class from Spring. Should I use loadbyusername
method to create and remove methods in account service or is it okay? Then where should we use loadbyusername
method?
Base class to cover fundamental properties like id
, createdAt
, etc.
@Accessors(chain = true)
@Data
@MappedSuperclass
public class Base {
@Id
private String id = UUID.randomUUID().toString();
@CreatedDate
private Date createdAt;
@LastModifiedDate
private Date updatedAt;
}
Account class
@Entity
@JsonIgnoreProperties(value = {"createdAt", "updatedAt"})
@Data
public class Account extends Base {
@NotNull
private String username;
@NotNull
private String password;
@NotNull
@Email
private String email;
@NotNull
private Role role;
}
Account details class implementing userdetails
public class AccountDetails implements UserDetails {
private Account account;
public AccountDetails(Account account) {
this.account = account;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return account.getPassword();
}
@Override
public String getUsername() {
return account.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Account service
@Service
public class AccountService {
@Autowired
AccountRepository accountRepository;
@Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
ModelMapper modelMapper;
public boolean create(AccountDTO accountDTO) {
if (usernameExists(accountDTO.getUsername())) {
throw new UsernameExistsException();
}
Account account = modelMapper.map(accountDTO, Account.class);
account.setPassword(bCryptPasswordEncoder.encode(account.getPassword()));
account.setId(UUID.randomUUID().toString());
account.setRole(Role.USER);
if (accountRepository.save(account) != null) {
return true;
} else {
throw new RuntimeException();
}
}
public boolean remove(AccountDTO accountDTO) {
if (!usernameExists(accountDTO.getUsername())) {
throw new UsernameNotFoundException("Account named " + accountDTO.getUsername() + " not found");
}
Optional<Account> account = accountRepository.findByUsername(accountDTO.getUsername());
accountRepository.delete(account.get());
if (!usernameExists(accountDTO.getUsername())) {
return true;
}
return false;
}
public boolean usernameExists(String username) {
return accountRepository.findByUsername(username).isPresent();
}
}
AccountDetailsService implementing userdetailsservice
@Service
public class AccountDetailsService implements UserDetailsService {
@Autowired
AccountRepository accountRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Optional<Account> optionalAccount = accountRepository.findByUsername(s);
if (!optionalAccount.isPresent()) {
throw new UsernameNotFoundException("Account named " + s + " not found");
}
return new AccountDetails(optionalAccount.get());
}
}