【问题标题】:Unexpected results when displaying error messages in Java EE application (no error when field is null)在 Java EE 应用程序中显示错误消息时出现意外结果(字段为空时没有错误)
【发布时间】:2013-01-31 11:17:36
【问题描述】:

我正在用 Java-EE 编写一个 web 应用程序,当我尝试在用户输入上显示错误时发现自己得到了一个非常意外的结果。

该应用程序基于 JSP/Servlet/Form/Bean 模型构建。基本上,JSP 将数据存储在请求中,并将其传输到 servlet。然后 servlet 将请求原始传输到表单,然后读取数据,执行必要的检查并将 bean 返回给 servlet。

大多数字段必须具有特定值,其他一些字段必须简单地为非空。

我已经编写了错误检测代码来保护输入,但是我发现自己得到了一个非常奇怪的结果:

  • 当字段非空但值不正确时(例如,位于 00:00-23:59 范围之外的一小时),它会返回正确的错误以及错误消息,并存储在 HashMap 中,我可以在我的 JSP 中访问它。
  • 但是,当字段为空时,它返回消息,可能也将其存储在 HashMap 中(我知道这一点是因为 ${!empty errors.dataErrors} 测试返回 true 并且错误字段显示在我的 JSP 中)但是没有办法访问错误的值

我已经搜索了我的代码,但仍然找不到错误的来源。如果有人知道问题出在哪里,这里是它的sn-ps

来自 servlet 的 doPost 方法:

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
    NewBookingForm form = new NewBookingForm();
    Booking booking = form.registerBooking(request);
    String VUE;

    request.setAttribute("booking", booking);
    request.setAttribute("errors", form);

    this.getServletContext().getRequestDispatcher(VIEW).forward(request, response);
}

地图是 NewBookingForm 类中的一个字段,在 registerBooking 方法之外声明和初始化,例如 private Map<String,String> dataErrors = new HashMap<String,String>();,它有一个私有 setter(用于在类内访问)和一个公共 getter(用于在 Servlet 中访问并在 JSP 中)

在表单类中,我使用这个函数来获取字段值:

private static String getFieldValue(HttpServletRequest request, String fieldName)
{
    String value = request.getParameter(fieldName);
    if (value == null || value.trim().length() == 0){return null;}
    else{return value;}
}

在我的方法开始时通过一系列调用(如 String fieldDepartureStation = getFieldValue(request, FIELD_DEPARTURE_STATION);)获取值后,然后我使用这样的 try/catch 块检查它们

try
{validation.departureStation(fieldDepartureStation);}
catch(Exception e)
{setDataErrors(FIELD_DEPARTURE_STATION, e.getMessage());}

如果数据必须具有特定的值范围或必须简单地为非空,则验证类中的验证方法会有所不同。

在前一种情况下,它们是这样的:

public void departureTime(String time) throws Exception
{
    if (!validationRETime(time)) { throw new Exception("Please input a time with the hh:mm pattern"); }
}
....
private boolean validationRETime(String strTime)
{
    String regExp = "^([01][0-9]|2[0-3])[:][0-5][0-9]$"; // hh:mm
    if (strTime.matches(regExp))
    {
        return true;
    }
    else
    {
        return false;
    }
}

而在后一种情况下,它们只是

public void departureStation(String station) throws Exception
{
    if (station.equals(null)) { throw new Exception("Please input a departure station"); }
}

最后,在我的 JSP 中,我使用以下代码来显示错误:

<c:if test="${!empty errors.dataErrors}">
     <p>Errors</p>
     <c:forEach items="${errors.dataErrors}" var="message">
           <p><c:out value="${message.value}" /></p>
     </c:forEach>
</c:if>

当我故意输入不正确的值时,它确实会显示错误段落,但 &lt;c:forEach&gt; 仅在错误字段为非空但值不正确时循环并显示错误消息。因此,对于一个只需要为非空的字段,我永远不会收到消息(但我确实收到了错误)

这些都是我能想到的可能出错的事情,但我还没有发现它们在哪里做的,如果有人可以帮助我,我会很高兴。

