Создание нового пользователя

 
 
 
Сообщения:16
Всем привет! Хотелось бы услышать мнение правильно ли я реализовал метод сервиса.

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(unique = true)
    private String username;
    private String password;
    
    @Column(unique = true)
    private String email;
    private boolean enabled;
    private Locale locale;
    private Date lastLogin;
    private String displayedName;

    //getters and setters
}


@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository; //JpaRepository

    @Autowired
    private PasswordEncoder passwordEncoder;

    //...

    private Object lockUserCheck = new Object();

       @Override
    public void createNewUser(NewUserDto user) throws ExistsEmailException, ExistUsernameException, CreateUserException {

        validateDto(user); //Проверка валидности данных прилетевших от вьюхи

        User newUser = DtoConverter.convertNewUserDtoToUser(user);
        String password = passwordEncoder.encode(newUser.getPassword());
        newUser.setPassword(password);
        newUser.setEnabled(true); // TODO: сделать активацию аккаунта

        synchronized (lockUserCheck) {
            checkUser(newUser);
        }

        try {
            userRepository.save(newUser);
        } catch (DataIntegrityViolationException e) {
            throw new CreateUserException("Can`t create user! " + e.getMessage());
        }
    }

    @Transactional
    private void checkUser(User newUser) throws ExistUsernameException, ExistsEmailException {
        if (null != userRepository.findByUsername(newUser.getUsername())) {
            throw new ExistUsernameException("Username already exists");
        }
        if (null != userRepository.findByEmail(newUser.getEmail())) {
            throw new ExistsEmailException("Email already exists");
        }
    }
}
 
 
Сообщения:547
Если работает, значит правильно! :-)

Хочу обратить ваше внимание, что @Transactional на приватных методах (да и на любых других, которые вызываются из этого же класса) не работает. А если бы и работал, то имело смысл добавить также атрибут readOnly = true.

Не вижу смысла в синхронизации, если честно. Аналогично и с ловлей DataIntegrityViolationException -- если каким-то чудом пользователь регистрирует уже существующий ник/e-mail, то должно выбрасываться исключение DataIntegrityViolationException и его можно бросать выше, пусть 500 отобразит :) Это очень редкий случай должен быть, ну и БД не должна позволять такие данные вставлять (пометили поля как уникальные?).

P.S. А почему createNewUser не @Transactional? и почему не используете JSR-303 валидацию, она же удобная очень.
Изменен:05 янв 2017 22:33
 
 
Сообщения:16
php-coder с синхронизацией (кстати в коде что у меня выше она и сделана то не правильно) согласен, действительно вероятность того что будет одновременно регистрироваться два одинаковых username очень мала, а если такое вдруг случится, то БД не позволит создать пользователя.

php-coder:
и почему не используете JSR-303 валидацию, она же удобная очень.

 Я так понимаю что мне нужно будет сделать аннотацию, которая выполнит нужные проверки в БД? Я прав?
 
 
Сообщения:547
Igor.78:
Я так понимаю что мне нужно будет сделать аннотацию, которая выполнит нужные проверки в БД? Я прав?


Да. Пример:
- UniqueLogin
- UniqueLoginValidator
 
 
Сообщения:9474
Не уверен, что использовать BeanValidation для проверок уникальности - хорошая идея. Ведь в таком случае поставил на уровне MVC Controller'ов @Valid и оп - транзакции и запросы в БД не на том уровне. А затем еще и Hibernate вызовет валидацию и снова запрос в БД. По-моему лучше проверить на уникальность явно как в коде выше.
 
 
Сообщения:547
Староверъ:
Ведь в таком случае поставил на уровне MVC Controller'ов @Valid и оп - транзакции и запросы в БД не на том уровне.


Самый плохой случай здесь, что будет race и мы не увидим, что кто-то уже "занял" логин. Я почитал этот случай очень редким и, так как БД все равно не позволит создать две одинаковые записи, решил что на него можно "закрыть глаза". У меня не нагруженое веб-приложение. Таким образом, следуя закону Парета, я с минимумом усилий покрыл большую часть вариантов.

Староверъ:
А затем еще и Hibernate вызовет валидацию и снова запрос в БД.


Это 1) зависит от приложения, в моем случае Hibernate не используется 2) дополнительную проверку перед сохранением можно отлючить совсем, либо только для этой аннотации если задать нестандартный groups 3) во многих случаях 2 простых запроса вместо одного, мало волнуют разработчиков (особенно, если они используют Hibernate)
 
Модераторы:Нет
Сейчас эту тему просматривают:Нет