使用JavaEE进行字段验证的良好实践

时间:2018-03-26 08:44:44

标签: java validation java-ee

我有一个用JavaEE编写的项目,但我是该技术的新手。

我的EJB依赖于从客户端前端收到的参数。

目前,我正在验证EJB中的参数,例如,我在EJB中有方法来验证参数,但我认为这是不好的做法,因为它导致代码重复,并为我的EJB增加了更多的职责

我想知道执行参数验证的最佳做法是什么。

编辑:客户端无法直接访问我的JavaEE后端。相反,我们有一个用Java编写的互操作性层,遵循SOAP架构,位于客户端前端和J2E后端之间。

我的代码示例如下:

    // Method inherited from the EJB interface
    // The eventOrganizer variable is another EJB that is injected into this very EJB
    @Override
        public boolean registerEvent(String name, int participantNumber, Calendar date, Coordinator coordinator) {

            l.log(Level.INFO, "Received request for event creation");

            if (!areParametersValid(name, participantNumber, date, coordinator)) {
                return false;
            }

            Calendar cal = Calendar.getInstance();
            cal.setTime(date.getTime());
            cal.add(Calendar.HOUR_OF_DAY, 12);

            Event event = new Event(coordinator, date.getTime(), cal.getTime(), participantNumber, name);

            return eventOrganizer.bookRoom(event);
        }

// Parameters validation methods
/**
     * Returns true if the given name is non null and
     * is not empty
     * @param name the name of the {@link Event}
     * @return true if the name semantically of the {@link Event} is valid
     */
    private boolean nameIsGood(String name) {
        return name != null && !name.trim().equals("");
    }

    /**
     * Returns true if the number of participant is strictly positive
     * @param participantNumber the number of people in the {@link Event}
     * @return true if the number of participant is valid
     */
    private boolean participantNumberIsGood(int participantNumber) {
        return participantNumber > 0;
    }

    /**
     * Checks if the given date is a date in the future,
     * and returns true if it is
     * @param date the date to check
     * @return true if the provided start date for the {@link Event} is valid
     */
    private boolean dateIsGood(Calendar date) {
        return date.after(Calendar.getInstance());
    }

    /**
     * Checks if the given {@link Coordinator} is a valid coordinator,
     * i.e., if he's not null, and returns true if he is not
     * @param coordinator the {@link Coordinator} to check
     * @return true if the {@link Coordinator} is valid
     */
    private boolean coordinatorIsGood(Coordinator coordinator) {
        return coordinator != null;
    }

    /**
     * Checks that all the parameters received for an {@link Event} creation are valid
     * and returns true if they are, or false if they're not
     * @param name the name of the {@link Event}, as a {@link String}
     * @param participantNumber the estimated number of people for the
     *                          {@link Event} as a {@link Integer}
     * @param date the date at which the {@link Event} is scheduled,
     *             as a {@link Calendar}
     * @param coordinator the {@link Coordinator} that created the {@link Event}
     * @return true if all the given parameters are valid, and the event creation shall be processed
     */
    private boolean areParametersValid(String name, int participantNumber, Calendar date, Coordinator coordinator) {
        return nameIsGood(name) && participantNumberIsGood(participantNumber) && dateIsGood(date) && coordinatorIsGood(coordinator);
    }


// Event object 
public class Event {
    private Coordinator coordinator;
    private Date startDate;
    private Date endDate;
    private int nbPeople;
    private String name;
    private List<Room> rooms;
    private List<RoomType> desiredRoomTypes;

    public Event(int nbPeople, String name, List<RoomType> roomTypes) {
        this.nbPeople = nbPeople;
        this.name = name;
        this.desiredRoomTypes = roomTypes;
        this.rooms = new ArrayList<>();
    }

    public Event(Coordinator coordinator, Date startDate, Date endDate, int nbPeople, String name) {
        this.coordinator = coordinator;
        this.startDate = startDate;
        this.endDate = endDate;
        this.nbPeople = nbPeople;
        this.name = name;
        this.rooms = new ArrayList<>();
    }

    public List<Room> getRooms() {
        return rooms;
    }

    public void addRooms(List<Room> rooms) {
        this.rooms.addAll(rooms);
    }

    public void addRoom(Room room) {
        this.rooms.add(room);
    }

    public Coordinator getCoordinator() {
        return coordinator;
    }

    public Date getStartDate() {
        return startDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public int getNbPeople() {
        return nbPeople;
    }

    public String getName() {
        return name;
    }
}

// Coordinator object 
public class Coordinator {
    private String firstName;
    private String lastName;
    private String email;
    private List<Event> eventsCreated;

    public Coordinator(String firstName, String lastName, String email) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }

    public List<Event> getEventsCreated() {
        return eventsCreated;
    }