【问题讨论】:

  • there's no way to access the values of the errors 是什么意思?您如何访问错误?尝试时会发生什么?
  • 严格来说什么也没发生: 什么也不写。但是所有应用程序都可以正常工作,并且不会发生 Java 异常。编辑:我还添加了代码 Iuse 来显示我忘记添加到我的问题中的错误
  • stationnull 时,if (station.equals(null)) 将抛出NPE。这意味着,你的throw new Exception(..),根本不会被执行。尝试将测试更改为:-if (station == null).
  • 非常感谢,我已经尝试过您的建议,它确实有效。但它提出了一个新问题:在 .equals(null) 测试中,由于异常冲突(NPE 与我定义的异常冲突)而没有执行 catch 块;那么为什么我的地图中仍然会出现错误,所以最后我的 JSP 会显示文本的错误块?
  • @FrenchFigaro.. 好吧,NPE 也是 Exception 的子类而已。所以,当它被抛出时,你在Exception catch 块中捕获它(这是一个重要原因,为什么你不应该捕获Exception,而只是特定的异常。)。因此,您实际上是将异常放入地图中。但是,可能抛出的异常没有任何消息,因此您看不到任何消息。

标签: java jsp jakarta-ee jstl


【解决方案1】:

问题出在您的departureStation 方法中:-

public void departureStation(String station) throws Exception
{
    if (station.equals(null)) { 
        throw new Exception("Please input a departure station"); 
    }
}

您对null 值的测试本身会触发NPE。因此,一旦为station = null 执行station.equals(null),就会引发NPE 异常,然后将其传播给调用者。因此,您的 if 块甚至不会被执行。因此,您并没有像您想的那样抛出Exception

现在,还要注意,抛出的NPE 不包含任何message。因此,e.getMessage() 将返回 null

现在,让我们回到调用者:-

try
{validation.departureStation(fieldDepartureStation);}
catch(Exception e)
{setDataErrors(FIELD_DEPARTURE_STATION, e.getMessage());}

在这里,您正在通过使用 Exception 的 catch 块进行 Exception Handling 世界上最大的犯罪。由于Exception 是所有异常的超类,它将以相同的方式处理所有异常。因此,它消耗NPE,并将其传递给setDataErrors()

因此,您当然会得到错误,但是值 e.getMessage() 将是 null。这就是为什么您没有看到任何消息的原因。你甚至可以通过上面catch blocke.getMessage()的值logging进行测试。


解决方案??

只需更改您的null 支票即可:-

if (station == null) { 
    throw new Exception("Please input a departure station"); 
}

一切都会好起来的。我认为,您必须在所有方法中进行此更改。始终使用== 运算符执行null check

【讨论】:

  • 非常详细的回答,谢谢。 Exception 类型是法国教程网站 le site du zero 推荐的类型,我主要用它来掌握 Java。我会在这部分深入挖掘。
【解决方案2】:
public class Test {

    public static void main(String[] args) {
        Test  c = new Test ();
        try {
            c.departureTime("30:30");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        try {
            c.departureTime(null);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public void departureTime(String time) throws Exception {
        if (!validationRETime(time)) {
            throw new Exception("Please input a time with the hh:mm pattern");
        }
    }

    private boolean validationRETime(String strTime) {
        String regExp = "^([01][0-9]|2[0-3])[:][0-5][0-9]$"; // hh:mm
        if (strTime.matches(regExp)) {
            return true;
        } else {
            return false;
        }
    }
}

您将通过运行上面的代码找出您的问题。简而言之,您需要确保 exp.getMessage() 始终具有价值。要解决此问题,您可能需要调整您的离开时间()方法以提供更细粒度的异常处理。

【讨论】:

  • 请将答案也用文字贴出来,而不是只强迫读者搜索并找到代码的差异。
猜你喜欢
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 2018-03-26
  • 2020-08-21
  • 2015-08-08
  • 1970-01-01
  • 2022-08-16
  • 1970-01-01
相关资源
最近更新 更多