1

My pressing question is how to best handle this exception in a JSP web form, however I believe the below might also be able to provide an answer.

I've been messing around with a java project which I have implemented as an applet/JFrame and also a web form via a JSP. In the last class I took (essentially Java 1), the method I learned for handling Exceptions such as NumberFormatException when a user is entering data is via a try/catch block within an ActionListener.

Example:

private ActionListener L_Weight() {
    return new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            double weight = Person.DEFAULT_WEIGHT;
            try {
                weight = Double.parseDouble(ae.getActionCommand());
            }
            catch (NumberFormatException e) {
                //e.printStackTrace();
            }
            person = new Person(
                    person.getGender(),
                    weight, 
                    person.getAge(),
                    person.getNumberOfDrinks(), 
                    person.getHoursSinceFirstDrink());
            view.updatePerson(person);
        }
        
    };
}

So while this works for the applet/JFrame, it doesn't seem like the best usage of try/catch, I don't know what to do with the NumberFormatException other than ignore it, and it does nothing for me on the web form side.

So on the web side, I have found various ideas for handling exceptions/errors, but none seem like they are the best option. My current favorite is to add onsubmit="return checkForm(this)" to my form submission, where checkForm() is javascript code that will return true if valid data is submitted. This still seems like an extraneous step, but other than declaring the variables as Strings and parsing them as doubles so that I can do try/catch errorhandling on the java side, I'm not sure where else I can validate the submissions.

So I implemented the checkForm() function and it's working, just wondering if this is a good practice for form validation in a JSP:

<form name="Name Input Form" action="index.jsp" method="POST" onsubmit="return checkForm(this)">

<script type="text/javascript">
    function checkForm(form) {
        var result = true;
        var numbers = /^[0-9|\.]+$/;
        var checkFields = new Array(
                form.age,
                form.weight,
                form.drinks,
                form.hours);
        
        for (i=0; i < checkFields.length; i++) {
            if (!checkFields[i].value.match(numbers)) {
                alert(checkFields[i].name + " field must be a number");
                checkFields[i].focus();
                result = false;
                break;
            }
        }
        return result;
    }
    
    function optionChange(form) {
        if (checkForm(form)) {
            form.submit();
        }
        
    }

I also made the gender selection a dropdown which calls the optionChange function:

<select name="gender" id="gender" onchange="optionChange(this.form)">
    <option value="Male">Male</option>
    <option value="Female">Female</option>
</select>

You're welcome to check out the web app and the source


Edit:

After posting this questions I realize I also have another question related to this, would it be a poor choice to create a constructor in the Person class which takes the gender, weight, age, drinks, and hours as String parameters, then handles the conversion into their respective types? I could place the error handling into try/catch blocks here but again I would (as I see it) be exploiting the error handling to force validation. From here I wouldn't need to worry about the validation as the java code would expect Strings, but that would seem like an unnecessary amount of refractoring to get working.

Community
  • 1
  • 1
Jens Bodal
  • 1,707
  • 1
  • 22
  • 32

2 Answers2

1

You can use JQuery's change function. So you add a listener to each of your text fields and each time it changes you can check if the text is a valid number (And display some sort of red inline message if it's not).

You can also use html5 input type number for your numeric fields.

xp500
  • 1,426
  • 7
  • 11
  • Great thank you, did not know about those. I guess the general idea though is I should do the validation on the HTML side rather than java? – Jens Bodal Mar 01 '14 at 22:50
  • @akevit You should do on both. On the client side, so that you don't overload the server validating this stuff. And on the server, in case someone bypasses the client and sends the data directly to the server (e.g. manual GETs or POSTs) – xp500 Mar 02 '14 at 00:11
  • So I think my question is then how do I do that on the server side without changing the variable types to Strings? It would seem that the only way I can do error checking is to change the expected input type to Strings, then to use a lot of casting to make it work. I'm extremely new to using JSP, and the Beans use the default get/set methods for the variables. – Jens Bodal Mar 02 '14 at 03:16
  • Only way to validate numeric types is catching the NumberFormatException (or parsing the number yourself, which I don't recommend). Then if there is an error you signal the jsp that an error happened (I don't remember how exactly, it's been a while since I used this stuff, but I'm sure there was a way, maybe returning a new jsp with the form completed and an error) – xp500 Mar 02 '14 at 03:33
  • I *think* where I'm confused at is that to catch the `NumberFormatException` I would need to do so in the jsp file, and from what I've read it is now considered bad practice to use java tags within HTML documents. Normally if I was catching this exception I would simply do `try {setWeight(input);}` followed by the appropriate catch; I don't believe there's any way to catch exceptions in the method itself? In other words, the JSP file simply has ``, I don't know how I would catch the NumberFormatException here – Jens Bodal Mar 03 '14 at 17:35
