Skip to content

Instantly share code, notes, and snippets.

@magicsih
Last active August 28, 2021 13:32
Show Gist options
  • Save magicsih/cea3c423ccd083f9070897eab5502759 to your computer and use it in GitHub Desktop.
Save magicsih/cea3c423ccd083f9070897eab5502759 to your computer and use it in GitHub Desktop.
DataTable (Front-end to Back-end)
@RequestMapping(path = "/scriptingonly/list", method = RequestMethod.GET)
public DataTable<Script> getScriptingOnlyList(@PathVariable("gameCode") String gameCode, @PathVariable("deviceOs") String deviceOs, @Valid DataTableParameter parameters, @RequestParam(name="search", required=false) String searchText) {
LOG.debug("GameCode:{} DeviceOs:{} DataTableParameter:{} SearchText:{}", gameCode, deviceOs, parameters, searchText);
DataTable<Script> scriptDataTable = scriptService.getScriptDataTable(gameCode, deviceOs, parameters, searchText);
return scriptDataTable;
}
div.dataTables_wrapper
div.dataTables_filter {
text-align: right;
}
div.dataTables_wrapper
div.dataTables_filter label {
font-weight: normal;
white-space: nowrap;
text-align: left;
}
div.dataTables_wrapper
div.dataTables_filter input {
margin-left: 0.5em;
display: inline-block;
width: auto;
}
div.dataTables_wrapper
div.dataTables_paginate {
margin: 0;
white-space: nowrap;
text-align: right;
}
.dataTables_paginate {
float: right;
text-align: right;
}
div.dataTables_wrapper
div.dataTables_paginate
ul.pagination {
margin: 2px 0px 2px 0px;
white-space: nowrap;
}
.dataTables_length {
width: 40%;
float: left;
}
.dataTables_filter {
/* width: 30%; */
float: right;
text-align: right;
}
.dataTables_info {
width: 60%;
float: left;
}
@media ( max-width :460px) {
.dataTables_wrapper .col-sm-6 {
width: 100%;
margin-bottom: 5px;
}
.dataTables_wrapper .col-sm-6 .dataTables_filter {
float: none;
}
th.unimportant {
display: none;
width: 0;
height: 0;
opacity: 0;
visibility: collapse;
}
td.unimportant {
display: none;
width: 0;
height: 0;
opacity: 0;
visibility: collapse;
}
th.littleimportant {
display: none;
width: 0;
height: 0;
opacity: 0;
visibility: collapse;
}
td.littleimportant {
display: none;
width: 0;
height: 0;
opacity: 0;
visibility: collapse;
}
}
@media (max-width: 680px) {
th.unimportant {
display: none;
width: 0;
height: 0;
opacity: 0;
visibility: collapse;
}
td.unimportant {
display: none;
width: 0;
height: 0;
opacity: 0;
visibility: collapse;
}
}
@media ( max-width :767px) {
.dataTables_length {
float: none;
}
}
.daterangepicker.xdisplay {
width: 228px;
}
.dataTables_wrapper>.row {
overflow: auto !important;
}
.imgTooltip {
display: none;
position: absolute;
}
.round {
border-radius: 5px;
border: 1px solid #d2d4d2;
}
<div id="datatableScriptingOnly">
<div id="datatable-buttons_wrapper" class="dataTables_wrapper form-inline dt-bootstrap no-footer" >
<!-- 좌측 상단 -->
<div class="dt-buttons btn-group">
<select class="form-control paging input-sm" id="selectPaging">
<option value="10">10행씩</option>
<option value="20">20행씩</option>
<option value="50">50행씩</option>
</select>
</div>
<!-- 우측 상단 -->
<div id="datatable-buttons" class="dataTables_filter">
<label><input type="search" class="form-control input-sm" placeholder="Search..." aria-controls="datatable-buttons"></label>
</div>
<!-- 테이블 영역 -->
<table class="table table-striped table-bordered">
<thead>
<tr>
<th data-column="DISPLAY_NAME">이름</th>
<th data-column="SCRIPT_DESCRIPTION">설명</th>
<th data-column="UPDATE_DATETIME">수정일</th>
<th>액션</th>
</tr>
</thead>
<tbody></tbody>
</table>
<!-- 좌측 하단 -->
<div class="dataTables_info" id="datatable-buttons_info"
role="status" aria-live="polite"></div>
<!-- 우측 하단 페이징 영역 -->
<div class="dataTables_paginate paging_simple_numbers"
id="datatable-buttons_paginate">
<ul class="pagination">
<li class="paginate_button previous" id="datatble-buttons_previous"><a href="javascript:void(0);" aria-controls="datatable-buttons" tabindex="0">Previous</a></li>
<li class="paginate_button next" id="datatable-buttons_next"><a href="javascript:void(0);" aria-controls="datatable-buttons" tabindex="0">Next</a></li>
</ul>
</div>
</div>
</div>
import java.io.Serializable;
import java.util.List;
public class DataTable<T> implements Serializable {
private static final long serialVersionUID = 1L;
private final int pageNumber; //페이지번호
private final int pageSize; //페이지크기
private final long totalCount; //전체 행의 갯수
private final long totalPage; //전체 페이지 수
private static final int pageCount = 10; //네비게이션에 보여줄 페이지 수
private final long minPageNumber; //시작 페이지 번호
private final long maxPageNumber; //끝 페이지 번호
private final long prevPageNumber; //이전 페이지 번호
private final long nextPageNumber; //다음 페이지 번호
private final long firstPageNumber; //첫목록
private final long lastPageNumber; //끝목록
private final List<T> data;
/**
* @param pageNumber : 현재 페이지 번호
* @param pageSize : 한 페이지에 보여줄 아이템 수
* @param totalCount : 전체 데이터 개수
* @param data : 한 페이지에 보여줄 아이템
*/
public DataTable(int pageNumber, int pageSize, long totalCount, List<T> data) {
super();
this.pageNumber = pageNumber;
this.pageSize = pageSize;
this.totalCount = totalCount;
this.data = data;
this.totalPage = (long)Math.ceil((double)totalCount/(double)pageSize);
double minPageNo;
if(this.pageNumber % DataTable.pageCount == 0){
minPageNo = Math.floor((double)this.pageNumber / DataTable.pageCount) * DataTable.pageCount - (DataTable.pageCount-1);
}else{
minPageNo = Math.floor((double)this.pageNumber / DataTable.pageCount) * DataTable.pageCount + 1;
}
double pageCnt = Math.ceil((double)this.totalCount/(double)this.pageSize) - minPageNo;
if(pageCnt > DataTable.pageCount){
pageCnt = DataTable.pageCount - 1;
}
double maxPageNo = minPageNo + pageCnt;
this.minPageNumber = (long) minPageNo;
this.maxPageNumber = (long) maxPageNo;
if(this.pageNumber <= DataTable.pageCount){
this.prevPageNumber = 0;
this.firstPageNumber = 0;
} else{
this.prevPageNumber = this.minPageNumber - DataTable.pageCount;
this.firstPageNumber = 1;
}
if(this.minPageNumber + DataTable.pageCount >= this.totalPage)
{
this.nextPageNumber = 0;
this.lastPageNumber = 0;
}else{
this.nextPageNumber = this.maxPageNumber + 1;
this.lastPageNumber = totalPage;
}
}
public int getPageNumber() {
return pageNumber;
}
public int getPageSize() {
return pageSize;
}
public long getTotalCount() {
return totalCount;
}
public long getTotalPage() {
return totalPage;
}
public static int getPagecount() {
return pageCount;
}
public long getMinPageNumber() {
return minPageNumber;
}
public long getMaxPageNumber() {
return maxPageNumber;
}
public long getPrevPageNumber() {
return prevPageNumber;
}
public long getNextPageNumber() {
return nextPageNumber;
}
public long getFirstPageNumber() {
return firstPageNumber;
}
public long getLastPageNumber() {
return lastPageNumber;
}
public List<T> getData() {
return data;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("DataTable [pageNumber=")
.append(pageNumber)
.append(", pageSize=")
.append(pageSize)
.append(", totalCount=")
.append(totalCount)
.append(", totalPage=")
.append(totalPage)
.append(", minPageNumber=")
.append(minPageNumber)
.append(", maxPageNumber=")
.append(maxPageNumber)
.append(", prevPageNumber=")
.append(prevPageNumber)
.append(", nextPageNumber=")
.append(nextPageNumber)
.append(", firstPageNumber=")
.append(firstPageNumber)
.append(", lastPageNumber=")
.append(lastPageNumber)
.append(", data=")
.append(data.toString())
.append("]");
return builder.toString();
}
}
/**
* @author Ilhwan Seo
* */
var DataTable = function(containerId, dataUrl, defaultRowCount, defaultOrderColumn, defaultOrder, listener, isCacheable = true, ignoreHash=false, defaultPage=1) {
const SEPARATOR_HASH_TAG = '|';
var containerId = containerId;
var container = jQuery(containerId);
var filterContainer = jQuery(containerId);
var columnCount = container.find('table thead tr').children().length;
var rowCount = 0;
var currentPage = 0;
var dataUrl = dataUrl;
var listener = listener;
var orderColumn = "";
var orderAsc = "";
var filter = [];
var ignoreHash = ignoreHash;
var needInitHashTag = false;
// 이 전에 init된 경우는 event 전부 해제한다.
// TODO datatable 재활용 y/n 받아서 처리
if($(containerId).data('isInitDataTable') !== undefined && $(containerId).data('isInitDataTable')){
//1. 물려있던 이벤트 해제
$(containerId).find("*").off();
//2. search box 초기화
jQuery(containerId+' input[type="search"]').val("");
//3. hash tag 안따라가게 조건 추가
needInitHashTag = true;
}
$(containerId).data("isInitDataTable", true);
container.ready(function() {
if(window.location.hash.length > 1 && !needInitHashTag) {
var encodedHashTags = window.location.hash.replace("#","").split(SEPARATOR_HASH_TAG);
var foundMyContainer = false;
for(var i=0;i<encodedHashTags.length;i++){
var hashtags = b64DecodeUnicode(encodedHashTags[i]).split(SEPARATOR_HASH_TAG);
// console.log("hashtags : ", hashtags);
//TODO hashTags length 1보다 작으면 return 하자..
var id = hashtags[0];
if(id === containerId.replace("#","")) {
foundMyContainer = true;
var page = hashtags[1];
var rows = hashtags[2];
var column = hashtags[3];
var order = hashtags[4];
var f = hashtags[5];
if(typeof f !== 'undefined') {
var fs = f.split("&");
for(var i in fs) {
var kv = fs[i].split("=");
// console.log(kv);
var name = kv[0];
var value = kv[1];
setFilterToDom(name, value); // Hashtag에서 추출한 filter 값을 자료구조에 세팅
}
} else{
setFiltersFromSelectBox();
}
setSearchOrder(column,order);
setRowCount(rows);
loadData(page);
break;
}
}
if(foundMyContainer === false) {
setSearchOrder(defaultOrderColumn, defaultOrder);
setRowCount(defaultRowCount);
setFiltersFromSelectBox();
loadData(defaultPage);
}
}
else{
setSearchOrder(defaultOrderColumn, defaultOrder);
setRowCount(defaultRowCount);
setFiltersFromSelectBox();
loadData(defaultPage);
}
});
function b64EncodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
function b64DecodeUnicode(str) {
return decodeURIComponent(atob(str).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
//테이블 안에 있는 Select box로 부터 필터값을 채운다.
function setFiltersFromSelectBox() {
var filters = filterContainer.find('.datatable-filter');
for(var i = 0 ; i < filters.length; ++i) {
var name = jQuery(filters[i]).data('filter-name');
var type = jQuery(filters[i]).data('filter-type');
var value = getFilterValues(name, type, filters[i]);
filter.push({"name":name, "value":value});
}
var searchColumn = jQuery(containerId+' select[type="column"]').val();
if(searchColumn !== undefined) {
filter.push({"name":"searchColumn","value":searchColumn});
}
var searchText = jQuery(containerId+' input[type="search"]').val();
if(searchText !== undefined) {
filter.push({"name":"search","value":searchText});
}
}
filterContainer.find('.datatable-filter').on('change', function() {
var name = jQuery(this).data('filter-name');
var type = jQuery(this).data('filter-type');
var value = getFilterValues(name, type, this);
if(name === undefined || value === undefined) {
return;
}
for(var i in filter) {
if(filter[i].name === name) {
filter[i] = {"name":name, "value":value};
break;
}
}
loadData(1);
});
function getFilterValues(filterName, filterType, selector) {
switch(filterType) {
case 'radio':
return [jQuery(selector).find('input:radio[name="' + containerId.replace("#","")+'_'+filterName + '"]:checked').val()];
case 'checkbox':
var values = [];
var checkedInputs = jQuery(selector).find('input:checkbox[name="' + containerId.replace("#","")+'_'+filterName + '"]:checked');
for(var input of checkedInputs) {
values.push(input.value);
}
return values;
case 'hidden':
return jQuery(selector).find('input:hidden[name="' + containerId.replace("#","")+'_'+filterName + '"]').val();
default:
return;
}
}
container.find('th').each(function() {
var column = jQuery(this).data('column');
if(column !== undefined){
jQuery(this).css("cursor","pointer");
}
else{
jQuery(this).css("cursor","auto");
}
});
container.find('th').on('mouseenter', function() {
var column = jQuery(this).data('column');
if(typeof column !== 'undefined') {
jQuery(this).css("text-decoration","underline");
}
});
container.find('th').on('mouseleave', function() {
var column = jQuery(this).data('column');
if(typeof column !== 'undefined') {
jQuery(this).css("text-decoration","");
}
});
container.find('select.paging').on('change', function() {
var rows = jQuery(this).val();
setRowCount(rows);
loadData(1);
});
container.find('input[type="search"]').on('keyup', function(e) {
if(e.keyCode == 13) {
var text = jQuery(this).val();
if(container.find('select[type="column"]') != null){
setFilterToDom("searchColumn", container.find('select[type="column"]').val());
}
setFilterToDom("search",text);
loadData(1);
}
});
container.find('li.paginate_button.previous').on('click', function() {
var prev = jQuery(this).data('prev');
if(typeof prev !== 'undefined') {
loadData(prev);
}
});
container.find('li.paginate_button.next').on('click', function() {
var next = jQuery(this).data('next');
if(typeof next !== 'undefined') {
loadData(next);
}
});
container.find('th').on('click', function() {
var column = jQuery(this).data('column');
if(typeof column === 'undefined') {
return;
}
if(typeof jQuery(this).data('order') === 'undefined') {
jQuery(this).data('order', 'asc');
} else if(jQuery(this).data('order') === 'asc') {
jQuery(this).parent().find("th").removeData('order');
jQuery(this).data('order','desc');
} else {
//jQuery(this).data('order','asc');
if (column === defaultOrderColumn ){
jQuery(this).data('order','asc');
}
else{
jQuery(this).parent().find("th").removeData('order');
}
}
var order = jQuery(this).data('order');
if(typeof order !== 'undefined') {
setSearchOrder(column, order);
loadData(currentPage);
} else{
setSearchOrder(defaultOrderColumn, defaultOrder);
loadData(currentPage);
}
});
container.find('.div-order').on('change', function(){
var orderingInfo = $(this).val();
if(typeof orderingInfo !== '') {
orderingInfo = orderingInfo.split("-");
var column = orderingInfo[0];
var order = orderingInfo[1];
setSearchOrder(column, order);
loadData(currentPage);
} else{
loadData(currentPage);
}
});
container.on('click', 'ul.pagination li:not(.previous,.next,.active) a', function() {
var page = jQuery(this).data('page');
Tracker.event('datatable','pagechange', containerId + "에 대한 페이지 변경:" + page);
loadData(page);
});
this.changePaginateClickEvent = function(func){
container.off('click', 'ul.pagination li:not(.previous,.next,.active) a');
container.on('click', 'ul.pagination li:not(.previous,.next,.active) a', func);
};
function setRowCount(rows){
rowCount = rows;
};
function setSearchOrder(column, order) {
orderColumn = column;
orderAsc = order;
}
//필터 배열에 값 채우기
function setFilterToDom(name, value) {
var found = false;
for(var i=0; i < filter.length; i++) {
if(filter[i].name === name) {
filter[i].value = value;
found = true;
break;
}
}
if(found === false) {
filter.push({"name":name, "value":value});
}
switch(name) {
case "searchColumn":
jQuery(containerId+' select[type="column"]').val(value);
break;
case "search":
jQuery(containerId+' input[type="search"]').val(value);
break;
case "status":
var filterInputs = filterContainer.find('input:checkbox[name="' + containerId.replace("#","")+'_'+name+ '"]');
var checkStatuses = value.split(",");
if(checkStatuses.length > 0) {
for(var input of filterInputs) {
if(checkStatuses.includes(input.value)) {
$(input.parentElement).addClass('active');
$(input).prop('checked', true);
}else {
$(input.parentElement).removeClass('active');
$(input).prop('checked', false);
}
}
}
break;
case "qaVersionList":
jQuery(containerId+' input[name="' + containerId.replace("#","")+'_'+name+ '"]').val(value);
break;
default:
filterContainer.find('select.filter[data-name="' + name + '"]').val(value);
break;
}
}
function setDataUrl(setUrl){
dataUrl = setUrl;
}
function loadData(page) {
$('.div-table').empty(); // table형이 아닌 div인 경우 비워주기위해 추가했습니다
$('#image-choice-btn').prop('disabled', true); // 이미지 선택 버튼 비활성화
var hashtag = [containerId.replace("#",""), page, rowCount, orderColumn, orderAsc].join(SEPARATOR_HASH_TAG);
var data = {
page: page,
rows: rowCount,
col: orderColumn,
order: orderAsc
};
if(filter.length > 0) {
var filterHashtag = SEPARATOR_HASH_TAG;
for(var i in filter) {
var value = filter[i].value;
if(value != null) {
// array인 경우에 query param에 추가할 때 toString()이 반드시 필요합니다.
value = value.toString();
}
data[filter[i].name] = value;
filterHashtag += filter[i].name + "=" + data[filter[i].name];
if(i < filter.length-1) {
filterHashtag += "&";
}
}
hashtag += filterHashtag;
}
// console.log("dataUrl : ", dataUrl);
jQuery.ajax(dataUrl, {
async : true,
data: data,
headers: {
"Accept": "application/json",
'Content-type': 'application/json',
'Cache-Control': isCacheable? 'cache' : 'no-cache'
},
beforeSend : function(jqXHR, settings) {
// console.log("beforeSend data is " + JSON.stringify(data));
// container.find("tbody").empty();
// container.find('ul.pagination li.paginate_button:not(.previous,.next)').remove();
if (!ignoreHash) {
if(window.location.hash.length > 0){
var finalUpdatingEncodedHashTags = "";
var encodedHashTags = window.location.hash.replace("#","").split(SEPARATOR_HASH_TAG);
var foundMyContainer = false;
for(var i=0;i<encodedHashTags.length;i++) {
var decodedHashTags = b64DecodeUnicode(encodedHashTags[i]).split(SEPARATOR_HASH_TAG);
if(decodedHashTags.length < 1) continue;
var id = decodedHashTags[0];
if(id !== containerId.replace("#","")) {
finalUpdatingEncodedHashTags += encodedHashTags[i];
} else {
foundMyContainer = true;
finalUpdatingEncodedHashTags += b64EncodeUnicode(hashtag);
}
if(i < encodedHashTags.length-1) {
finalUpdatingEncodedHashTags += SEPARATOR_HASH_TAG;
}
}
if(foundMyContainer === false) {
finalUpdatingEncodedHashTags += SEPARATOR_HASH_TAG;
finalUpdatingEncodedHashTags += b64EncodeUnicode(hashtag);
}
window.location.hash=finalUpdatingEncodedHashTags;
} else {
window.location.hash=b64EncodeUnicode(hashtag);
}
}
},
success : function(datatable, textStatus, jqXHR) {
// console.log(datatable);
var data = datatable.data;
var tbody = container.find("tbody");
currentPage = datatable.pageNumber;
// 초기화 위치 변경 beforeSend -> afterReceive : why? 빠르게 여러번 요청 시 동시에 받으면서 여러 개의 응답이 한 번에 쌓임
container.find("tbody").empty();
container.find('ul.pagination li.paginate_button:not(.previous,.next)').remove();
if (data.length < 1) {
if(typeof listener.onDataEmpty === 'function') {
listener.onDataEmpty(tbody, data, rowCount);
}
var tr = '<tr><td colspan="' + columnCount + '" style="text-align:center;"><span class="tas-lang" lang-key="common-table-no-data"></span></td></tr>';
tbody.append(tr);
TAS_LANG.setValues('common-table-no-data');
container.find('div#datatable-buttons_info').text("Page: 1 / 1 Total: 0");
} else {
container.find('div#datatable-buttons_info').text("Page: " + datatable.pageNumber + " / " + datatable.maxPageNumber + " Total: " + datatable.totalCount);
for(var i = datatable.minPageNumber; i <= datatable.maxPageNumber; ++i) {
if(i == datatable.pageNumber) {
jQuery('<li class="paginate_button active"><a href="javascript:void(0);" data-page="' + i + '" aria-controls="datatable-buttons">' + i + '</a></li>').insertBefore(container.find('ul.pagination li:last-child'));
} else{
jQuery('<li class="paginate_button"><a href="javascript:void(0);" data-page="' + i + '" aria-controls="datatable-buttons">' + i + '</a></li>').insertBefore(container.find('ul.pagination li:last-child'));
}
}
if(datatable.prevPageNumber != 0) {
container.find('#datatable-buttons_previous').removeClass('disabled').data('prev', datatable.prevPageNumber);
} else {
container.find('#datatable-buttons_previous').addClass('disabled').removeData('prev');
}
if(datatable.nextPageNumber != 0) {
container.find('#datatable-buttons_next').removeClass('disabled').data('next', datatable.nextPageNumber);
} else{
container.find('#datatable-buttons_next').addClass('disabled').removeData('next');
}
container.find('select.paging').val(rowCount).attr("selected","selected");
container.find('th').each(function() {
jQuery(this).find('i.fa').remove();
if(jQuery(this).data('column') === orderColumn) {
//jQuery(this).find('i.fa').remove();
if(orderAsc === 'asc') {
jQuery(this).append(' <i class="fa fa-caret-up"></i>');
} else{
jQuery(this).append(' <i class="fa fa-caret-down"></i>');
}
}
});
listener.onDataLoad(tbody, data, datatable);
}
// 전처리, 후처리 스크립트 선택 시 선택된 아이들 css 처리
if(typeof dtBeforeScripts !== 'undefined' && dtBeforeScripts !== null){
Array.from(beforeScriptSeqs).forEach(function(seq){
$("#trB"+seq).css('opacity', '0.3');
$("#trB"+seq).css('cursor', 'not-allowed');
});
}
if(typeof dtAfterScripts !== 'undefined' && dtBeforeScripts !== null){
Array.from(afterScriptSeqs).forEach(function(seq){
$("#trA"+seq).css('opacity', '0.3');
$("#trA"+seq).css('cursor', 'not-allowed');
});
}
},
complete : function(jqXHR, textStatus) {
},
error: function(jqXHR, textStatus, errorThrown) {
if(typeof listener.onDataError !== 'undefined') {
listener.onDataError(textStatus);
}
else{
container.find("tbody").append('<tr><td colspan="' + columnCount + '" style="text-align:center;">' + errorThrown + '</td></tr>');
}
}
});
};
this.setRowCount = function(rows) {
setRowCount(rows);
};
this.setSearchOrder = function(column, order) {
setSearchOrder(column, order);
};
this.reloadData = function() {
this.loadData(currentPage);
};
this.loadData = function(page) {
loadData(page);
};
this.setFilterToDom = function(name, value) {
setFilterToDom(name, value);
}
this.setDataUrl = function(url) {
setDataUrl(url);
};
};
Date.prototype.format = function(f) {
if (!this.valueOf())
return " ";
var d = this;
return f.replace(/(yyyy|yy|MM|dd|E|hh|mm|ss|a\/p)/gi, function($1) {
switch ($1) {
case "yyyy":
return d.getFullYear();
case "yy":
return (d.getFullYear() % 1000).zf(2);
case "MM":
return (d.getMonth() + 1).zf(2);
case "dd":
return d.getDate().zf(2);
case "HH":
return d.getHours().zf(2);
case "hh":
return ((h = d.getHours() % 12) ? h : 12).zf(2);
case "mm":
return d.getMinutes().zf(2);
case "ss":
return d.getSeconds().zf(2);
case "a/p":
return d.getHours() < 12 ? "AM" : "PM";
default:
return $1;
}
});
};
Date.prototype.setUTCEpoch = function(epoch) {
var d = this;
var offset = d.getTimezoneOffset() * 60 * 1000;
d.setTime(epoch - offset);
return d;
};
String.prototype.string = function(len) {
var s = '', i = 0;
while (i++ < len) {
s += this;
}
return s;
};
String.prototype.zf = function(len) {
return "0".string(len - this.length) + this;
};
Number.prototype.zf = function(len) {
return this.toString().zf(len);
};
import javax.validation.constraints.Min;
public class DataTableParameter {
@Min(1) private int page;
@Min(1) private int rows;
private String col;
private String order;
public DataTableParameter() {
}
public DataTableParameter(int page, int rows) {
this.page = page;
this.rows = rows;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getRows() {
return rows;
}
public void setRows(int rows) {
this.rows = rows;
}
public String getCol() {
return col;
}
public void setCol(String col) {
this.col = col;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
@Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((col == null) ? 0 : col.hashCode());
result = prime * result + ((order == null) ? 0 : order.hashCode());
result = prime * result + page;
result = prime * result + rows;
return result;
}
@Override public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DataTableParameter other = (DataTableParameter) obj;
if (col == null) {
if (other.col != null)
return false;
} else if (!col.equals(other.col))
return false;
if (order == null) {
if (other.order != null)
return false;
} else if (!order.equals(other.order))
return false;
if (page != other.page)
return false;
if (rows != other.rows)
return false;
return true;
}
@Override public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("page=").append(page).append("&rows=").append(rows).append("&col=").append(col)
.append("&order=").append(order);
return builder.toString();
}
}
import java.lang.reflect.Field;
public class DataTableQueryParameter<T> {
final Class<T> typeParameterClass;
private final String gameCode;
private final String deviceOs;
private final int start;
private final int count;
private String orderColumn;
private String order;
private String versionName;
public DataTableQueryParameter(final Class<T> typeParameterClass, final String gameCode,
final String deviceOs, final DataTableParameter dataTableParameters) {
super();
this.typeParameterClass = typeParameterClass;
this.gameCode = gameCode;
this.deviceOs = deviceOs;
this.start = (dataTableParameters.getPage() - 1) * dataTableParameters.getRows();
this.count = dataTableParameters.getRows();
this.setOrder(dataTableParameters.getOrder());
this.setOrderColumn(dataTableParameters.getCol());
}
public String getGameCode() {
return gameCode;
}
public String getDeviceOs() {
return deviceOs;
}
public int getStart() {
return start;
}
public int getCount() {
return count;
}
public String getOrderColumn() {
return orderColumn;
}
private void setOrderColumn(String orderColumn) {
if (orderColumn == null || orderColumn.isEmpty())
return;
String replace = orderColumn.replace("_", "");
if (typeParameterClass.getSuperclass() != null) {
// TODO 부모가 없을 때 까지 올라가는 로직 까지는 안 짰음
for (Field f : typeParameterClass.getSuperclass().getDeclaredFields()) {
if (f.getName().equalsIgnoreCase(replace)) {
this.orderColumn = orderColumn;
return;
}
}
}
for (Field f : typeParameterClass.getDeclaredFields()) {
if (f.getName().equalsIgnoreCase(replace)) {
this.orderColumn = orderColumn;
return;
}
}
throw new RuntimeException("No match columns!");
}
public void setOrderColumnManually(String orderColumn) {
this.orderColumn = orderColumn;
}
public void setOrderManually(String order) {
this.order = order;
}
public String getOrder() {
return order;
}
private void setOrder(String order) {
if (order == null || order.isEmpty())
return;
if (order.equalsIgnoreCase("asc") || order.equalsIgnoreCase("desc")) {
this.order = order;
} else {
throw new RuntimeException("No match column order!");
}
}
public String getVersionName() { return versionName; }
public void setVersionName(String versionName) { this.versionName = versionName; }
@Override public String toString() {
return "DataTableQueryParameter [gameCode=" + gameCode + ", deviceOs=" + deviceOs + ", start="
+ start + ", count=" + count + ", orderColumn=" + orderColumn + ", order=" + order
+ ", typeParameterClass=" + typeParameterClass + "]";
}
}
List<Script> selectScriptList(DataTableQueryParameter<Script> qp, String searchText);
int selectTotalScriptCount(String gameCode, String deviceOs, String searchText);
<select id="selectTotalScriptCount" resultType="int">
SELECT COUNT(1) AS CNT FROM TB_SCRIPT
WHERE
GAME_CODE = #{0}
AND
DEVICE_OS = #{1}
<if test="param3 != null">
AND
DISPLAY_NAME LIKE '%${param3}%'
</if>
</select>
<select id="selectScriptList" resultType="com.netmarble.tas.dashboard.domain.Script">
SELECT
SCRIPT_SEQ,
GAME_CODE,
DEVICE_OS,
DISPLAY_NAME,
SCRIPT_DESCRIPTION,
UPDATE_DATETIME
FROM
TB_SCRIPT
WHERE
GAME_CODE = #{param1.gameCode}
AND
DEVICE_OS = #{param1.deviceOs}
<if test="param2 != null">
AND
DISPLAY_NAME LIKE '%${param2}%'
</if>
<if test="param1.order != null and param1.order != '' and param1.orderColumn != null and param1.orderColumn != ''">
ORDER BY ${param1.orderColumn} ${param1.order}
</if>
LIMIT
#{param1.start}, #{param1.count}
</select>
@Transactional(readOnly=true)
public DataTable<Script> getScriptDataTable(final String gameCode, final String deviceOs, final DataTableParameter parameters, final String searchText) {
int totalCount = scriptMapper.selectTotalScriptCount(gameCode, deviceOs, searchText);
DataTableQueryParameter<Script> qp = new DataTableQueryParameter<Script>(Script.class, gameCode, deviceOs, parameters);
List<Script> selectScriptList = scriptMapper.selectScriptList(qp, searchText);
DataTable<Script> dt = new DataTable<Script>(parameters.getPage(), parameters.getRows(), totalCount, selectScriptList);
return dt;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment