验证程序抛出的JSF bean验证和异常

时间:2014-02-08 17:56:18

标签: validation jsf jpa ejb bean-validation

验证程序抛出异常时,将禁止Bean验证。我想知道处理这个问题的正确方法是什么。表格:

<h:form id="registration_form">
<h:panelGrid columns="3">
    <h:outputLabel for="username">Username</h:outputLabel>
    <h:inputText id="username" value="#{userController.user.username}">
    <f:validator binding="#{userController$UniqueUsernameValidator}"
        redisplay="true"/> <!-- Not sure about this -->
        <f:ajax event="blur" render="usernameMessage" />
    </h:inputText>
    <h:message id="usernameMessage" for="username" />
    <!-- etc-->
</h:panelGrid>
</h:form>

UserController:

@ManagedBean
@ViewScoped
public class UserController {

    // http://stackoverflow.com/a/10691832/281545
    private User user;
    @EJB
    // do not inject stateful beans !
    private UserService service;

    public User getUser() {
        return user;
    }

    @PostConstruct
    void init() {
        // http://stackoverflow.com/questions/3406555/why-use-postconstruct
        user = new User();
    }

    @ManagedBean
    @RequestScoped
    public static class UniqueUsernameValidator implements Validator {

        // Can't use a Validator (no injection) - see:
        // http://stackoverflow.com/a/7572413/281545
        @EJB
        private UserService service;

        @Override
        public void validate(FacesContext context, UIComponent component,
                Object value) throws ValidatorException {
            if (value == null) return; // Let required="true" handle, if any.
            try {
                if (!service.isUsernameUnique((String) value)) {
                    throw new ValidatorException(new FacesMessage(
                        FacesMessage.SEVERITY_ERROR,
                        "Username is already in use.", null));
                }
            } catch (Exception e) {
                System.out.println(cause(e));
                Throwable cause = e.getCause();
                if (cause instanceof PersistenceException) {
                    Throwable cause2 = cause.getCause();
                    // ((PersistenceException)cause) - only superclass methods
                    if (cause2 instanceof DatabaseException) {
                        // now this I call ugly
                        int errorCode = ((DatabaseException) cause2)
                            .getDatabaseErrorCode(); // no java doc in eclipse
                        if (errorCode == 1406)
                            throw new ValidatorException(new FacesMessage(
                                FacesMessage.SEVERITY_ERROR, "Max 45 chars",
                                null));
                    }
                }
                // TODO: DEGUG, btw the EJBException has null msg
                throw new ValidatorException(new FacesMessage(
                    FacesMessage.SEVERITY_ERROR, cause.getMessage(), null));
            }
        }

        private static String cause(Exception e) {
            StringBuilder sb = new StringBuilder("--->\nEXCEPTION:::::MSG\n"
                + "=================\n");
            for (Throwable t = e; t != null; t = t.getCause())
                sb.append(t.getClass().getSimpleName()).append(":::::")
                    .append(t.getMessage()).append("\n");
            sb.append("FIN\n\n");
            return sb.toString();
        }
    }
}

实体:

/** The persistent class for the users database table. */
@Entity
@Table(name = "users")
@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    private int iduser;
    @NotNull(message = "Please enter a username")
    @Pattern(regexp = "[A-Za-z0-9_]{6}[A-Za-z0-9_]*",
            message = "Usernames can have latin characters, the underscore and "
                + "digits and are at least 6 characters")
    @Size(max = 45)
    private String username;
    //etc
}

和服务:

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public boolean isUsernameUnique(String username) {
        Query query = em
            .createNativeQuery("SELECT r1_check_unique_username(?)");
        short i = 0;
        query.setParameter(++i, username);
        return (boolean) query.getSingleResult();
    }
}

如果我输入超过45个字符的用户名,MySql会抛出异常 - cause()的输出为:

INFO: --->
EXCEPTION:::::MSG
=================
EJBException:::::null
PersistenceException:::::Exception[EclipseLink-4002](Eclipse Persistence Services\
 - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data\
 too long for column 'username_given' at row 198
Error Code: 1406
Call: SELECT r1_check_unique_username(?)
    bind => [1 parameter bound]
Query: DataReadQuery(sql="SELECT r1_check_unique_username(?)")
DatabaseException:::::
Internal Exception: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data\
 too long for column 'username_given' at row 198
Error Code: 1406
Call: SELECT r1_check_unique_username(?)
    bind => [1 parameter bound]
Query: DataReadQuery(sql="SELECT r1_check_unique_username(?)")
MysqlDataTruncation:::::Data truncation:Data too long for column 'username_given'\
 at row 198
FIN

我处理它的方式显示"Max 45 chars"消息。

但是这种处理(明确检查错误代码)有点臭。另一方面,如果我没有抛出ValidatorException(并且只是catch (Exception e) {}也是臭的)bean验证开始(由@Size(max = 45)引起的那个)但我仍然看到异常玻璃鱼日志中的痕迹

问题

  • 这种处理方式是否正确(我应该在验证器中catch (Exception ignore) {}还是检查我手动获取的异常 - 理想情况下我可以要求验证器在之后运行 > User中的(所有)bean验证 - 并且只有在这些验证通过时才会生效)
  • 如何禁止在服务器日志中打印异常?

0 个答案:

没有答案