Upload multiple files in Spring MVC 3

It was just another long day at office with the database not available and one of the team members lagging by a week now. So, we had to work as a team to get it delivered. In Spring 3, it looked straight forward to upload a file. However, there was little help on offer, to upload multiple files from a jsp file.

There are three basic things which need to be done to upload multiple files are:

a) The JSP needs to have the input[file] elements passed as an array.

<td><input name="fileData[0]" id="image0" type="file" /></td>
<td><input name="fileData[1]" id="image1" type="file" /></td>

b) The ModelAttribute/Model object in Spring MVC needs to have a list of MultipartFile.

import java.util.List;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
public class UploadItem {
     private String filename;
     private List<CommonsMultipartFile> fileData;

c) Configure Multipart Resolver bean in dispatcher-servlet.xml[applicationContext-servlet.xml]

<!-- Configure the multipart resolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>

d) Logic to read the files from the Model and store it in a file location in the Controller layer.

@RequestMapping(method = RequestMethod.POST)
public String create(UploadItem uploadItem, BindingResult result,
HttpServletRequest request, HttpServletResponse response,
HttpSession session) {
if (result.hasErrors()) {
for (ObjectError error : result.getAllErrors()) {
System.err.println("Error: " + error.getCode() + " - "
+ error.getDefaultMessage());
}
return "/uploadfile";
}
// Some type of file processing...
System.err.println("-------------------------------------------");
try {
for(MultipartFile file:uploadItem.getFileData()){
String fileName = null;
InputStream inputStream = null;
OutputStream outputStream = null;
if (file.getSize() > 0) {
inputStream = file.getInputStream();
if (file.getSize() > 20000) {
System.out.println("File Size exceeded:::" + file.getSize());
return "/uploadfile";
}
System.out.println("size::" + file.getSize());
fileName = request.getRealPath("") + "/images/"
+ file.getOriginalFilename();
outputStream = new FileOutputStream(fileName);
System.out.println("fileName:" + file.getOriginalFilename());
int readBytes = 0;
byte[] buffer = new byte[10000];
while ((readBytes = inputStream.read(buffer, 0, 10000)) != -1) {
outputStream.write(buffer, 0, readBytes);
}
outputStream.close();
inputStream.close();
// ..........................................
session.setAttribute("uploadFile", file.getOriginalFilename());
}
//MultipartFile file = uploadItem.getFileData();
}
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/forms/uploadfileindex";
}

I have extended the example which is found @ RoseIndia to dynamically create the file nodes and post them to the Controller.

Just download the source-code and replace the below jsp file and make other necessary changes:

Upload.jsp

<%@page contentType="text/html;charset=UTF-8"%>
<%@page pageEncoding="UTF-8"%>
<%@ page session="false"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<html>
<head>
<META http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Upload Example</title>
<script language="JavaScript">
var count=0;
function add(type) {
//Create an input type dynamically.
var table = document.getElementById("fileUploadTable");
var tr = document.createElement("tr");
var td = document.createElement("td");
var element = document.createElement("input");

//Assign different attributes to the element.
element.setAttribute("type", "file");
element.setAttribute("value", "");
element.setAttribute("name", "fileData["+type+"]");
//Append the element in page (in span).
td.appendChild(element);
tr.appendChild(td);
table.appendChild(tr);
}
function Validate()
{
var image =document.getElementById("image").value;
if(image!=''){
var checkimg = image.toLowerCase();
if (!checkimg.match(/(\.jpg|\.png|\.JPG|\.PNG|\.jpeg|\.JPEG)$/)){
alert("Please enter Image File Extensions .jpg,.png,.jpeg");
document.getElementById("image").focus();
return false;
}
}
return true;
}

</script>
</head>
<body>
<form:form modelAttribute="uploadItem" name="frm" method="post"
enctype="multipart/form-data" onSubmit="return Validate();">
<fieldset><legend>Upload File</legend>
<table >
<tr>
<input type="button" name="Add Image" onclick="add(count++)" value="Add Image"/>
</tr>
<tr>
<table id="fileUploadTable">
<!--td><form:label for="fileData" path="fileData">File</form:label><br />
</td>
<td><input name="fileData[0]" id="image0" type="file" /></td>
<td><input name="fileData[1]" id="image1" type="file" /></td-->
</table>
</tr>
<tr>
<td><br />
</td>
<td><input type="submit" value="Upload" /></td>
</tr>
</table>
</fieldset>
</form:form>
</body>
</html>

UploadItem.java

Generate getter and setter methods for the private List fileData;

UploadFileController.java

Just copy and paste the create(…) mentioned in the blog above.

Note: If you are still facing issue with file upload in Spring MVC, please add a MultipartFilter. Refer here.

<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/springrest/*</url-pattern>
</filter-mapping>
<bean id="filterMultipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>10000000</value>
</property>
</bean>
Advertisements

Proxy objects in Spring are not evil

Firstly, let me give some back-ground about Spring Transaction Management. Spring uses Proxies for transaction management and these proxies are JDK dynamic proxies. However, Spring uses CGLIB proxies when a bean class doesn’t implement an interface. A point to note, proxy as such delegates control to a transaction manager to manage transactions.

To understand how proxies are used in Spring, refer to Micheal Isvy’s blog.

A month ago, i was discussing with a colleague about the performance problems with proxying which is used left, right and center in Spring’s transaction management and other features. As i am a strong supporter of Spring, i couldn’t agree but at the same time couldn’t disagree with him. However, i am ready to take a stand now:

a. Proxies do add a performance over-head. A direct call to a method in target object always takes less time than a call through a proxy object.  However, it is negligible compared to the benefits we reap out of a ready-to-use features without having to worry about writing code to do it.

b. The advice above, needs to be taken with a pinch of salt, though. Too much proxying results in performance problems. A better solution in such a situation would be to perform byte code weaving using AspectJ. This is achieved by using JavaAgent.

Courtesy: Alef Arendenson

 

Effective Logging in Java/JEE

It all started when i was sitting with a colleague to resolve some application issue, when i noticed something interesting. He was merging the code and my eyes caught the attention of this class “org.apache.log4j.MDC”. This led to few discoveries on the way which  follow here:

What is MDC?

MDC stands for Mapped Diagnostic Context. It helps you to distinguish inter-leaving logs from multiple sources. Let me explain in detail. When we have multiple user-requests coming in for a given servlet, each request of an user is serviced using a thread. This leaves multiple users logging to the same log file and the log statements get inter-mixed. Now, to filter out logs of a particular user, we need to append the user-id to the log statements so that we can grep(search) them in the log file, to make some sense of it.

An obvious way of logging, is to append the user-id in the log statements i.e. log.info(userId+” logged something “);

A non-invasive way of logging is to use MDC. With MDC, you put the user-id in a context-map which is attached to the thread (of each user request) by the logger.

MDC is thread-safe and uses a Map internally to store the context information.[Courtesy : Kalyan Dabburi]

How to use MDC?

a. Configure the information, which needs to be logged (user-id in this case) in the log4j.xml as part of ConversionPattern.

log4j.appender.consoleAppender.layout.ConversionPattern 
= %d %i - %m - %X{user-id}%n

b. In your respective class, before you start processing the user request, place the actual user-id in the context(MDC).

MDC.put("user-id","SKRS786");

c. Remove the context information from MDC at the end of the processing.

MDC.remove("user-id");

References :

Logback implementation

Log4J implementation

 

What is NDC ? Which one to use MDC or NDC?

NDC stands for Nested Diagnostic Context. It is a stack-based implementation of attaching context information. For all purposes, use MDC over NDC, as MDC is memory efficient. For a detailed comparison, click here.

Which logging framework to use? Log4J or SLF4J or logback?

For all new application development, use logback. logback is a run-time implementation of SLF4J. If you have an existing application with Log4J, it is still worth-while to switch to logback. For a detailed explanation, click here.

To understand the evolution of logging in Java and JEE world, refer to this article by Micheal Andrews.

 

Dynamically Changing JBoss Ports

Changing Http Port:

Add the required http port to ${jboss}/server/default/deploy/jbossweb.sar/server.xml in the the following element:

Changing JNDI and RMI Port:

  • Add the correct port to your ${jboss}/server/default/conf/jndi.properties (see above). The entry might look like java.naming.provider.url=jnp://myhost:1199.
  • Change the settings in ${jboss}/server/default/conf/jboss-service.xml: Find the entry for mbean code=”org.jboss.naming.NamingService” and change the attributes Port and RmiPort to the appropriate.

Dynamically Changing the Http/JNDI/RMI Port:

When two JBoss servers are running on one physical machine, you can dynamically change the Http/JNDI/RMI Ports by executing the following command during server start-up in JBoss bin folder:

nohup ./run.sh -c SERVER_NAME -b 0.0.0.0 -Djboss.service.binding.set=ports-02 -Dconfiguration.url=CONFIG_FOLDER

The above command increments the port numbers by +200 i.e. 8080 becomes 8280 , 1099 becomes 1299, etc

SERVER_NAME=myserver
CONFIG_FOLDER=file:///home/user/softwares/jboss/server/myserver/conf/my-config

nohup generates the nohup.out file in the same jboss bin folder where we need to execute the above command

Note: Default JBoss Http port=8080, JNDI port=1099, RMI port=1098, AJP port=8009

Courtesy: JFire

Communicating between a JSP and Flex application

As part of Flex development, we had designed our UI in such a way that, there was a Main Action class which used to re-direct to Main.jsp. In this JSP, we had included the SWF file in Object tag which would load the Flex application for us. We had a requirement to pass the user-details to the Flex application from this very JSP rather than making an explicit call from Flex. In addition, we also had a requirement to set this data globally to all the Flex screens. We achieved this by following the below steps:

a) Set the User details in HttpSession or HttpRequest as an attribute or header variable
b) Make use of “FlashVars” attribute in Flash and set the parameters in the Main.jsp in a Java-Script block as shown below:

var userName= '';
var flashvars = 'userName='+userName;

c) Include flashVars while embedding the Flash Content SWF


AC_FL_RunContent(
"src", "MyApplication",
"width", "100%",
"height", "100%",
"align", "middle",
"id", "MyApplicationId",
"quality", "high",
"bgcolor", "#869ca7",
"name", "MyApplicationName",
"allowScriptAccess","sameDomain",
"type", "application/x-shockwave-flash",
"pluginspage", "http://www.adobe.com/go/getflashplayer",
"FlashVars", flashvars
);

d) Include it in the Object Tag of the JSP page under tag


<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
			id="MyApplicationId" width="100%" height="100%"
			codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
			<param name="movie" value="MyApplication.swf" />
			<param name="quality" value="high" />
			<param name="bgcolor" value="#869ca7" />
			<param name="allowScriptAccess" value="sameDomain" />
			<param name="FlashVars" value="" />
			embed src="MyApplication.swf" quality="high" bgcolor="#869ca7"
				width="100%" height="100%" name="MyApplicationName" align="middle"
				FlashVars=""
				play="true"
				loop="false"
				quality="high"
				allowScriptAccess="sameDomain"
				type="application/x-shockwave-flash"
				pluginspage="http://www.adobe.com/go/getflashplayer"
			embed
</object>

e) Access the ‘FlashVars’ in mxml file as shown below in the Header.mxml:


<s:Label text="{FlexGlobals.topLevelApplication.parameters.userName}, {resourceManager.getString('resources','Welcome')}"/>

f) Finally, dont forget to include the import statement in the Header.mxml

import mx.core.FlexGlobals

Using “varStatus” in JSTL

Recently, there was a requirement to display a list of entries(key,value) of a Map separated by comma in a JSP. An effective way of doing it is by using JSTL’s “c:forEach” tag and its attribute “varStatus” to iterate through the key-value pairs. The code is as follows:


(<c:foreach var="entry" items="${criticalityMap}" varstatus="status">
  <bean:message key="arhat.asset.criticality.${entry.key}"></bean:message> : ${entry.value}
  ${not status.last ? ',' : ''}
</c:foreach>)

Output:
( Low : 1 , Medium : 1 , High : 2 , Most Critical : 1 )

Courtesy:

Andrew Beacock’s blog

P.S. : There was a problem while pasting the above piece of code into the blog, which could be resolved again by an elegant solution by Greg Houston. Even this pointer, i had picked up from Andrew Beacock.