当前位置: 首页 > 知识库问答 >
问题:

如何在验证程序中为字段传递其他参数?

骆昊阳
2023-03-14

我确认电子邮件是唯一的。这是注册期间的工作。但当我试图更改用户配置文件中的电子邮件时,我出现了一个错误。

我检查电子邮件以运行userRepository。findByEmail。如果找到用户,则电子邮件不是唯一的。但当用户在profile中更改其电子邮件时,findByEmail将返回此用户。验证失败。

我需要检查用户是由findByUser返回的不是更改电子邮件的同一用户。为此,我需要传递在验证器中更改电子邮件的用户。

这是我的代码。

实体:

@Data
@Table(name = "users")
@NoArgsConstructor
@CheckPasswordConfirm(message = "Password not equal!")
@Entity
public class User implements UserDetails{

    private static final long serialVersionUID = 1L;

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

    @NotBlank(message = "Username is empty!")
    @UniqueUsername(message = "Username isn't unique")
    private String username;

    @NotBlank(message = "Password is empty!")
    private String password;

    @Transient
    @NotBlank(message = "Password confirm is empty!")
    private String passwordconfirm;

    private boolean active;

    @Email(message = "E-mail!")
    @NotBlank(message = "E-mail is empty!")
    @UniqueEmail(message = "Email isn't unique!")
    private String email;

    private String activationCode;

    @ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
    @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
    @Enumerated(EnumType.STRING)
    private Set<Role> roles;

