- 이번에는 그래프를 통해 게시글 통계를 출력하여 사용자들의 게시글 작성 현황을 한 눈에 확인할 수 있도록 구현해보았습니다.
- 우선 해당 페이지의 구현은 아래와 같습니다.
- 해당 통계 페이지의 디자인은 티스토리 블로그의 방문 통계 페이지를 참고하였습니다.
- 그래프 구현 말고는 어려운 부분이 없기 때문에 그래프 구현에 대한 부분만 설명하겠습니다.
📝 Google Chart
- 먼저 그래프는 최근 7일간의 카테고리별 게시글 작성 통계를 나타내도록 할 것입니다.
- 저의 경우 검색을 통해 맘에드는 그래프 템플릿을 찾을 수 있었으며 해당 템플릿의 큰 틀에서 저의 입맛대로 조정해보았습니다.
- 제가 사용한 구글 차트 그래프 템플릿은 아래 블로그에서 확인하실 수 있습니다.
- 그래프 구현은 아래와 같이 진행하였습니다.
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
var chartDrowFun = {
chartDrow : function(){
var queryObject = "";
var queryObjectLen = "";
$.ajax({
type : 'POST',
url : '/api/admin/data',
dataType : 'json',
success : function(data) {
queryObject = eval('(' + JSON.stringify(data, null, 2)
+ ')');
queryObjectLen = queryObject.boardList.length;
//alert('Total lines : ' + queryObjectLen + 'EA');
},
error : function(xhr, type) {
//alert('server error occoured')
alert('server msg : ' + xhr.status)
}
});
var chartData = '';
//날짜형식 변경하고 싶으시면 이 부분 수정하세요.
var chartDateformat = 'MM월 dd일';
//라인차트의 라인 수
var chartLineCount = 10;
//컨트롤러 바 차트의 라인 수
var controlLineCount = 10;
function drawDashboard() {
var data = new google.visualization.DataTable();
//그래프에 표시할 컬럼 추가
data.addColumn('datetime' , '날짜');
data.addColumn('number' , '전체');
data.addColumn('number' , '자유게시판');
data.addColumn('number' , '비밀게시판');
data.addColumn('number' , '스크린샷 게시판');
data.addColumn('number' , '질문과 답변');
//그래프에 표시할 데이터
var dataRow = [];
var dateList = [];
for (var i = 0; i < queryObjectLen; i++) {
var create_date = queryObject.boardList[i].create_date;
var none = queryObject.boardList[i].none;
var secret = queryObject.boardList[i].secret;
var screenshot = queryObject.boardList[i].screenshot;
var question = queryObject.boardList[i].question;
dateList.push(new Date(create_date.substring(0, 4), create_date.substring(5, 7) - 1, create_date.substring(8, 10)));
dataRow = [new Date(create_date.substring(0, 4), create_date.substring(5, 7) - 1, create_date.substring(8, 10)),
none + secret + screenshot + question, none, secret, screenshot, question];
data.addRow(dataRow);
}
var chart = new google.visualization.ChartWrapper({
chartType : 'LineChart',
containerId : 'lineChartArea', //라인 차트 생성할 영역
options : {
chartArea: {width: '85%', height: '70%'},
curveType: 'function',
isStacked : 'percent',
focusTarget : 'category',
height : 500,
width : '100%',
legend : { position: "top", textStyle: {fontName: 'nanumsquare', fontSize: 13}},
pointSize : 5,
tooltip : {textStyle : {fontName: 'nanumsquare', fontSize:12}, showColorCode : true,trigger: 'both'},
hAxis : {format: chartDateformat, gridlines:{count:chartLineCount,units: {
years : {format: ['yyyy년']},
months: {format: ['MM월']},
days : {format: ['dd일']},
hours : {format: ['HH시']}}
},textStyle: {fontName: 'nanumsquare', fontSize:12},
ticks: dateList},
vAxis : {minValue: 15,viewWindow:{min:0},gridlines:{count:-1}, format: '#', textStyle:{fontName: 'nanumsquare', fontSize:12}},
animation : {startup: true,duration: 1000,easing: 'in' },
annotations : {pattern: chartDateformat,
textStyle: {
fontName: 'nanumsquare',
fontSize: 15,
bold: true,
italic: true,
color: '#871b47',
auraColor: '#d799ae',
opacity: 0.8,
pattern: chartDateformat
}
}
}
});
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'controlsArea', //control bar를 생성할 영역
options: {
ui:{
chartType: 'LineChart',
chartOptions: {
chartArea: {'width': '60%','height' : 80},
hAxis: {'baselineColor': 'none', format: chartDateformat, textStyle: {fontName: 'nanumsquare', fontSize:12},
gridlines:{count:controlLineCount,units: {
years : {format: ['yyyy년']},
months: {format: ['MM월']},
days : {format: ['dd일']},
hours : {format: ['HH시']}}
}}
}
},
filterColumnIndex: 0
}
});
var date_formatter = new google.visualization.DateFormat({ pattern: chartDateformat});
date_formatter.format(data, 0);
var dashboard = new google.visualization.Dashboard(document.getElementById('Line_Controls_Chart'));
window.addEventListener('resize', function() { dashboard.draw(data); }, false); //화면 크기에 따라 그래프 크기 변경
dashboard.bind([control], [chart]);
dashboard.draw(data);
}
google.charts.setOnLoadCallback(drawDashboard);
}
}
$(document).ready(function(){
google.charts.load('50', {'packages':['line','controls']});
chartDrowFun.chartDrow(); //chartDrow() 실행
});
</script>
- 컨트롤러와 함께보면 위 코드에 대한 이해가 더 빠를것입니다.
📝 AdminApiController
- 해당 컨트롤러는 위의 그래프를 화면에 그리기 전에 DB에서 뷰페이지까지 데이터를 가져오는 역할을 수행합니다.
- 쿼리문은 아래와 같이 작성하였습니다.
select date(create_date) as 'cd',
count(case when category = 'none' then 0 end) as 'none',
count(case when category = 'secret' then 0 end) as 'secret',
count(case when category = 'screenshot' then 0 end) as 'screenshot',
count(case when category = 'question' then 0 end) as 'question'
from board
where create_date between date_add(now(), interval - 1 week) and now()
group by cd
order by cd;
package com.cos.blog.controller.api;
...
@RestController
@RequiredArgsConstructor
public class AdminApiController {
@PostMapping("/api/admin/data")
public ResponseEntity<?> alarmConfirm() {
Connection con = null;
JSONObject responseObj = new JSONObject();
try {
String url = "jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Seoul";
String user = "cos";
String passwd = "cos1234";
// 드라이버 호출, 커넥션 연결
con = DriverManager.getConnection(url, user, passwd);
// DB에서 뽑아온 데이터(JSON) 을 담을 객체. 후에 responseObj에 담기는 값
List<JSONObject> boardList = new LinkedList<JSONObject>();
String query = "select date(create_date) as 'cd', "
+ "count(case when category = 'none' then 0 end) as 'none', "
+ "count(case when category = 'secret' then 0 end) as 'secret', "
+ "count(case when category = 'screenshot' then 0 end) as 'screenshot', "
+ "count(case when category = 'question' then 0 end) as 'question' "
+ "from board where create_date between date_add(now(), interval - 1 week) and now() group by cd "
+ "order by cd";
PreparedStatement pstm = con.prepareStatement(query);
ResultSet rs = pstm.executeQuery(query);
// ajax에 반환할 JSON 생성
JSONObject lineObj = null;
while (rs.next()) {
String create_date = rs.getString("cd");
int none = rs.getInt("none");
int secret = rs.getInt("secret");
int screenshot = rs.getInt("screenshot");
int question = rs.getInt("question");
lineObj = new JSONObject();
lineObj.put("create_date", create_date);
lineObj.put("none", none);
lineObj.put("secret", secret);
lineObj.put("screenshot", screenshot);
lineObj.put("question", question);
boardList.add(lineObj);
}
responseObj.put("boardList", boardList);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return new ResponseEntity<>(responseObj, HttpStatus.OK);
}
}
📝 admin.jsp
- jsp 코드는 아래와 같습니다.
<div class="data">
<div class="data-summary">
<dl>
<dt>오늘 작성글</dt>
<dd>${countToday}</dd>
</dl>
<dl>
<dt>어제 작성글</dt>
<dd>${countYesterday}</dd>
</dl>
<dl>
<dt>누적 작성글</dt>
<dd>${countTotal}</dd>
</dl>
</div>
<div class="data-summary">
<dl>
<dt style="color: red;">자유 게시판</dt>
<dd>${countNone}</dd>
</dl>
<dl>
<dt style="color: orange;">비밀 게시판</dt>
<dd>${countSecret}</dd>
</dl>
<dl>
<dt style="color: green;">스크린샷 게시판</dt>
<dd>${countScreenshot}</dd>
</dl>
<dl>
<dt style="color: purple;">질문과 답변</dt>
<dd>${countQuestion}</dd>
</dl>
</div><br><br>
<div class="chart-title">최근 7일 통계</div>
<div id="Line_Controls_Chart">
<!-- 라인 차트 생성할 영역 -->
<div id="lineChartArea" class="chart"></div>
<!-- 컨트롤바를 생성할 영역 -->
<div id="controlsArea" style="display: none;"></div>
</div>
</div>
- 참고로 제가 사용한 그래프 템플릿에는 컨트롤러도 따로 달려있었는데 저의 경우 이 부분은 필요없는 부분이라 제거하였습니다.
'🚗 Backend Toy Project > 스프링 부트 게시판' 카테고리의 다른 글
[스프링부트 게시판] 37. 비밀번호 찾기 (0) | 2022.11.01 |
---|---|
[스프링부트 게시판] 35. 관리자 페이지 - 회원 관리 (0) | 2022.10.24 |
[스프링부트 게시판] JPA Specification을 통해 쿼리 조건 다루기 (0) | 2022.10.06 |
[스프링부트 게시판] 34. 사용자 프로필 이미지 추가 (0) | 2022.09.27 |
[스프링부트 게시판] 33. 댓글 알림 기능 (1) | 2022.09.23 |