Spring Model Attribute overriding the Session Attribute with same name - spring

I am very new to Spring world and trying a few things related to Spring MVC and session handling.
my question is that if we have Model Attribute and session attribute of same name then does the Model Attribute overrides the value of session attribute ?
In code snippet below (apologies for poor formatting, I am new here) I am adding an attribute names sessionAttribute into Model and Session. While accessing the same attribute in JSP I am getting value of Model Attribute ([name] as Model Attribute ).
#RequestMapping(value="/hello", method=RequestMethod.GET)
public String hello(#RequestParam(value="username", required=false,defaultValue="World") String name, Model model,HttpServletRequest req) {
model.addAttribute("sessionAttribute", name+" as Model Attribute");
System.out.println("In controller");
HttpSession hs=req.getSession();
hs.setAttribute("sessionAttribute","overridden Session attribute"); //prints"overridden Session attribute"
System.out.println(hs.getAttribute("sessionAttribute"));
return "someViewName";
}
Below is the View (someViewName) and it is printing the value of sessionAttribute as Model attribute
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring4 MVC -HelloWorld</title>
</head>
<body>
<% HttpSession hs=request.getSession();
String sesstionAttr=(String)session.getAttribute("sessionAttribute");
out.println(sesstionAttr); //printin [name] as Model Attribute
%>
</body>
</html>

my question is that if we have Model Attribute and session attribute
of same name then does the Model Attribute overrides the value of
session attribute ?
In general, model and session are different things, therefore model attributes and session attributes are different. Model attributes are referring to the model properties (which you have in your view), and session attributes are stored in http session, so that if you add one attribute in session in one controller and then change a view, you can still access added attribute in another one.
So if you are inside of your controller method, adding the session attribute into session will not override the value in model attribute.
However, this may happen in one case - if you are using #SessionAttributes provided by Spring exactly for this reason.
When using #SessionAttributes after your method execution will be finished, Spring will load all attributes from your model, and add them into the session (so that if you have the same name it will be overridden). And next time you try to access the attribute from the session - you will see overridden value from model.
For me it looks like this is happening in your case. However I do not how you have configured your controller, so check if you have specified
SessionAttributes or not.

Related

Bind a form object to a ModelAttribute with a prefix?

I have a legacy application that contains lots of forms from a previous framework that required a prefix for the entity. For example, an Item object with a name would have a form field of:
<input name="item.name" ... />
In my spring controller, I use a ModelAttribute as normal:
#ModelAttribute Item item
But the binding fails because spring does not expect the prefix for the item. Is there some way I can tell spring to ignore the prefix and bind without having to create a wrapper object or having to change the prefix from every form field?
If you are using jsp as your view, you will also need to add modelAttribute in your form as well, and make sure that you have declared getters for your form fields in Item object. Ex: getName()
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form id="new-item-form"
method="post"
modelAttribute="item" ...>
<input name="item.name" ... />
</form:form>
If you're using Thymeleaf , then you have to add its XML namespace to your html, and then you can access model attributes in views with Thymeleaf using Spring EL as follows:
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
...
<p th:text="${item.name}">Name</p>
...
</html>

<form:form have method GET or POST

This may be a very basic question but I am confused. I have couple of doubts:
In spring form <form:form if method is not specified then is it GET or POST?
If a spring form has <form:form with commandName then is that GET or POST?
The second question is because I see a "form:form commandName=xyz action=abc" in the code
When I check the HTML code (view source) it translates to
"form action=abc method=POST"
Please help me with this.
HTML form without specified action is always GET. It's HTML standard.
http://www.w3.org/TR/html401/interact/forms.html#h-17.3
But when you look inside FormTag in Spring source you'll notice this code:
public class FormTag extends AbstractHtmlElementTag {
/** The default HTTP method using which form values are sent to the server: "post" */
private static final String DEFAULT_METHOD = "post";
So for spring tag <form:form action is post by default.
commandName is just name for model attribute binded with your form. It has nothing to method type. Moreover, it's equivalent to modelAttribute so you can use either.
Spring form has default method as POST. If you want to do the get, you have to write, method="get" in form:form tag.

Java - modelandview in modelandview

How can I addObject to modelandview with modelandview parameter? I mean something like that:
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
ModelAndView m = new ModelAndView();
m.addObject("test", t, '1');
mav.addObject("site", m);
I mean I have a index file witch I deal like a template and I want to parse it to other file (template)
My second question:
Is this good solution? If not, please tell me what is preffered:)
Sorry, I'm new to Java EE and Spring
edit: source code
ModelAndView is just a container used by Spring's MVC request handling. Every object you add to ModelAndView will be added as request attribute (request#setAttribute) and then available within your JSP.
Nesting ModelAndView does not make any sense. You can just forward the request from your JSP file and all the model attributes will be still set on the request and available.
Regarding your approach:
I would say that having template JSP (such as your index) can be used. I personally prefer having TAG file with layout and then JSP files being enclosed within this layout.
<%# tag language="java" description="Content border for layout decoration." trimDirectiveWhitespaces="true" %>
<!DOCTYPE html>
<html lang="cs">
<head profile="http://www.w3.org/2005/10/profile">
<meta charset="utf-8" />
</head>
<body>
<div class="pageContent">
<jsp:doBody />
</div>
</body>
</html>
-
<%# include file="/WEB-INF/taglib.jspf"%>
<layout:admin>
THIS IS MY CONTENT
</layout:admin>
Alternatively you can use templating engine such as Apache Tiles.

