이전 포스트 >>
Spring-Boot Blog Project 8. 메인페이지에 글 노출 구현하기
앞서 포스트에서 index에 a태그를 걸었었다.
--중략--
<td><a href="/post/${post.id}">${post.title }</a></td>
--하략--
이 uri를 통해 이 id값을 가지는 게시글의 세부사항을 도출한다.
먼저, 세부사항을 도출할 페이지를 생성한다.
../views/post/detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="../layout/header.jsp" %>
<div class="container">
<table class="table table-striped">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
</tr>
</thead>
<tbody>
<tr>
<td><input id="id" type="text" value="${postDetailRespDto.id }" readonly="readonly"></td>
<td><input id="title" type="text" value="${postDetailRespDto.title }" readonly="readonly"></td>
<td><input id="content" type="text" value="${postDetailRespDto.content }" readonly="readonly"></td>
<td><input id="username" type="text" value="${postDetailRespDto.username }" readonly="readonly"></td>
</tr>
<tr>
</tbody>
</table>
</div>
<script src="/js/post.js"></script>
<%@include file="../layout/footer.jsp" %>
이 때, 현재 페이지에서는 값을 확인만 할 것이므로 readonly 속성을 전 태그에 걸어둔다.
이제 값을 가져오자.
/controller/PostController.java
--중략--
@GetMapping("/post/{id}")
//?주소 -> 쿼리스트링 받는 것
// /post/{id} -> 파라메터를 받는 것
public String getPost(@PathVariable int id, Model model) {
model.addAttribute("postDetailRespDto", postService.상세보기(id));
return "post/detail";
}
--하략--
주소를 보면 id를 {}를 통해 동적으로 받고 있다.
따라서, @PathVariable 어노테이션을 통해 동적으로 받아오는 주소값을 변수로써 받아온다.
이 동적으로 받아온 id값을 통해 상세보기를 유도한다.
서비스에서 이 값을 도출시킬 트랜젝션을 생성한다.
/service/PostService.java
//중략
@Transactional(readOnly = true)
public PostDetailRespDto 상세보기(int id) {
return postRepository.findById(id);
}
//하략
이 때 상세보기를 할때 글의 제목과 내용뿐만 아니라 작성자도 호출해야하므로, 하나의 테이블로 처리할 수 없다. 따라서 이걸 합쳐줄 DTO를 제작한다.
/controller/dto/PostDetailRespDto.java
package com.mary.blog.controller.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
//웬만하면 컴포지션 하지 말고
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class PostDetailRespDto {
private int id;
private String title;
private String content;
private String username;
}
서비스가 값을 가져올 저장소를 생성한다.
/repository/PostRepository.java
package com.mary.blog.repository;
import java.util.List;
import com.mary.blog.controller.dto.PostDetailRespDto;
import com.mary.blog.model.Post;
public interface PostRepository {
public void save(Post post);
public List<Post> findAll();
public PostDetailRespDto findById(int id);
}
findById를 실행해줄 mapper xml 을 생성한다.
<select id="findById" resultType="com.mary.blog.controller.dto.PostDetailRespDto">
select p.id, p.title, p.content, u.username
from post p inner join user u
on p.userId=u.id
where p.id=#{id}
</select>
이제 이 값을 가져와서 jsp에서 도출하면 결과를 얻을 수 있다.
화면에 수정 삭제가 보일 것이다. 그렇다, 수정 삭제도 구현해보자.
버튼을 jQuery를 통해 동적으로 구현할텐데, 일단 어떻게 구현하는지 보자.
버튼이 동적으로 구현되는게 보이는가?
버튼을 먼저 생성해보자.
/post/detail.jsp
//중략
</tbody>
</table>
<button id="btn-update" class="btn btn-primary">수정하기</button>
<button id="btn-update-mode" class="btn btn-warning">수정</button>
<button id="btn-delete" class="btn btn-danger">삭제</button>
</div>
<script src="/js/post.js"></script>
<%@include file="../layout/footer.jsp" %>
보면 버튼이 3개인데, 버튼을 보였다가, 말았다가 할 것이다.
이제 이 값을 js 파일을 통해 동적으로 구현한다.
let index = {
init: function(){
// let _this = this; //this 바인딩
// $("#btn-save").on("click", function (){
// 1. 리스너
$("#btn-save").on("click", ()=>{
// 콜백 스택
this.save();
});
// 1. 리스너
$("#btn-delete").on("click", ()=>{
// 콜백 스택
this.deleteContent();
});
// 1. 리스너
$("#btn-update-mode").on("click", ()=>{
console.log(this);
// 콜백 스택
this.updateMode();
});
$("#btn-update").on("click", ()=>{
// 콜백 스택
console.log("클릭됨");
this.update();
});
$("#btn-update").hide();
},
update: function(){
console.log("업데이트 요청");
let data = {
id: $("#id").val(),
title: $("#title").val(),
content: $("#content").val()
};
$.ajax({
type: "PUT",
url: "/post/"+data.id,
data: JSON.stringify(data), // json 으로 바꿔줌
contentType: "application/json; charset=utf-8",
dataType: "json"
}).done(function(resp){
// console.log(JSON.parse(resp)); // text 타입으로 데이터를 받았을때 json 오브젝트로
// 바꿔줌
alert("수정 성공");
location.href="/post/"+data.id;
}).fail(function(error){
alert("수정 실패");
console.log(error);
})
},
save: function(){
// alert("btn-save 로직 실행");
let data = {
title: $("#title").val(),
content: $("#content").val(),
userId: $("#userId").val()
};
$.ajax({
type: "POST",
url: "/post",
data: JSON.stringify(data), // json 으로 바꿔줌
contentType: "application/json; charset=utf-8",
dataType: "json"
}).done(function(resp){
// console.log(JSON.parse(resp)); // text 타입으로 데이터를 받았을때 json 오브젝트로
// 바꿔줌
alert("글쓰기 성공");
location.href="/";
}).fail(function(error){
alert("글쓰기 실패");
console.log(error);
})
},
deleteContent: function(){
// alert("btn-save 로직 실행");
let data = {
Id: $("#id").val()
};
console.log(data.Id);
$.ajax({
type: "DELETE",
url: "/post/"+data.Id,
dataType: "json"
}).done(function(resp){
alert("삭제 성공");
location.href="/";
}).fail(function(error){
alert("삭제 실패");
console.log(error);
})
},
updateMode: function(){
// alert("btn-save 로직 실행");
$("#title").attr("readOnly",false);
$("#content").attr("readOnly",false);
$("#btn-update").show();
$("#btn-update-mode").hide();
}
}
index.init();
버튼을 누르면 updateMode 함수가 작동하며 수정 버튼을 숨기고 수정하기 버튼을 출력 시키고, readOnly 속성을 제거한다.
왜 굳이 id를 바꾸지 않냐면,
리스너가 로드 될때 같은 id를 가지고 있는 값이 없으면 리스너가 바인딩 되지 않기 때문이다. 따라서, element에 동적으로 id를 바꾸어 하는 방식은 선택할 수 없다.
동적으로 나타난 update 버튼을 누르면 update함수가 실행되면서 수정된 제목과 타이틀 값이 컨트롤러로 날아간다.
PostController.java
//중략
@PutMapping("/post/{id}")
public @ResponseBody CommonRespDto<?> update(@RequestBody Post post){
System.out.println("수정하기");
postService.수정하기(post);
return new CommonRespDto<String>(1,"수정 성공");
}
//하략
들어온 값이 json 형태이므로 RequestBody를 통해 값을 받는다.
PostService.java
//중략
@Transactional
public void 수정하기(Post post) {
postRepository.update(post);
}
//하략
PostRepository.java
package com.mary.blog.repository;
import java.util.List;
import com.mary.blog.controller.dto.PostDetailRespDto;
import com.mary.blog.model.Post;
public interface PostRepository {
public void save(Post post);
public List<Post> findAll();
public PostDetailRespDto findById(int id);
public void update(Post post);
}
이제 이 값을 받아올 xml mapper을 생성한다.
post.xml
<update id="update">
update post set title=#{title}, content=#{content}
where id=#{id}
</update>
여기서 성공한다면 값을 1로 도출하며 성공을 표기하고, 아니면 중간에서 error을 도출하며 삭제 실패를 도출한다.
삭제도 마찬가지로 구현한다.
PostController.java
@DeleteMapping("/post/{id}")
public @ResponseBody CommonRespDto<?> deletePost(@PathVariable int id){
if(principal.getId()!=postEntity.getUserId()) {
throw new MyRoleException();
}
postService.삭제하기(id);
return new CommonRespDto<String>(1,"삭제 성공");
}
PostService.java
//중략
@Transactional
public void 삭제하기(int id) {
System.out.println("삭제하기 : "+id);
postRepository.deleteContentById(id);
}
//하략
PostRepository.java
package com.mary.blog.repository;
import java.util.List;
import com.mary.blog.controller.dto.PostDetailRespDto;
import com.mary.blog.model.Post;
public interface PostRepository {
public void save(Post post);
public List<Post> findAll();
public PostDetailRespDto findById(int id);
public void deleteContentById(int id);
public void update(Post post);
}
Post.xml
<delete id="deleteContentById">
delete from post where id=#{id}
</delete>
'SpringBoot' 카테고리의 다른 글
Spring Boot Project(in★ gram) 01. 환경세팅하기 (0) | 2020.08.24 |
---|---|
Spring-Boot Blog Project 10. 삭제에 작성자 확인해서 권한 부여하기 (0) | 2020.07.27 |
Spring-Boot Blog Project 8. 메인페이지에 글 노출 구현하기 (0) | 2020.07.27 |
Spring-Boot Blog Project 7. 글쓰기 구현하기 (0) | 2020.07.27 |
Spring-Boot Blog Project 6. 로그아웃 구현하기 (0) | 2020.07.27 |