使用Spring

时间:2018-06-15 00:52:20

标签: java spring hibernate validation

我想确保在创建新用户名或更新一个用户名时,用户名是唯一的。我编写了下面的代码,它可以很好地创建和更新用户名。但是,当仅更新其他用户字段(如年龄或性别)并保留相同的用户名时,它会返回无效,因为用户名已存在。

重要的是要说我想要的验证是使用BindingResult。我已经有一个数据库,它认为用户名是一个独特的约束。但现在我想要与BindingResult进行相同的验证。但是我这样做的方式在更新用户时会导致错误。

定义注释@UniqueUsername

package app.condominio.validator;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy = UniqueUsernameValidator.class)
@Target({ ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueUsername {
    String message() default "Nome de usuário já está sendo usado";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

实施验证器

package app.condominio.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.springframework.beans.factory.annotation.Autowired;

import app.condominio.service.UsuarioService;

public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {

    @Autowired
    UsuarioService usuarioService;

    @Override
    public void initialize(UniqueUsername username) {
    }

    @Override
    public boolean isValid(String username, ConstraintValidatorContext cxt) {
        return !usuarioService.existe(username);
    }
}

在Usuario.class中

@Entity
@Table(name = "Usuarios")
public class Usuario implements Serializable {

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

@NotBlank
@UniqueUsername
private String username;

@NotBlank
private String password;

@NotBlank
private String nome;

@Email
private String email;

...

UsuarioService

@Service
@Transactional
public class UsuarioServiceImpl implements UsuarioService {

    @Autowired
    private UsuarioDao usuarioDao;

    @Override
    @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
    public boolean existe(String username) {
        return usuarioDao.existsByUsername(username);
    }

UsuarioDao

public interface UsuarioDao extends CrudRepository<Usuario, Long> {

    Usuario findByUsername(String username);

    Boolean existsByUsername(String username);

}

控制器

@Controller
@RequestMapping("conta")
public class UsuarioController {

    @Autowired
    private UsuarioService usuarioService;

    @GetMapping("/cadastrar/sindico")
    public ModelAndView preCadastro(@ModelAttribute("usuario") Usuario usuario, ModelMap model) {
        model.addAttribute("conteudo", "cadastrarSindico");
        return new ModelAndView("site/layout", model);
    }

    @PostMapping("/cadastrar/sindico")
    public ModelAndView posCadastro(@Valid @ModelAttribute("usuario") Usuario usuario, BindingResult validacao, ModelMap model) {
        if (validacao.hasErrors()) {
            return preCadastro(usuario, model);
        }
        usuarioService.salvarSindico(usuario);
        model.addAttribute(usuario);
        model.addAttribute("conteudo", "cadastrarCondominio");
        return new ModelAndView("site/layout", model);
    }

2 个答案:

答案 0 :(得分:2)

我认为UniqueUsernameValidator行动符合预期。

我对你的应用程序不是很清楚。因此很难实现一种方法来检查验证用户是否在数据库中具有相同的用户ID。可能你应该提供更多的细节,比如方法代码usuarioService.existe(username)

对我来说,为了确保用户名是唯一的,我这样做:

@Column(unique=true)
String username;

或使用@UniqueConstraint

@Table(name = "users", uniqueConstraints = {
    @UniqueConstraint(columnNames = {
        "username"
    })
})

注意如果让JPA创建表格,它将会起作用。

答案 1 :(得分:0)

您可以使用验证组尝试以下方法:

创建标记接口(或类)

public interface UserCreateValidationGroup {
}

然后在你的实体中使用它,如下面的

@NotBlank
@UniqueUsername(groups = UserCreateValidationGroup.class)
private String username;

然后在Controller中使用它和@Validated(JSR-303的Spring的变体)。请注意,您必须将单个方法拆分为单独的创建和更新方法,以进行不同的验证。

创建:

@PostMapping("/cadastrar/sindico")
public ModelAndView create(
    @Validated(UserCreateValidationGroup.class) @ModelAttribute("usuario") Usuario usuario, 
    BindingResult validacao, 
    ModelMap model
) { ... }

更新

// note, here I did use PUT and no argument for @Validated annotation
@PutMapping("/cadastrar/sindico") 
public ModelAndView update(
    @Validated @ModelAttribute("usuario") Usuario usuario, 
    BindingResult validacao, 
    ModelMap model
) { ... }

但是,您必须在更新案例中对用户名执行手动检查(UsuarioService.existe)。