request.getParameter() returns null

Got a homework assignment that is giving me problems.... Its modifying a JSF project with two pages and a bean to fit MVC2 by adding two more pages and a controller servlet and another bean for the two additional pages. the new main page forwards to either the second new page or the old first page. My issue is response.getParameter() always results in null.
<%#page session="false" import="java.util.Iterator"%>
<%#taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%#taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<jsp:useBean id="status" scope="request" class="JSFRegistration.Status" />
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>JSP Page</title>
</head>
<body>
<% if (status!=null && !status.isSuccessful()){%>
<font color="red">Processing errors:
<ul><%Iterator errors=status.getExceptions();
while (errors.hasNext()){
Exception e = (Exception) errors.next();%>
<li><%= e.getMessage()%><%}%></ul></font><%}%>
<form action="LoginServlet" method="POST">
<% String username = request.getParameter("username");
if (username==null) username="";%>
<input type="text" name="usernameTF" value="<%=username%>" />
<% String password = request.getParameter("password");
if (password==null) password="";%>
<input type="password" name="passwordTF" value="<%=password%>" />
<input type="submit" value="Login" />
</form>
</body>
</html>
this is basically a direct copy from our book but the fields I need for the new main page. Same for the controller servlet, a direct copy except only contains the fields I need.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher view = null;
Status status = new Status();
request.setAttribute("status", status);
String username = request.getParameter("username");
String password = request.getParameter("password");
if (username==null || username.length()==0)
status.addException(new Exception("Please enter username"));
if (password==null)
status.addException(new Exception("Please enter password"));
if (!status.isSuccessful()){
view = request.getRequestDispatcher("Login.jsp");
//view.forward(request, response);
}
else
try{
request.setAttribute("username", username);
request.setAttribute("password", password);
view = request.getRequestDispatcher("Registration.jsp");
} catch (Exception e) {
status.addException(new Exception("Error"));
view = request.getRequestDispatcher("Login.jsp");
}
view.forward(request, response);
}
and the Status class, again a direct copy from the book.
public class Status {
private ArrayList exceptions;
public Status(){
exceptions = new ArrayList();
}
public void addException(Exception exception) {
exceptions.add(exception);
}
public boolean isSuccessful(){
return (exceptions.isEmpty());
}
public Iterator getExceptions(){
return exceptions.iterator();
}
regardless of what is typed into the two boxes, stepping through a debug shows the values not getting passed to the parameters. I get the created exceptions printed above the screen for both fields if both have text, if only one has text and when both are empty.
Your request parameter names do not match the input field names. You've assigned the input fields a name of usernameTF and passwordTF. They are then available by exactly those names as request parameter, but you're attempting to get them using the names username and password. So you need either to fix the input field names, or the request parameter names so that they match each other.
By the way, why falling back from a modern MVC framework like JSF to awkward 90's style JSP with mingled business code? Is that really what the homework assignment is asking you? Also the HTML <font> element is deprecated since 1998. Where did you learn about it? Is the quality of the course really good?

extending spring form tag library attributes

I'm using Spring's form tag library in a Spring MVC application that I am developing. The company I am working for has implemented some company-wide policies based on the definition of custom attributes for certain tags. For instance, by default (though the inclusion of a standard javascript file) all tags have their values automatically converted to upper case. In order to disable this one would define their tag with a custom attribute in the following way:
<input type="text" uppercase="false" />
The problem is that the addition of these custom attributes to a spring:form tag causes an error at runtime. I've pasted the error below.
org.apache.jasper.JasperException: /WEB-INF/jsp/reportCriteria.jsp(45,5) Attribute uppercase invalid for tag input according to TLD
My question is: is there any way to extend the TLD to allow for these attributes, or is there any other way add these custom attributes to these spring:form tags?
Ok, 2 years later... here we go!
HOW TO CREATE OUR OWN TAG EXTENDING CLASSIC ONE WITH NEW ATTRIBUTES IN SPRING MVC 3
1. Create your own taglib.tld
You need to create your own TLD file. There you are going to add the new attribute you are going to use. The best option is copy/paste spring-form.tld. You can find it in spring-mvc package (org.springframework.web.servlet-.jar).Search in META-INF folder.
Feel free to put it directly inside WEB-INF or in a subfolder. I putted it in /WEB-INF/tld.
Now search inside your new TLD file for the tag you are going to modify. I modified input tag, so i had to search for:
...
<tag>
<description>Renders an HTML 'input' tag with type 'text' using the bound value.</description>
<name>input</name>
<tag-class>org.domain.tags.CustomTags</tag-class>
<body-content>empty</body-content>
<attribute>
...
Copy from to and paste it below. Change the of the new tag for your own name. Mine was myInput. So now we have this:
...
<tag>
<description>Renders an HTML 'input' tag with type 'text' using the bound value.</description>
<name>input</name>
<tag-class>org.springframework.web.servlet.tags.form.InputTag</tag-class>
<body-content>empty</body-content>
<attribute>
...
</tag>
<tag>
<description>Renders an HTML 'input' tag with type 'text' using the bound value.</description>
<name>myInput</name>
<tag-class>org.domain.tags.CustomTags</tag-class>
<body-content>empty</body-content>
<attribute>
...
</tag>
SUMMARY: now I have a new file called taglib.tld here: /WEB-INF/tld/taglib.tld. Pay attention to the <tag-class> part
In your own new tag add a new attribute (copy/paste another one) call render.
<attribute>
<description>Enables/Disables the field rendering</description>
<name>render</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Boolean</type>
</attribute>
Now we have created the taglib file we need. Let's see how to use it.
2. Create your own handler
Now we are going to create the class that will handle the new attribute (and the classic ones). I created the class CustomTags.java en el paquete org.domain.tags. Let's see first the code and explain it:
package org.domain.tags;
import javax.servlet.jsp.JspException;
import org.springframework.web.servlet.tags.form.InputTag;
import org.springframework.web.servlet.tags.form.TagWriter;
public class CustomTags extends InputTag {
private static final long serialVersionUID = 1L;
private boolean render;
public boolean isRender() {
return render;
}
public void setRender(boolean render) {
this.render = render;
}
protected int writeTagContent(TagWriter tagWriter) throws JspException {
if(render){
super.writeTagContent(tagWriter);
return SKIP_BODY;
}
else
return SKIP_BODY;
}
}
Of course, if we are going to add some features to the Input tag of Spring framework, we must extend it in order to mantain the rest of the features. As you can see, we have just added the render private attribute as boolean (in taglib.tld we also put it).
We have added to the getter and setter methods for this attribute.
Finally we have overwrite the writeTagContent method in order to make the JSP do what we want. In this case we want the input field to be shown if render is true. Otherwise the field can't be shown. That's why we call the writeTagContent of the parent class.
If we need to make some changes on the tag behaviour, this method is the right place to do them.
3. Using the new tag.
Now we only need a JSP with a form to use the new tag. It's easy to do, so i only let here the code:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib prefix = "newtags" uri = "/WEB-INF/tld/taglib.tld" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring 3.0 MVC Series: Welcome World</title>
</head>
<body>
<h1>User Data</h1>
Please, fill the fields with your information:<br>
<newtags:form name="userForm" id="userForm" modelAttribute="userForm" action="user.htm" method="POST">
Name: <newtags:myInput type="text" name="textName" path="userName" render="true" size="50" /><newtags:errors path="userName" /><br>
Surname: <newtags:myInput type="text" name="textSurname" path="userSurname" render="true" size="50" /><newtags:errors path="userSurname" /><br>
Age: <newtags:myInput type="text" name="textAge" path="userAge" render="true" size="2" /><newtags:errors path="userAge" /><br>
Example: <newtags:myInput type="text" name="textSurname" render="false" size="20" path="userSurname"/>
<hr>
<input type="submit" value="Next" />
</newtags:form>
</body>
</html>
Now instead of calling springframework tld, we call our own TLD. As you can see the only field that is not going to be shown is Example one.
Good Luck all!
It's implemented in Spring 3.0 (SPR-5931).

Resources