extending spring form tag library attributes - spring

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).

Related

How to remove Public render parameter from jsp or render phase of portlet class

I have two portlets :
1. Blog Portlet.
2. Author Portlet.
I used the concept of Public render parameter to send data (say key "urlTitle") from Blog portlet to Author portlet
But after sending "urlTitle" from Blog portlet how can I remove the data from Public render parameter
In Blog Portlet
EX code: view.jsp
<portlet:renderURL var="viewEntryURL">
<portlet:param name="struts_action" value="/blogs/view_entry" />
<portlet:param name="redirect" value="<%= currentURL %>" />
<portlet:param name="urlTitle" value="<%= entry.getUrlTitle() %>" />
</portlet:renderURL>
Send Data
Now how I can remove "urlTitle" form the public render parameter after data is sent.
Please give feedback.
-Thanks in advance
You could think about the following:
The LiferayPortletURL (the class that models portlet render, action and resource URLs tags) offers a method called setCopyCurrentRenderParameters
https://docs.liferay.com/portal/6.2/javadocs/com/liferay/portal/kernel/portlet/LiferayPortletURL.html#setCopyCurrentRenderParameters(boolean)
which when set to false, avoids copying render parameters, and the URLs are "cleaned" from those.
The caveat with this is that you would need to create a LiferayPortletURL in the back end doing the following:
LiferayPortletURL renderUrl = PortletURLFactoryUtil.create(
httpServletRequest,
themeDisplay.getPortletDisplay().getId(),
themeDisplay.getPlid(),
PortletRequest.RENDER_PHASE);
renderUrl.setCopyCurrentRenderParameters(false);
and after that pass it to your JSP set as an attribute (maybe renderRequest.setAttribute("renderUrl",renderUrl)?). I haven't done this for render URLs, but for resource URLs and it works!
You need to set
javax.portlet.init-param.copy-request-parameters=false
in your portlet class.

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>

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.

Proccess HTML tags to Spring MVC View

I'm currently struggling with the following problem. In my Spring web application I have different content types (e.g. text, images or code). Depending on the content type I need to display it in different ways:
text: <p>some text</p>
image: <img src="path/to/my.img" />
code <pre>some code</pre>
The HTML tags should be concatened to the actual content. The problem is, if I simply build the output text in my Java class, the HTML tags won't be resolved in my view, so that <p>some text</p> will be displayed.
Is it somehow possible that the HTML tags can be resolved in my view?
If it's just the escaping part that is the problem, use:
<c:out value="${model.snippets.html12}" escapeXml="false" />
(I am assuming your HTML string is in the model.snippets.html12).
Of course, the whole idea is bad. I am not affiliated with the MVC Police, but what is the point of using a MVC framework if you feel that it's a good idea to generate HTML inside your controller and pass it, as a string - into a view? From my point of view it's a bit of a schizophrenia.
You can save a lot of sanity by just rendering the whole thing in a switch, inside the template. I mean like:
<c:choose>
<c:when test="${thing.type == 'CODE'}">
<div> some code: ${thing.content} </div>
</c:when>
<c:when test="${thing.type == 'IMAGE'}">
<img src="${thing.src}" alt="${thing.whatever}" />
</c:when>
<!-- some other choices -->
</c:choose>
Even better, create a simple tag file that will let you reuse the logic anywhere you need it.
Or ditch MVC - be honest.
If you do have jquery, set the content type in your model. Set it to the HTML.
<input type = hidden id = contentType value = "${yourmodel.contentType}"
Add span to your elements
<span id = "textspan" style = "display:none"><p>some text</p></span>
<span id = "imgspan><img src="path/to/my.img" /></span>
<span id = "codespan><pre>some code</pre></span>
write a jquery
if($("contentType").val() == text){
$("#textspan").show();
}else if($("contentType").val() == img){
$("#imgspan").show();
}else{
$("#codespan").show();
}

populate one dropdown on selection of other using struts2 dojo tags

I have two dropdowns. I want to populate the second dropdown on selection of first dropdown.
I am using struts-dojo-tags for accomplishing this.
<%# page contentType="text/html; charset=UTF-8"%>
<%# taglib prefix="s" uri="/struts-tags"%>
<%# taglib prefix="sx" uri="/struts-dojo-tags"%>
<html>
<head>
<title>Welcome</title>
<script>
</script>
<sx:head />
</head>
<body>
<h2>Struts 2 + Ajax Example 2!</h2>
<s:form name="f1">
<s:textfield name="proj" label="Project Name" />
<s:url id="url" value="/populateStates.action" />
<s:select id="id1" list="countryList"
listKey="countryId" listValue="countryName" headerKey="0"
headerValue="-Select-" label="Country"/>
<s:select id="id2" list="list2" listKey="stateId"
listValue="stateName" headerKey="0" headerValue="-Select-"
label="State" />
<sx:bind sources="id1" targets="id2" events="onchange"
href="%{#url}" />
</s:form>
<br>
</body>
</html>
My action class has two action methods.
public String populateCountry() throws Exception{
list1 = new ArrayList<Country>();
list1.add(new Country(1, "Country1"));
list1.add(new Country(2, "Country2"));
list1.add(new Country(3, "Country3"));
return SUCCESS;
}
public String populateStates() throws Exception{
System.out.println("populateStates******************"+id1);
list2 = new ArrayList<State>();
if (id1 != null && !id1.equals(""))
{
if(id1.equals("1"))
{
list2.add(new State(1, "UMB1"));
list2.add(new State(2, "UMB2"));
list2.add(new State(3, "UMB3"));
}
else if(id1.equals("2"))
{
list2.add(new State(4, "UMB4"));
list2.add(new State(5, "UMB5"));
list2.add(new State(6, "UMB6"));
}
else if(id1.equals("3"))
{
list2.add(new State(7, "UMB7"));
list2.add(new State(8, "UMB8"));
list2.add(new State(9, "UMB9"));
}
}
return SUCCESS;
}
First action method is called when the jsp is loaded the first time (with populated Country drop down) and second action method is called when I select a country from the Country dropdown.
Problem: States drop down is not getting populated. When I debug the code, I see that when control reaches populateStates all the variables of my Action class are reset(id1, id2, list1, list2, proj). Due to which I get an empty States dropdown. Please help me to solve this issue.
I don't think <sx:bind> does what you think it does; the target's HTML will be replaced by what the action returns.
You could try returning just the list of <option>s (and perhaps that's what you're doing), but I don't believe it would work. (If it does, definitely follow up with your own answer.)
I'd actually recommend using the jQuery plugin; the Dojo tags have been deprecated for some time, use a very outdated version of Dojo, and often a pain to work with.
Another option would be to just use plain old jQuery (or library of your choice)--it's almost always easier than implementing custom functionality via a tag library. The Ajax tag libraries are great for really simple usecases, but as soon as there's anything custom, I'm not convinced they save much effort. YMMV.

Resources