728x90
게시판.vol2.egg
8.00MB
게시판.vol1.egg
10.00MB
1. DB 테이블 생성
2. DTO 작성
3. Mapper XML 작성 , mybatis-configs.xml 작성
4. DAO 작성 , test
5. Service 작성 , test
@Transactional(rollbackFor = Exception.class)
6. Controller 작성 , test
7. View 작성
1. DB 테이블 생성
CREATE TABLE IF NOT EXISTS `board` (
`bno` int NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
`content` text NOT NULL,
`writer` varchar(30) NOT NULL,
`view_cnt` int DEFAULT '0',
`comment_cnt` int DEFAULT '0',
`reg_date` datetime DEFAULT CURRENT_TIMESTAMP,
`up_date` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`bno`)
) ENGINE=InnoDB AUTO_INCREMENT=387 DEFAULT CHARSET=utf8mb3;
CREATE TABLE IF NOT EXISTS `comment` (
`cno` int NOT NULL AUTO_INCREMENT,
`bno` int NOT NULL,
`pcno` int DEFAULT NULL,
`comment` varchar(3000) DEFAULT NULL,
`commenter` varchar(30) DEFAULT NULL,
`reg_date` datetime DEFAULT CURRENT_TIMESTAMP,
`up_date` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`cno`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb3;
CREATE TABLE IF NOT EXISTS `user_info` (
`id` varchar(30) NOT NULL,
`pwd` varchar(30) DEFAULT NULL,
`name` varchar(30) DEFAULT NULL,
`email` varchar(30) DEFAULT NULL,
`birth` date DEFAULT NULL,
`sns` varchar(30) DEFAULT NULL,
`reg_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
2. CommentDTO 작성
package com.test.ch4.domain;
import java.util.*;
public class CommentDto {
private Integer cno;
private Integer bno;
private Integer pcno;
private String comment;
private String commenter;
private Date reg_date;
private Date up_date;
public CommentDto() {}
public CommentDto(Integer bno, Integer pcno, String comment, String commenter) {
this.bno = bno;
this.pcno = pcno;
this.comment = comment;
this.commenter = commenter;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CommentDto that = (CommentDto) o;
return Objects.equals(cno, that.cno) && Objects.equals(bno, that.bno) && Objects.equals(pcno, that.pcno) && Objects.equals(comment, that.comment) && Objects.equals(commenter, that.commenter);
}
@Override
public int hashCode() {
return Objects.hash(cno, bno, pcno, comment, commenter);
}
public Integer getBno() {
return bno;
}
public void setBno(Integer bno) {
this.bno = bno;
}
public Integer getPcno() {
return pcno;
}
public void setPcno(Integer pcno) {
this.pcno = pcno;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getCommenter() {
return commenter;
}
public void setCommenter(String commenter) {
this.commenter = commenter;
}
public Date getReg_date() {
return reg_date;
}
public void setReg_date(Date reg_date) {
this.reg_date = reg_date;
}
public Date getUp_date() {
return up_date;
}
public void setUp_date(Date up_date) {
this.up_date = up_date;
}
public Integer getCno() {
return cno;
}
public void setCno(Integer cno) {
this.cno = cno;
}
@Override
public String toString() {
return "CommentDto{" +
"cno=" + cno +
", bno=" + bno +
", pcno=" + pcno +
", comment='" + comment + '\'' +
", commenter='" + commenter + '\'' +
", reg_date=" + reg_date +
", up_date=" + up_date +
'}';
}
}
3. CommentMapper XML 작성 , mybatis-configs.xml 작성
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias alias="BoardDto" type="com.test.ch4.domain.BoardDto"/>
<typeAlias alias="CommentDto" type="com.test.ch4.domain.CommentDto"/>
<typeAlias alias="SearchCondition" type="com.test.ch4.domain.SearchCondition"/>
</typeAliases>
</configuration>
<?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.test.ch4.dao.BoardMapper">
<select id="count" resultType="int">
SELECT count(*) FROM board
</select>
<delete id="deleteAll">
DELETE FROM board
</delete>
<delete id="delete" parameterType="map">
DELETE FROM board WHERE bno = #{bno} and writer = #{writer}
</delete>
<insert id="insert" parameterType="BoardDto">
INSERT INTO board
(title, content, writer)
VALUES
(#{title}, #{content}, #{writer})
</insert>
<select id="selectAll" resultType="BoardDto">
SELECT *
FROM board
ORDER BY reg_date DESC, bno DESC
</select>
<select id="select" parameterType="int" resultType="BoardDto">
SELECT bno, title, content, writer
, view_cnt, comment_cnt, reg_date
FROM board
WHERE bno = #{bno}
</select>
<select id="selectPage" parameterType="map" resultType="BoardDto">
SELECT bno, title, content, writer, view_cnt, comment_cnt, reg_date
FROM board
ORDER BY reg_date DESC, bno DESC
LIMIT #{from}, #{size}
</select>
<update id="update" parameterType="BoardDto">
UPDATE board
SET title = #{title}
, content = #{content}
, up_date = now()
WHERE bno = #{bno}
</update>
<update id="increaseViewCnt" parameterType="int">
UPDATE board
SET view_cnt = view_cnt + 1
WHERE bno = #{bno}
</update>
<sql id="searchCondition">
<choose>
<when test='option=="T"'>
AND title LIKE concat('%', #{keyword}, '%')
</when>
<when test='option=="W"'>
AND writer LIKE concat('%', #{keyword}, '%')
</when>
<otherwise>
AND (title LIKE concat('%', #{keyword}, '%')
OR content LIKE concat('%', #{keyword}, '%'))
</otherwise>
</choose>
</sql>
<select id="searchSelectPage" parameterType="SearchCondition" resultType="BoardDto">
SELECT bno, title, content, writer, view_cnt, comment_cnt, reg_date
FROM board
WHERE bno > 0
<include refid="searchCondition"/>
ORDER BY reg_date DESC, bno DESC
LIMIT #{offset}, #{pageSize}
</select>
<select id="searchResultCnt" parameterType="SearchCondition" resultType="int">
SELECT count(*)
FROM board
WHERE bno > 0
<include refid="searchCondition"/>
</select>
<update id="updateCommentCnt" parameterType="map">
update board
set comment_cnt = comment_cnt + #{cnt}
where bno = #{bno}
</update>
</mapper>
<?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.test.ch4.dao.CommentMapper">
<delete id="deleteAll" parameterType="int">
DELETE FROM comment
WHERE bno = #{bno}
</delete>
<select id="count" parameterType="int" resultType="int">
SELECT count(*) FROM comment
WHERE bno = #{bno}
</select>
<delete id="delete" parameterType="map">
DELETE FROM comment WHERE cno = #{cno} AND commenter = #{commenter}
</delete>
<insert id="insert" parameterType="CommentDto">
INSERT INTO comment
(bno, pcno, comment, commenter, reg_date, up_date)
VALUES
(#{bno}, #{pcno}, #{comment}, #{commenter}, now(), now())
</insert>
<select id="selectAll" parameterType="int" resultType="CommentDto">
SELECT cno, bno, ifnull(pcno,cno) as pcno, comment, commenter, reg_date, up_date
FROM comment
WHERE bno = #{bno}
ORDER BY pcno ASC, cno ASC
</select>
<select id="select" parameterType="int" resultType="CommentDto">
SELECT cno, bno, pcno, comment, commenter, reg_date, up_date
FROM comment
WHERE cno = #{cno}
</select>
<update id="update" parameterType="CommentDto">
UPDATE comment
SET comment = #{comment}
, up_date = now()
WHERE cno = #{cno} and commenter = #{commenter}
</update>
</mapper>
4. CommentDao 작성 , test
package com.test.ch4.dao;
import com.test.ch4.domain.CommentDto;
import java.util.List;
public interface CommentDao {
int count(Integer bno) throws Exception;
int deleteAll(Integer bno);
int delete(Integer cno, String commenter) throws Exception;
int insert(CommentDto dto) throws Exception;
List<CommentDto> selectAll(Integer bno) throws Exception;
CommentDto select(Integer cno) throws Exception;
int update(CommentDto dto) throws Exception;
}
package com.test.ch4.dao;
import com.test.ch4.domain.CommentDto;
import org.apache.ibatis.session.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
import java.util.*;
@Repository
public class CommentDaoImpl implements CommentDao {
@Autowired
private SqlSession session;
private static String namespace = "com.test.ch4.dao.CommentMapper.";
@Override
public int count(Integer bno) throws Exception {
return session.selectOne(namespace+"count", bno);
} // T selectOne(String statement)
@Override
public int deleteAll(Integer bno) {
return session.delete(namespace+"deleteAll", bno);
} // int delete(String statement)
@Override
public int delete(Integer cno, String commenter) throws Exception {
Map map = new HashMap();
map.put("cno", cno);
map.put("commenter", commenter);
return session.delete(namespace+"delete", map);
} // int delete(String statement, Object parameter)
@Override
public int insert(CommentDto dto) throws Exception {
return session.insert(namespace+"insert", dto);
} // int insert(String statement, Object parameter)
@Override
public List<CommentDto> selectAll(Integer bno) throws Exception {
return session.selectList(namespace+"selectAll", bno);
} // List<E> selectList(String statement)
@Override
public CommentDto select(Integer cno) throws Exception {
return session.selectOne(namespace + "select", cno);
} // T selectOne(String statement, Object parameter)
@Override
public int update(CommentDto dto) throws Exception {
return session.update(namespace+"update", dto);
} // int update(String statement, Object parameter)
}
test
package com.test.ch4.dao;
import com.test.ch4.domain.CommentDto;
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 java.util.List;
import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"file:src/main/webapp/WEB-INF/spring/root-context.xml"})
public class CommentDaoImplTest {
@Autowired
CommentDao commentDao;
@Test
public void count() throws Exception {
commentDao.deleteAll(1);
assertTrue(commentDao.count(1)==0);
}
@Test
public void delete() throws Exception {
commentDao.deleteAll(1);
CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf");
assertTrue(commentDao.insert(commentDto)==1);
assertTrue(commentDao.count(1)==1);
}
@Test
public void insert() throws Exception {
commentDao.deleteAll(1);
CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf");
assertTrue(commentDao.insert(commentDto)==1);
assertTrue(commentDao.count(1)==1);
commentDto = new CommentDto(1, 0, "comment", "asdf");
assertTrue(commentDao.insert(commentDto)==1);
assertTrue(commentDao.count(1)==2);
}
@Test
public void selectAll() throws Exception {
commentDao.deleteAll(1);
CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf");
assertTrue(commentDao.insert(commentDto)==1);
assertTrue(commentDao.count(1)==1);
List<CommentDto> list = commentDao.selectAll(1);
assertTrue(list.size()==1);
commentDto = new CommentDto(1, 0, "comment", "asdf");
assertTrue(commentDao.insert(commentDto)==1);
assertTrue(commentDao.count(1)==2);
list = commentDao.selectAll(1);
assertTrue(list.size()==2);
}
@Test
public void select() throws Exception {
commentDao.deleteAll(1);
CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf");
assertTrue(commentDao.insert(commentDto)==1);
assertTrue(commentDao.count(1)==1);
List<CommentDto> list = commentDao.selectAll(1);
String comment = list.get(0).getComment();
String commenter = list.get(0).getCommenter();
assertTrue(comment.equals(commentDto.getComment()));
assertTrue(commenter.equals(commentDto.getCommenter()));
}
@Test
public void update() throws Exception {
commentDao.deleteAll(1);
CommentDto commentDto = new CommentDto(1, 0, "comment", "asdf");
assertTrue(commentDao.insert(commentDto)==1);
assertTrue(commentDao.count(1)==1);
List<CommentDto> list = commentDao.selectAll(1);
commentDto.setCno(list.get(0).getCno());
commentDto.setComment("comment2");
assertTrue(commentDao.update(commentDto)==1);
list = commentDao.selectAll(1);
String comment = list.get(0).getComment();
String commenter = list.get(0).getCommenter();
assertTrue(comment.equals(commentDto.getComment()));
assertTrue(commenter.equals(commentDto.getCommenter()));
}
}
5. Service 작성 , test
package com.test.ch4.service;
import com.test.ch4.domain.CommentDto;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public interface CommentService {
int getCount(Integer bno) throws Exception;
@Transactional(rollbackFor = Exception.class)
int remove(Integer cno, Integer bno, String commenter) throws Exception;
@Transactional(rollbackFor = Exception.class)
int write(CommentDto commentDto) throws Exception;
List<CommentDto> getList(Integer bno) throws Exception;
CommentDto read(Integer cno) throws Exception;
int modify(CommentDto commentDto) throws Exception;
}
package com.test.ch4.service;
import com.test.ch4.dao.*;
import com.test.ch4.domain.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
import org.springframework.transaction.annotation.*;
import java.util.*;
@Service
public class CommentServiceImpl implements CommentService {
// @Autowired
BoardDao boardDao;
// @Autowired
CommentDao commentDao;
@Autowired
public CommentServiceImpl(CommentDao commentDao, BoardDao boardDao) {
this.commentDao = commentDao;
this.boardDao = boardDao;
}
@Override
public int getCount(Integer bno) throws Exception {
return commentDao.count(bno);
}
@Override // 런타임은 예외처리 자동, 컴파일 에러는 예외처리 필수
@Transactional(rollbackFor = Exception.class)
public int remove(Integer cno, Integer bno, String commenter) throws Exception {
int rowCnt = boardDao.updateCommentCnt(bno, -1);
System.out.println("updateCommentCnt - rowCnt = " + rowCnt);
// throw new Exception("test");
rowCnt = commentDao.delete(cno, commenter);
System.out.println("rowCnt = " + rowCnt);
return rowCnt;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int write(CommentDto commentDto) throws Exception {
boardDao.updateCommentCnt(commentDto.getBno(), 1);
// throw new Exception("test");
return commentDao.insert(commentDto);
}
@Override
public List<CommentDto> getList(Integer bno) throws Exception {
// throw new Exception("test");
return commentDao.selectAll(bno);
}
@Override
public CommentDto read(Integer cno) throws Exception {
return commentDao.select(cno);
}
@Override
public int modify(CommentDto commentDto) throws Exception {
return commentDao.update(commentDto);
}
}
6. Controller 작성 , test
★ 서버가 잘못처리해서 500 에러가 나와야 하는데
에러가 나든 성공하든 상태코드 200이 나옴.... > ResponseEntity 이용하기.
엔티티 : 응답이나 요청할때 전송할 대상을 말함
new ResponseEntity< List<CommentDto> >(list , HttpStatus.OK);
그럼 이제 controller 코드를 보자
package com.test.ch4.controller;
import com.test.ch4.domain.CommentDto;
import com.test.ch4.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpSession;
import java.util.List;
//@Controller
//@ResponseBody
@RestController
public class CommentController {
@Autowired
CommentService service;
//댓글을 수정하는 메서드
@PatchMapping("/comments/{cno}") // /ch4/comments/70 POST
public ResponseEntity<String> modify(@PathVariable Integer cno, @RequestBody CommentDto dto , HttpSession session ) {
String commenter = (String)session.getAttribute("id");
dto.setCommenter(commenter);
dto.setCno(cno);
System.out.println("dto = " + dto);
try {
if(service.modify(dto) != 1)
throw new Exception("Write failed");
return new ResponseEntity<String>("MOD_OK" , HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<String>("MOD_ERR", HttpStatus.BAD_REQUEST);
}
}
//댓글을 저장하는 메서드
@PostMapping("/comments") // /ch4/comments?bno=11 POST
public ResponseEntity<String> write(@RequestBody CommentDto dto, Integer bno , HttpSession session ) {
String commenter = (String)session.getAttribute("id");
dto.setCommenter(commenter);
dto.setBno(bno);
System.out.println("dto = " + dto);
try {
if(service.write(dto) != 1)
throw new Exception("Write failed");
return new ResponseEntity<String>("WRT_OK" , HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<String>("WRT_ERR", HttpStatus.BAD_REQUEST);
}
}
//지정된 댓글을 삭제하는 메서드
@DeleteMapping("/comments/{cno}") // comments/11?bno=1010 (삭제할댓글번호) , uri 방식{cno}의 경우 @PathVariable
public ResponseEntity<String> remove(@PathVariable Integer cno , Integer bno , HttpSession session ){
String commenter = (String)session.getAttribute("id");
try {
int rowCount = service.remove(cno , bno, commenter);
if(rowCount !=1)
throw new Exception("Delete Failed");
return new ResponseEntity<String>( "DEL_OK", HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<String>("DEL_ERR", HttpStatus.BAD_REQUEST);
}
}
//지정된 게시물의 모든 댓글을 가져오는 메서드
@RequestMapping(value = "/comments") //comments?bno=11
public ResponseEntity<List<CommentDto>> list(Integer bno){
List<CommentDto> list = null;
try {
list = service.getList(bno);
return new ResponseEntity<List<CommentDto>>(list , HttpStatus.OK); //200
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<List<CommentDto>>(HttpStatus.BAD_REQUEST); //400
}
}
}
클래스 안의 메서드 모두 @ResponseBody 가 붙어야 한다면
클래스에 @ResponseBody 붙이고 메서드 에는 붙이지 않아도 된다.
@ResponseBody + @Controller 합친것 @RestController
//@Controller
//@ResponseBody
@RestController
public class CommentController {
7. View 작성
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
</head>
<body>
<h2>commentTest</h2>
comment : <input type="text" name="comment"></body>
<button id="sendBtn" type="button">등록</button>
<button id="modBtn" type="button">수정</button>
<div id="commentList"></div>
<div id='replyForm' style='display: none'>
<input type='text' name='replyComment'/>
<button id='wrtRepBtn' type='button' >답글등록</button>
</div>
<script>
let bno = 386; /** 이 부분은 게시판 상세보기와 연동하여 개발한다.. */
$(document).ready(function(){
showList(bno);
/** 댓글 등록 */
$("#sendBtn").click(function(){
let comment = $("input[name=comment]").val();
if(comment.trim() == ""){
alert("댓글을 입력하세요.");
$("input[name=comment]").focus();
return;
}
$.ajax({
type:'POST',
url: '/ch4/comments?bno=' + bno,
headers : { "content-type": "application/json"},
dataType : 'text',
data : JSON.stringify( {bno : bno , comment : comment} ),
success : function(result){
alert(result);
showList(bno);
},
error : function(){ alert("error") }
});
});
/** 대댓글 등록 */
$("#wrtRepBtn").click(function(){
let pcno = $("#replyForm").parent().attr("data-pcno");
let comment = $("input[name=replyComment]").val();
if(comment.trim() == ""){
alert("댓글을 입력하세요.");
$("input[name=replyComment]").focus();
return;
}
$.ajax({
type:'POST',
url: '/ch4/comments?bno=' + bno,
headers : { "content-type": "application/json"},
dataType : 'text',
data : JSON.stringify( {bno : bno, pcno : pcno, comment : comment} ),
success : function(result){
alert(result);
showList(bno);
},
error : function(){ alert("error") }
});
});
/** 댓글 수정 */
$("#modBtn").click(function(){
let cno = $(this).attr("data-cno");
let comment = $("input[name=comment]").val();
if(comment.trim() == ""){
alert("댓글을 입력하세요.");
$("input[name=comment]").focus();
return;
}
if(cno == undefined){
alert("수정할 댓글을 선택하세요.");
return;
}
$.ajax({
type:'PATCH',
url: '/ch4/comments/' + cno,
headers : { "content-type": "application/json"},
dataType : 'text',
data : JSON.stringify( {comment : comment} ),
success : function(result){
alert(result);
showList(bno);
},
error : function(){ alert("error") }
});
});
});
/** 댓글 삭제 */
$("#commentList").on("click", ".delBtn", function(){
let cno = $(this).parent().attr("data-cno");
let bno = $(this).parent().attr("data-bno");
$.ajax({
type:'DELETE',
url: '/ch4/comments/' + cno + '?bno=' + bno,
success : function(result){
alert(result);
showList(bno);
},
error : function(){ alert("error") }
});
});
/** 댓글에서 수정 click */
$("#commentList").on("click", ".modBtn", function(){
let cno = $(this).parent().attr("data-cno");
let comment = $("span.comment", $(this).parent()).text();
// 1. comment의 내용을 input에 뿌려주기
$("input[name=comment]").val(comment);
// 2. cno 전달하기
$("#modBtn").attr("data-cno", cno);
});
/** 댓글에서 답글 click */
$("#commentList").on("click", ".replyBtn", function(){
// 1.답글 입력 폼의 위치를 이동시킨다.
$(this).parent().append( $("#replyForm") );
// 1.답글을 입력할 폼을 보여준다.
$("#replyForm").css("display","block");
});
/** 댓글 리스트 불러오기 */
let showList = function(bno){
$.ajax({
type:'GET',
url: '/ch4/comments?bno='+ bno,
success : function(result){
$("#commentList").html(toHtml(result));
},
error : function(){ alert("error") }
});
}
/** 댓글 html */
let toHtml = function (comments){
replyFormClear();
let tmp = "<ul>";
comments.forEach(function(comment){
tmp +='<li data-cno=' + comment.cno
tmp +=' data-pcno=' + comment.pcno
tmp +=' data-bno=' + comment.bno + '>'
if(comment.cno != comment.pcno){ tmp += " ㄴ "}
tmp +=' commenter = <span class="commenter">' + comment.commenter + '</span>'
tmp +=' comment = <span class="comment">' + comment.comment +'</span>'
tmp +=' <button class="delBtn">삭제</button>'
tmp +=' <button class="modBtn">수정</button>'
tmp +=' <button class="replyBtn">답글</button>'
tmp +='</li>'
})
return tmp + "</ul>"
}
/** form 원래대로 복원 */
let replyFormClear = function(){
$("input[name=replyComment]").val('');
$("#replyForm").css("display","none");
$("#replyForm").appendTo("body");
}
</script>
</body>
</html>
7. View 디자인 예시..
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<title>Document</title>
<style>
* {
border : 0;
padding : 0;
}
ul {
border: 1px solid rgb(235,236,239);
border-bottom : 0;
}
li {
background-color: #f9f9fa;
list-style-type: none;
border-bottom : 1px solid rgb(235,236,239);
padding : 18px 18px 0 18px;
}
#commentList {
width : 50%;
margin : auto;
}
.comment-content {
overflow-wrap: break-word;
}
.comment-bottom {
font-size:9pt;
color : rgb(97,97,97);
padding: 8px 0 8px 0;
}
.comment-bottom > a {
color : rgb(97,97,97);
text-decoration: none;
margin : 0 6px 0 0;
}
.comment-area {
padding : 0 0 0 46px;
}
.commenter {
font-size:12pt;
font-weight:bold;
}
.commenter-writebox {
padding : 15px 20px 20px 20px;
}
.comment-img {
font-size:36px;
position: absolute;
}
.comment-item {
position:relative;
}
.up_date {
margin : 0 8px 0 0;
}
#comment-writebox {
background-color: white;
border : 1px solid #e5e5e5;
border-radius: 5px;
}
textarea {
display: block;
width: 100%;
min-height: 17px;
padding: 0 20px;
border: 0;
outline: 0;
font-size: 13px;
resize: none;
box-sizing: border-box;
background: transparent;
overflow-wrap: break-word;
overflow-x: hidden;
overflow-y: auto;
}
#comment-writebox-bottom {
padding : 3px 10px 10px 10px;
min-height : 35px;
}
.btn {
font-size:10pt;
color : black;
background-color: #eff0f2;
text-decoration: none;
padding : 9px 10px 9px 10px;
border-radius: 5px;
float : right;
}
#btn-write-comment, #btn-write-reply {
color : #009f47;
background-color: #e0f8eb;
}
#btn-cancel-reply {
background-color: #eff0f2;
margin-right : 10px;
}
#btn-write-modify {
color : #009f47;
background-color: #e0f8eb;
}
#btn-cancel-modify {
margin-right : 10px;
}
#reply-writebox {
display : none;
background-color: white;
border : 1px solid #e5e5e5;
border-radius: 5px;
margin : 10px;
}
#reply-writebox-bottom {
padding : 3px 10px 10px 10px;
min-height : 35px;
}
#modify-writebox {
background-color: white;
border : 1px solid #e5e5e5;
border-radius: 5px;
margin : 10px;
}
#modify-writebox-bottom {
padding : 3px 10px 10px 10px;
min-height : 35px;
}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 50%;
}
/* The Close Button */
.close {
color: #aaaaaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
.paging {
color: black;
width: 100%;
text-align: center;
}
.page {
color: black;
text-decoration: none;
padding: 6px;
margin-right: 10px;
}
.paging-active {
background-color: rgb(216, 216, 216);
border-radius: 5px;
color: rgb(24, 24, 24);
}
.paging-container {
width:100%;
height: 70px;
margin-top: 50px;
margin : auto;
}
</style>
</head>
<body>
<div id="commentList">
<ul>
<li class="comment-item" data-cno="1" data-bno="1070">
<span class="comment-img">
<i class="fa fa-user-circle" aria-hidden="true"></i>
</span>
<div class="comment-area">
<div class="commenter">asdf</div>
<div class="comment-content">asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf
</div>
<div class="comment-bottom">
<span class="up_date">2022.01.01 23:59:59</span>
<a href="#" class="btn-write" data-cno="1" data-bno="1070" data-pcno="">답글쓰기</a>
<a href="#" class="btn-modify" data-cno="1" data-bno="1070" data-pcno="">수정</a>
<a href="#" class="btn-delete" data-cno="1" data-bno="1070" data-pcno="">삭제</a>
</div>
</div>
</li>
<li class="comment-item" data-cno="2" data-bno="1070">
<span class="comment-img">
<i class="fa fa-user-circle" aria-hidden="true"></i>
</span>
<div class="comment-area">
<div class="commenter">qwer</div>
<div class="comment-content">qwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwerqwer
</div>
<div class="comment-bottom">
<span class="up_date">2022.01.01 23:59:59</span>
<a href="#" class="btn-write" data-cno="2" data-bno="1070" data-pcno="">답글쓰기</a>
<a href="#" class="btn-modify" data-cno="2" data-bno="1070" data-pcno="">수정</a>
<a href="#" class="btn-delete" data-cno="2" data-bno="1070" data-pcno="">삭제</a>
</div>
</div>
</li>
</ul>
<div class="paging-container">
<div class="paging">
<a class="page" href="#"><</a>
<a class="page" href="#">1</a>
<a class="page" href="#">2</a>
<a class="page" href="#">3</a>
<a class="page" href="#">4</a>
<a class="page paging-active" href="#">5</a>
<a class="page" href="#">6</a>
<a class="page" href="#">7</a>
<a class="page" href="#">8</a>
<a class="page" href="#">9</a>
<a class="page" href="#">10</a>
<a class="page" href="#">></a>
</div>
</div>
<div id="comment-writebox">
<div class="commenter commenter-writebox">${id}</div>
<div class="comment-writebox-content">
<textarea name="" id="" cols="30" rows="3" placeholder="댓글을 남겨보세요"></textarea>
</div>
<div id="comment-writebox-bottom">
<div class="register-box">
<a href="#" class="btn" id="btn-write-comment">등록</a>
</div>
</div>
</div>
</div>
<div id="reply-writebox">
<div class="commenter commenter-writebox">${id}</div>
<div class="reply-writebox-content">
<textarea name="" id="" cols="30" rows="3" placeholder="댓글을 남겨보세요"></textarea>
</div>
<div id="reply-writebox-bottom">
<div class="register-box">
<a href="#" class="btn" id="btn-write-reply">등록</a>
<a href="#" class="btn" id="btn-cancel-reply">취소</a>
</div>
</div>
</div>
<div id="modalWin" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<p>
<h2> | 댓글 수정</h2>
<div id="modify-writebox">
<div class="commenter commenter-writebox"></div>
<div class="modify-writebox-content">
<textarea name="" id="" cols="30" rows="5" placeholder="댓글을 남겨보세요"></textarea>
</div>
<div id="modify-writebox-bottom">
<div class="register-box">
<a href="#" class="btn" id="btn-write-modify">등록</a>
</div>
</div>
</div>
</p>
</div>
</div>
<script>
let id = 'asdf';
let addZero = function(value=1){
return value > 9 ? value : "0"+value;
}
let dateToString = function(ms=0) {
let date = new Date(ms);
let yyyy = date.getFullYear();
let mm = addZero(date.getMonth() + 1);
let dd = addZero(date.getDate());
let HH = addZero(date.getHours());
let MM = addZero(date.getMinutes());
let ss = addZero(date.getSeconds());
return yyyy+"."+mm+"."+dd+ " " + HH + ":" + MM + ":" + ss;
}
$(document).ready(function(){
$("a.btn-write").click(function(e){
let target = e.target;
let cno = target.getAttribute("data-cno")
let bno = target.getAttribute("data-bno")
let repForm = $("#reply-writebox");
repForm.appendTo($("li[data-cno="+cno+"]"));
repForm.css("display", "block");
repForm.attr("data-pcno", pcno);
repForm.attr("data-bno", bno);
});
$("#btn-cancel-reply").click(function(e){
$("#reply-writebox").css("display", "none");
});
$("a.btn-modify").click(function(e){
let target = e.target;
let cno = target.getAttribute("data-cno");
let bno = target.getAttribute("data-bno");
let pcno = target.getAttribute("data-pcno");
let li = $("li[data-cno="+cno+"]");
let commenter = $(".commenter", li).first().text();
let comment = $(".comment-content", li).first().text();
$("#modalWin .commenter").text(commenter);
$("#modalWin textarea").text(comment);
$("#btn-write-modify").attr("data-cno", cno);
$("#btn-write-modify").attr("data-pcno", pcno);
$("#btn-write-modify").attr("data-bno", bno);
// 팝업창을 열고 내용을 보여준다.
$("#modalWin").css("display","block");
});
$("a.btn-delete").click(function(e){
alert("delete");
});
$("#btn-write-modify").click(function(){
// 1. 변경된 내용을 서버로 전송
// 2. 모달 창을 닫는다.
$(".close").trigger("click");
});
$(".close").click(function(){
$("#modalWin").css("display","none");
});
});
</script>
</body>
</html>
728x90