스프링부트+리액트간의 통신이 어떻게 이루어지는지 알기 위해서 게시판+좋아요 기능이 담긴 프로젝트를 진행하고 있었다.
좋아요 기능은 생각보다 고려해야 되는 점이 꽤나 있었다..
backend : spring boot
frontend : react
두 개의 창을 띄워놓고서 좋아요 기능을 테스트해보는 상황이었다.
왼쪽은 사용자 A가 로그인 한 화면, 오른쪽은 사용자 B가 로그인 한 화면이다.

당연히 사용자 A가 클릭한 것은 사용자 A의 정보가 등록되어야했다.
그러나 사용자 B가 클릭한 것으로 인식되어서 기능이 정상적으로 작동하지 못했다.
.sessionManagement(session -> session
.maximumSessions(2) // 여러 계정이 동시에 유지되도록 설정 (원하는 숫자로 변경 가능)
.maxSessionsPreventsLogin(false) // 기존 세션을 만료하지 않도록 설정
)
우선 security.config에 다음과 같이 설정을 해주었다.
여러계정이 동시에 유지되도록 우선 설정해보았다.
1. Controller
public class LikeController {
private final HeartLikeService heartLikeService;
@PostMapping("/article/like/{articleId}")
public ResponseEntity<HeartDto> articleLike(@PathVariable("articleId") Long articleId,@RequestBody Map<String, String> requestData){
HeartDto heartDto=heartLikeService.addLike(articleId,requestData);
return ResponseEntity.status(HttpStatus.OK).body(heartDto);
}
}
public class HeartLikeService {
@Transactional
public HeartDto addLike(Long articleId,Map<String, String> requestData){
String userEmail = requestData.get("userEmail"); // 프론트에서 받은 userEmail
User currentUser=userService.getUserInfo(userEmail);
Authentication authentication= SecurityContextHolder.getContext().getAuthentication();
String email=authentication.getName();
User user = userService.getUserInfo(email);
System.out.println("요청한 currentUser"+currentUser);
Article article=articleRepository.findByArticleId(articleId);
if(likeRepository.findByArticleAndUser(article, currentUser)==null){ //해당 게시글에 articleUser가 없는경우 +1
article.setLikeCnt(article.getLikeCnt()+1);
HeartLike heartLike=HeartLike.addLike(currentUser, article);
likeRepository.save(heartLike);
return HeartDto.createHeartDto("좋아요 완료❤️",heartLike);
}
현재 세션을 backend로 넘겨주도록 했다.
const userEmail = sessionStorage.getItem("email");
const responseLike = await axios({
url: `http://localhost:8080/article/like/${params}`,
method: 'POST',
withCredentials: true,
data: { userEmail },
headers: {
"Content-Type":
"application/json"
}
});
현재 login한 사용자가 이미 좋아요를 누른 게시글이라면 채워진 하트여야 했다. 처음에는 게시글 상세조회를 GetMapping메서드로 가져오고 있었다.
GetMapping은 요청시에 body가 비어있다. 따라서 PostMapping으로 body에 session email이 담긴 요청을 해주어야 한다고 판단했다.
@PostMapping("/article/{articleId}")
public ResponseEntity<Map<String,Object>> detail(@PathVariable("articleId") Long articleId,@RequestBody Map<String, String> requestData){
Map<String,Object> response=articleService.getArticleInfoAndUser(articleId,requestData);
return ResponseEntity.status(HttpStatus.OK).body(response);
}
public Map<String,Object> getArticleInfoAndUser(Long articleId,Map<String, String> requestData){
Article article=articleRepository.findByArticleId(articleId);
String userEmail = requestData.get("userEmail"); // 프론트에서 받은 userEmail
User currentUser=userService.getUserInfo(userEmail);
System.out.println("요청한 currentUser"+currentUser);
//like여부 정보 가져오기
boolean isLiked=likeRepository.existsByArticleIdAndUserId(articleId, currentUser.getId());
Map<String,Object> response=new HashMap<>();
response.put("article",article);
response.put("isLiked",isLiked);
return response;
}
try {
const userEmail = sessionStorage.getItem("email");
const response = await axios({
url: `http://localhost:8080/article/${params}`,
method: 'POST',
data: { userEmail },
headers: {
"Content-Type":
"application/json"
},
withCredentials: true,
});
console.log(response.data.article);
setDetail(response.data.article);
setLike(response.data.isLiked);
console.log(response.data.isLiked);
} catch (error) {
console.log("에러 발생", error);
}
<HeartButton like={like ? true : false} onClick={handleLike} />