Dropdown used on multiple pages, should I componentize it? - java

I got this dropdown that will be utilized on some pages and I am concerning if I should componentize it and include it on each page or if I call the dropdown service on each service that is needed. I building a spring mvc with thymeleaf

In case when you have a dropdown, or any other html element for that matter, that needs to appear on several pages, it makes sense to place that element(s) inside a thymeleaf fragment so as to avoid code duplication. Not only do you avoid code duplication, but your code will become easier to maintain as well (because there's less code to maintain).
<div th:fragment="dropdownFragment">
....
<select>
<th:block th:each="item : ${dropdownItems}">
<option th:value="${item}" th:text="${item}"></option>
</th:block>
</select>
</div>
In order to reduce the number of trips to the database, we should cache our data. Possibly the easiest way to do this is to make use of the built in HttpSession object (especially when our data is relatively small).The code might look something like
HttpSession session = request.getSession();
//code to retrive data from the db
session.setAttribute("dropdownItems", dropdownItems);
The session object can be referenced in thymeleaf as #{session.some_object} but this has been deprecated since Thymeleaf 3.1. For this reason, it's best to copy the session attribute into a Model (or ModelAndView) object, which can then be referenced as ${modelObject}.
#GetMapping("/getItems")
public ModelAndView getDropdownItems(HttpSession session )
ModelAndView mv = new ModelAndView();
mv.setViewName("someView");
//this assumes that you already have a session with dropdownItemsattribute
mv.addObject("dropdownItems", session.getAttribute("dropddownItems"));
return mv;
}
Hope this helps.

Related

How does the Spring forms .jsp tag library work?

So I have a .jsp page which has a form on it, like this (naturally this is a massive simplification):
<form:form commandName="myCommand" method="post">
<form:select path="values" class="select-tall" multiple="multiple" id="mySelect">
<option>first</option>
<option>second</option>
<option>third</option>
</form:select>
<button type="submit" class="button">Save</button>
</form:form>
When the submit button is pressed, the form is submitted(somehow) and the path= attributes are used to bind the data inside the form elements to the properties of an instance of a plain old java object. I understand how this POJO is specified, and I understand how the POST request is routed to the correct controller, but I don't understand where or how the form values are mapped to the given POJO.
What I don't understand is:
How does the spring tag library modify the form such that this binding takes place?
How would one go about doing this in a manual or ad-hoc fashion(using a Javascript onSubmit() method, say)?
Essentially my question is: How does the spring-form.tld tag library work?
Any resources, or even a high-level explanation in your own words, would be extremely helpful.
I've implemented a work-around solution in the mean time (dynamically adding items to a hidden form element), but I feel like this is hack-y and the wrong solution.

Spring mvc form post to different controller, or overthinking this

I made this way more confusing than it needed to be. Here is the simplified version.
1 - I have a drop down and a submit button on every page in the upper right hand corner. The drop down is a list of languages. The user can change the language and press the submit button to go to the language controller and update the current language.
public class LanguageController {
#ModelAttribute("languageList")
public LanguageList populateLanguageList() {
return LanguageDAO.all();
}
#RequestMapping("/setLanguage.mvc")
public ModelAndView setLanguage(
#ModelAttribute("languageForm") LanguageForm languageForm,
HttpServletRequest request,
HttpServletResponse response
){
//do stuff
}
}
<form:form modelAttribute="languageForm">
<form:select path="acctGrpId" >
<form:options items="${languageList}"/>
</form:select>
<input type="submit"/>
</form:form>
How would I make that available on every page? Given that the page might be a page where you are editing/creating a user so the "Controller" of that page is actually a UserController, or RoleController, or DepartmentController, not the LanguageController. I need this particular jsp to hit a specific controller regardless of what the page is doing.
You just specify different action attribute in different forms. There's no problem in having multiple forms on one page.
In your case it would be:
<form action="Context/adduser.mvc">
</form>
and
<form action="Context/addBookmark.mvc">
</form>
etc
I would love to help you on this, but I am unsure of your requirements.
Are you talking about BookMarkController having various methods and add/upload calling the methods?
or you want BookMarkController to have more than one form?
Could you please elaborate more on this?
I believe, you want all the jsp pages to post data to a controller which can save the form when a link is clicked. This is quite simple, you can add a savePage method in all the controllers and map the uri accordingly and from the savePage method you can reedirect the request to the specific controller which you have written to save the pages.
Hope this helps.
Your JSP is the view, which is separate from your controller. That's the beauty of MVC, the separation of the Model, View, and Controller. You shouldn't necessarily think of the view as being tied to a controller, or a page as having a "current" controller. Yes, we often make that association pretty strong because the controller handles populating the model attributes to render the view and processing the form post as a result of an action in the view, but really any controller can return any view as long as it populates the model correctly, and any view can submit to any controller. A view can even submit to different controllers at different times depending on the url that is followed.
So, in your case, as soulcheck says, you simply change the URL that the form submits to. Because the controllers are mapped by the #RequestMapping, changing the form's action will change the controller class and/or method that is called when the form is submitted as long as Spring MVC can find a suitable RequestMapping.
Is this what you are looking for?
What are the best practices around setting global model attributes in Spring MVC?
implement a HandlerInterceptor, and expose the data to every request

