Exporting to Excel :JXLS
Posted by Sayan Guharoy
JXLS helps you format your report excel sheet with a template & a few lines of code.
1. First design a template with required formatting, coloring and other report specific changes. Below is a very basic template of employees.xls.
1. First design a template with required formatting, coloring and other report specific changes. Below is a very basic template of employees.xls.
2. Put this excel under C:\Report_ Export
3. Add the following jars in your class path
| Jxls-core-1.0.jar | Download |
| Poi-3.6-20091214.jar | Download |
| Commons-beanutils-1.7.0.jar | Download |
| poi-ooxml-3.6-20091214.jar | In POI Package |
Additional Jars
| commons-digester-2.1.jar | Download |
| commons-logging.jar | Download |
| Commons-jexl-2.1.1.jar | Download |
4. Write your java code The Export report method
//this method is getting called from ajax request servlet which extends http servlet I am passing servletContext here from my Ajax servlet
public String exportReport(String servletContext) {
Connection connection = null;
ResultSet rs = null;
//report drive will give me the drive letter where I will save my generated
Reports
String reportdrive=servletContext.substring(0, 2);
//I will overwriting the file if it exists ,if you want to retain all exported files use time stamp
String newfilename="report_output.xls";
//path for my template file name
String templateFileName =servletContext+"report-templates/envirowatch.xls";
//I will creating a folder under my reportdrive which is also my tomcat root drive
String desdirectry=reportdrive+"\\result_reports";
File f1 = new File(desdirectry2);
if (!f1.exists()) new File(desdirectry2).mkdir();
//path for my destination file, where I will placing my exported report
String destFileName = desdirectry+"\\"+newfilename;
try {
//below is a simple jdbc connection pattern where I will be connecting to my database & extract beans and to the Staff arraylist
Class.forName("oracle.jdbc.OracleDriver");
connection = DriverManager.getConnection("your connection string”);
PreparedStatement ps = null;
ps = connection.prepareStatement(DataManager.getQuery("your query"));
rs = ps.executeQuery();
List staff = new ArrayList();
while (rs.next()) {
// add your result set to employee beans
Employee bean123 = transformResultsBean(rs);
staff.add(bean123);
}
//finally I will add my array list of beans to resultReportbeans
Map beans = new HashMap();
beans.put("employee", staff);
//lets initiate jxls transformer
XLSTransformer transformer = new XLSTransformer();
//we will catch any exception if it fails to write the destination file
try{ transformer.transformXLS( templateFileName, beans, destFileName);}
catch (IOException e)
{ e.printStackTrace();
}
}//end of try
catch (SQLException e)
{
e.printStackTrace();
}
return newfilename;
}
Remember: Result report Beans which are used in the template xls uses property name of the result set beans. Be sure that the property exists in the employee bean.
It behaves very similar to JSTL.
public class Employee {
private String name;
private int age;
private Double payment;
private Double bonus;
private Date birthDate;
private Employee superior;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Double getPayment() {
return payment;
}
public void setPayment(Double payment) {
this.payment = payment;
}
}
5. Additionally if we want a hyperlink that will allow access of this report from client side browser we will create a url pattern in the servlet and a java class that will open the exported file copy the content and stream the content in the response, also we will set the response header mime type to xls so that browser recognizes it and give user a option to save or open the excel. Let write the java file first
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//our servlet will extend HttpServlet
public class MyServlet extends HttpServlet{
private static final int BYTES_DOWNLOAD = 1024;
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws IOException{
//set the content type as excel
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition",
"attachment;filename=downloadname.xls");
//we will get report drive same way we are doing while creating the report
ServletContext ctx = getServletContext();
String reportdrive=getServletContext().getRealPath("/").toString().substring(0, 2);
String desdirectry=reportdrive+"\\result_reports";
String newfilename="report_output.xls";
String destFileName = desdirectry+"\\"+newfilename;
FileInputStream fstream = new FileInputStream(destFileName2);
// Get the object of DataInputStream
DataInputStream is = new DataInputStream(fstream);
int read=0;
byte[] bytes = new byte[BYTES_DOWNLOAD];
OutputStream os = response.getOutputStream();
while((read = is.read(bytes))!= -1){
os.write(bytes, 0, read);
}
os.flush();
os.close();
}
}
Let’s add the URL pattern in Web xml.
<servlet> <servlet-name>ServletName</servlet-name> <servlet-class>com.osg.sqe.env.framework.control.web.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletName</servlet-name> <url-pattern>/DownloadDemo</url-pattern> </servlet-mapping>
Finally we will place a hyperlink to our html page to initiate the download
http://localhost:port/modulename/DownloadDemo
Few more points while designing your jxls template