    public void setEventsCreated(List<Event> eventsCreated) {
        this.eventsCreated = eventsCreated;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getEmail() {
        return email;
    }
}

3 个答案:

答案 0 :(得分:0)

避免混乱的一种方法是将未经验证的(可变)对象与经过验证的(不可变)对象分开。不要害怕根据需要拥有多个不可变对象。 验证的行为是确定您拥有哪些数据,并通过扩展来确定它实际上是什么类型/对象。

至于它自己的验证,如果它的用户反馈使一个方法给一些对象提供所有问题并传递它。这样,您就可以使用相同的界面验证所有对象。

UserFeedbackObject validate(UserFeedbackObject f){
  if (name.length == 0) f = f.badField("username","expected a username");
  if (date.after(Calendar.getInstance()) == 0) f = f.badField("username","date needs to be in the future");
  return  f;
}

答案 1 :(得分:0)

Bean验证

一旦您正在寻找良好做法,我强烈建议您使用Bean Validation而不是编写自己的验证机制,特别是对于简单约束。

Bean Validation是Java EE的一部分。它基于注释,并带有built-in set of constraints。如果他们不适合你,你可以编写自己的约束。

根据您当前的验证限制,您将拥有以下内容:

Event registerEvent(@NotNull @NotBlank String name, 
                    @Min(1) int participantNumber, 
                    @NotNull @Future Calendar date, 
                    @NotNull @Valid Coordinator coordinator);

Bean验证是规范。实际验证由实现执行,例如Hibernate Validator。如何设置Bean Validation或Hibernate Validator超出了这个答案的范围。

一些有用的资源:

答案 2 :(得分:-1)

由于专注于业务逻辑bean 可重用性等多种原因,我决定将字段验证委托给拦截器

我在一个名为FieldsValidator的帮助器类中提取了验证方法,我在拦截器中使用了它。

这种剪纸提供了三件事:

  • 验证和测试的逻辑仅针对一个类进行,例如, FieldsValidator

  • 拦截器专注于验证和WebFault例外 抛

  • Beans现在只关心业务逻辑,参数完整性/有效性是在可重复使用的拦截器中完成的

查找以下示例:

验证String不为空且不为空的拦截器

@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
    Object[] parameters = ctx.getParameters();

    // loops through the parameters of the method
    for (Object parameter : parameters) {
        if (parameter == null) {
            throw new InvalidRequestParametersException("One or more parameters of type String in the request are null!");
        }

        // if the parameter is of type String
        if (parameter.getClass().getName().equals(String.class.getName())) {
            // if the string is invalid
            if (!FieldsValidator.isStringValid((String) parameter)) {
                throw new InvalidRequestParametersException("One or more parameters of type String in the request are invalid!");
            }
        }
    }
    return ctx.proceed();
}

以下是我的FieldsValidator类的示例:

/**
 * A static helper class used to validate fields within the EJBs
 *
 * @author Maxime Flament (maxime.flament@etu.unice.fr)
 */
public class FieldsValidator {

    /**
     * Returns true if the given string is non null and
     * is not empty
     *
     * @param str the string to validate
     * @return true if the string is semantically correct
     */
    public static boolean isStringValid(String str) {
        return str != null && !str.equals("");
    }

    /**
     * Returns true if the given value is strictly positive
     *
     * @param value the number to check
     * @return true if the value is strictly positive
     */
    public static boolean isStrictlyPositive(int value) {
        return value > 0;
    }

    /**
     * Checks if the given date is a date in the future,
     * and returns true if it is
     *
     * @param date the date to check
     * @return true if the provided start date is valid
     */
    public static boolean dateIsGood(Calendar date) {
        return date.after(Calendar.getInstance());
    }

    /**
     * Checks if the given {@link Object} is a valid object,
     * i.e., if he's not null, and returns true if he is not
     * @param object the {@link Object} to check
     * @return true if the {@link Object} is valid
     */
    public static boolean isObjectNotNull(Object object) {
        return object != null;
    }

    /**
     * Checks that the provided email is correct, and returns true if it is,
     * or false otherwise
     *
     * @implNote this method doesn't check that the provided email
     *           actually exists, but it only checks if the email
     *           is valid according to the RFC
     *
     * <a href="https://stackoverflow.com/a/26687649/5710894">Inspired by this</a>
     *
     * @param email the email to check
     * @return true if the given email is valid
     */
    public static boolean isValidEmail(String email) {
        return EmailValidator.getInstance().isValid(email);
    }
}

下面是我的一个bean中拦截器使用的一个例子:

@Interceptors({InterceptorStringVerifier.class /* Add more interceptors here */})
Event registerEvent(String name, int participantNumber, Calendar date, Coordinator coordinator)

注意:拦截器应始终在bean的接口中声明,而不是实现。