본문 바로가기
ICIA 수업일지

2021.10.07 수업일지(Spring Framework 연습)

by 주성씨 2021. 10. 7.

- Spring Framework란?

자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크로서 엔터프라이즈급 애플리케이션을 개발하기 위한 모든 기능을 종합적으로 제공하는 경량화된 솔루션입니다.

엔터프라이즈급 개발이란 뜻대로만 풀이하면 기업을 대상으로 하는 개발이라는 말입니다. 즉, 대규모 데이터 처리와 트랜잭션이 동시에 여러 사용자로 부터 행해지는 매우 큰 규모의 환경을 엔터프라이즈 환경이라 일컫습니다.

Spirng Framework는 경량 컨테이너로 자바 객체를 담고 직접 관리합니다. 객체의 생성 및 소멸 그리고 라이프 사이클을관리하며 언제든 Spring 컨테이너로 부터 필요한 객체를 가져와 사용할 수 있습니다. 

 

- 어제와 마찬가지로 setup project를 이용해서 ex03을 만들겠다.

- 서버 모듈 경로를 /로 수정해주고 아래와 같이 정상 적으로 서버가 작동하는지 확인하자.

 

- /ex03/src/main/webapp/WEB-INF/spring/root-context.xml -> 스프링이 어떤 DB를 사용하는지 알 수 있다.

 

- 이제 컨트롤러부터 만들도록 하겠다.

- /ex03/src/main/java/com/example/controller/HomeController.java

package com.example.controller;

import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HomeController {

	//Servlet - /면  home view로 간다.
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
			
		return "home";
	}
	
}

 

- /ex03/src/main/webapp/WEB-INF/views/home.jsp

<%@ 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>
<title>게시판 관리</title>
<link rel="stylesheet" href="/resources/home.css" />
</head>
<body>
	<div id="page">
		<div id="header">
			<img src="/resources/back.png" width="930"/>
		</div>
		<div id="center">
			<div id="menu">
				<h4><a href="">게시판 관리</a></h4>
			</div>
			<div id="content">
			<jsp:include page="${pageName}"></jsp:include>
			</div>
		</div>
		<div id="footer"></div>
	</div>
</body>
</html>

 

- /ex03/src/main/webapp/resources/home.css

@CHARSET "UTF-8";

@font-face {
	font-family: 'SpoqaHanSansNeo-Regular';
	src:
		url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2108@1.1/SpoqaHanSansNeo-Regular.woff')
		format('woff');
	font-weight: normal;
	font-style: normal;
}

body {
	font-family: 'SpoqaHanSansNeo-Regular';
}

#page {
	width: 960px;
	padding: 20px;
	margin: 0px auto;
	border: 1px solid black;
}

#header {
	width: auto;
	border: 1px solid black;
	padding: 10px;
	margin-bottom: 20px;
	text-align: center;
}
#center {
	width: auto;
	border: 1px solid black;
	padding: 10px;
	margin-bottom: 20px;
}
#footer{
	width: auto;
	border: 1px solid black;
	padding: 10px;
}
#menu a:nth-child(n){
	text-decoration: none;
	padding: 10px 20px 10px 20px;
}
#menu a:visited{
	color: black;
}

.pagination {
	display: inline-block;
	margin-top: 20px;
}

.pagination a {
	color: black;
	float: left;
	padding: 8px 16px;
	text-decoration: none;
}

.pagination a.active {
	background-color: #4CAF50;
	color: white;
}

.pagination a:hover{
	background: gray;
	color: white;
}

h1 {
	text-align: center;
}

table {
	border-collapse: collapse;
	margin: 0px auto;
}

td {
	border: 1px solid gray;
}

.title {
	background: gray;
	color: white;
	text-align: center;
}

.row:hover {
	cursor: pointer;
	background: gray;
	color: white;
}

.btn {
	text-align: center;
}

 

