Showing posts with label form. Show all posts
Showing posts with label form. Show all posts

Friday, December 18, 2009

Handling Profile Updates

We have a profile page with a form that allows logged in users to update their name. Now we need to add handling to ProfileServlet that will update the data store when the Save Changes button is clicked.

The trick is to know if the servlet is being called by clicking on a My Profile link, or as a result of the Save Changes button being clicked. The secret to that is to look at the form submission data provided to every servlet.

The HTTPServletRequest object (passed into the doPost and doGet methods by the web server) contains a method called getParameter. Pass it the name of a form element, and it will give you back the values associated with that element. If the element doesn't exist, you'll get null back.

So code like this:


if (req.getParameter("submit") == null)
{
// Servlet called because of link click
}
else
{
// Servlet called because of button click
}


will allow you to decide which situation is calling the servlet, so you can make the appropriate response.

In the case of the profile page, I still want to display the form after they click submit, but I want to update the data store, too. So I'm going to have code like this just after I fetch the user record from the data store, but just before I get any values out of it:


User user = results.get(0);

if (req.getParameter("submit") != null)
{
user.setName(req.getParameter("name").trim());
pm.makePersistent(user);
}

String name = user.getName ();



This completes the form processing round trip. We really should add some error checking and error messages, too. For example, someone shouldn't be able to save a blank name. Add appropriate error handling and messages to your own projects.

Following this same pattern, you can add however many profile fields you need. Just remember to add them to the User object, too, if they aren't already in there.

Wednesday, December 16, 2009

Adding The Profile Page

I want the user to be able to edit their profile page, so they can change their name to something other than what RPX reported. And so they can add information not given in RPX (for example, in my contest site I might want their birthday so I can calculate their age, and so I can display a Happy Birthday message on their birthday).

In the FreeMarker template for the front page I put the link for the profile page as /profile. That will have to map to a Java servlet that displays the profile editing page for the currently logged in user, and saves changes to the data store.

This will also let us set up a pattern for pages that require the user to be logged in to view, as well as a pattern for pages that do form processing.

So let's add a handler for the profile page, and start out by requiring the user to be logged in to view it. If they aren't logged in, they'll get a message and a Sign In link.

If you don't remember how to add a new servlet, read my original post on Java Servlets. Add a new servlet mapped to /profile. I'll call mine ProfileServlet, so the code for it will be in ProfileServlet.java in my project.server package.

In ProfileServlet.java, I'll use code like this to show one page if they're logged in, and another if they're not:


Map root = new HashMap();
String template = "profileNotLoggedIn.ftl";

if (session != null)
{
// Get the User's name
Long userid = (Long) session.getAttribute ("userid");
PersistenceManager pm = PMF.get().getPersistenceManager();

Query query = pm.newQuery("select from omega.server.User where id == idParam");
query.declareParameters("Long idParam");

try
{
List<User> results = (List<User>) query.execute(userid);
User user = results.get(0);
String name = user.getName ();
Integer userLevel = user.getUserLevel ();
root.put("loggedIn", true);
root.put("name", name);
root.put("userLevel", userLevel);
template = "profileLoggedIn.ftl";
}
finally
{
query.closeAll();
pm.close();
}
}
else
{
root.put("loggedIn", false);
}

Template temp = config.getTemplate(template);

PrintWriter out = resp.getWriter();

try
{
temp.process(root, out);
out.flush();
} catch (TemplateException e)
{
e.printStackTrace(out);
}


Notice how the FreeMarker template we use depends on whether the user is logged in or not. This allows us to separate out those pages for web design purposes, rather than forcing the web designer to put logic into the pages.

I'll need to create both FreeMarker templates. profileNotLoggedIn.ftl will just be a simple error page with the standard links across the top. profileLoggedIn.ftl will display a form, populating the fields with the data from the data model.

I'll create those templates by copying over my Front.ftl file and adding the extra bits. Next post we'll see how to centralize some of the common navigation elements so we aren't duplicating them between templates.

Here's the form from profileLoggedIn.ftl:


<form action="/profile" method="POST">
<input type="text" name="name" value="${name}">
<input type="submit" name="submit" value="Save Changes">
</form>


This is the simplest form possible that will do the job. It really should be a bit fancier, providing at least a label for the edit field.

Right now clicking Save Changes just redisplays the form. After we remove the duplication among the templates, we'll add in handling of the form to actually update the data store.