페이지에 접속하면 보이는 글과 각각의 글에 달린 답변을 누가 작성했는지 글쓴이를 표시해보겠습니다.
글쓴이를 표시하기 위해서는 Question 과 Answer 엔티티에 author 속성을 추가해야 합니다.
시작
Question 엔티티에 author 속성을 추가하고
Question 과 글쓴이의 관계는 N:1 관계이기 때문에 @ManyToOne 애노테이션을 붙입니다.
package com.crud.model;
...
@Entity
@Getter
@Setter
public class Question {
...
@ManyToOne
private User author;
}
Answer 엔티티에도 author 속성을 추가하고 Answer 또한 N:1 관계이므로 @ManyToOne 을 붙입니다.
package com.crud.model;
...
@Entity
@Getter
@Setter
public class Answer {
...
@ManyToOne
private User author;
}
mysql 을 통해 question 과 answer 테이블을 확인해보면
각각 author_id 라는 칼럼이 추가된것을 알 수 있습니다.
MariaDB [springboot_crud]> desc question;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| content | text | YES | | NULL | |
| create_date | datetime | YES | | NULL | |
| subject | varchar(200) | YES | | NULL | |
| author_id | bigint(20) | YES | MUL | NULL | |
+-------------+--------------+------+-----+---------+----------------+
5 rows in set (0.010 sec)
MariaDB [springboot_crud]> desc answer;
+-------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| content | text | YES | | NULL | |
| create_date | datetime | YES | | NULL | |
| question_id | int(11) | YES | MUL | NULL | |
| author_id | bigint(20) | YES | MUL | NULL | |
+-------------+------------+------+-----+---------+----------------+
5 rows in set (0.007 sec)
Service 작성
다음으로 QuestionService 와 AnswerService 의 create 메서드에 author 를 넣어서
Question 과 Answer 이 생성될때 author 값도 저장되도록 create 메서드를 수정합니다.
package com.crud.service;
...
@Service
public class QuestionService {
@Autowired
private QuestionRepository questionRepository;
...
public void create(String subject, String content, User author) {
Question q = new Question();
q.setSubject(subject);
q.setContent(content);
q.setAuthor(author);
q.setCreateDate(LocalDateTime.now());
questionRepository.save(q);
}
...
}
package com.crud.service;
...
@Service
public class AnswerService {
@Autowired
private AnswerRepository answerRepository;
public void create(Question question, String content, User author) {
Answer answer = new Answer();
answer.setContent(content);
answer.setCreateDate(LocalDateTime.now());
answer.setQuestion(question);
answer.setAuthor(author);
answerRepository.save(answer);
}
}
UserService 작성
위에서 만든 Service 를 Controller 에서 사용하기 위해서는 Controller 에서 User 를 가져와야합니다.
User 를 가져오는 메서드를 UserService 에 작성해보겠습니다.
package com.crud.service;
...
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
...
public User getUser(String username) {
Optional<User> user = userRepository.findByusername(username);
// user를 못찾을 경우 예외처리 필요
return user.get();
}
}
getUser 메서드에서 user 를 못찾았을 경우 예외처리는 이후에 다시 수정하겠습니다.
Controller 수정
다음으로 QuestionController 와 AnswerController 를 수정하겠습니다.
package com.crud.controller;
...
@Controller
public class QuestionController {
@Autowired
private QuestionService questionService;
@Autowired
private UserService userService;
...
@PreAuthorize("isAuthenticated()")
@GetMapping("/question/create")
public String questionCreate(QuestionForm questionForm) {
return "question_form";
}
@PreAuthorize("isAuthenticated()")
@PostMapping("question/create")
public String questionCreate(@Valid QuestionForm questionForm, BindingResult bindingResult, Principal principal) {
if(bindingResult.hasErrors()) {
return "question_form";
}
User user = userService.getUser(principal.getName());
questionService.create(questionForm.getSubject(), questionForm.getContent(), user);
return "redirect:/question/list";
}
}
questionCreate 의 인자로 Principal 객체가 추가되었습니다.
Principal 은 스프링 시큐리티에서 제공하는 현재 로그인한 사용자를 알 수 있는 객체로
Principal 의 getName 메서드를 사용하면 현재 로그인한 사용자의 이름을 알 수 있습니다.
Principal 객체의 getName 메서드를 통해 현재 로그인한 사용자명을 알 수 있음.
앞에서 만든 userService 의 getUser 메서드를 통해 현재 로그인한 사용자의 이름(principal.getName()) 을 통해
사용자를 가져와서 저장합니다.
Principal 객체는 로그인한 상태에서만 사용할 수 있기 때문에 만약, 로그인 하지 않은 경우 오류가 발생합니다.
때문에 로그인을 한 상태에서만 메서드를 사용하게 해주는 @PreAuthorize("isAuthenticated()") 애너테이션을 사용합니다.
@PreAuthorize("isAuthenticated()") 는 메서드를 로그인한 상태에서만 사용하게 해줌
AnswerController 또한 동일하게 작성합니다.
package com.crud.controller;
...
@Controller
public class AnswerController {
@Autowired
private QuestionService questionService;
@Autowired
private AnswerService answerService;
@Autowired
private UserService userService;
@PreAuthorize("isAuthenticated()")
@PostMapping("/answer/create/{id}")
public String createAnswer(Model model, @PathVariable("id") Integer id, @Valid AnswerForm answerForm, BindingResult bindingResult, Principal principal) {
Question question = questionService.getQuestion(id);
User user = userService.getUser(principal.getName());
if(bindingResult.hasErrors()) {
model.addAttribute("question", question);
return "question_detail";
}
answerService.create(question, answerForm.getContent(), user);
return String.format("redirect:/question/detail/%s", id);
}
}
다음으로 Controller 에서 PreAuthorize 애노테이션을 사용할 수 있도록
SecurityConfig 파일에 @EnableMethodSecurity 를 추가합니다.
package com.crud;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
...
}
결과
로그인을 해서 글을 question 을 하나 작성하고 답글을 달아보면
다음과 같이 author_id 에 1이라는 숫자가 저장된것을 알 수 있습니다.
MariaDB [springboot_crud]> select * from question;
+-----+---------------------------------------+---------------------+--------------------+-----------+
| id | content | create_date | subject | author_id |
+-----+---------------------------------------+---------------------+--------------------+-----------+
...
| 106 | hello nice to meet you. | 2023-01-26 16:01:49 | hello | 1 |
+-----+---------------------------------------+---------------------+--------------------+-----------+
106 rows in set (0.000 sec)
MariaDB [springboot_crud]> select * from answer;
+----+-----------------------+---------------------+-------------+-----------+
| id | content | create_date | question_id | author_id |
+----+-----------------------+---------------------+-------------+-----------+
...
| 3 | nice to meet you too~ | 2023-01-26 16:02:01 | 106 | 1 |
+----+-----------------------+---------------------+-------------+-----------+
3 rows in set (0.000 sec)
'Spring > Springboot 실습' 카테고리의 다른 글
게시판 만들기 - 글 수정 및 삭제(1) (0) | 2023.02.02 |
---|---|
게시판 만들기 - 글쓴이 표시(2) (0) | 2023.01.26 |
게시판 만들기 - 로그아웃 (0) | 2023.01.25 |
게시판 만들기 - 로그인 (0) | 2023.01.25 |
게시판 만들기 - 회원가입(2) (0) | 2023.01.24 |