2

My basic question is with JavaEE, JSP, and JSTL, how do you get user-updated information to update a bean on the controller side (i.e. in the serlvet)?

I am fairly new to web apps and I have read several different approaches, but I have a feeling the way I am going about it is really outdated or has some significant flaws I am overlooking. My solution is as follows:

My particular bean is a Task bean with properties taskID, title, and instructions. It actually has many more properties, but I scaled it down for the sake of the question.

public class Task {
    private int taskID;
    private String title;
    private String instructions;

    constructor here...

    getters and setters defined here...

In the servlet I get the bean from the DAO and put it in the request:

Task task = dao.getTaskByID(taskID);
request.setAttribute("task", task);

In the JSP page I set the corresponding inputs to the beans properties, using a hidden input for taskID. The user sees the data, makes changes to it, and submits:

<form action="./UpdateTask" method="POST">
    <input type="hidden" name="taskID" value="${task.taskID }">
    <input type="text" id="taskTitle" name="taskTitle" value="${task.title }">
    <input type="text" id="taskInstructions" name="taskInstructions" value="${task.instructions}">
    <button type="submit">Submit</button>
</form>

Back in the controller I am get all the parameters from the request and build a bean with the updated data and then send it back to the DAO to update in the database.

int taskID = Integer.parseInt(request.getParameter("taskID));
String title = request.getParameter("taskTitle");
String instructions = request.getParameter("taskInstructions");

Task updatedTask = new Task(taskID, title, instructions);

dao.updateTaskInfo(updatedTask );

So a couple of specific questions:

  • Am I misunderstanding how JSTL and beans are used together?
  • Is there a way to just grab the whole bean from the request without having to rebuild it like I did?
  • If I do end up rebuilding the bean from request data, what if I don't want to expose some of the property values to the user (such as foreign key ids)?

I know asking about best practices is frowned upon, so I am not asking for the "best" way, but simply if what I've describes is an unorthodox way that deviates from standard practices. Or if there something I am not doing that would make it simpler, or more up to speed with current practices.

I have also considered making the task bean a session variable to maintain sate of the object and then just getting it back from the session after the request and updating the fields that could have changed based on user input but I worry about concurrency issues with that approach.

Thanks for any help. SO is amazing in helping newbies. There is sooooo much information out there and it changes so quickly it sure can be overwhelming to figure out what approaches to learn.

arcademonkey
  • 109
  • 9

1 Answers1

1

Am I misunderstanding how JSTL and beans are used together?

Apart from the XSS attack hole, you're doing it fine, given that this is a "plain vanilla" JSP/Servlet web application.

You just came to realize that this all is boilerplate code. Code which needs to collect request parameters, convert and validate them, update the model values and invoke the business logic. You see this back in almost every single "plain vanilla" servlet. You need to repeat that same kind of code logic over and over.

That's exactly why MVC frameworks like JSF, Spring MVC, Wicket, Play!, Struts, etc exist. They offer a single "controller" servlet/filter which takes over (most) of that boilerplate code, so that you can end up with just a JSP or Facelets file as "view" and a Javabean class as "model". Depending on the MVC framework's nature, it will for you transparently update the referenced entity (Task as in your example) with converted, validated and/or raw submitted values.


Is there a way to just grab the whole bean from the request without having to rebuild it like I did?

I have also considered making the task bean a session variable to maintain sate of the object and then just getting it back from the session after the request and updating the fields that could have changed based on user input but I worry about concurrency issues with that approach.

Putting it in the session scope may indeed cause trouble when enduser has the same view open in multiple browser tabs/windows. For example, Java EE's MVC framework JSF offers the "view scope" which keeps a backing bean alive as long as you're postbacking on the very same form on which the backing bean was initialized for first time. A "master-detail" example in JSF can be found in this Q&A: Creating master-detail pages for entities, how to link them and which bean scope to choose.


If I do end up rebuilding the bean from request data, what if I don't want to expose some of the property values to the user (such as foreign key ids)?

You're going to always need to pass around some identifier, such as taskID in your dao.getTaskByID(taskID) example. How else should the system know which entity the enduser would like to view/edit? You only don't need to pass around all other identifiers or unused properties. You simply use the taskID to obtain a Task entity from the DAO and then update its properties instead of recreating the Task from scratch.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Wow, that is a fantastic answer. Thanks. I'm not using frameworks because I want to lean the fundamentals well and I guess I am! Your final comment was something I was thinking of doing but was worried that would result in too many DOA calls. Glad to know it isn't, so I'll be doing that! Is storing the taskID in a hidden input the standard for getting it from the request or is there a more secure way? – arcademonkey Sep 20 '15 at 20:13
  • 1
    If "too many DB calls" is your concern, then the problem should be solved by a 2nd level entity cache between DB and DAO in backend, not by duplicating entities over all sessions in frontend. Java EE's ORM framework JPA supports this. Coming back to the fundamentals (I always support learning the fundamentals first, this way you'll understand better why all those abstract frameworks exist ;) ), may I assume that you're well aware of our servlets wiki page http://stackoverflow.com/tags/servlets/info and this Q&A about idempotence http://stackoverflow.com/q/2349633? If not, go through them too. – BalusC Sep 20 '15 at 20:16
  • I didn't have those references, they're great. I didn't know about XSS attacks. Very helpful. Re: storing taskID in a hidden input; ok to do? I didn't see anything about that on those pages. I'll stop bothering you now :) Thanks again! – arcademonkey Sep 20 '15 at 20:42
  • Answer depends on how you got the task ID in first place (for the `dao.getTaskByID(taskID)`). If it was already passed as URL query string parameter like so `/edittask?taskID=42`, then it doesn't make sense to obfuscate the hidden input value. The enduser already knows the exact value. – BalusC Sep 20 '15 at 20:45
  • Right. I should have clarified. I'd be getting taskID from a query that used the user's id, so they'd never see it. I guess I am asking more to generalize how to most securely handle the exposing ids. For this particular example, the taskID probably doesn't need to be protected too much, but I figure it doesn't hurt to err on the side of security and not expose ids. OK, I'll really stop bothering you! You've been very generous with your time. – arcademonkey Sep 20 '15 at 20:53
  • If user-task is one-to-one relationship, then simply re-query it using user's ID. After all, just the same way as you initially got the task. – BalusC Sep 20 '15 at 21:03