How do I bind HTML table data to a java object in a spring controller?

I have a spring MVC application using JSP as my view technologies with Jquery for AJAX. I have a table such as the following:
<table>
<tr>
<td>name1</td>
<td>value1</td>
<td>setting1</td>
</tr>
<tr>
<td>name2</td>
<td>value2</td>
<td>setting2</td>
</tr>
</table>
I need to serialize this table so that it can later be bound to an object in my controller. However the jquery serialize() method only works on form fields. What would be the best approach to get the table data into the HTTP request so that I can later bind it to a java object?
EDIT:
I have a java object that has a collection so
class MyOject {
private List<AnotherObject> items = new ArrayList<AnotherObject>();
// standard getters and setters
}
class AnotherObject {
private name;
private value;
private setting;
// getters and setters
}
In the screen the user is creating new items on the fly. When the user is done, they submit the form and then I need to process all the items in the list and instantiate a new collection with those items.
For display purposes I am creating a new table row when an item is created.
The <Form> tag is how you tell the browser "Put this stuff in the web request." That's how you get object binding in Spring. What is your reason for not using a Form? You don't necessarily have to put it in a form in the page, you could give your table elements IDs and fetch their contents in the javascript if you really needed to.
Edit: I think maybe it's hard to answer because it's not clear why you want the browser to give you back things that you gave it in the first place. Maybe what you really need is the #SessionAttributes() annotation on your controller so that you can preserve State of the original page shown to the user?
More Edit:
kk, see now. If what you want is Spring web data binding then create a form in parallel as you add more table rows. e.g.,
<form id="myObject" action="whateverYouNeedHere.htm" method="post">
<input type="hidden" id="items[0].name" name="items[0].name" value="foo"/>
<input type="hidden" id="items[0].value" name="items[0].value" value="bar"/>
<input type="hidden" id="items[0].setting" name="items[0].setting" value="buzz"/>
<input type="hidden" id="items[1].name" name="items[1].name" value="foo"/>
<input type="hidden" id="items[1].value" name="items[1].value" value="bar"/>
....
Then just submit that and it will bind right on for you. If you did mean to handle the content yourself, then you probably could use XHR as someone else mentioned.
Use the Spring Data Binding and Validation API to bind it into a Java object of your own design. That documentation is web-agnostic; check out the later chapter to see how the web tier leverages it.
You'll want an abstraction beyond a table, I presume.
in order to stick your table information into a java object, you will first need to send it to the server.. for that you will need to either send it via XHR or in a form.
in order to serialize the object you will need to write some javascript/jquery.
i could write it for you, but your requirements are somewhat vague when it comes to how your table will look, nor do i want to guess about what the java object you want to add your data to looks like.

Using Servlets and HTML