0

Although xp500 provided some useful information for making my HTML code better, I believe I have finally found out how to validate user input after submitting a form without having to accept all the inputs as Strings then cast them to their appropriate datatypes.

So part of my research led to researching taglets and scriptlets and the such, and as far as I can tell using the JSTL taglibs is an accepted practice

So with that said, here are the changes that I've implemented (note that you can see a working version of the App on Heroku and the source at GitHub:


First I created a servlet called FormValidation.java, the source can be seen on GitHub but the gist of it is that my form now submits to this servlet, the parameters are then validated and parsed and returned as a response.

FormValidation Servlet

public class FormValidation extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest request,HttpServletResponse response)
            throws ServletException, IOException {

        String gender = request.getParameter("gender");
        String age_s = request.getParameter("age");
        String weight_s = request.getParameter("weight");
        String drinks_s = request.getParameter("drinks");
        String hours_s = request.getParameter("hours");
        String gender_s;
        int age_i;
        double weight_d, drinks_d, hours_d;

        if (gender.toLowerCase().equals("male") || 
                gender.toLowerCase().equals("female")) {
            gender_s = gender;
        }
        else {
            gender_s = Person.DEFAULT_GENDER;
        }

        try {
            age_i = Integer.parseInt(age_s);
        }
        catch (NumberFormatException e) {
            age_i = Person.DEFAULT_AGE;
        }
        try {
            weight_d = Double.parseDouble(weight_s);
        }
        catch (NumberFormatException e) {
            weight_d = Person.DEFAULT_WEIGHT;
        }
        try {
            drinks_d = Double.parseDouble(drinks_s);
        }
        catch (NumberFormatException e) {
            drinks_d = Person.DEFAULT_DRINKS;
        }
        try {
            hours_d = Double.parseDouble(hours_s);
        }
        catch (NumberFormatException e) {
            hours_d = Person.DEFAULT_HOURS;
        }

        request.setAttribute("gender", gender_s);
        request.setAttribute("age", age_i);
        request.setAttribute("weight", weight_d);
        request.setAttribute("drinks", drinks_d);
        request.setAttribute("hours", hours_d);
        request.getRequestDispatcher("/index.jsp").forward(request, response);

    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

}

Next the servlet was added to my web.xml:

<servlet>
    <servlet-name>FormValidation</servlet-name>
    <servlet-class>drunkstuff.view.FormValidation</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ErrorHandler</servlet-name>
    <url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>FormValidation</servlet-name>
    <url-pattern>/FormValidation</url-pattern>
</servlet-mapping>

From there I modified my index.jsp file to use the new attributes, and to set the initial default values form the bean:

<jsp:useBean id="WebViewBean" scope="session" class="drunkstuff.view.WebView" />
<c:set var="gender" scope="session" value="${WebViewBean.gender}" />
<c:set var="age" scope="session" value="${WebViewBean.age}" />
<c:set var="weight" scope="session" value="${WebViewBean.weight}" />
<c:set var="drinks" scope="session" value="${WebViewBean.drinks}" />
<c:set var="hours" scope="session" value="${WebViewBean.hours}" />
<jsp:setProperty name="WebViewBean" property="gender" value="${gender}" />
<jsp:setProperty name="WebViewBean" property="age" value="${age}" />
<jsp:setProperty name="WebViewBean" property="weight" value="${weight}" />
<jsp:setProperty name="WebViewBean" property="drinks" value="${drinks}" />
<jsp:setProperty name="WebViewBean" property="hours" value="${hours}" />

And submitting to the servlet:

<form name="Name Input Form" action="./FormValidation" method="GET" onsubmit="return checkForm(this)">

I'm sure what I've done has been done elsewhere, but I had a lot of trouble finding examples I could use to do what I wanted. Also a lot of the answers required using scriptlets which I don't believe I should be using. So I would love to see how this could be improved so I can learn more about java web projects, but thus far I'm pretty happy. I could definitely make some changes to the form validation to change that behavior if I wanted, and possibly return the form with information on the fact that I changed the values, however the main reason for this was so that if someone enters parameters in the URL string, they will get validated.

Community
  • 1
  • 1
Jens Bodal
  • 1,707
  • 1
  • 22
  • 32