- /ex03/src/main/webapp/WEB-INF/views/(new)about.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<h1>소개란</h1>
<p>티스토리는 대한민국의 가입형/설치형 블로그 서비스다. 2006년 5월 25일, 다음커뮤니케이션과 태터앤컴퍼니가 함께
	공동운영을 시작했으나, 서비스 시작 1년 2개월 만인 2007년 7월 10일에 모든 서비스의 운영권이 다음커뮤니케이션으로
	이관되었다.</p>

 

- /ex03/src/main/java/com/example/controller/HomeController.java

package com.example.controller;

import java.util.Locale;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HomeController {

	//Servlet - /면  home view로 간다.
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		model.addAttribute("pageName","about.jsp");
		return "home";
	}
	
}

 

확인

 

- 인터페이스로 메퍼를 만들겠다.

- /ex03/src/main/java/com/example/mapper/BoardMapper.java

package com.example.mapper;

import java.util.List;

import com.example.domain.BoardVO;
import com.example.domain.Criteria;

public interface BoardMapper {
	public List<BoardVO> list(Criteria cri);
}

 

- /ex03/src/main/resources/mapper/BoardMapper.xml

<?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.example.mapper.BoardMapper">
	<select id="list" resultType="com.example.domain.BoardVO">
		select * from tbl_board
		order by bno desc
		limit #{pageStart}, #{perPageNum}
	</select>
</mapper>

 

- 이제 맵퍼 테스트를 해보겠다.

- /ex03/src/test/java/com/example/controller/MysqlTest.java

package com.example.controller;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.example.domain.Criteria;
import com.example.mapper.BoardMapper;
import com.example.mapper.MysqlMapper;

@RunWith(SpringJUnit4ClassRunner.class) // 먼저 SpringJUnit4ClassRunner.class
										// import한다.
@ContextConfiguration(locations={"file:src/main/webapp/WEB-INF/spring/**/*.xml"})
public class MysqlTest {
	// 자동으로 연결
	@Autowired
	private BoardMapper mapper;

	// 연결해서 getTime을 테스트
	@Test
	public void getList() {
		Criteria cri = new Criteria();
		mapper.list(cri);
	}
}

 

확인

 

- 이제 보드 컨트롤러를 만들겠다.

- /ex03/src/main/java/com/example/controller/BoardController.java

package com.example.controller;

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.example.domain.Criteria;
import com.example.domain.PageMaker;
import com.example.mapper.BoardMapper;

@Controller
@RequestMapping("/board")
public class BoardController {
	@Autowired
	BoardMapper mapper;
	
	@RequestMapping("/list.json")
	@ResponseBody
	public HashMap<String, Object> list(Criteria cri){
		HashMap<String, Object> map = new HashMap<String, Object>();
		cri.setPerPageNum(5);
		
		// map에 list 결과를 put
		map.put("list", mapper.list(cri));
		map.put("cri", cri);
		
		PageMaker pm = new PageMaker();
		// 순서 중요
		pm.setDisplayPageNum(5);
		pm.setCri(cri);
		pm.setTotalCount(120);
		map.put("pm", pm);
		return map;
	}
}

 

json 데이터 확인

 

- 이제 목록을 페이지에 출력할 수 있도록 하겠다.

- /ex03/src/main/java/com/example/controller/BoardController.java

.....
	// 2. list 출력
	@RequestMapping("/list")
	public String listGet(Model model){
		// list.jsp에 데이터를 출력하고
		model.addAttribute("pageName","board/list.jsp");
		// 최종적으로 home.jsp에 보여질 것이니깐
		return "home";
	}
.....

 

- /ex03/src/main/webapp/WEB-INF/views/home.jsp

<%@ 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">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<title>게시판 관리</title>
<link rel="stylesheet" href="/resources/home.css" />
<script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
<script
	src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.js"></script>