Thanks much, very useful for me.
ReplyDeleteGlad to help you Jassu :)
ReplyDeleteMany Thanks... for the post and info on RFC
ReplyDeleteYou are welcome !
ReplyDeleteHi Sayan!
ReplyDeleteMany thanks for your post it very useful for the new beginner in report like me.But i have a little question, your code will work with huge data?I am trying with jasper, it running smothly with small or medium data but it alway get a trouble with huge data.The system running is alway out of memories.Have you give me some ideal with jExcel?
Thank and good luck!
Hi Lan Ta Bao,
ReplyDeleteThanks for dropping by.In one word i would say yes.I have implemented this techniques in an enterprise architecture and it worked out pretty well with around 2k records with 40 formatted columns to display.But again if your data exceeding more than mine,you should give jExcel a try!.Please share your experience here if you do that also :)
Hey, thanks for the post.
ReplyDeleteI'm having some trouble using the ResultsReportBean. Where is it? what do I have to import?
thanks in advance.
Hi Aeonphyxius,
ReplyDeleteThanks for pointing out.It should be Employee Bean.There will be no import needed.Hope i clarified your point.And your transformResultsBean will be function that will set your each employee bean and send back the bean to add up to the array list.
Like: bean.setName(rs.getString("ST_NAME"));
Please revert back in case of any difficulties you face.Good luck!
Excellent dude...Thank you ver much for this.. :)
ReplyDeleteYou are welcome!
ReplyDeleteHello
ReplyDeleteIm having this problem after trying to export the xml file:
log4j:WARN No appenders could be found for logger (net.sf.jxls.transformer.SheetTransformer).
log4j:WARN Please initialize the log4j system properly.
That is not an exception.
What can i do??
thanks
Hi,
ReplyDeleteThis is a Warning as you haven't set properly or have setted your log4j wrongly.My assumption, this is not the reason for your problem...log will help you to trace your error...but system console will work fine for you now to trace the error...look on the console for any exception and post back here....glad to help you :)
Hi
ReplyDeleteThank you for the nice turorial. I am having trouble with grouping data at two levels (e.g division , month). I can easily do it one level using this information http://jxls.sourceforge.net/reference/tags.html. I am not sure if there is any easy way to group collection at multiple level other than nested collection. http://jxls.sourceforge.net/samples/collectionsample.html.
I would appreciate any help.
Thank you.
Hi ,Sorry for late reply,if i am getting you correctly grouping multilple level is easy your main bean can a composition of different sub beans so
ReplyDeletetransformer.groupCollection("mainbean.division");
transformer.groupCollection("mainbean.month");
both the above statements are valid and can be read out in the excel like
${mainbean.division.name} division_name
Hope it helps,please come back if am not getting you correctly
Thank you Sayan for your response. I will give a shot. Is there any way to achieve this on template level? I have SQL in first forEach alongwith groupBy.
ReplyDeleteCurrently I have following in template:
${employee.division_id} ${employee.month} ${employee.lname} ${employee.fname} ${employee.cost}
Division: ${group.item.division_id} Total: $[SUM(E6)]
Hello, I noticed, it did not publish my complete code in my previous post. I am posting it again. I am sorry for duplicate post. Here grouping by division, I want to add month grouping inside each division.
ReplyDeleteThanks again for your help.
<jx:forEach items="${rm.exec("SELECT month , division_id, lname , fname, id, COST FROM testtable ORDER BY division_id, month, lname" ) }" groupBy="division_id">
<jx:outline>
<jx:forEach items="${group.items}" var="employee">
${employee.division_id} ${employee.month} ${employee.lname} ${employee.fname} ${employee.cost}
</jx:forEach>
</jx:outline>
Division: ${group.item.division_id} Total: $[SUM(E6)]
</jx:forEach>
Hi,I guess it will be something like this
ReplyDelete<jx:forEach items="${rm.exec('SELECT distinct d.division_id FROM testtable d')}" var="div">
Division: ${div.division_id}
<jx:forEach items="${rm.exec('SELECT month , lname, fname, cost FROM testtable e where e.divid = ' + div.division_id)}" var="employee">
${employee.month} | ${employee.lname} | ${employee.fname} | ${employee.cost}
</jx:forEach>
</jx:forEach>