jfreechart로 차트 기능 구현
1. jfreechart 다운 로드
- http://www.jfree.org/jfreechart/
- jfreechart-X.X.X.jar, jcommon-X.X.X.jar를 어플리케이션 밑의 /WEB-INF/lib 폴더에 복사해 줌.
2. 환경 설정
<servlet>
<servlet-name>DisplayChart</servlet-name>
<servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayChart</servlet-name>
<url-pattern>/DisplayChart</url-pattern>
</servlet-mapping>
3. 구현 코드
- Chart.java
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.entity.StandardEntityCollection;
import org.jfree.chart.servlet.ServletUtilities;
public class Chart
{
protected String type;
protected String title;
protected String yaxis;
protected String varId;
protected int id = -1;
protected boolean displayChart;
protected boolean savetofile;
protected JFreeChart _chart;
protected Log log = LogFactory.getLog(this.getClass());
public Chart(String type, String title, String yaxis, String varId,
boolean displayChart, boolean savetofile) {
this.type = type; //차트 종류
this.title = title; // 차트 제목
this.yaxis = yaxis; //y범례title
this.varId = varId; //x범례title
this.displayChart = displayChart;
this.savetofile = savetofile;
}
public String getType() {
return type;
}
public JFreeChart getChart () {
return _chart;
}
public void initXYSeries (String variableid, int variableindex, int flag) {
// The XY charts need to implement this
}
public void addValue (double tpsd, String variableid,
String variableindex, int flag) {
// All charts need to implement this
}
public void addSeries(int flag) {
// The XY charts need to implement this
}
public void createChart() {
// All charts need to implement this
}
// 파일로 저장한 차트
public String saveChart(String outfileprefix, int width, int height)
{
String filename = null;
String fullpath = "/www/test";
try {
if (_chart == null) {
log.info("Chart.saveChart: Chart has not been created");
filename = "public_error_700x300.png";
return filename;
}
if (savetofile && outfileprefix != null) {
filename = fullpath + File.separator + outfileprefix + "." + type + ".jpg";
File imgfile = new File (filename);
ChartUtilities.saveChartAsJPEG(imgfile,
_chart, width, height);
}
} catch (Exception e) {
e.printStackTrace();
log.error(e);
}
return filename;
}
//response chart 결과 출력
public void displayChart(HttpServletResponse response, int width, int height)
{
BufferedImage image = null;
ByteArrayOutputStream stream = null;
OutputStream os = null;
try {
if (displayChart && _chart != null) {
image = _chart.createBufferedImage(width, height);
stream = new ByteArrayOutputStream();
ChartUtilities.writeBufferedImageAsJPEG(stream, image);
response.setDateHeader("Expires", 1);
byte[] data = stream.toByteArray();
response.setContentLength(data.length);
response.setContentType("image/jpeg");
os = response.getOutputStream();
os.write(data);
}
} catch (Exception e) {
e.printStackTrace();
log.error(e);
} finally {
try {
if (os != null) {
os.flush();
os.close();
}
} catch (Throwable t) {
// ignore
}
}
}
// session에 결과 출력
public String displayChart(HttpSession session, PrintWriter pw,
int width, int height)
{
ChartRenderingInfo info = null;
String filename = null;
try {
if (displayChart && _chart != null) {
info = new ChartRenderingInfo(new StandardEntityCollection());
filename = ServletUtilities.saveChartAsJPEG(_chart, width, height,
info, session);
}
} catch (Exception e) {
e.printStackTrace();
log.error(e);
filename = "public_error_700x300.png";
} finally {
info = null;
}
return filename;
}
}
- ChartFactory.java
public class ChartFactory
{
public static String[] SUPPORTED_CHARTS = {"BarChart3D", "XYLine", "XYScatter",
"RatioBarChart3D", "RatioXYLine", "RatioXYScatter", "Line"};
private static final int BARCHART3D = 0;
private static final int XYLINE = 1;
private static final int XYSCATTER = 2;
private static final int RATIOBARCHART3D = 3;
private static final int RATIOXYLINE = 4;
private static final int RATIOXYSCATTER = 5;
private static final int LINECHART = 6;
public static Chart createChart (String type,
String title, String yaxis, String varId,
boolean displayChart, boolean savetofile) {
int id = 0;
for (int i=0; i<SUPPORTED_CHARTS.length; i++) {
if (type.equalsIgnoreCase (SUPPORTED_CHARTS[i])) {
id = i;
break;
}
}
switch (id) {
case BARCHART3D:
return new BarChart3D (type, title, yaxis, varId, displayChart,
savetofile);
case RATIOBARCHART3D:
return new RatioBarChart3D (type, title, yaxis, varId,
displayChart, savetofile);
case XYLINE:
return new XYLineChart (type, title, yaxis, varId,
displayChart, savetofile);
case XYSCATTER:
return new XYScatterChart (type, title, yaxis, varId,
displayChart, savetofile);
case RATIOXYLINE:
return new RatioXYLineChart (type, title, yaxis, varId,
displayChart, savetofile);
case RATIOXYSCATTER:
return new RatioXYScatterChart (type, title, yaxis, varId,
displayChart, savetofile);
case LINECHART:
return new LineChart(type, title, yaxis, varId,
displayChart, savetofile);
}
return null;
}
}
- LineChart.java
import java.awt.Color;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
public class LineChart extends Chart
{
protected DefaultCategoryDataset dataset;
public LineChart(String type, String title, String yaxis/*y범례title*/,
String varId/*x범례title*/, boolean displayChart, boolean savetofile) {
super (type, title, yaxis, varId, displayChart, savetofile);
dataset = new DefaultCategoryDataset();
}
public void addValue (double tpsd, String variableid, String variableindex,
int flag) {
dataset.addValue(tpsd/* y */, variableid, variableindex/* x */);
}
public void createChart()
{
CategoryPlot categoryplot = null;
NumberAxis numberaxis = null;
LineAndShapeRenderer lineandshaperenderer = null;
try {
_chart = org.jfree.chart.ChartFactory.createLineChart(title, varId, yaxis,
(CategoryDataset)dataset, PlotOrientation.VERTICAL/*라인orientation*/,
true/*범례설정여부*/, true/*도움말설정여부*/, false/*urls설정여부*/);
_chart.setBackgroundPaint(Color.white);
_chart.setAntiAlias(true);
categoryplot = (CategoryPlot) _chart.getPlot();
categoryplot.setRangeGridlinePaint(Color.lightGray);
numberaxis = (NumberAxis) categoryplot.getRangeAxis();
numberaxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
numberaxis.setAutoRangeIncludesZero(false);
numberaxis.setUpperMargin(0.12D);
lineandshaperenderer = (LineAndShapeRenderer) categoryplot.getRenderer();
lineandshaperenderer.setBaseShapesVisible(true);
lineandshaperenderer.setDrawOutlines(true);
lineandshaperenderer.setUseFillPaint(true);
lineandshaperenderer.setBaseFillPaint(Color.white);
lineandshaperenderer.setBaseItemLabelsVisible(true);
lineandshaperenderer.setBaseItemLabelGenerator(
new StandardCategoryItemLabelGenerator());//속도 안나옴
} catch (Exception e) {
log.error(e);
}
}
}
- Controller에 위 클래스 사용 예
public ModelAndView handleRequest(HttpServletRequest req,
HttpServletResponse resp) throws Exception
{
ModelAndView mv = null;
String fromdate = null;
String todate = null;
DateUtil du = null;
Chart charts = null;
PrintWriter pw = null;
String filename = null;
String graphURL = null;
try {
fromdate = StringUtils.defaultIfEmpty(
req.getParameter("fromdate"), StringUtils.EMPTY);
todate = StringUtils.defaultIfEmpty(req.getParameter("todate"),
StringUtils.EMPTY);
if (StringUtils.isEmpty(fromdate) || StringUtils.isEmpty(todate)) {
du = new DateUtil();
fromdate = du.addDays(du.getShortDateString(), -8, "yyyyMMdd");
todate = du.addDays(du.getShortDateString(), -1, "yyyyMMdd");
}
charts = ChartFactory.createChart("Line", "일별 가입자 수 통계", "가입자 수",
"가입 일자", false, true);
charts.addValue(5, "성년 가입자수", "2008.09.09", 1);
charts.addValue(2, "미성년 가입자수", "2008.09.09", 1);
charts.addValue(9, "성년 가입자수", "2008.09.10", 1);
charts.addValue(1, "미성년 가입자수", "2008.09.10", 1);
charts.addValue(4, "성년 가입자수", "2008.09.11", 1);
charts.addValue(3, "미성년 가입자수", "2008.09.11", 1);
charts.addValue(7, "성년 가입자수", "2008.09.12", 1);
charts.addValue(3, "미성년 가입자수", "2008.09.12", 1);
charts.addValue(7, "성년 가입자수", "2008.09.13", 1);
charts.addValue(4, "미성년 가입자수", "2008.09.13", 1);
charts.addValue(2, "성년 가입자수", "2008.09.14", 1);
charts.addValue(5, "미성년 가입자수", "2008.09.14", 1);
charts.addValue(10, "성년 가입자수", "2008.09.15", 1);
charts.addValue(1, "미성년 가입자수", "2008.09.15", 1);
charts.addValue(18, "성년 가입자수", "2008.09.16", 1);
charts.addValue(1, "미성년 가입자수", "2008.09.16", 1);
charts.createChart();
filename = charts.saveChart("Signup", 700, 300);
graphURL = "/upload_img/" + filename;
log.info(graphURL);
mv = new ModelAndView();
mv.addObject("graphurl", graphURL);
mv.addObject("filename", "#" + filename);
mv.setViewName("register-statistics");
} catch (Exception e) {
e.printStackTrace();
log.error(e);
} finally {
}
return mv;
}
- vm(Velocity)파일에서 사용 예
<div id="bodyWrapper">
<p class="more"><img src="$!{graphurl}"
width=700 height=300 border=0 usemap="$!{filename}"></p>
</div>
4. 구현 결과 화면

5. 팁
- http://mimul.com/examples/jfree/jfreechart-1.0.10-demo.jnlp을 다운 받아서 실행하면 샘플 예제들과 소스를 확인 할 수 있어 개발하는 데 많은 도움을 받을 수 있습니다.
- DisplayChart를 활용해서 이미지를 렌더링 할 경우 차트의 속성을 자세하게 설정하고 데이터를 차트에 할당 할 경우 이미지 로딩 속도가 현저하게 떨어지는 경우가 있습니다. 이럴 경우는 차트이미지를 파일로 만들어서 로딩하면 됩니다. 아직 성능 이슈가 좀 있긴 하네요.