    public boolean isAdmin()
    {
        return roles.contains(Role.ADMIN);
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return getRoles();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

注释:电子邮件:

@Constraint(validatedBy = UniqueEmailValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface UniqueEmail {

    public String message();

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

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

}

验证器:

package ru.watchlist.domain.validation.validators;

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

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

import ru.watchlist.domain.validation.annotations.UniqueEmail;
import ru.watchlist.service.UserService;

public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {

    @Autowired
    private UserService userService;

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value != null && !userService.isEmailAlredyUse(value);
    }

}

用户服务。isEmailAlredyUse:

    public boolean isEmailAlredyUse(String value) {
        User user = userRepository.findByEmail(value);
        if(user != null) {
            return true;
        }
        return false;
    }

这里我需要检查一下:

User userFromDB = userRepository.findByEmail(value);
        if(userFromDB != null && user != userFromDB) {
            return true;
        }

我该如何解决这个问题?

另外,如果我要使用跨字段对类进行验证,我不能在Thymeleaf中显示其字段的错误。因此,我需要字段的验证器。

请注意我的控制器:

@Controller
@RequestMapping("/profile")
public class ProfileController {

    @Autowired
    UserService userService;

    @GetMapping
    public String profile(@AuthenticationPrincipal User user, Model model) {

        model.addAttribute(user);
        return "profile";

    }

    @PostMapping("/update")
    public String saveChanges(@Valid User user, Errors errors) {

        if(errors.hasErrors()) {
            return "profile";
        }

        userService.addUser(user);

        return "redirect:/profile";
    }

}

用户存储库:

public interface UserRepository extends JpaRepository<User, Long>{

    User findByUsername(String username);

    User findByActivationCode(String code);

    User findByEmail(String email);

}

共有2个答案

姚俊贤
2023-03-14
User userFromDB = userRepository.findByEmail(value);
    if(userFromDB != null && user != userFromDB) {
        return true;
    }

在这种情况下,user和userFromDB总是不同的,因为这些对象可以有不同的hashCodes。你能在返回user的地方添加存储库和类的实现吗?我假设您没有使用JPA规范,但是如果您使用它,请尝试用这个附件替换您自己的验证@Coliv(独特=真实)

如果您想在控制器中验证您的对象,您可以使用@Valid注释,其中控制器侧的代码可以如下所示:

 @PostMapping
public String saveObject(@Valid @ModelAttribute("email") Object object, BindingResult bindingResult) {

    if(bindingResult.hasErrors()){
        return view_with_form;
    }

    repository.save(object)
    return "redirect:path";
}

从Thymeleaf表格:

 <div class="col-md-6 mt-2 form-group">
                                <label>Recipe Description:</label>
                                <input type="text" class="form-control" th:field="*{email}" th:errorclass="is-invalid"/>
                                <span class="invalid-feedback" th:if="${#fields.hasErrors('email')}">
                                    <ul>
                                        <li th:each="error : ${#fields.errors('email')}" th:text="${error}"></li>
                                    </ul>
                                </span>
                            </div>

此示例适用于引导程序4。

武友樵
2023-03-14

我们不建议使用Hibernate Validator来检查数据库约束。

但是,如果您想这样做,可以使用约束验证器负载:https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/#constraint-验证器有效负载。它们是为这种需求而创建的。

示例6.7是您正在寻找的,因为您不想每次都构建一个完整的ValidatorFactory,只是一个特定的上下文。

现在,这是针对Hibernate验证器端的,但是您需要一种方法来正确配置由Spring创建的验证器,以便将登录用户注入其中。我帮不了你。

 类似资料:
  • 问题内容: 我使用passportJS,我想提供的不仅仅是更多的和我的身份验证策略(护照本地)。 我有3个表单字段:,,和 我如何从本地策略访问,该策略如下所示: 我在我的路由(而不是路由中间件)中称呼它,像这样: 问题答案: 您可以启用一个选项,如下所示: 何时,set 成为verify回调的第一个参数,您可以根据需要对其进行检查。

  • 问题内容: 该文档讨论了使用numba的作为的参数。我需要带有附加参数的相同内容。 我基本上是想做这样的事情: 但是,它不起作用,因为应该是/并且不能将它们转换为。我收到以下错误消息: 我没有找到有关如何从Numba中提取值的任何信息。在C语言中,应该类似于—在Numba中可以做同样的事情吗? 问题答案: 1.通过传递额外的参数 该文件说: 如果用户希望改善集成性能,则可以使用以下签名之一: 该是

  • 我想使自定义验证器除了必需的_之外,如果所有字段都已填充,也不会失败。 现行规则: 将导致: Foo、Bar和Baz都是空的(错误) 一个Foo/Bar已填充,另一个为空(错误) Foo和Bar已满,Baz为空(OK) Foo和Bar是空的,Baz是满的(OK) Foo-Bar和Baz已填充(OK)← 我希望这变成一个错误 所以我使用扩展创建自定义验证器,并希望像这样使用它: AppService

  • 我写了一个代码来管理一个咖啡馆,所以在框架中我添加了一个JTable,每次我从JComboBox中选择一个项目,它都应该显示在JTable中。为此,我添加了一个按钮,对于它的操作,我确保每次单击它时,它都将从JComboBox中单击的项存储在数据库中,然后将从数据库中获取的项存储在JTable中。但问题是JTable有两列,而JComboBox中的选择只有一列。因此,另一列必须从其他数据库调用,这

  • 问题内容: 我正在使用一个存储过程,在其中发送数据库中其类型为的存储过程,并且还声明parameter 。 当我将列名传递为float时,它给出了错误: 消息8114,将数据类型nvarchar转换为float时出错。 这是我的测试查询 当我将参数类型更改为时,它给了我这个错误: 消息8117,操作数数据类型varchar对avg运算符无效。 我该如何解决? 更新 : 这是我的存储过程: 问题答案

  • 问题内容: 为了解释这个问题,请考虑我有2个詹金斯工作。 职位1:PARAM_TEST1 它接受称为“ MYPARAM”的参数化值 职位2:PARAM_TEST2 它还接受称为“ MYPARAM”的参数化值 有时我需要按顺序运行这两个作业-因此我创建了一个单独的管道作业,如下所示。它工作正常。 它还接受名为“ MYPARAM”的参数化值,以将其简单地传递到构建作业步骤。 我的问题: 这个例子很简单