학습 목표
-객체 간의 관계 설정(@OneToMany, @ManyToOne 등)
학습 목차
4-1. 회원과 질문 간의 관계 매핑 및 리팩토링
4-2. 질문 상세보기 기능 구현
4-3. 질문 수정/삭제 기능 구현
4-4. 수정/삭제 기능에 대한 보안 처리 및 LocalDateTime 설정
4-5. 답변 추가 및 답변 목록 기능 구현
4-6. QuestionController 중복 제거 리팩토링
4-7. 원격 서버에 소스 코드 배포
//Question.java
@Entity
public class Question {
@Id
@GeneratedValue
private Long id;
@ManyToOne //2.
@JoinColumn(foreignKey=@ForeignKey(name="fk_question_writer")) //3.
private User writer; //1.
private String writer;
private String title;
private String contents;
private LocalDateTime createDate; //4.
public Question() {}
public Question(String writer, String title, String contents) {
super();
this.writer=writer;
this.title=title;
this.contents=contents;
this.createDate=LocalDateTime.now(); //4.
}
public String getFormattedCreateDate() { //5.
if(createDate==null) {
return "";
}
return createDate.format(DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss"));
}
}
1. Question 클래스에서 User와 관계를 정의해줍니다.
사용자와의 관계를 String이 아니라 User로 정의합니다.
2. @ManyToOne: Question과 User의 관계는 다 대 일
3. 외래키로 지정해줍니다.
4. 현재 날짜 및 시간을 생성해줍니다.
5. 날짜 출력 형식을 지정해줍니다.
Question이라는 데이터를 조회할 때 외래키로 연결되어 있는 User의 해당 사용자의 데이터를 조회해서 함께 로딩해줍니다.
//QuestionController.java
@Controller
@RequestMapping("/questions")
public class QuestionController {
@Autowired
private QuestionRepository questionRepository;
@GetMapping("/form")
public String form(HttpSession session) {
if(HttpSessionUtils.isLoginUser(session)) {
return "/users/loginForm";
}
return "/qna/form";
}
@PostMapping("")
public String create(String title, String contents, HttpSession session) {
if(!HttpSessionUtils.isLoginUser(session)) {
return "/users/loginForm";
}
User sessionUser=HttpSessoinUtils.getUserFromSession(session);
Question newQuestion=new Question(sessionUser, title, contents); //1.
questionRepository.save(newQuestion);
return "redirect:/";
}
}
1. 객체에서 값을 꺼내오지 않고, 객체를 가져오도록 합니다.
<!--index.html-->
<div class="container" id="main">
<div class="col-md-12 col-sm-12 col-lg-10 col-lg-offset-1">
<div class="panel panel-default qna-list">
<ul class="list">
{{#questions}}
<li>
<div class="wrap">
<div class="main">
<strong class="subject"> <a href="/questions/{{id}}">{{title}}</a> <!--2.-->
</strong>
<div class="auth-info">
<i class="icon-add-comment"></i> <span class="time">{{formattedCreateDate}}</span> <!--1.-->
<a href="./user/profile.html" class="author">{{writer.userId}}</a>
</div>
<div class="reply" title="댓글">
<i class="icon-reply"></i> <span class="point">8</span>
</div>
</div>
</div>
</li>
{{/questions}}
</ul>
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-6 text-center">
<ul class="pagination center-block" style="display: inline-block;">
<li><a href="#">«</a></li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<li><a href="#">»</a></li>
</ul>
</div>
<div class="col-md-3 qna-write">
<a href="/questions/form" class="btn btn-primary pull-right"
role="button">질문하기</a>
</div>
</div>
</div>
</div>
</div>
1. 현재 시간을 mustache 문법을 이용해 구현합니다.
2. /questions/{{id}} 경로를 이용해서 해당하는 질문의 상세보기 페이지로 이동할 수 있습니다.
//QuestionController.java
@Controller
@RequestMapping("/questions")
public class QuestionController {
@Autowired
private QuestionRepository questionRepository;
@GetMapping("/form")
public String form(HttpSession session) {
if(HttpSessionUtils.isLoginUser(session)) {
return "/users/loginForm";
}
return "/qna/form";
}
@PostMapping("")
public String create(String title, String contents, HttpSession session) {
if(!HttpSessionUtils.isLoginUser(session)) {
return "/users/loginForm";
}
User sessionUser=HttpSessoinUtils.getUserFromSession(session);
Question newQuestion=new Question(sessionUser, title, contents);
questionRepository.save(newQuestion);
return "redirect:/";
}
@GetMapping("/{id}")
public String show(@PathVariable Long id, Model model) { //1.
model.addAttribute("question", questionRepository.findById(id).get());
return "/qna/show";
}
@GetMapping("/{id}/form")
public String updateForm(@PathVariable Long id, Model model) { //2.
return "/qna/updateForm";
}
}
1. 질문 목록에서 하나의 데이터를 상세보기 할 수 있는 페이지로 이동하도록 해줍니다.
2. 질문 수정 페이지로 이동할 수 있게 해줍니다.
<!--show.html-->
<div class="container" id="main">
<div class="col-md-12 col-sm-12 col-lg-12">
{{#question}} <!--1.-->
<div class="panel panel-default">
<header class="qna-header">
<h2 class="qna-title">{{title}}</h2>
</header>
<div class="content-main">
<article class="article">
<div class="article-header">
<div class="article-header-thumb">
<img src="https://graph.facebook.com/v2.3/100000059371774/picture" class="article-author-thumb" alt="">
</div>
<div class="article-header-text">
<a href="/users/92/kimmunsu" class="article-author-name">{{writer.userId}}</a> <!--2.-->
<a href="/questions/413" class="article-header-time" title="퍼머링크">
{{formattedCreateDate}} <!--2.-->
<i class="icon-link"></i>
</a>
</div>
</div>
<div class="article-doc">
{{contents}} <!--2.-->
</div>
<div class="article-util">
<ul class="article-util-list">
<li>
<a class="link-modify-article" href="/questions/{{id}}/form">수정</a> <!--3.-->
</li>
<li>
<form class="form-delete" action="/questions/{{id}}" method="POST"> <!--4.-->
<input type="hidden" name="_method" value="delete"> <!--5.-->
<button class="link-delete-article" type="submit">삭제</button>
</form>
</li>
<li>
<a class="link-modify-article" href="/">목록</a>
</li>
</ul>
</div>
</article>
<div class="qna-comment">
<div class="qna-comment-slipp">
<p class="qna-comment-count"><strong>2</strong>개의 의견</p>
<div class="qna-comment-slipp-articles">
{{#answers}}
<article class="article" id="answer-1405">
<div class="article-header">
<div class="article-header-thumb">
<img src="https://graph.facebook.com/v2.3/1324855987/picture" class="article-author-thumb" alt="">
</div>
<div class="article-header-text">
<a href="/users/1/자바지기" class="article-author-name">{{writer.userId}}</a>
<a href="#answer-1434" class="article-header-time" title="퍼머링크">
{{formattedCreateDate}}
</a>
</div>
</div>
<div class="article-doc comment-doc">
<p>{{contents}}</p>
</div>
<div class="article-util">
<ul class="article-util-list">
<li>
<a class="link-modify-article" href="/questions/413/answers/1405/form">수정</a>
</li>
<li>
<a class="link-delete-article" href="/api/questions/{{question.id}}/answers/{{id}}">삭제</a>
</li>
</ul>
</div>
</article>
{{/answers}}
<form class="answer-write" method="post" action="/api/questions/{{id}}/answers">
<div class="form-group" style="padding:14px;">
<textarea class="form-control" placeholder="Update your status" name="contents"></textarea>
</div>
<input type="submit" class="btn btn-success pull-right" value="답변하기"/>
<div class="clearfix" />
</form>
</div>
</div>
</div>
</div>
</div>
{{/question}}
</div>
</div>
1. mustache를 이용해서 question정보를 연결합니다.
2. 글쓴이, 시간, 내용 등을 mustache로 전달합니다.
3. /questions/{{id}}/form 경로를 통해 수정 페이지로 이동하게 합니다.
4. /questions/{{id}} 경로를 통해 삭제할 질문을 받아옵니다.
5. delete를 이용해서 삭제 기능을 구현합니다.
<!--updateForm.html-->
<div class="container" id="main">
<div class="col-md-12 col-sm-12 col-lg-10 col-lg-offset-1">
<div class="panel panel-default content-main">
{{#question}}
<form name="question" method="post" action="/questions/{{id}}"> <!-- 질문하기 버튼을 클릭하면 questions라는 URL을 통해서 제목과 내용이 전달됨 -->
<input type="hidden" name="_method" value="put" /> <!--1.-->
<div class="form-group">
<label for="title">제목</label>
<input type="text" class="form-control" id="title" name="title" value="{{title}}" placeholder="제목"/>
</div>
<div class="form-group">
<label for="contents">내용</label>
<textarea name="contents" id="contents" rows="5" class="form-control">{{contents}}</textarea>
</div>
<button type="submit" class="btn btn-success clearfix pull-right">질문하기</button>
<div class="clearfix" />
</form>
{{/question}}
</div>
</div>
</div>
1. put을 이용해서 질문을 등록할 수 있게 해줍니다.
//Question.java
@Entity
public class Question {
@Id
@GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(foreignKey=@ForeignKey(name="fk_question_writer"))
private User writer;
private String writer;
private String title;
private String contents;
private LocalDateTime createDate;
public Question() {}
public Question(String writer, String title, String contents) {
super();
this.writer=writer;
this.title=title;
this.contents=contents;
this.createDate=LocalDateTime.now();
}
public String getFormattedCreateDate() {
if(createDate==null) {
return "";
}
return createDate.format(DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss"));
}
public void update(String title, String contents) { //1.
this.title=title;
this.contents=contents;
}
}
1. 질문을 수정하는 update 메소드를 만들어줍니다.
//QuestionController.java
@Controller
@RequestMapping("/questions")
public class QuestionController {
@Autowired
private QuestionRepository questionRepository;
@GetMapping("/form")
public String form(HttpSession session) {
if(HttpSessionUtils.isLoginUser(session)) {
return "/users/loginForm";
}
return "/qna/form";
}
@PostMapping("")
public String create(String title, String contents, HttpSession session) {
if(!HttpSessionUtils.isLoginUser(session)) {
return "/users/loginForm";
}
User sessionUser=HttpSessoinUtils.getUserFromSession(session);
Question newQuestion=new Question(sessionUser, title, contents);
questionRepository.save(newQuestion);
return "redirect:/";
}
@GetMapping("/{id}")
public String show(@PathVariable Long id, Model model) {
model.addAttribute("question", questionRepository.findById(id).get());
return "/qna/show";
}
@GetMapping("/{id}/form")
public String updateForm(@PathVariable Long id, Model model) {
return "/qna/updateForm";
}
@PutMapping("/{id}") //2.
public String update(@PathVariable Long id, String title, String contents) { //1.
Question question=questionRepository.findById(id).get();
question.update(title, contents);
questionRepository.save(question);
return String.format("redirect:/questions/%d", id);
}
@DeleteMapping("/{id}") //4.
public String delete(@PathVariable Long id) { //3.
questionRepository.delete(id);
return "redirect:/";
}
}
1. 수정한 내용을 갱신하고, questionRepository에 갱신한 내용을 저장한 후, 수정한 페이지를 리턴합니다.
2. 수정은 'put'을 이용합니다.
3. 삭제할 질문의 id를 받아와서 questionRepository에서 삭제합니다.
4. 삭제는 'delete'를 이용합니다.
'Spring > 게시판 만들기 프로젝트' 카테고리의 다른 글
[Spring Boot] #4_3 게시판 만들기 (0) | 2020.12.23 |
---|---|
[Spring Boot] #4_2 게시판 만들기 (0) | 2020.12.22 |
[Spring Boot] #3_2 게시판 만들기 (0) | 2020.12.21 |
[Spring Boot] #3_1 게시판 만들기 (0) | 2020.12.21 |
[Spring Boot] #2_2 게시판 만들기 (0) | 2020.12.09 |