应该使用异常来描述用户输入错误吗?

时间:2018-10-29 18:57:12

标签: java exception exception-handling

我有一项将树状结构保存到数据库的服务。在持久化树之前,先对树进行验证,并且在验证过程中,许多事情可能会出错。该树可能具有重复的节点,或者一个节点可能缺少重要字段(例如其缩写,全名或级别)。

为了与服务进行通信,我使用了异常。当validateTree()方法遇到问题时,它将引发适当的异常。然后HttpService类使用此异常来形成适当的响应(例如,响应AJAX调用)。

public class HttpService {

    private Service service;
    private Logger logger;

    // ...

    public HttpServiceResponse saveTree(Node root) {
        try {
            service.saveTree(root);  
        } catch (DuplicateNodeException e) {
            return HttpServiceResponse.failure(DUPLICATE_NODE);
        } catch (MissingAbbreviationException e) {
            return HttpServiceResponse.failure(MISSING_ABBREV);
        } catch (MissingNameException e) {
            return HttpServiceResponse.failure(MISSING_NAME);
        } catch (MissingLevelException e) {
            return HttpServiceResponse.failure(MISSING_LEVEL);
        } catch (Exception e) {
            logger.log(e.getMessage(), e. Logger.ERROR);
            return HttpServiceResponse.failure(INTERNAL_SERVER_ERROR);
        }
    }
}

public class Service {

    private TreeDao dao;

    public void saveTree(Node root) 
        throws DuplicateNodeException, MissingAbbreviationException, MissingNameException, MissingLevelException {

        validateTree(root);
        dao.saveTree(root);
    }

    private void validateTree(Node root) 
        throws DuplicateNodeException, MissingAbbreviationException, MissingNameException, MissingLevelException {

        // validate and throw checked exceptions if needed
    }
}

我想知道,这是例外的好用法吗?本质上,我使用它们来传达错误消息。另一种选择是让我的saveTree()方法返回一个整数,并且该整数将传达错误。但是,为此,我必须记录每个返回值的含义。 C / C ++的风格似乎比Java多。我当前使用异常在Java中是一种好习惯吗?如果没有,最好的选择是什么?

3 个答案:

答案 0 :(得分:1)

否,例外不适用于您需要在此处进行的验证。您可能希望显示多个验证错误消息,以便用户可以一次看到所有验证错误,并且为每个无效输入引发单独的异常将不允许这样做。

相反,创建一个列表并将错误放入其中。然后,您可以向用户显示所有验证错误的列表。

等待直到您的请求完全到达DAO,似乎是进行此验证的错误时间。服务器端的前端控制器应该对这些项目进行验证,然后再进行进一步的传输,以防止注入或跨站点脚本等攻击。

答案 1 :(得分:1)

TL; DR您向我们展示的Java端部件几乎是完美的。但是您可以添加一个独立的验证检查,并在尝试保存之前从客户端使用它。

涉及许多软件层,所以让我们看一下每一层-这里没有“一刀切”的答案。

  • 对于Service对象,如果它无法保存树(出于任何原因,不限于此),它是从saveTree()方法引发异常的完美解决方案验证)。这就是异常的含义:传达某种方法无法完成其工作的信息。并且Service对象不应依赖某些外部验证,而应确保自身仅保存有效数据。

  • 如果HttpService.saveTree()无法保存树(通常由Service表示异常,则它也应与其调用者进行通信)。但是,由于它是HTTP服务,它不能引发异常,而必须返回结果代码和文本消息,就像您做的那样。这永远不能包含来自Java异常的完整信息,因此,在将错误结果传递给HTTP客户端之前,最好在这里记录所有不清楚的错误(但是您还应确保也记录了堆栈跟踪!)。

  • Web客户端UI软件当然应该向用户显示详细的错误列表,而不仅仅是翻译的单个异常。因此,我将创建一个HttpService.validateTree(...)方法,该方法返回一个验证错误列表,并在尝试保存之前从客户端调用该方法。这使您可以独立于保存而检查有效性。

为什么要这样?

  • 您永远无法控制客户端中发生的事情,在某些浏览器中,您甚至都不知道请求是来自您的应用还是来自curl之类的东西。因此,您不能依赖JavaScript(?)应用程序可能实现的任何验证。您所有的服务方法都应自行进行验证,以拒绝无效数据。

  • 在JavaScript客户端应用程序中实施验证检查仍需要在Java服务中进行相同的验证(请参见上文),因此您必须维护两种使用不同语言的代码来执行完全相同的业务逻辑-不要重复自己!只有在无法忍受额外往返的情况下,我才认为这是可以接受的解决方案。

答案 2 :(得分:0)

在消息本身以及如何指示用户必须修复哪些对话元素方面,

可见且引人注目的

来自尼尔森(Guru Nielsen), https://www.nngroup.com/articles/error-message-guidelines/