</head>
<body>
	<div id="page">
		<div id="header">
			<a href="/"><img src="/resources/back.png" width="930"/></a>
		</div>
		<div id="center">
			<div id="menu">
				<h4><a href="/board/list">게시판 관리</a></h4>
			</div>
			<div id="content">
			<jsp:include page="${pageName}"></jsp:include>
			</div>
		</div>
		<div id="footer"></div>
	</div>
</body>
</html>

 

- /ex03/src/main/webapp/WEB-INF/views/board/list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<h1>[게시판 관리]</h1>
<table id="tbl"></table>
<script id="temp" type="text/x-handlebars-template">
	<tr class="title">
		<td width="50">No.</td>
		<td width="250">제목</td>
		<td width="100">작성자</td>
		<td width="200">작성일</td>
		<td width="200">수정일</td>
	</tr>
	{{#each list}}
		<tr class="row">
			<td>{{bno}}</td>
			<td>{{title}}</td>
			<td>{{writer}}</td>
			<td>{{regdate}}</td>
			<td>{{updatedate}}</td>
		</tr>
	{{/each}}
</script>
<div id="pagination" class="pagination"></div>
<script>
	var page=1;
	getList();
	function getList(){
		$.ajax({
			type:'get',
			url:'/board/list.json',
			dataType:"json",
			data:{'page':page},
			success:function(data){
				var temp = Handlebars.compile($('#temp').html());
				$("#tbl").html(temp(data));
				
				//페이지 목록 생성
				var src = getPagination(data);
				$("#pagination").html(src);
			}
		})
	}
	
	// 특정 페이지 번호를 클릭한 경우
	$('#pagination').on('click','a',function(e){
		e.preventDefault();
		page = $(this).attr("src");
		getList();
	})
</script>
<script src="/resources/pagination.js"></script>

 

확인

 

- 이제 조건 검색을 해보고 검색한 데이터의 갯수까지 출력해보도록 하겠다.

- /ex03/src/main/webapp/WEB-INF/views/board/list.jsp

.....
<h1>[게시판 관리]</h1>
<div id="condition">
	<select name="" id="searchType">
		<option value="title">제목</option>
		<option value="content">내용</option>
		<option value="writer">작성자</option>
	</select> <input type="text" id="keyword" placeholder="검색어" />
	검색수 : <span id="total"></span>
	<hr />
</div>
<table id="tbl"></table>
.....
<script>
	var page = 1;
	getList();

	// 검색어 enter시
	$('#keyword').on('keypress', function(e) {
		if (e.keyCode == 13) {
			page == 1;
			getList();
		}
	})

	function getList() {
		var keyword = $('#keyword').val();
		var searchType = $('#searchType').val();
		$.ajax({
			type : 'get',
			url : '/board/list.json',
			dataType : "json",
			data : {
				'page' : page,
				'keyword':keyword,
				'searchType':searchType
			},
			success : function(data) {
				var temp = Handlebars.compile($('#temp').html());
				$("#tbl").html(temp(data));
				$("#total").html(data.pm.totalCount);
				//페이지 목록 생성
				var src = getPagination(data);
				$("#pagination").html(src);
			}
		})
	}
.....

 

- /ex03/src/main/java/com/example/mapper/BoardMapper.java

.....
	public int totalCount(Criteria cri);
}

 

- /ex03/src/main/java/com/example/controller/BoardController.java

....
	// 1. data list 추출
	@RequestMapping("/list.json")
	@ResponseBody
	public HashMap<String, Object> list(Criteria cri){
		HashMap<String, Object> map = new HashMap<String, Object>();
		cri.setPerPageNum(5);
		
		// map에 list 결과를 put
		map.put("list", mapper.list(cri));
		map.put("cri", cri);
		
		PageMaker pm = new PageMaker();
		// 순서 중요
		pm.setDisplayPageNum(5);
		pm.setCri(cri);
		pm.setTotalCount(mapper.totalCount(cri)); <<<---
		map.put("pm", pm);
		return map;
	}
....

 

- /ex03/src/main/resources/mapper/BoardMapper.xml

<?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.example.mapper.BoardMapper">
	<select id="list" resultType="com.example.domain.BoardVO">
		select * from tbl_board
		<if test="searchType=='title'">
			where title like concat('%',#{keyword},'%')
		</if>
		<if test="searchType=='content'">
			where content like concat('%',#{keyword},'%')
		</if>
		<if test="searchType=='writer'">
			where writer like concat('%',#{keyword},'%')
		</if>
		order by bno desc
		limit #{pageStart}, #{perPageNum}
	</select>
	<select id="totalCount" resultType="int">
		select count(*) from tbl_board
		<if test="searchType=='title'">
			where title like concat('%',#{keyword},'%')
		</if>
		<if test="searchType=='content'">
			where content like concat('%',#{keyword},'%')
		</if>
		<if test="searchType=='writer'">
			where writer like concat('%',#{keyword},'%')
		</if>
	</select>
</mapper>

 

확인

 

 

- 이제 리드페이지를 만들고 댓글까지 작성할 수 있도록 하겠다.

- /ex03/src/main/resources/mapper/BoardMapper.xml

.....
	<select id="read" resultType="com.example.domain.BoardVO">
		select * from tbl_board
		where bno=#{bno}
	</select>
....

 

- /ex03/src/main/java/com/example/mapper/BoardMapper.java

.....
	public BoardVO read(int bno);
}

 

- /ex03/src/main/webapp/WEB-INF/views/board/read.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<h1>[]게시글 정보]</h1>

 

- /ex03/src/main/java/com/example/controller/BoardController.java

.....
	// 3. read 출력
	@RequestMapping("/read")
	public String readGet(Model model, int bno){
		// 데이터를 담아와 vo에 넣고
		model.addAttribute("vo",mapper.read(bno));
		// read.jsp에 데이터를 출력하고
		model.addAttribute("pageName","board/read.jsp");
		// 최종적으로 home.jsp에 보여질 것이니깐
		return "home";
	}
.....

 

- /ex03/src/main/webapp/WEB-INF/views/board/read.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt"%>
<h1>[게시글 정보]</h1>
<div style="text-align: left">
	<h3 style="text-align: left">[${vo.bno}] ${vo.title}</h3>
	<h4 style="text-align: left">
		<f:formatDate value="${vo.regdate}" pattern="yyyy-MM-dd HH:mm:ss" />
	</h4>
	<hr />
	<p>${vo.content}</p>
</div>

 

- /ex03/src/main/webapp/WEB-INF/views/board/list.jsp - 클릭 시 이동

....
	{{#each list}}
		<tr class="row" onClick="location.href='/board/read?bno={{bno}}'"> <<<---
			<td>{{bno}}</td>
			<td>{{title}}</td>
			<td>{{writer}}</td>
			<td>{{regdate}}</td>
			<td>{{updatedate}}</td>
		</tr>
	{{/each}}
....

 

화인

 

- 이제 댓글을 작성할 수 있도록 하겠다.

- 댓글을 위한 테이블 부터 만들겠다.

- go to mysql

#2021.10.07
#댓글 처리를 위한 DB 작업
create table tbl_reply(
 rno int auto_increment primary key, 
 bno int not null, 
 reply varchar(1000) not null, 
 replyer varchar(50) not null, 
 replydate datetime default now(), 
 updatedate datetime default now(), 
 foreign key(bno) references tbl_board(bno)
);

 

- 이전에 설정하지 못한 테이블간 외래키 관계를 설정해주도록 하겠다.

# 회원가입한 사람만 댓글 또는 게시글을 달 수 있다는 가정하에 아래와 같이 외래키를 설정한다.
alter table tbl_reply add foreign key(replyer) references tbl_user(uid);

alter table tbl_board add foreign key(writer) references tbl_user(uid);

 

다이어그램 확인

 

- simple data를 넣어주겠다.

- 259, 192번 게시글에 댓글 데이터를 넣어주겠다.

alter table tbl_board add foreign key(writer) references tbl_user(uid);

insert into tbl_reply(bno,reply,replyer) values(259,'259번에 댓글 달았어요','user01'); 
insert into tbl_reply(bno,reply,replyer) values(259,'259번에 두번째로 댓글 달았어요','user02');
insert into tbl_reply(bno,reply,replyer) values(259,'259번에 세번째로 댓글 달았어요','user03');
insert into tbl_reply(bno,reply,replyer) values(259,'259번에 네번째로 댓글 달았어요','user04');
insert into tbl_reply(bno,reply,replyer) values(259,'259번에 다섯번째로 댓글 달았어요','user05');

select * from tbl_reply; 

insert into tbl_reply(bno,reply,replyer) values(192,'192번에 댓글 달았어요','user01'); 
insert into tbl_reply(bno,reply,replyer) values(192,'192번에 두번째로 댓글 달았어요','user02');
insert into tbl_reply(bno,reply,replyer) values(192,'192번에 세번째로 댓글 달았어요','user03');
insert into tbl_reply(bno,reply,replyer) values(192,'192번에 네번째로 댓글 달았어요','user04');
insert into tbl_reply(bno,reply,replyer) values(192,'192번에 다섯번째로 댓글 달았어요','user05');

insert into tbl_reply(bno,reply,replyer)
select bno,reply,replyer from tbl_reply;

select count(*),bno from tbl_reply
group by bno;

 

확인

 

- 이제 게시글 정보란에서 댓글을 확인할 수 있도록 하겠다.

- /ex03/src/main/java/com/example/mapper/ReplyMapper.java

package com.example.mapper;

import java.util.HashMap;
import java.util.List;

import com.example.domain.ReplyVO;

public interface ReplyMapper {
	// 값을 두개 보내면 오류가 나서 hashmap으로 보내겠다.
	public List<ReplyVO> list(HashMap<String, Object> map);
}

 

- /ex03/src/main/java/com/example/domain/ReplyVO.java

package com.example.domain;

import java.util.Date;

import com.fasterxml.jackson.annotation.JsonFormat;

public class ReplyVO {
	private int rno;
	private int bno;
	private String reply;
	private String replyer;
	
	@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
	private Date replydate;
	@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
	private Date updatedate;
    
    .... getter, setter, tostring

 

- /ex03/src/main/resources/mapper/ReplyMapper.xml

- cri는 object로 넘어오기 때문에 붙는다.

<?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.example.mapper.ReplyMapper">
	<select id="list" resultType="com.example.domain.ReplyVO">
		select * from tbl_reply
		where bno=#{bno}
		order by rno desc
		limit #{cri.pageStart}, #{cri.perPageNum}
	</select>
</mapper>

 

- 값이 잘 넘어오는지 테스트해보겠다.

- /ex03/src/test/java/com/example/controller/MysqlTest.java

.....
	@Autowired
	private ReplyMapper rmapper;
	
	@Test
	public void list(){
		Criteria rcri = new Criteria();
		HashMap<String, Object> map = new HashMap<>();
		map.put("bno", 259);
		map.put("cri", rcri);
		rmapper.list(map);
	}
}

 

확인

 

- 총 댓글 갯수를 구해보도록 하겠다.

- /ex03/src/main/java/com/example/mapper/ReplyMapper.java

.....
	public int totalCount(int bno);
}

 

- /ex03/src/main/resources/mapper/ReplyMapper.xml

.....
	<select id="totalCount" resultType="int">
		select count(*) from tbl_reply
		where bno=#{bno}
	</select>
</mapper>

 

- /ex03/src/test/java/com/example/controller/MysqlTest.java

확인

 

- reply 컨트롤러를 만들도록 하겠다.

- /ex03/src/main/java/com/example/controller/ReplyController.java

package com.example.controller;

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.domain.Criteria;
import com.example.domain.PageMaker;
import com.example.mapper.ReplyMapper;

// 데이터 처리 전용은 @RestController Responsebody는 없어도 된다.
@RestController
@RequestMapping("/reply")
public class ReplyController {
	@Autowired
	ReplyMapper rmapper;
	
	// 1. 댓글 목록 불러오기
	@RequestMapping("/list.json")
	public HashMap<String, Object> list(Criteria cri, int bno){
		HashMap<String, Object> map = new HashMap<String, Object>();
		cri.setPerPageNum(5); // 5개씩 보이도록 하겠다.
		
		HashMap<String, Object> rMap = new HashMap<String, Object>();
		
		rMap.put("cri", cri);
		rMap.put("bno", bno);
		
		map.put("list", rmapper.list(rMap));
		map.put("cri", cri);
		
		// 페이지 버튼 설정
		PageMaker pm = new PageMaker();
		pm.setDisplayPageNum(5); // 페이지 버튼이 5개씩
		pm.setCri(cri);
		pm.setTotalCount(rmapper.totalCount(bno));
		map.put("pm",pm);
		return map;
	}
}

 

데이터 출력 확인

 

- 이제 댓글을 template을 이용해 read page에 출력할 수 있도록 하겠다.

- /ex03/src/main/webapp/WEB-INF/views/board/read.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt"%>
<style>
.box{
	text-align: left;
	margin-top: 10px;
	padding: 10px;
	border-bottom: 1px dotted gray;
	
}
.replyer{
	font-weight: bold;
	color: #396dc0;
	margin-bottom: 5px;
}
.replydate{
	text-align: right;
}
</style>
<h1>[게시글 정보]</h1>
<div style="text-align: left">
	<h2 style="text-align: left">[${vo.bno}] ${vo.title}</h2>
	<h4 style="text-align: left;">
		<f:formatDate value="${vo.regdate}" pattern="yyyy-MM-dd HH:mm:ss" />
	</h4>
	<hr />
	<p>${vo.content}</p>
	<hr />
</div>
<h3 style="text-align: left; margin-left: 20px;">댓글</h3>
<span id="total"></span>
<div id="reply"></div>
<script id="temp" type="text/x-handlebars-template">
	{{#each list}}
	<div class="box">
		<div class="replyer">
			<span>[{{rno}}]</span>
			<span>{{replyer}}</span>
		</div>
		<div class="reply">
			<span>{{reply}}</span>
		</div>
		<div class="replydate">
			<span>{{replydate}}</span>
		</div>
	</div>
	{{/each}}
</script>
<div id="pagination" class="pagination"></div>
<script>
	var page = 1;
	var bno = "${vo.bno}"
	getList();
	function getList() {
		$.ajax({
			type : 'get',
			url : '/reply/list.json',
			dataType : 'json',
			data : {
				"page" : page,
				"bno" : bno
			},
			success : function(data) {
				var temp = Handlebars.compile($('#temp').html());
				$("#reply").html(temp(data));
				$("#total").html(data.pm.totalCount);
				//페이지 목록 생성
				var src = getPagination(data);
				$("#pagination").html(src);
			}
		})
	}
	
	// 특정 페이지 번호를 클릭한 경우
	$('#pagination').on('click', 'a', function(e) {
		e.preventDefault();
		page = $(this).attr("href");
		getList();
	})
</script>
<script src="/resources/pagination.js"></script>

 

확인

 

 

- 이제 댓글을 작성해 INSERT 할 수 있도록 하겠다.

- /ex03/src/main/webapp/WEB-INF/views/board/read.jsp

.....
<!-- 댓글작성란 -->
<h3 style="text-align: left; margin-left: 20px;">댓글</h3>
<div class="replyBox">
	<div id="uid" style="text-align: left; margin-bottom: 10px;">user01</div>
	<textarea id="txtReply" cols="120" rows="10"></textarea>
	<hr/>
	<button id="btnInsert">등록</button>
</div>
.....
.....
	// 댓글 등록 버튼을 클릭한 경우
	$('#btnInsert').on('click',function(e){
		var reply=$('#txtReply').val();
		var replyer=$('#uid').html();
		if(reply==""){
			alert("댓글 내용을 입력하세요.");
			return;
		};
		if(!confirm("등록하시겠습니까?")) return;
		alert("bno:"+bno+"\n reply:"+reply+"\n replyer:"+replyer);
	})
</script>
<script src="/resources/pagination.js"></script>

 

확인

 

- 값이 잘 넘어가는 것을 확인했으니 insert 하는 mapper.xml을 작성하겠다.

- /ex03/src/main/java/com/example/mapper/BoardMapper.java

.....
	public void insert(ReplyVO vo);
}

 

- /ex03/src/main/resources/mapper/ReplyMapper.xml

.,...
	<insert id="insert">
		insert into tbl_reply(bno,reply,replyer)
		values(#{bno},#{reply},#{replyer})
	</insert>
.....

 

- /ex03/src/main/java/com/example/controller/ReplyController.java

.....
	// 2. 댓글 등록하기
	@RequestMapping(value="/insert", method=RequestMethod.POST)
	public void insert(ReplyVO vo){
		rmapper.insert(vo);
	}
.....

 

- /ex03/src/main/webapp/WEB-INF/views/board/read.jsp

.....
	// 댓글 등록 버튼을 클릭한 경우
	$('#btnInsert').on('click', function(e) {
		var reply = $('#txtReply').val();
		var replyer = $('#uid').html();
		if (reply == "") {
			alert("댓글 내용을 입력하세요.");
			return;
		}
		;
		if (!confirm("등록하시겠습니까?"))
			return;
		//alert("bno:"+bno+"\n reply:"+reply+"\n replyer:"+replyer);
		$.ajax({
			type : 'post',
			url : '/reply/insert',
			data : {
				"bno" : bno,
				"reply" : reply,
				"replyer" : replyer
			},
			success:function(){
				$('#txtReply').val("");
				alert("댓글이 등록되었습니다.");
				page=1;
				getList();
			}
		})
	})
.....

 

확인

 

 

- 이제 내가 작성한 댓글만 삭제할 수 있도록 하겠다.

- registerHelper를 이용해 특정 uid가 쓴 댓글에만 삭제버튼이 보이도록 하겠다.

- /ex03/src/main/webapp/WEB-INF/views/board/read.jsp

.....
<script id="temp" type="text/x-handlebars-template">
	{{#each list}}
	<div class="box">
		<div class="replyer">
			<span>[{{rno}}]</span>
			<span>{{replyer}}</span>
		</div>
		<div class="reply">
			<span>{{reply}}</span>
		</div>
		<div class="replydate">
			<span>{{replydate}}</span>
			<a href="#" style="display:{{printDel replyer}}">삭제</a>
		</div>
	</div>
	{{/each}}
</script>
<script>
	Handlebars.registerHelper("printDel", function(replyer) {
		var uid = $('#uid').html();
		if (replyer != uid) {
			return "none";
		}
	})
</script>
.....

 

확인

 

 

- 이제 댓글을 삭제해보도록 하겠다.

- /ex03/src/main/webapp/WEB-INF/views/board/read.jsp

.....
	// 댓글 삭제 버튼을 클릭한 경우
	$("#reply").on('click','.box a',function(e){
		e.preventDefault();
		var rno = $(this).attr("href");
		if(!confirm(rno+"을(를) 삭제하시겠습니까?")) return;
	});
.....

 

- /ex03/src/main/java/com/example/mapper/ReplyMapper.java

.....
	public void delete(int rno);
}

 

- /ex03/src/main/resources/mapper/BoardMapper.xml

.....
	<delete id="delete">
		delete from tbl_reply
		where rno=#{rno}
	</delete>
.....

 

- /ex03/src/main/java/com/example/controller/ReplyController.java

.....
	// 3. 댓글 삭제
	@RequestMapping(value="/delete", method=RequestMethod.POST)
	public void delete(int rno){
		rmapper.delete(rno);
	}
.....

 

- /ex03/src/main/webapp/WEB-INF/views/board/read.jsp

.....
	// 댓글 삭제 버튼을 클릭한 경우
	$("#reply").on('click','.box a',function(e){
		e.preventDefault();
		var rno = $(this).attr("href");
		if(!confirm(rno+"을(를) 삭제하시겠습니까?")) return;
		$.ajax({
			type : 'post',
			url : '/reply/delete',
			data : {
				"rno" : rno
			},
			success : function() {
				alert("댓글이 삭제되었습니다.");
				getList();
			}
		})
	});
.....

 

확인

 

 

- read할때마다 조회수를 추가해보도로 하겠다.

- go to mysql

alter table tbl_board add viewcount int default 0;

 

- vo에 추가한다.

- /ex03/src/main/java/com/example/domain/BoardVO.java

....
	private int viewcount;
....

 

- /ex03/src/main/webapp/WEB-INF/views/board/list.jsp

.....
<script id="temp" type="text/x-handlebars-template">
	<tr class="title">
		<td width="50">No.</td>
		<td width="250">제목</td>
		<td width="100">작성자</td>
		<td width="200">작성일</td>
		<td width="200">수정일</td>
		<td width="50">조회수</td>
	</tr>
	{{#each list}}
		<tr class="row" onClick="location.href='/board/read?bno={{bno}}'">
			<td>{{bno}}</td>
			<td>{{title}}</td>
			<td>{{writer}}</td>
			<td>{{regdate}}</td>
			<td>{{updatedate}}</td>
			<td>{{viewcount}}</td>
		</tr>
	{{/each}}
</script>
.....

 

확인

 

- /ex03/src/main/java/com/example/mapper/BoardMapper.java

....
	public void updateViewCount(int bno);
}

 

- /ex03/src/main/resources/mapper/BoardMapper.xml

.....
	<update id="updateViewCount">
		update tbl_board set viewcount=viewcount+1
		where bno=#{bno}
	</update>
.....

 

- 클라이언트의 요청을 처리하는 서비스 패키지를 만들어서 read와 viewcount의 update를 사용할 수 있도록 하겠다.

- /ex03/src/main/java/com/example/service

 

- 등록한 패키지를 스캔한다.

- /ex03/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml

.....
	<context:component-scan base-package="com.example.controller" />
	<context:component-scan base-package="com.example.service" /> <<<---
		
</beans:beans>

 

- /ex03/src/main/java/com/example/service/BoardService.java

package com.example.service;

import com.example.domain.BoardVO;

public interface BoardService {
	public BoardVO read(int bno);
}

 

- /ex03/src/main/java/com/example/service/BoardServieImpl.java

package com.example.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.domain.BoardVO;
import com.example.mapper.BoardMapper;

@Service
public class BoardServieImpl implements BoardService {

	@Autowired
	BoardMapper bmapper;
	
	@Override
	public BoardVO read(int bno) {
		bmapper.updateViewCount(bno);
		return bmapper.read(bno);
	}
}

 

- /ex03/src/main/java/com/example/controller/BoardController.java

.....
@Controller
@RequestMapping("/board")
public class BoardController {
	@Autowired
	BoardMapper mapper;
	
	// 3. read 출력
	@Autowired
	BoardService service;
	
	@RequestMapping("/read")
	public String readGet(Model model, int bno){
		// 데이터를 담아와 vo에 넣고
		model.addAttribute("vo",service.read(bno));
		// read.jsp에 데이터를 출력하고
		model.addAttribute("pageName","board/read.jsp");
		// 최종적으로 home.jsp에 보여질 것이니깐
		return "home";
	}
.....

 

조회수 증가 확인