สร้างไฟล์ Excel ด้วย JSP

“สุดยอด Framework คือการไม่มี Framework”
โพสต์นี้ผมจะพาทำ Function export ข้อมูลเป็น Excel แบบเกรียนๆ โดยไม่ต้องง้อ Framework พวก Apache POI หรือ jxls ไม่ต้องไปศึกษาให้เสียเวลา

สิ่งที่ต้องเตรียมก็แค่ Web App แค่ Servlet/JSP ธรรมดาๆ ก็ใช้งานได้ แต่พอดีผมกำลังหัด Spring Framework อยู่ก็เลยขอเอามาใช้ไปก่อน เพราะจุดหลักไม่ได้อยู่ที่ Spring มันอยู่ที่ JSP ผลลัพธ์

ที่มา


เนื่องจากผมไม่สามารถหาวิธีการทำ dynamic merge cell ด้วย jxls ได้ อารมณ์ประมาณนี้ http://stackoverflow.com/questions/15921752/how-to-merge-cells-dynamically-in-jxls-api-in-transformed-template พอคิดว่าต้องลงมือเขียน apache poi ก็ลำบากเกินไป พอดีไปเจอน้องที่กำลังทำ view ด้วย excel ก็เลยได้ idea นี้มา

เครื่องมือ


  • Eclipse
  • Spring MVC หรือ Servlet/JSP ก็ได้

ลงมือ


เนื่องจากผมใช้ spring mvc แต่ผมจะไม่พา setup spring mvc แล้วนะครับ เนื่องจากในบล็อกนี้มีเยอะแล้ว

  1. สร้างไฟล์ jsp ที่มีปุ่ม submit ไว้ export excel ดังนี้
    <%@ page language="java" contentType="text/html; charset=US-ASCII"
    	pageEncoding="US-ASCII"%>
    <!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=US-ASCII">
    <title>Export Excel</title>
    </head>
    <body>
    	<form action="excel" method="post">
    		<input type="submit" value="Export" />
    	</form>
    </body>
    </html>
    
  2. หน้า jsp สำหรับไว้สร้างไฟล์ Excel ดังนี้ ซึ่งพระเอกของงานนี้ก็คือบรรทัดที่ 7-9 ซึ่งเป็นการเปลี่ยนค่า content-type ให้เป็น excel แล้วตั้งชื่อไฟล์ในค่า filename

    <%@ page language="java" contentType="text/html; charset=US-ASCII"
    	pageEncoding="US-ASCII"%>
    
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    
    <%
    	response.setContentType("application/vnd.ms-excel");
    	response.setHeader("Content-Disposition", "inline; filename="
    			+ request.getAttribute("filename") + ".xls");
    %>
    
    <!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=US-ASCII">
    <title>Excel</title>
    </head>
    <body>
    	<table>
    		<tr bgcolor="lightblue">
    			<td>Group</td>
    			<td><table>
    					<tr>
    						<td>Name</td>
    						<td>Age</td>
    						<td>Email</td>
    					</tr>
    				</table></td>
    		</tr>
    		<c:forEach items="${employees}" var="group">
    			<tr>
    				<td>${ group.key }</td>
    				<td><table>
    						<c:forEach items="${ group.value }" var="employee">
    							<tr>
    								<td>${ employee.name }</td>
    								<td>${ employee.age }</td>
    								<td>${ employee.email }</td>
    							</tr>
    						</c:forEach>
    					</table></td>
    			</tr>
    		</c:forEach>
    	</table>
    </body>
    </html>
    
  3. สร้าง Bean ไว้เก็บข้อมูล

    package com.magicalcyber.blog.excel.model;
    
    public class Employee {
    	private String name;
    	private int age;
    	private String email;
    
    	public Employee(String name, int age, String email) {
    		this.name = name;
    		this.age = age;
    		this.email = email;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public String getEmail() {
    		return email;
    	}
    
    }
    
  4. สร้าง Controller เพื่อทำการจำลองว่า มีการดึงข้อมูลจาก Database ขึ้นมาเพื่อนำไป export ดังนี้
    package com.magicalcyber.blog.excel.controller;
    
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.Locale;
    import java.util.Map;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    import com.magicalcyber.blog.excel.model.Employee;
    
    @Controller
    @RequestMapping("/excel")
    public class ExcelController {
    
    	@RequestMapping(method = RequestMethod.GET)
    	public String home() {
    		return "excel";
    	}
    
    	@RequestMapping(method = RequestMethod.POST)
    	public String export(Model model) {
    
    		// Generate filename
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.US);
    		model.addAttribute("filename", "Employee_" + sdf.format(new Date()));
    
    		// Mockup data
    		Map<String, ArrayList<Employee>> employees = new HashMap<String, ArrayList<Employee>>();
    
    		ArrayList<Employee> group1 = new ArrayList<Employee>();
    		group1.add(new Employee("MagicalCyber", 30, "abc123@gmail.com"));
    		employees.put("Group1", group1);
    
    		ArrayList<Employee> group2 = new ArrayList<Employee>();
    		group2.add(new Employee("AAAAA", 29, "aaaaa@gmail.com"));
    		group2.add(new Employee("BBBBB", 28, "bbbbb@gmail.com"));
    		employees.put("Group2", group2);
    
    		ArrayList<Employee> group3 = new ArrayList<Employee>();
    		group3.add(new Employee("CCCCC", 27, "ccccc@gmail.com"));
    		group3.add(new Employee("DDDDD", 26, "ddddd@gmail.com"));
    		group3.add(new Employee("EEEEE", 25, "eeeee@gmail.com"));
    		employees.put("Group3", group3);
    
    		model.addAttribute("employees", employees);
    
    		return "excel_export";
    	}
    }
    
    

ผลลัพธ์


เปิดหน้าเว็บ http://localhost:8080/excel/excel Screen Shot 2014-06-05 at 5.38.57 PM

พอกดปุ่ม export ก็จะปรากฏ dialog ให้ save file
export popup download

พอเปิดไฟล์ขึ้นมาก็พบกับ excel ที่ merge cell แล้ว
export excel

ยังต้องปรับปรุง


เป็นวิธีการที่ง่ายที่สุดที่ผมนึกออกในการแก้ปัญหาเรื่อง merge cell แต่จากที่เห็นรูป พบว่าการจัดรูปแบบยังไม่สวยงาม ซึ่งผมไม่แน่ใจว่า หากใช้ css เต็มที่จะได้ผลลัพธ์เหมือนกับการ generate จาก template ที่ถูกจัดไว้สวยงามเหมือน jxls หรือเปล่า

ต้องลองครับ!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s