I have a doubt regarding the use of servlets.
In the application I'm building I use Html pages to ask the user for info.
Imagine a Html page that lets the user request to see on the screen the content of a data base. What I'm doing is:
1.- From the Html page I'm calling a servlet that will open a connection with the database.
2.- The servlet builds the web page that the user will see.
My question is: is there any other way of doing this? Do I have to build the web page in the servlet or is there any way of sending the information contained in the database to an .html file which will build the web page (in my case I need to show on the screen a table containing all the information) ?
Thanks
Servlets are meant to control, preprocess and/or postprocess requests, not to present the data. There the JSP is for as being a view technology providing a template to write HTML/CSS/JS in. You can control the page flow with help of taglibs like JSTL and access any scoped attributes using EL.
First create a SearchServlet and map it on an url-pattern of /search and implement doGet() and doPost() as follows:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Preprocess request here and finally send request to JSP for display.
request.getRequestDispatcher("/WEB-INF/search.jsp").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Postprocess request here. Get results from your DAO and store in request scope.
String search = request.getParameter("search");
List<Result> results = searchDAO.find(search);
request.setAttribute("results", results);
request.getRequestDispatcher("/WEB-INF/search.jsp").forward(request, response);
}
Here's how the JSP /WEB-INF/search.jsp would look like, it makes use of JSTL (just drop JAR in /WEB-INF/lib) to control the page flow.
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
...
<form action="search" method="post">
<input type="text" name="search">
<input type="submit" value="search">
</form>
<c:if test="${not empty results}">
<p>There are ${fn:length(results)} results.</p>
<table>
<c:forEach items="${results}" var="result">
<tr>
<td>${result.id}</td>
<td>${result.name}</td>
<td>${result.value}</td>
</tr>
</c:forEach>
</table>
</c:if>
Note that JSP is placed in /WEB-INF to prevent users from direct access by URL. They are forced to use the servlet for that by http://example.com/contextname/search.
To learn more about JSP/Servlets, I can recommend Marty Hall's Coreservlets.com tutorials. To learn more about the logic behind searchDAO, I can recommend this basic DAO tutorial.
To go a step further, you could always consider to make use of a MVC framework which is built on top of the Servlet API, such as Sun JSF, Apache Struts, Spring MVC, etcetera so that you basically end up with only Javabeans and JSP/XHTML files. The average MVC frameworks will take care about gathering request parameters, valitate/convert them, update Javabeans with those values, invoke some Javabean action method to process them, etcetera. This makes the servlet "superfluous" (which is however still used as being the core processor of the framework).
In addition to Servlets, Java has JSP pages, which are a mix of HTML and custom tags (including the Java Standard Tag Library or JSTL) which are eventually compiled into Servlets.
There are other technologies for making web applications, including things like Java Server Faces (JSF), Apache Struts, Spring, etc... Spring in particular is very widely used in modern web application development.
Ultimately, though, it's like Brian Agnew said... you have to communicate back and forth from the browser to the server. These are just various technologies to facilitate that.
Ultimately the browser has to send a request to the server for the database info. You can do this in many ways:
build the whole page in the servlet (perhaps the simplest)
build a page in the servlet containing (say) XML data, and the browser renders it into HTML (via XSL/Javascript etc.). That may be suitable if you want the browser to control the formatting and presentation.
build a page containing AJAX requests to go back to the server and get the data. That may be more suitable for data that updates regularly, or more interactive applications.
There are numerous ways to skin this cat. I suspect you're doing the simplest one, which is fine. I would tend towards this without explicit requirements that mean I need to do something else. Further requirements that complicate matters may include paging the data if there's too much to fit on the screen. All the solutions above can be made to incorporate this in some fashion.
My java is rusty but...
in your Data Access layer, iterate over the result set and build a custom object and insert it into an ArrayList;
class DataAccess {
public ArrayList foo() {
// Connect to DB
// Execute Query
// Populate resultSet
ArrayList result = new ArrayList();
while (resultSet.hasNext()) {
CustomObject o = new CustomObject();
o.setProperty1(resultSet.getInt(1));
o.setProperty2(resultSet.getString(2));
// and so on
result.add(o);
}
return result;
}
}
Call this method from your Servlet. After you have populated the ArrayList, put it on the Request object and forward on to your .jsp page
ArrayList results = DataAccessClass.foo();
Request.setAttribute("Results", results);
In your jsp, build your markup using scriptlets
<% foreach (CustomObject o in Request.getAttribute("Results"))
{%>
<td><%= o.getProperty1()</td>
<td><%= o.getProperty2()</td>
<% } %>
Good luck

Using HTML builders in grails instead of GSP

is there a way to use groovy builders to build JSP files in a Grails application keeping things enough integrated?
To explain better: by default Grails uses gsp files that are nice but quite verbose..
<div class="clear">
<ul id="nav">
<li><g:link controller="snippets" action="list">Snippets</g:link></li>
<li><g:link controller="users" action="list">Users</g:link></li>
<li><g:link controller="problems" action="list">Problems</g:link></li>
<li><g:link controller="messages" action="list">Messages</g:link></li>
</div>
<div id="content">
is there a way to use groovy.xml.MarkupBuilder tha would turn the previous piece into
div(class:'clear') {
ul(id:'nav') {
li { g_link(controller:'snippets', action:'list', 'Snippets') }
// and so on
Of course g_link is invented just to give the idea..
Do a search for builder under the web layer section of the grails user guide. There is an example in there that shows you exactly how to do this using the xml builder.
I don't have a complete answer for you, but I suspect the key will be gaining access to the "view resolvers". In a normal SpringMVC app, these are configured in views.properties (or views.xml) as follows:
csv=com.example.MyCSVResolver
xml=com.example.MyXMLResolver
audio=com.example.MySpeechResolver
In a regular SpringMVC app, you return something like new ModelAndView(myModel, 'csv') from a controller action.
This would cause the CSVResolver class to be invoked passing it the data in myModel. In addition to containing the data to be rendered, myModel would likely also contain some formatting options (e.g. column widths).
Spring searches the views file for a key matching the view name. If it doesn't find a match, by default it just renders a JSP with the view name and passes it the model data.
Now back to Grails....remember that Grails is really just a Groovy API over SpringMVC and most of the features of SpringMVC can be accessed from Grails. So if you can figure out how to modify the views file, just change your controller actions to return an appropriate ModelAndView instance, and it should work as described above.
GSP allows you to run arbitrary Groovy code inside <% %> brackets. So you can have something like this (borrowing example from page linked to by BlackTiger):
<% StringWriter w = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(w)
builder.html{
head{
title 'Log in'
}
body{
h1 'Hello'
builder.form{ }
}
}
out << w.toString()
%>
Note that the above calls g:form tag, and you can pass additional stuff to it.
So what you are asking for is certainly possible, though I am not sure if it will end up being a win. I'd suggest you perhaps look more at TagLibs in combination with Templates and SiteMesh Layouts - can definitely simplify things tremendously.

Categories