Spring MVC에서 jexcel 모듈을 활용한 엑셀 파일 다운로드 기능 구현하기
Framework/Spring / 2010/07/28 14:25
Spring MVC의 유연함을 확인할 수 있는 기능 중에 하나가 엑셀 다운로드와 같은 기능이리라. 지금까지 JSP 기반으로 UI를 서비스하다가 특정 기능에 대하여 엑셀로 다운로드하는 기능을 구현하고 싶다면 Spring MVC에서는 엑셀 다운로드를 담당하는 View를 만들어 교체해 주기만 하면 된다. 이전에 개발했던 비지니스 로직과 모델 API는 그대로 사용 가능하다. 물론 Spring MVC를 이용하지 않더라도 같은 기능을 구현할 수 있다. 하지만 Spring MVC를 이해하고 이 기반으로 엑셀 다운로드 기능을 구현하기란 정말 쉽다.
Spring MVC 3.0 기능에 대하여 먼저 공부하고 싶은 개발자가 있다면 최근에 공개된 Spring MVC 3 Showcase 문서를 참고한다. 동영상까지 제공하고 있으며, Spring MVC 3.0에서 제공하는 모든 기능을 예제 소스까지 포함하고 있어 Spring MVC 3.0을 공부하는 개발자에게 많은 도움이 되리라 생각한다.
먼저 엑셀 다운로드 기능을 구현하기 위하여 Controller를 다음과 같이 구현한다. 구현할 기능은 설문 결과를 엑셀로 다운로드 하는 기능이다.
위 예제 소스와 같이 설문 조사 결과를 Survey 클래스에서 조회한 후 ModelMap을 통하여 전달한다. 위와 같이 간단하게 Controller를 구현한 후 SurveyExcelView 클래스를 구현하면 된다.
Spring MVC 3.0 기능에 대하여 먼저 공부하고 싶은 개발자가 있다면 최근에 공개된 Spring MVC 3 Showcase 문서를 참고한다. 동영상까지 제공하고 있으며, Spring MVC 3.0에서 제공하는 모든 기능을 예제 소스까지 포함하고 있어 Spring MVC 3.0을 공부하는 개발자에게 많은 도움이 되리라 생각한다.
먼저 엑셀 다운로드 기능을 구현하기 위하여 Controller를 다음과 같이 구현한다. 구현할 기능은 설문 결과를 엑셀로 다운로드 하는 기능이다.
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.View;
@Controller
@RequestMapping("/survey")
public class SurveyController {
@RequestMapping(value="/excel", method=RequestMethod.GET)
public View excel(ModelMap model) {
model.addAttribute("surveys", Survey.findAll(Survey.class));
return new SurveyExcelView();
}
}
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.View;
@Controller
@RequestMapping("/survey")
public class SurveyController {
@RequestMapping(value="/excel", method=RequestMethod.GET)
public View excel(ModelMap model) {
model.addAttribute("surveys", Survey.findAll(Survey.class));
return new SurveyExcelView();
}
}
위 예제 소스와 같이 설문 조사 결과를 Survey 클래스에서 조회한 후 ModelMap을 통하여 전달한다. 위와 같이 간단하게 Controller를 구현한 후 SurveyExcelView 클래스를 구현하면 된다.
이 글의 댓글에 토비님이 의견을 달았듯이 Spring의 View 클래스는 무상태 클래스이기 때문에 위 예제 소스와 같이 View 클래스를 매번 생성하기 보다는 설정 파일에서 View 클래스를 관리하고 DI를 통해서 구현하는 것이 더 좋은 습관이다. 위 예제 소스를 보면 단위 테스트 없이 구현한 것이 확 들어날 것이다.
위와 같은 형태로 JExcel 기반으로 엑셀 파일을 생성한다. 위 예제 소스를 보면 알 수 있듯이 JExcel API를 이용하여 WritableWorkbook을 생성하고 엑셀 파일을 생성하는 부분은 모두 Spring 프레임워크에서 제공하는 AbstractJExcelView클래스가 담당하고 있다. 우리가 추가적으로 구현해야 할 부분은 WritableWorkbook API에 생성할 데이터를 추가하는 작업만 해주면 된다.
이와 같이 Spring MVC는 하나의 데이터를 여러 가지 View로 변환하는 작업을 어렵지 않게 할 수 있다. 앞으로 사용자가 엑셀 다운로드와 같은 기능을 요청하면 상당히 어려운 작업이라고 뻥치고 짧은 시간 내에 구현해 버려라. 이렇게 얻은 시간으로 다른 것을 공부하는데 투자하면 좋을 듯 하다.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import org.springframework.web.servlet.view.document.AbstractJExcelView;
public class SurveyExcelView extends AbstractJExcelView {
protected void buildExcelDocument
(Map<String, Object> model, WritableWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String fileName = createFileName();
setFileNameToResponse(request, response, fileName);
List<Survey> surveys = (List<Survey>)model.get("surveys");
WritableSheet sheet = workbook.createSheet("설문 목록", 0);
sheet.addCell(new jxl.write.Label(0, 0, "사용자아이디"));
for(int i=1; i < 13; i++) {
sheet.addCell(new jxl.write.Label(i, 0, "답변" + i));
}
int row = 1;
for (Iterator iterator = surveys.iterator(); iterator.hasNext();) {
Survey survey = (Survey) iterator.next();
sheet.addCell(new jxl.write.Label(0, row, survey.getUserId()));
sheet.addCell(new jxl.write.Number(1, row, survey.getAnswer1()));
sheet.addCell(new jxl.write.Number(2, row, survey.getAnswer2()));
sheet.addCell(new jxl.write.Label(3, row, survey.getAnswer3()));
sheet.addCell(new jxl.write.Number(4, row, survey.getAnswer4()));
row++;
}
}
private void setFileNameToResponse
(HttpServletRequest request, HttpServletResponse response, String fileName) {
String userAgent = request.getHeader("User-Agent");
if (userAgent.indexOf("MSIE 5.5") >= 0) {
response.setContentType("doesn/matter");
response.setHeader("Content-Disposition","filename=\""+fileName+"\"");
} else {
response.setHeader("Content-Disposition","attachment; filename=\""+fileName+"\"");
}
}
private String createFileName() {
SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
return new StringBuilder("설문조사")
.append("-").append(fileFormat.format(new Date())).append(".xls").toString();
}
}
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import org.springframework.web.servlet.view.document.AbstractJExcelView;
public class SurveyExcelView extends AbstractJExcelView {
protected void buildExcelDocument
(Map<String, Object> model, WritableWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String fileName = createFileName();
setFileNameToResponse(request, response, fileName);
List<Survey> surveys = (List<Survey>)model.get("surveys");
WritableSheet sheet = workbook.createSheet("설문 목록", 0);
sheet.addCell(new jxl.write.Label(0, 0, "사용자아이디"));
for(int i=1; i < 13; i++) {
sheet.addCell(new jxl.write.Label(i, 0, "답변" + i));
}
int row = 1;
for (Iterator iterator = surveys.iterator(); iterator.hasNext();) {
Survey survey = (Survey) iterator.next();
sheet.addCell(new jxl.write.Label(0, row, survey.getUserId()));
sheet.addCell(new jxl.write.Number(1, row, survey.getAnswer1()));
sheet.addCell(new jxl.write.Number(2, row, survey.getAnswer2()));
sheet.addCell(new jxl.write.Label(3, row, survey.getAnswer3()));
sheet.addCell(new jxl.write.Number(4, row, survey.getAnswer4()));
row++;
}
}
private void setFileNameToResponse
(HttpServletRequest request, HttpServletResponse response, String fileName) {
String userAgent = request.getHeader("User-Agent");
if (userAgent.indexOf("MSIE 5.5") >= 0) {
response.setContentType("doesn/matter");
response.setHeader("Content-Disposition","filename=\""+fileName+"\"");
} else {
response.setHeader("Content-Disposition","attachment; filename=\""+fileName+"\"");
}
}
private String createFileName() {
SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
return new StringBuilder("설문조사")
.append("-").append(fileFormat.format(new Date())).append(".xls").toString();
}
}
위와 같은 형태로 JExcel 기반으로 엑셀 파일을 생성한다. 위 예제 소스를 보면 알 수 있듯이 JExcel API를 이용하여 WritableWorkbook을 생성하고 엑셀 파일을 생성하는 부분은 모두 Spring 프레임워크에서 제공하는 AbstractJExcelView클래스가 담당하고 있다. 우리가 추가적으로 구현해야 할 부분은 WritableWorkbook API에 생성할 데이터를 추가하는 작업만 해주면 된다.
이와 같이 Spring MVC는 하나의 데이터를 여러 가지 View로 변환하는 작업을 어렵지 않게 할 수 있다. 앞으로 사용자가 엑셀 다운로드와 같은 기능을 요청하면 상당히 어려운 작업이라고 뻥치고 짧은 시간 내에 구현해 버려라. 이렇게 얻은 시간으로 다른 것을 공부하는데 투자하면 좋을 듯 하다.
