그리드를 그리는(drawing) Toast Grid.ㅂㅂ
<div class="gridWrapper">
<div id="grid"></div>
<div id="pagination" class="tui-pagination"></div>
</div>
$(function() {
review.init();
});
let review = {
seq: null,
pagination : null,
cnt : null,
limit : 11,
currentPage: 1,
init: function () {
let _this = this;
let Grid = tui.Grid;
Grid.applyTheme('clean');
this.grid = new Grid({
el: document.getElementById('grid'),
scrollX: false,
scrollY: false,
bodyHeight: 450,
rowHeaders: ['checkbox'],
columns: [
{
header: "게시글 번호",
name: "review_id",
align: "center",
},
{
header: "글쓴이",
name: "writer",
align: "center",
},
{
header: "제목",
name: "title",
align: "center",
},
{
header: "내용",
name: "content",
align: "center",
resizable: true,
editor: 'text',
},
{
header: "작성일자",
name: "create_dt",
align: "center",
},
{
header: "수정일자",
name: "update_dt",
align: "center",
},
],
});
/* 데이터 총 개수 세는 함수 */
this.cnt = this.readCnt();
/* 초기 데이터 읽어오는 함수 */
let list = this.read();
/* 페이지네이션 초기화하는 함수 */
this.pagination = new tui.Pagination(document.getElementById('pagination'), {
visiblePages: 5, // 한 번에 보여줄 1,2,3,4 목차 개수
totalItems : this.cnt, // 전체 아이템 개수가 몇 개인지
itemsPerPage: this.limit, // 한 페이지에 몇 개씩 보여줄 것인지
centerAlign: true // 현재 선택된 페이지 중앙 정렬
});
/* 읽어온 데이터 그리드에 그리는 함수 */
if (list) {
this.grid.resetData(list);
this.pagination.setTotalItems(this.cnt);
}
/* 페이지 이동 시 실행되는 함수 */
this.pagination.on('afterMove', function (ev) {
_this.currentPage = ev.page;
let list = _this.read();
if (list) {
_this.grid.resetData(list);
_this.pagination.setTotalItems(_this.cnt);
}
});
/* 검색창 관련 함수 */
const searchEl = $(".search");
const searchInputEl = searchEl.find("input");
searchEl.click(function () {
searchInputEl.focus();
searchInputEl.val('');
})
searchInputEl.on("focus", function() {
searchEl.addClass("focused");
searchInputEl.attr("placeholder", "검색할 내용을 입력하세요.");
});
searchInputEl.on("blur", function() {
searchEl.removeClass("focused");
// searchInputEl.val('');
searchInputEl.attr("placeholder", "");
});
/* 검색창 enterkey 이벤트 */
$(".search_input").on("keydown", function(e){
if(e.keyCode === 13) {
let list = _this.read();
if (list) {
_this.grid.resetData(list);
_this.cnt = _this.readCnt();
_this.pagination.setTotalItems(_this.cnt);
}
}
});
/* 게시글 상세보기 */
this.grid.on('click', (ev) => {
let _this = this;
let selectedColumn = ev.columnName;
/* 내용을 선택하는 경우에만 수행 */
if (selectedColumn != "content") return;
/* Column을 클릭했을 때만 수행 */
let focuesCell = this.grid.getFocusedCell();
if (focuesCell) {
let review_id = _this.grid.getRow(ev.rowKey).review_id;
this.readOne(review_id);
}
});
},
/* CRUD 함수들 */
/* CREATE */
create: function (data) {
let _this = this;
data = data;
$.ajax({
type: "PUT",
url: "/review",
async: false,
contentType:"application/json; charset=utf-8",
data: JSON.stringify({
title: data.title,
content: data.content
}),
success: function(response) {
$("dialog").hide();
_this.read();
},
error: function () {
}
})
},
/* READ */
read: function() {
let _this = this;
let data;
$.ajax({
type:"POST",
url:"/review",
async: false,
contentType:"application/json; charset=utf-8",
data: JSON.stringify({
page: this.currentPage, // 현재 페이지
limit: this.limit, // 한번에 몇 개의 데이터를 보여줄 것인지
content: $(".search_input").val(),
}),
success: function(response){
data = response;
_this.grid.resetData(data);
// _this.pagination.setTotalItems(response.length);
},
error: function(response) {
console.log(response);
swal({
title: response.responseText,
type: 'warning'
})
}
});
return data;
},
/* CRUD 도와주는 함수들 */
/* 데이터 개수 세는 함수 */
readCnt: function () {
let _this = this;
let cnt;
$.ajax({
type: "POST",
url: "/review/cnt",
async: false,
contentType:"application/json; charset=utf-8",
data: JSON.stringify({
content: $(".search_input").val(),
}),
success: function(response){
cnt = response;
},
error: function() {
}
});
return cnt;
},
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.iraefolio.mapper.ReviewMapper">
<select id="read" resultType="com.iraefolio.domain.ReviewEntity">
SELECT * FROM TB_REVIEW
<if test="CONTENT != null and !CONTENT.equals('')">
WHERE CONTENT LIKE CONCAT('%', #{CONTENT}, '%')
</if>
ORDER BY REVIEW_ID DESC
LIMIT #{limit} OFFSET #{offset}
</select>
<select id="readOne" resultType="com.iraefolio.domain.ReviewEntity">
SELECT * FROM TB_REVIEW
WHERE REVIEW_ID = #{REVIEW_ID}
</select>
<select id="readCnt" resultType="Integer">
SELECT COUNT(*)
FROM TB_REVIEW
<if test="CONTENT != null and !CONTENT.equals('')">
WHERE CONTENT LIKE CONCAT('%', #{CONTENT}, '%')
</if>
</select>
<insert id="create">
INSERT INTO TB_REVIEW(TITLE, CONTENT, CREATE_DT)
VALUES (#{TITLE}, #{CONTENT}, current_timestamp)
</insert>
<update id="update">
UPDATE TB_REVIEW SET
UPDATE_DT = current_timestamp
<if test="isUpdated">
, CONTENT = #{CONTENT}
</if>
WHERE REVIEW_ID = #{REVIEW_ID}
</update>
<delete id="delete">
DELETE FROM TB_REVIEW
WHERE REVIEW_ID = #{REVIEW_ID}
</delete>
</mapper>
package com.iraefolio.controller;
import com.iraefolio.domain.ReviewEntity;
import com.iraefolio.service.ReviewService;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Tag(name = "review Controller", description = "review Controller")
@Log4j2
@RequiredArgsConstructor
@RequestMapping("/review")
@PreAuthorize("hasRole('USER')")
@RestController
public class ReviewController {
private final ReviewService service;
/* PAGING */
@Operation(summary = "review paging", description = "/review로 이동합니다.")
@GetMapping
public ModelAndView review() {
ModelAndView mav = new ModelAndView("review");
return mav;
}
/* READ */
@Operation(summary = "READ review data", description = "/review의 데이터를 읽어옵니다.")
@PostMapping
public ResponseEntity read(@Valid @RequestBody ReviewEntity entity, BindingResult bindingResult) throws Exception {
if (bindingResult.hasErrors()) throw new BindException(bindingResult);
List<ReviewEntity> list = service.read(entity);
return ResponseEntity.ok(list);
}
/* READONE */
@Operation(summary = "READ review data by seq", description = "/review의 데이터를 한 개 읽어옵니다.")
@GetMapping("/reviewDetail")
public ModelAndView readOne(@RequestParam Integer review_id) throws Exception {
ReviewEntity data = service.readOne(review_id);
ModelAndView mav = new ModelAndView("/reviewDetail");
mav.addObject("data", data);
return mav;
}
/* CNT */
@Operation(summary = "READ review cnt", description = "/review의 데이터 개수를 읽어옵니다.")
@PostMapping("/cnt")
public Integer readCnt(ReviewEntity entity) throws Exception {
Integer cnt = service.readCnt(entity);
return cnt;
}
/* CREATE */
@Operation(summary = "CREATE review", description = "새로운 review를 작성합니다.")
@PutMapping
public void create(@RequestBody ReviewEntity entity) throws Exception {
service.create(entity);
}
/* UPDATE */
@Operation(summary = "UPDATE review", description = "review를 수정합니다.")
@PatchMapping
public void update(@RequestBody List<ReviewEntity> entity) throws Exception {
service.update(entity);
}
}
package com.iraefolio.service;
import com.iraefolio.domain.ReviewEntity;
import com.iraefolio.mapper.ReviewMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@Log4j2
@RequiredArgsConstructor
@Service
public class ReviewService {
private final ReviewMapper mapper;
/* READ */
public List<ReviewEntity> read(ReviewEntity entity) throws Exception {
List<ReviewEntity> list = mapper.read(entity);
return list;
}
/* READONE */
public ReviewEntity readOne(Integer review_id) throws Exception {
ReviewEntity data = mapper.readOne(review_id);
return data;
}
/* ReadCnt */
public Integer readCnt(ReviewEntity entity) throws Exception {
Integer cnt = mapper.readCnt(entity);
return cnt;
}
/* CREATE */
public void create(ReviewEntity entity) throws Exception {
mapper.create(entity);
}
/* UPDATE */
public void update(List<ReviewEntity> entity) throws Exception {
for (int i = 0; i < entity.size(); i++) {
ReviewEntity e = entity.get(i);
if (e.isUpdated()) {
mapper.update(e);
}
if (e.isDeleted()) {
mapper.delete(e);
}
}
}
}
package com.iraefolio.domain;
import com.fasterxml.jackson.annotation.JsonGetter;
import lombok.Data;
@Data
public class BaseEntity {
@Schema(description = "CRUD 구분을 위한 flag", nullable = false)
boolean isCreated;
@Schema(description = "CRUD 구분을 위한 flag", nullable = false)
boolean isUpdated;
@Schema(description = "CRUD 구분을 위한 flag", nullable = false)
boolean isDeleted;
@Schema(description = "pagination에 사용하는 변수", nullable = false)
private int limit;
@Schema(description = "pagination에 사용하는 변수", nullable = false)
private int page;
@Schema(description = "pagination에 사용하는 변수", nullable = false)
private int offset;
@JsonGetter
public int getOffset(){
if(limit <= 0)
limit = 10;
if(page <= 0)
page = 1;
return (page - 1) * limit;
}
}