🐻 오늘은 게시글을 확인하고 게시글에 조회수 올리기! 그다음 게시글에 댓글 달기! 🐻
쿼리문 돌린후
🦦 mapper.xml
getBlogCount: 블로그 게시물의 총 수를 가져오는 쿼리입니다. 결과 유형은 정수(int)입니다.
getBlogList: 블로그 게시물 목록을 가져오는 쿼리입니다.
begin과 end 매개 변수를 사용하여 페이지네이션을 지원하며, BlogMap resultMap을 사용하여 결과를 매핑합니다.
updateHit: 블로그 게시물의 조회수(HIT)를 업데이트하는 쿼리입니다.
blogNo 매개 변수를 사용하여 특정 게시물을 식별합니다.
getBlog: 특정 블로그 게시물의 정보를 가져오는 쿼리입니다.
blogNo를 사용하여 게시물을 식별하고 BlogMap resultMap을 사용하여 결과를 매핑합니다.
insertComment: 댓글을 삽입하는 쿼리입니다. CommentDto 매개 변수를 사용하여 댓글 내용 및 관련 정보를 삽입합니다.
getCommentCount: 특정 블로그 게시물에 대한 댓글 수를 가져오는 쿼리입니다.
blogNo를 사용하여 게시물을 식별하고 결과 유형은 정수(int)입니다.
getCommentList: 특정 블로그 게시물의 댓글 목록을 가져오는 쿼리입니다.
begin과 end 매개 변수를 사용하여 페이지네이션을 지원하며, CommentMap resultMap을 사용하여 결과를 매핑합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
<select id="getBlogCount" resultType="int">
SELECT COUNT(*)
FROM BLOG_T
</select>
<select id="getBlogList" parameterType="Map" resultMap="BlogMap">
SELECT A.BLOG_NO, A.TITLE, A.CONTENTS, A.USER_NO, A.HIT, A.IP, A.CREATED_AT, A.MODIFIED_AT, A.EMAIL
FROM (SELECT ROW_NUMBER() OVER(ORDER BY B.BLOG_NO DESC) AS RN, B.BLOG_NO, B.TITLE, B.CONTENTS, B.USER_NO, B.HIT, B.IP, B.CREATED_AT, B.MODIFIED_AT, U.EMAIL
FROM USER_T U INNER JOIN BLOG_T B
ON B.USER_NO = U.USER_NO) A
WHERE A.RN BETWEEN #{begin} AND #{end}
</select>
<update id="updateHit" parameterType="int">
UPDATE BLOG_T
SET HIT = HIT + 1
WHERE BLOG_NO = #{blogNo}
</update>
<select id="getBlog" parameterType="int" resultMap="BlogMap">
SELECT B.BLOG_NO, B.TITLE, B.CONTENTS, B.HIT, B.IP, B.CREATED_AT, B.MODIFIED_AT, U.USER_NO, U.EMAIL, U.NAME
FROM USER_T U, BLOG_T B
WHERE U.USER_NO = B.USER_NO
AND B.BLOG_NO = #{blogNo}
</select>
<insert id="insertComment" parameterType="CommentDto">
INSERT INTO COMMENT_T (
COMMENT_NO
, CONTENTS
, USER_NO
, BLOG_NO
, CREATED_AT
, STATUS
, DEPTH
, GROUP_NO
) VALUES (
COMMENT_SEQ.NEXTVAL
, #{contents}
, #{userDto.userNo}
, #{blogNo}
, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:MI:SS')
, 1
, 0
, COMMENT_SEQ.CURRVAL
)
</insert>
<select id="getCommentCount" parameterType="int" resultType="int">
SELECT COUNT(*)
FROM COMMENT_T
WHERE BLOG_NO = #{blogNo}
</select>
<select id="getCommentList" parameterType="Map" resultMap="CommentMap">
SELECT A.COMMENT_NO, A.CONTENTS, A.BLOG_NO, A.CREATED_AT, A.STATUS, A.DEPTH, A.GROUP_NO, A.USER_NO, A.NAME
FROM (SELECT ROW_NUMBER() OVER(ORDER BY GROUP_NO DESC, DEPTH ASC, COMMENT_NO DESC) AS RN, C.COMMENT_NO, C.CONTENTS, C.BLOG_NO, C.CREATED_AT, C.STATUS, C.DEPTH, C.GROUP_NO, U.USER_NO, U.NAME
FROM USER_T U INNER JOIN COMMENT_T C
ON U.USER_NO = C.USER_NO
WHERE C.BLOG_NO = #{blogNo}) A
WHERE A.RN BETWEEN #{begin} AND #{end}
</select>
|
cs |
🦦 BlogDto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package com.gdu.myhome.dto;
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class BlogDto {
private int blogNo;
private String title;
private String contents;
private int hit;
private String ip;
private String createdAt;
private String modifiedAt;
private String email;
private UserDto userDto; // private int userNo;
}
|
cs |
🦦 CommentDto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.gdu.myhome.dto;
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class CommentDto {
private int commentNo;
private String contents;
private int blogNo;
private String createdAt;
private int status;
private int depth;
private int groupNo;
private UserDto userDto; // private int userNo;
}
|
cs |
🦦 mapper.xml에 추가사항
BlogMap: 이 resultMap은 BlogDto의 필드와 데이터베이스 테이블의 열 간의 매핑을 정의합니다. BlogDto 내에 userDto 필드가 있으며, javaType="UserDto" 및 property="userDto"를 사용하여 이 필드에 대한 매핑 정보를 정의합니다. 결과 매핑 정보를 사용하여 데이터베이스 결과를 BlogDto 객체로 변환합니다.
CommentMap: 이 resultMap은 CommentDto의 필드와 데이터베이스 테이블의 열 간의 매핑을 정의합니다. CommentDto도 userDto 필드가 있으며, javaType="UserDto" 및 property="userDto"를 사용하여 이 필드에 대한 매핑 정보를 정의합니다. 결과 매핑 정보를 사용하여 데이터베이스 결과를 CommentDto 객체로 변환합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
<resultMap type="BlogDto" id="BlogMap">
<id column="BLOG_NO" property="blogNo" />
<result column="TITLE" property="title" />
<result column="CONTENTS" property="contents" />
<result column="HIT" property="hit" />
<result column="IP" property="ip" />
<result column="CREATED_AT" property="createdAt" />
<result column="MODIFIED_AT" property="modifiedAt" />
<association javaType="UserDto" property="userDto">
<id column="USER_NO" property="userNo"/>
<result column="EMAIL" property="email" />
<result column="PW" property="pw" />
<result column="NAME" property="name" />
<result column="GENDER" property="gender" />
<result column="MOBILE" property="mobile" />
<result column="POSTCODE" property="postcode" />
<result column="ROAD_ADDRESS" property="roadAddress" />
<result column="JIBUN_ADDRESS" property="jibunAddress" />
<result column="DETAIL_ADDRESS" property="detailAddress" />
<result column="AGREE" property="agree" />
<result column="STATE" property="state" />
<result column="PW_MODIFIED_AT" property="pwModifiedAt" />
<result column="JOINED_AT" property="joinedAt" />
</association>
</resultMap>
<resultMap type="CommentDto" id="CommentMap">
<id column="COMMENT_NO" property="commentNo"/>
<result column="CONTENTS" property="contents"/>
<result column="BLOG_NO" property="blogNo"/>
<result column="CREATED_AT" property="createdAt"/>
<result column="STATUS" property="status"/>
<result column="DEPTH" property="depth"/>
<result column="GROUP_NO" property="groupNo"/>
<association javaType="UserDto" property="userDto">
<id column="USER_NO" property="userNo"/>
<result column="EMAIL" property="email" />
<result column="PW" property="pw" />
<result column="NAME" property="name" />
<result column="GENDER" property="gender" />
<result column="MOBILE" property="mobile" />
<result column="POSTCODE" property="postcode" />
<result column="ROAD_ADDRESS" property="roadAddress" />
<result column="JIBUN_ADDRESS" property="jibunAddress" />
<result column="DETAIL_ADDRESS" property="detailAddress" />
<result column="AGREE" property="agree" />
<result column="STATE" property="state" />
<result column="PW_MODIFIED_AT" property="pwModifiedAt" />
<result column="JOINED_AT" property="joinedAt" />
</association>
</resultMap>
</mapper>
|
cs |
🦦 BlogMapper 인터페이스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
package com.gdu.myhome.dao;
@Mapper
public interface BlogMapper {
public int getBlogCount();
public List<BlogDto> getBlogList(Map<String, Object> map);
public int updateHit(int blogNo);
public BlogDto getBlog(int blogNo);
public int insertComment(CommentDto comment);
public int getCommentCount(int blogNo);
public List<CommentDto> getCommentList(Map<String, Object> map);
}
|
cs |
🦦 BlogService 인터페이스
1
2
3
4
5
6
7
8
9
10
|
package com.gdu.myhome.service;
public interface BlogService {
public void loadBlogList(HttpServletRequest request, Model model);
public int increseHit(int blogNo);
public BlogDto getBlog(int blogNo);
public Map<String, Object> addComment(HttpServletRequest request);
public Map<String , Object> loadCommentList(HttpServletRequest request);
}
|
cs |
🦦 BlogServiceImpl
loadBlogList 메서드: 블로그 게시물 목록을 불러오는 메서드입니다. 요청(request)에서 페이지 번호를 받아와서, 해당 페이지에 표시할 블로그 게시물 목록을 데이터베이스에서 가져옵니다. 페이징 처리를 위한 정보를 생성하고, 이를 모델(Model)에 추가하여 뷰로 전달합니다.
increseHit 메서드: 블로그 게시물의 조회수(hit)를 증가시키는 메서드입니다. 게시물의 번호를 받아와서 해당 게시물의 조회수를 증가시킵니다.
getBlog 메서드: 특정 블로그 게시물을 가져오는 메서드입니다. 게시물의 번호를 받아와서 해당 게시물 정보를 데이터베이스에서 가져옵니다.
addComment 메서드: 댓글을 추가하는 메서드입니다. 요청에서 댓글 내용, 사용자 번호, 게시물 번호를 받아와서, 이 정보를 사용하여 CommentDto 객체를 생성하고 데이터베이스에 댓글을 추가합니다. 댓글이 추가된 후, 해당 게시물의 댓글 목록을 다시 불러옵니다.
loadCommentList 메서드: 특정 블로그 게시물의 댓글 목록을 불러오는 메서드입니다. 요청에서 게시물 번호와 페이지 번호를 받아와서, 해당 게시물의 댓글 목록을 데이터베이스에서 가져오고 페이징 처리를 수행합니다. 그리고 댓글 목록과 페이징 정보를 반환합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
package com.gdu.myhome.service;
@Transactional
@RequiredArgsConstructor
@Service
public class BlogServiceImpl implements BlogService {
private final BlogMapper blogMapper;
private final MyFileUtils myFileUtils;
private final MyPageUtils myPageUtils;
@Transactional(readOnly=true)
@Override
public void loadBlogList(HttpServletRequest request, Model model) {
Optional<String> opt = Optional.ofNullable(request.getParameter("page"));
int page = Integer.parseInt(opt.orElse("1"));
int total = blogMapper.getBlogCount();
int display = 10;
myPageUtils.setPaging(page, total, display);
Map<String, Object> map = Map.of("begin", myPageUtils.getBegin()
, "end", myPageUtils.getEnd());
List<BlogDto> blogList = blogMapper.getBlogList(map);
model.addAttribute("blogList", blogList);
model.addAttribute("paging", myPageUtils.getMvcPaging(request.getContextPath() + "/blog/list.do"));
model.addAttribute("beginNo", total - (page - 1) * display);
}
@Override
public int increseHit(int blogNo) {
return blogMapper.updateHit(blogNo);
}
@Override
public BlogDto getBlog(int blogNo) {
return blogMapper.getBlog(blogNo);
}
@Override
public Map<String, Object> addComment(HttpServletRequest request) {
String contents = request.getParameter("contents");
int userNo = Integer.parseInt(request.getParameter("userNo"));
int blogNo = Integer.parseInt(request.getParameter("blogNo"));
CommentDto comment = CommentDto.builder()
.contents(contents)
.userDto(UserDto.builder()
.userNo(userNo)
.build())
.blogNo(blogNo)
.build();
int addCommentResult = blogMapper.insertComment(comment);
Map<String, Object> map = Map.of("blogNo", blogNo
, "begin", myPageUtils.getBegin()
, "end", myPageUtils.getEnd());
List<CommentDto> commentList = blogMapper.getCommentList(map);
return Map.of("addCommentResult", addCommentResult);
}
@Override
public Map<String, Object> loadCommentList(HttpServletRequest request) {
int blogNo = Integer.parseInt(request.getParameter("blogNo"));
int page = Integer.parseInt(request.getParameter("page"));
int total = blogMapper.getCommentCount(page);
int display = 10;
myPageUtils.setPaging(page, total, display);
Map<String, Object> map = Map.of("blogNo", blogNo
, "begin", myPageUtils.getBegin()
, "end", myPageUtils.getEnd());
List<CommentDto> commentList = blogMapper.getCommentList(map);
String paging = myPageUtils.getAjaxPaging();
Map<String, Object> result = new HashMap<String, Object>();
result.put("commentList", commentList);
result.put("paging", paging);
return result;
}
}
|
cs |
🦦 BlogController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
package com.gdu.myhome.controller;
@RequestMapping("/blog")
@RequiredArgsConstructor
@Controller
public class BlogController {
private final BlogService blogService;
@GetMapping("/increseHit.do")
public String increseHit(@RequestParam(value="blogNo", required=false, defaultValue="0") int blogNo) {
int increseResult = blogService.increseHit(blogNo);
if(increseResult == 1) {
return "redirect:/blog/detail.do?blogNo=" + blogNo;
} else {
return "redirect:/blog/list.do";
}
}
@GetMapping("/detail.do")
public String detail(@RequestParam(value="blogNo", required=false, defaultValue="0") int blogNo
, Model model) {
BlogDto blog = blogService.getBlog(blogNo);
model.addAttribute("blog", blog);
return "blog/detail";
}
@ResponseBody
@PostMapping(value="/addComment.do", produces="application/json")
public Map<String, Object> addComment(HttpServletRequest request) {
return blogService.addComment(request);
}
@ResponseBody
@GetMapping(value="/commentList.do", produces="application/json")
public Map<String, Object> commentList(HttpServletRequest request){
return blogService.loadCommentList(request);
}
}
|
cs |
🦦 list.jsp
${blogList}는 JSP 모델에 저장된 블로그 목록을 나타냅니다. var 속성을 사용하여 각 블로그 항목을 b라는 변수에 할당하고, varStatus 속성을 사용하여 반복 상태를 vs라는 변수에 할당합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
<div>
<a href="${contextPath}/blog/write.form">
<button type="button" class="btn btn-primary">새글작성</button>
</a>
</div>
<hr>
<div>
<table border="1">
<thead>
<tr>
<td>순번</td>
<td>제목</td>
<td>조회수</td>
<td>작성자</td>
<td>작성일자</td>
</tr>
</thead>
<tbody>
<c:forEach items="${blogList}" var="b" varStatus="vs">
<tr>
<td>${beginNo - vs.index}</td>
<td>
<!-- 내가 작성한 블로그의 조회수는 증가하지 않는다. -->
<c:if test="${sessionScope.user.userNo == b.userDto.userNo}">
<a href="${contextPath}/blog/detail.do?blogNo=${b.blogNo}">${b.title}</a>
</c:if>
<!-- 내가 작성하지 않았다면 조회수를 증가시킨 뒤 상세보기 요청을 한다. -->
<c:if test="${sessionScope.user.userNo != b.userDto.userNo}">
<a href="${contextPath}/blog/increseHit.do?blogNo=${b.blogNo}">${b.title}</a>
</c:if>
</td>
<td>${b.hit}</td>
<td>${b.userDto.email}</td>
<td>${b.createdAt}</td>
</tr>
</c:forEach>
</tbody>
<tfoot>
<tr>
<td colspan="5">${paging}</td>
</tr>
</tfoot>
</table>
</div>
|
cs |
🦦 detail.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
<!-- 블로그 상세보기 -->
<div>
<h1>${blog.title}</h1>
<div>작성자 : ${blog.userDto.name}</div>
<div>조회수 : ${blog.hit}</div>
<div>작성IP : ${blog.ip}</div>
<div>작성일 : ${blog.createdAt}</div>
<div>수정일 : ${blog.modifiedAt}</div>
<div>
버튼구역
</div>
<div>${blog.contents}</div>
</div>
<hr>
<!-- 댓글 작성 화면 -->
<div>
<form id="frm_comment_add">
<textarea rows="3" cols="50" name="contents" id="contents" placeholder="댓글을 작성해 주세요"></textarea>
<input type="hidden" name="userNo" value="${sessionScope.user.userNo}">
<input type="hidden" name="blogNo" value="${blog.blogNo}">
<button type="button" id="btn_comment_add">작성완료</button>
</form>
</div>
<!-- 블로그 댓글 목록 -->
<div style="width: 100%; border-bottom: 1px solid gray;"></div>
<div id="comment_list"></div>
<div id="paging"></div>
<script>
const fnRequiredLogin = () => {
// 로그인을 안하고 작성을 시도하면 로그인 페이지로 보내기
$('#contents, #btn_comment_add').click(() => {
if('${sessionScope.user}' === ''){
if(confirm('로그인이 필요한 기능입니다. 로그인할까요?')){
location.href = '${contextPath}/user/login.form';
} else {
return;
}
}
})
}
const fnCommentAdd = () => {
$('#btn_comment_add').click(() => {
$.ajax({
// 요청
type: 'post',
url: '${contextPath}/blog/addComment.do',
data: $('#frm_comment_add').serialize(),
// 응답
dataType: 'json',
success: (resData) => { // {"addCommentResult": 1}
if(resData.addCommentResult === 1){
alert('댓글이 등록되었습니다.');
$('#contents').val('');
fnCommentList();
}
}
})
})
}
// 전역 변수
var page = 1;
const fnCommentList = () => {
$.ajax({
// 요청
type: 'get',
url: '${contextPath}/blog/commentList.do',
data: 'page=' + page + '&blogNo=${blog.blogNo}',
// 응답
dataType: 'json',
success: (resData) => { // resData = {"commentList": [], "paging": "<div>...</div>"}
$('#comment_list').empty();
$('#paging').empty();
if(resData.commentList.length === 0){
$('#comment_list').text('첫 번째 댓글의 주인공이 되어 보세요');
$('#paging').text('');
return;
}
$.each(resData.commentList, (i, c) => {
let str = '';
if(c.depth === 0){
str += '<div style="width: 100%; border-bottom: 1px solid gray;">';
} else {
str += '<div style="width: 100%; border-bottom: 1px solid gray; margin-left: 32px;">';
}
str += ' <div>' + c.userDto.name + '</div>';
str += ' <div>' + c.contents + '</div>';
str += ' <div style="font-size: 12px;">' + c.createdAt + '</div>';
str += '</div>';
$('#comment_list').append(str);
})
$('#paging').append(resData.paging); // fnAjaxPaging() 함수가 호출되는 곳
}
})
}
const fnAjaxPaging = (p) => {
page = p;
fnCommentList();
}
fnRequiredLogin();
fnCommentAdd();
fnCommentList();
</script>
</div>
|
cs |
'코딩기록 저장소 🐕 > 기능구현연습' 카테고리의 다른 글
11/1 첨부형 게시판 ①🍁 (0) | 2023.11.01 |
---|---|
10/31 게시글 수정,댓글과 대댓글 작성🐧 (0) | 2023.10.31 |
10/27 게시글 첨부파일, 저장, 삭제🐼 (0) | 2023.10.27 |
10/26 게시판 댓글, 게시글 검색🐹 (0) | 2023.10.26 |
10/25 게시판 시작🐵 (0) | 2023.10.25 |