
DB 조회 조건
구글링 해보니깐 JPQL에서 limit 기능은 Pageable 사용하라고 해서 아래와 같이 JPQL 작성
나머지 답변이나 댓글도 동일한 방식으로 작성 가능하므로 생략~
public interface QuestionRepository extends JpaRepository<Question, Integer> {
...(생략)...
@Query("select q "
+ "from Question q "
+ "join SiteUser u on q.author=u "
+ "where u.username = :username "
+ "order by q.createDate desc ")
List<Question> findCurrentQuestion(@Param("username") String username,
Pageable pageable);
}
서비스 계층에서는 최근 몇개를 조회하고 싶은지 결정해서 Pageable 객체 생성
@RequiredArgsConstructor
@Service
public class QuestionService {
...(생략)...
public List<Question> getCurrentListByUser(String username, int num) {
Pageable pageable = PageRequest.of(0, num);
return questionRepository.findCurrentQuestion(username, pageable);
}
}
프로필 화면은 로그인이 완료된 상태에서 보여질 수 있으므로 @PreAuthorize("isAuthenticated()") 추가
@RequiredArgsConstructor
@Controller
@RequestMapping("/user")
public class UserController {
private final UserService userService;
private final QuestionService questionService;
private final AnswerService answerService;
private final CommentService commentService;
...(생략)...
@PreAuthorize("isAuthenticated()")
@GetMapping("/profile")
public String profile(Model model, Principal principal) {
String username = principal.getName();
model.addAttribute("username", username);
model.addAttribute("questionList",
questionService.getCurrentListByUser(username, 5));
model.addAttribute("answerList",
answerService.getCurrentListByUser(username, 5));
model.addAttribute("commentList",
commentService.getCurrentListByUser(username, 5));
return "profile";
}
}
간단하게 html 코드도 작성
<html layout:decorate="~{layout}">
<div layout:fragment="content" class="container my-3">
<section>
<div class="row">
<div class="col-lg-4">
<div class="card mb-4">
<div class="card-body text-center">
<img src="https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-chat/ava3.webp"
alt="avatar" class="rounded-circle img-fluid" style="width: 150px;">
<h5 class="my-3" th:text="${username}"></h5>
</div>
</div>
</div>
<div class="col-lg-8">
<h5>최근 게시글</h5>
<div class="card mb-4">
<div class="card-body">
<th:block th:each="question: ${questionList}">
<div class="row">
<div class="col-sm-3">
<p class="mb-0" th:text="${question.subject}"></p>
</div>
<div class="col-sm-9">
<p class="text-muted mb-0" th:text="${question.createDate}"></p>
</div>
</div>
</th:block>
</div>
</div>
<h5>최근 답변</h5>
<div class="card mb-4">
<div class="card-body">
<th:block th:each="answer: ${answerList}">
<div class="row">
<div class="col-sm-3">
<p class="mb-0" th:text="${answer.content}"></p>
</div>
<div class="col-sm-9">
<p class="text-muted mb-0" th:text="${answer.createDate}"></p>
</div>
</div>
</th:block>
</div>
</div>
<h5>최근 댓글</h5>
<div class="card mb-4">
<div class="card-body">
<th:block th:each="comment: ${commentList}">
<div class="row">
<div class="col-sm-3">
<p class="mb-0" th:text="${comment.content}"></p>
</div>
<div class="col-sm-9">
<p class="text-muted mb-0" th:text="${comment.createDate}"></p>
</div>
</div>
</th:block>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
<script layout:fragment="script" type='text/javascript'>
</script>
</html>

(최근 댓글, 답변은 그냥 skip... 크게 의미있진 않은듯?)
@Getter
@Setter
@Entity
public class Question {
...(생략)...
private Integer hit;
}
기존 테이블 수정하는 sql
alter table question
add hit integer;
update question
set hit = 0
where hit is null;
기존 서비스 계층에서 게시글을 조회하는 메서드는 getQuestion 메서드가 있었다. 하지만 이 메서드는 게시글을 조회하는 것 뿐만 아니라 수정, 삭제 등 다른 곳에서도 사용되는 메서드이다. 이런 곳들에서는 조회수를 높이는 것이 아니라 단지 게시글을 불러오는 것만 필요하다. 그렇기 때문에 게시글을 조회할 때 조회수 + 1 로직을 수행하는 메서드를 따로 하나 추가했다.
@RequiredArgsConstructor
@Service
public class QuestionService {
...(생략)...
@Transactional
public Question hitQuestion(Integer id) {
Optional<Question> oquestion = this.questionRepository.findById(id);
if (oquestion.isPresent()) {
Question question = oquestion.get();
question.setHit(question.getHit() + 1);
return question;
} else {
throw new DataNotFoundException("question not found");
}
}
}
@Slf4j
@RequiredArgsConstructor
@Controller
public class QuestionController {
private final QuestionService questionService;
...(생략)...
@GetMapping(value = "/question/detail/{id}")
public String detail(Model model, @PathVariable("id") Integer id,
AnswerForm answerForm,
@RequestParam(value = "answerPage",
defaultValue = "0") int answerPage) {
Question question = this.questionService.hitQuestion(id);
Page<Answer> answerPaging =
this.answerService.getList(question, answerPage);
model.addAttribute("question", question);
model.addAttribute("answerPaging", answerPaging);
return "question_detail";
}
...(생략)...
}