C3는 D3 Chart 기반으로 쉽게 Chart를 생성할 수 있는 Chart 솔루션이다.
C3 Chart는 다양한 Chart를 제공하고 있으며, 개발 시 http://c3js.org/를 참조하여 개발을 수행할 수 있다.
C3 Chart를 사용하면서 데이터를 생성하는데 이슈가 되었던 부분들을 간략하게 설명한다.
■ JSON 데이터 처리
C3 Chart는 Json Data를 사용할 수 있다고 되어 있으나, 예제를 찾을 수 없어 column으로 데이터를 처리하였다.
또한 java script에서 loop를 최소화하기 위해 Oracle의 PIVOT 기능을 이용하여 데이터 조회 시 Row를 Column으로 변환하였다.
■ PIVOT을 이용한 Row를 Column으로 변환
SELECT * FROM ( SELECT TO_CHAR(START_TIME, 'YYYY-MM-DD') START_DAY ,INTERFACE_ID FROM TRANS_LOG WHERE 1 = 1 <if test='startDate != "" and startDate != null'> <![CDATA[AND START_TIME >= #{startDate}]]> </if> <if test='interfaceId != "" and interfaceId != null'> AND INTERFACE_ID LIKE '%' || #{interfaceId} || '%' </if> ) PIVOT ( COUNT(START_DAY) FOR START_DAY IN <foreach collection="condDate" item="item" open="(" close=")" separator=","> ${item} </foreach> ) |
PIVOT을 사용할 경우 바인딩 변수를 사용할 수 없으며, 바인딩 변수를 사용하면 ORA-56900 오류가 발생한다.
이를 해결하기 위해서 Mybatis의 #{itme} 대신에 ${item}을 사용하여 해결하였다.
또한 PIVOT의 IN 내에 조건을 바인딩하기 위해 사전에 다음 SQL로 데이터를 조회한 후 조회결과를 파라미터를 전송하였다.
■ PIVOT의 IN 바인딩 데이터 조회
SELECT q'[']' || START_DATE || q'[']' START_DATE FROM (SELECT DISTINCT(TO_CHAR(START_TIME, 'YYYY-MM-DD')) START_DATE FROM TRANS_LOG WHERE 1 = 1 <if test='startDate != "" and startDate != null'> <![CDATA[AND START_TIME >= #{startDate}]]> </if> <if test='interfaceId != "" and interfaceId != null'> AND INTERFACE_ID LIKE '%' || #{interfaceId} || '%' </if> ORDER BY 1 ) |
START_DATE를 값으로 사용하기 위해 조회 시 Single Quotation을 붙여주었다.
■ JSP Source
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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=UTF-8"> <link rel="stylesheet" href="/resources/css/jquery-ui-1.10.1.css"> <link rel="stylesheet" href="/resources/css/table.css"> <link rel="stylesheet" href="/resources/css/c3.min.css"> <link rel="stylesheet" href="/resources/css/melon.datepicker.css"> <script type="text/javascript" src="/resources/js/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="/resources/js/jquery-ui-1.10.1.min.js"></script> <script type="text/javascript" src="/resources/js/c3.min.js"></script> <script type="text/javascript" src="/resources/js/d3.v3.min.js" charset="utf-8"></script> <script> $(document).ready(function() { $("#btnSearch").click(function(e) { e.preventDefault();
debugger;
var objectData = { startDate: $('#startDate').val(), chartType: $('#chartType').val(), interfaceId: $('#interfaceId').val() }; var sendData = JSON.stringify(objectData);
$.ajax({ type: "POST", url: '/chart/showStatistics.do', data : sendData, dataType : "json", //Cross domain contentType: "application/json", success : function(response, status, xhr) { alert(response); debugger; console.log(response); showChart(response); }, error: function(jqXHR, textStatus, errorThrown) { debugger; console.log(jqXHR.responseText); } }); }); }); //Date Picker $(function() { $( "#startDate" ).datepicker({ defaultDate: new Date(), dateFormat: "yy-mm-dd", changeMonth: true, changeYear: true, dayNames:['Sun', 'Mon', 'Tue', 'Wed', 'Thr', 'Fri', 'Sat'] }); });
function showChart(response) { debugger; var graphType = $('#chartType').val().toUpperCase() + " Statistic Graph"; $( "#graphType" ).text(graphType); var categories=[]; $.each(response.categories, function(idx, data) { categories.push(data); });
var columns = []; $.each(response.columns, function (idx, data) { var col = []; var idx = 0; $.each(data, function(key, value) { debugger; col[idx] = value; idx++; }); columns.push(col);
});
var chart = c3.generate({ bindto: "#interfacechart", size: { height: 600, width: 1200 }, data: { type: 'bar', columns: columns, }, bar: { width: { ratio: 0.3 // this makes bar width 50% of length between ticks } // or //width: 100 // this makes bar width 100px }, axis: { x: { type: 'category', categories:categories } }, grid: { x: { show: true }, y: { show: true } } }); // setTimeout(function () { // chart.load({ // columns: [ // ['data3', 130, -150, 200, 300, -200, 100] // ] // }); // }, 1000); }
</script> <title>Interface Monitoring</title> </head> <body> <!-- Search Area --> <div class="container"> <form action=""> <div class="fieldName"> <label>START DATE</label> </div> <div class="select"> <input type="text" id="startDate" size=10 style="align=center;"/> </div>
<div class="fieldName"> <label>Statistic Period</label> </div> <div class="select"> <select name="chartType" id="chartType"> <option value="daily">Daily</option> <option value="monthly">Monthly</option> </select> </div> <div class="fieldName"> <label>Interface Name</label> </div> <div class="data"> <input type="text" id="interfaceId" title="Enter Interface Name" size="30"></input> </div> <div class="logbutton"> <button id="btnSearch">Search</button> </div> </form> </div> <div> <label style="height:100%;padding:5px; margin-top:10px; font-family:Sans-serif; font-size:1.2em;" id="graphType">Statistic Graph</label> </div>
<div id="interfacechart" style="width: 1200px; height: 500px;"></div> </body>
</body> </html> |
■Controller 소스
import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import cmn.util.base.BaseController; import cmn.util.dao.CamelMap; import sehati.inf.chart.service.ChartService; @Controller public class CharController extends BaseController { @Resource(name = "chartService") private ChartService chartService;
@RequestMapping("/chart/viewChart") public ModelAndView viewChart() throws Exception { ModelAndView mav = new ModelAndView(); mav.setViewName("InterfaceStatistics"); return mav; }
@RequestMapping(value="/chart/showStatistics.do") public @ResponseBody Map<String, Object> showStatistics(@RequestBody Map<String, Object> param) throws Exception { Map<String, Object> resultMap = new HashMap<String, Object>();
/** Search Condition **/ List<String> categories = chartService.selectPivotQueryTarget(param); param.put("condDate", categories);
List<CamelMap> resultList = chartService.selectChartData(param);
resultMap.put("categories", categories); resultMap.put("columns", resultList);
return resultMap; } }
|
먼저 날짜별 PIVOT을 적용하기 위해 날짜를 조회한 후 실제 데이터 조회하기 위해 condData를 파라미터로 전달한다.
'Spring Framrwork' 카테고리의 다른 글
spring framework interceptor (0) | 2018.03.02 |
---|---|
Google Map javascript API 사용법 (0) | 2018.02.07 |
Spring Batch 모니터링 SQL (0) | 2018.02.03 |
MybatisBatchWriter 오류 해결방법 (0) | 2018.02.03 |
Solve the Cross Domain issue with JSP (0) | 2018.02.02 |