오늘 한 일
💡글 상세 조회 페이지 사용자의 역할별로 버튼 다르게 붙임
🚩 문제 : 작성자로 로그인하면 상세글 페이지가 출력되지 않는 문제 해결
🚩문제 : 받아온 데이터가 화면에 출력되지 않는 문제 해결
🚩문제 : 버튼이 안 보이는 문제 해결
🚩문제 : 모집마감이 되지 않는 문제 해결
💡메뉴페이지 만듦
🚩문제 : Bean Validation에서 걸리는 문제 해결
🚩문제 : 메뉴가 안 뜨는 문제 해결
🚩문제 : Get할때 JSON 형식으로 Object를 전송하면 url에 이상하게 들어가는 문제 해결
💡메뉴 추가하는 부분 접었다 폈다 하는 기능 추가해봄
💡자동 새로고침 기능 추가해봄
💡글 상세 조회 페이지 사용자의 역할별로 버튼 다르게 붙임
글 상세조회 페이지 post.html 새로 만드는데
글 주인이냐 참가자냐 아니냐에 따라서 버튼을 다르게 보여줘야 해서
DetailedPostResponse에 UserPostRole 추가해봄
그리고 postId가 있어야 해서 추가해봄
@Builder
public record DetailedPostResponse(
Long id,
String address,
Double latitude,
Double longitude,
String store,
Integer minPrice,
Integer deliveryCost,
List<NickMenusResponse> menus,
Integer sumPrice,
LocalDateTime deadline,
UserPostRole role
) {
}
@Override
public DetailedPostResponse getPost(Long postId, User user) {
Post post = getPostById(postId);
List<UserPost> userPosts = getUserPostsByPost(post);
return DetailedPostResponse.builder()
.id(post.getId())
.longitude(post.getLongitude())
.latitude(post.getLatitude())
.address(post.getAddress())
.store(post.getStore())
.minPrice(post.getMinPrice())
.deliveryCost(post.getDeliveryCost())
.menus(getNickMenus(userPosts))
.sumPrice(getSumPrice(userPosts, post))
.deadline(getDeadline(post))
.role(getUserPostByUserIfParticipant(user,userPosts).getRole())
.build();
}
지금보니 참가자인지 판별하는 로직이 안 들어있어서 바꿔봄
내가 이미 이 함수를 짜둠 하지만 나는 해당 Post의 List<UserPost> 가 이미 있기때문에 오버로딩해봄
private UserPost getUserPostIfParticipant(User user, Post post) {
return userPostRepository.findByPostAndUserAndRoleEquals(post, user,
UserPostRole.PARTICIPANT).orElseThrow(() ->
new GlobalException(PostErrorCode.FORBIDDEN_ACCESS_PARTICIPANT)
);
}
이라고 생각하고 위를 보니 과거의 내가 똑같이 생각하고 오버로딩을 해놨다 ㅋㅋㅋㅋㅋㅋㅋ
private UserPost getUserPostByUserIfParticipant(User user, List<UserPost> userPosts) {
for (UserPost userPost : userPosts) {
if (userPost.getRole().equals(UserPostRole.HOST)) {
continue;
}
if (user.getId().equals(userPost.getUser().getId())) {
return userPost;
}
}
throw new GlobalException(PostErrorCode.FORBIDDEN_ACCESS_PARTICIPANT);
}
private UserPost getUserPostIfParticipant(User user, Post post) {
return userPostRepository.findByPostAndUserAndRoleEquals(post, user,
UserPostRole.PARTICIPANT).orElseThrow(() ->
new GlobalException(PostErrorCode.FORBIDDEN_ACCESS_PARTICIPANT)
);
}
그래서 이렇게 됐다
@Override
public DetailedPostResponse getPost(Long postId, User user) {
Post post = getPostById(postId);
List<UserPost> userPosts = getUserPostsByPost(post);
return DetailedPostResponse.builder()
.longitude(post.getLongitude())
.latitude(post.getLatitude())
.address(post.getAddress())
.store(post.getStore())
.minPrice(post.getMinPrice())
.deliveryCost(post.getDeliveryCost())
.menus(getNickMenus(userPosts))
.sumPrice(getSumPrice(userPosts, post))
.deadline(getDeadline(post))
.role(getUserPostByUserIfParticipant(user,userPosts).getRole())-> 이부분이 추가됨
.build();
}
→
html내부에서 role에 따라 구분해서 버튼을 달아봄
<script th:inline="javascript">
$(document).ready(function () {
getData();
});
function getData() {
$.ajax({
type: 'GET',
url: `/api/v1/posts/[[${postId}]]`,
dataType: "json",
contentType: 'application/json',
data: {},
success: function (response) {
console.log('Success:', response);
let data = response.data;
latitude = data.latitude;
longitude = data.longitude
deadline = data.deadline;
deliveryCost = data.deliveryCost;
minPrice = data.minPrice;
store = data.store;
sumPrice = data.sumPrice;
nickmenus = data.menus;
drawMap(latitude, longitude);
drawField(store,sumPrice,minPrice,deliveryCost,minPrice,deadline);
drawMenus(nickmenus);
/**이 부분!**/
if(data.role == "HOST"){
drawHostButtons();
}else if(data.role == "Participant"){
drawParticipantButtons();
}else{
drawAnyoneButtons();
}
},
그리고 각각 버튼 다르게 달아봄
글 주인용 상세페이지
<div id = "buttons" style="padding:10px;width:1000px;height:min-content;">
</div>
button을 달 element를 일단 만들어봄
function drawHostButtons(){
$('#buttons').append(
`
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" name="btnradio" onclick="etc()" id="getOffers" autocomplete="off" checked>
<label class="btn btn-outline-secondary" for="else">요청 조회</label>
<input type="radio" class="btn-check" name="btnradio" onclick="burger()" id="editmenus" autocomplete="off">
<label class="btn btn-outline-secondary" for="burger">메뉴 수정</label>
<input type="radio" class="btn-check" name="btnradio" onclick="chicken()" id="closeApplication" autocomplete="off">
<label class="btn btn-outline-secondary" for="chicken">모집 마감</label>
<input type="radio" class="btn-check" name="btnradio" onclick="korean()" id="cancelRecruitment" autocomplete="off">
<label class="btn btn-outline-secondary" for="korean">모집 취소</label>
<input type="radio" class="btn-check" name="btnradio" onclick="western()" id="completeOrder" autocomplete="off">
<label class="btn btn-outline-secondary" for="western">주문 완료</label>
</div>
`
)
}
postId 연결해줌
if(data.role == "HOST"){
drawHostButtons(data.id);
}else if(data.role == "PARTICIPANT"){
drawParticipantButtons(data.id);
}else{
drawAnyoneButtons(data.id);
}
버튼에도 postId달아줌
function drawHostButtons(postId){
$('#buttons').append(
`
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" post = "${postId}" onclick="getOffers(this)" name="btnradio" id="getOffers" autocomplete="off" checked>
<label class="btn btn-outline-secondary" for="getOffers">요청 조회</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="editmenus(this)" name="btnradio" id="editmenus" autocomplete="off">
<label class="btn btn-outline-secondary" for="editmenus">메뉴 수정</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="closeApplication(this)" name="btnradio" id="closeApplication" autocomplete="off">
<label class="btn btn-outline-secondary" for="closeApplication">모집 마감</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="cancelRecruitment(this)" name="btnradio" id="cancelRecruitment" autocomplete="off">
<label class="btn btn-outline-secondary" for="cancelRecruitment">모집 취소</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="completeOrder(this)" name="btnradio" id="completeOrder" autocomplete="off">
<label class="btn btn-outline-secondary" for="completeOrder">주문 완료</label>
</div>
`
)
}
아 근데 저렇게 안 하고 그냥 전역변수에 postId 넣어버려도 될 듯함
이건 어차피 script내부에서 동작하는거라…
package com.moayo.moayoeats.backend.domain.post.controller;
import com.moayo.moayoeats.backend.domain.post.dto.request.PostCategoryRequest;
import com.moayo.moayoeats.backend.domain.post.dto.request.PostIdRequest;
import com.moayo.moayoeats.backend.domain.post.dto.request.PostRequest;
import com.moayo.moayoeats.backend.domain.post.dto.request.PostSearchRequest;
import com.moayo.moayoeats.backend.domain.post.dto.response.BriefPostResponse;
import com.moayo.moayoeats.backend.domain.post.dto.response.DetailedPostResponse;
import com.moayo.moayoeats.backend.domain.post.service.PostService;
import com.moayo.moayoeats.backend.global.dto.ApiResponse;
import com.moayo.moayoeats.backend.global.security.UserDetailsImpl;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/v1")
public class PostController {
private final PostService postService;
// 글 생성하기
@PostMapping("/posts")
public ApiResponse<Void> createPost(
@Valid @RequestBody PostRequest postReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
postService.createPost(postReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.CREATED.value(), "글을 생성했습니다.");
}
// 인증정보 없이 모든 글 조회하기
@GetMapping("/readonly/posts")
public ApiResponse<List<BriefPostResponse>> getPostsForAnyone() {
return new ApiResponse<>(HttpStatus.OK.value(), "모든 글 조회에 성공했습니다.",
postService.getPostsForAnyone());
}
// 모든 글 조회하기
@GetMapping("/posts")
public ApiResponse<List<BriefPostResponse>> getPosts(
@AuthenticationPrincipal UserDetailsImpl userDetails) {
return new ApiResponse<>(HttpStatus.OK.value(), "모든 글 조회에 성공했습니다.",
postService.getPosts(userDetails.getUser()));
}
//글 단독 조회, 글 상세페이지
@GetMapping("/posts/{postId}")
public ApiResponse<DetailedPostResponse> getPost(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@PathVariable(name = "postId") Long postId
) {
return new ApiResponse<>(HttpStatus.OK.value(), "글 상세페이지 조회에 성공했습니다.",
postService.getPost(postId, userDetails.getUser()));
}
//글 카테고리별 조회
@GetMapping("/posts/category")
public ApiResponse<List<BriefPostResponse>> getPostsByCategory(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostCategoryRequest postCategorySearchReq
) {
return new ApiResponse<>(HttpStatus.OK.value(), "글 카테고리별 조회에 성공했습니다.",
postService.getPostsByCategory(postCategorySearchReq, userDetails.getUser()));
}
//글 검색하기
@GetMapping("/posts/search")
public ApiResponse<List<BriefPostResponse>> searchPost(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostSearchRequest postSearchReq
) {
return new ApiResponse<>(HttpStatus.OK.value(), "검색 결과",
postService.searchPost(postSearchReq, userDetails.getUser()));
}
//모집 취소하기
@DeleteMapping("/posts")
public ApiResponse<Void> deletePost(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostIdRequest postIdReq
) {
postService.deletePost(postIdReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "모집 취소에 성공했습니다.");
}
//모집 마감
@PatchMapping("/posts/close")
public ApiResponse<Void> closeApplication(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostIdRequest postIdReq
) {
postService.closeApplication(postIdReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "모집이 마감되었습니다.");
}
//주문 완료
@PatchMapping("/posts/complete-order")
public ApiResponse<Void> completeOrder(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostIdRequest postIdReq
) {
postService.completeOrder(postIdReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "주문완료 처리가 되었습니다.");
}
//나가기 기능
@DeleteMapping("/posts/exit")
public ApiResponse<Void> exit(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostIdRequest postIdReq
) {
postService.exit(postIdReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "글에서 나가기 되었습니다.");
}
//수령 완료
@DeleteMapping("/posts/received")
public ApiResponse<Void> receiveOrder(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostIdRequest postIdReq
) {
postService.receiveOrder(postIdReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "수령완료 처리가 되었습니다.");
}
//Test
@GetMapping("/test/posts/{postId}")
public ApiResponse<DetailedPostResponse> getPostTest(
@PathVariable(name = "postId") Long postId
) {
return new ApiResponse<>(HttpStatus.OK.value(), "글 상세페이지 조회에 성공했습니다.",
postService.getPostTest(postId));
}
}
모집마감 달아봄
function closeApplication(button){
var postId = $(button).attr("post");
$.ajax({
type: 'POST',
url: "/api/v1/posts/close",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
},
error: function (error,response) {
alert(response.message);
console.error('Error:', error);
}
});
}
모집취소 달아봄
function cancelRecruitment(button){
var postId = $(button).attr("post");
$.ajax({
type: 'DELETE',
url: "/api/v1/posts",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
},
error: function (error,response) {
alert(response.message);
console.error('Error:', error);
}
});
}
주문완료 달아봄
function completeOrder(button){
var postId = $(button).attr("post");
$.ajax({
type: 'PATCH',
url: "/api/v1/posts/complete-order",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
},
error: function (error,response) {
alert(response.message);
console.error('Error:', error);
}
});
}
🚩 문제 : 작성자로 로그인하면 상세글 페이지가 출력되지 않는다
작성자로 로그인해도 글 상세 페이지가 보이지 않았음
범인이 전역변수인가 싶어서 값 전달을 파라미터로 다시 해봄
그래도 상황이 변하지 않았다
UserPost에 관계가 멀쩡하게 들어있는데 왜 참가자가 아니라고 뜰까?
⛳ 해결 : getRole에서 HOST 걸러내던거 거르지 않게 변경함
@Override
public DetailedPostResponse getPost(Long postId, User user) {
Post post = getPostById(postId);
List<UserPost> userPosts = getUserPostsByPost(post);
return DetailedPostResponse.builder()
.id(post.getId())
.longitude(post.getLongitude())
.latitude(post.getLatitude())
.address(post.getAddress())
.store(post.getStore())
.minPrice(post.getMinPrice())
.deliveryCost(post.getDeliveryCost())
.menus(getNickMenus(userPosts))
.sumPrice(getSumPrice(userPosts, post))
.deadline(getDeadline(post))
.role(getUserPostByUserIfParticipant(user,userPosts).getRole())
.build();
}
아까 여기서
.role(getUserPostByUserIfParticipant(user,userPosts).getRole())
이거 추가한거 로직이 잘못된듯
private UserPost getUserPostByUserIfParticipant(User user, List<UserPost> userPosts) {
for (UserPost userPost : userPosts) {
if (userPost.getRole().equals(UserPostRole.HOST)) {
continue;
}
if (user.getId().equals(userPost.getUser().getId())) {
return userPost;
}
}
throw new GlobalException(PostErrorCode.FORBIDDEN_ACCESS_PARTICIPANT);
}
호스트는 걸러버리고 있음
메서드 재사용이 안 될거 같아서 하는수없이 새로 만듦
private UserPostRole getRoleByUserAndUserPosts(User user, List<UserPost> userPosts) {
for (UserPost userPost : userPosts) {
if (userPost.getRole().equals(UserPostRole.HOST)) {
return UserPostRole.HOST;
}
if (user.getId().equals(userPost.getUser().getId())) {
return UserPostRole.PARTICIPANT;
}
}
return null;
}
@Override
public DetailedPostResponse getPost(Long postId, User user) {
Post post = getPostById(postId);
List<UserPost> userPosts = getUserPostsByPost(post);
return DetailedPostResponse.builder()
.id(post.getId())
.longitude(post.getLongitude())
.latitude(post.getLatitude())
.address(post.getAddress())
.store(post.getStore())
.minPrice(post.getMinPrice())
.deliveryCost(post.getDeliveryCost())
.menus(getNickMenus(userPosts))
.sumPrice(getSumPrice(userPosts, post))
.deadline(getDeadline(post))
.role(getRoleByUserAndUserPosts(user,userPosts)) -> 수정해봄!!!
.build();
}
다시 테스트해봄
데이터는 이제 잘 받아와진다
🚩문제 : 받아온 데이터가 화면에 출력되지 않음
⛳ 해결 : data.id보내는거 response.data.id로 고쳐줌
화면이 잘 뜬다
🚩문제 : 버튼이 안 보임
버튼이 안 보여서
if(data.role == "HOST"){
drawHostButtons(response.data.id);
}else if(data.role == "PARTICIPANT"){
drawParticipantButtons(response.data.id);
}else{
drawAnyoneButtons(response.data.id);
}
이부분 ==을 ===으로 수정해봄
if(data.role === "HOST"){
drawHostButtons(response.data.id);
}else if(data.role === "PARTICIPANT"){
drawParticipantButtons(response.data.id);
}else{
drawAnyoneButtons(response.data.id);
}
여전히 뜨지 않는다
role이 HOST로 잘 왔는데 왜 안 뜰까?
저 drawHostButtons가 실행이 안 돼서 안 뜨겠지
function drawHostButtons(postId){
$('#buttons').append(
`
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" post = "${postId}" onclick="getOffers(this)" name="btnradio" id="getOffers" autocomplete="off" checked>
<label class="btn btn-outline-secondary" for="getOffers">요청 조회</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="editmenus(this)" name="btnradio" id="editmenus" autocomplete="off">
<label class="btn btn-outline-secondary" for="editmenus">메뉴 수정</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="closeApplication(this)" name="btnradio" id="closeApplication" autocomplete="off">
<label class="btn btn-outline-secondary" for="closeApplication">모집 마감</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="cancelRecruitment(this)" name="btnradio" id="cancelRecruitment" autocomplete="off">
<label class="btn btn-outline-secondary" for="cancelRecruitment">모집 취소</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="completeOrder(this)" name="btnradio" id="completeOrder" autocomplete="off">
<label class="btn btn-outline-secondary" for="completeOrder">주문 완료</label>
</div>
`
)
}
if else가 안 되나 싶어서 밖으로 빼 봄
drawHostButtons(response.data.id);
if(data.role === "HOST"){
}else if(data.role === "PARTICIPANT"){
drawParticipantButtons(response.data.id);
}else{
drawAnyoneButtons(response.data.id);
}
됐다!
부트스트랩 추가하고 지도 사이즈 줄여봄
<link crossorigin="anonymous"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
rel="stylesheet">
<link href="./css/sticky-footer-navbar.css" rel="stylesheet">
<link href="./css/style.css" rel="stylesheet">
🚩문제 : 모집마감이 되지 않음
모집마감 눌러봄
⛳ 해결 : ajax의 POST를 PATCH로 바꿈
@PatchMapping인데다가
type: ‘POST’ 로 보내고 있었어서
‘PATCH’로 바꾸고 한번 더 해봄
해결되었다!
이제 참가자용 버튼 만들어봄
function drawParticipantButtons(postId){
$('#buttons').append(
`
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" post = "${postId}" onclick="editmenus(this)" name="btnradio" id="editmenus" autocomplete="off">
<label class="btn btn-outline-secondary" for="editmenus">메뉴 수정</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="cancelApplication(this)" name="btnradio" id="closeApplication" autocomplete="off">
<label class="btn btn-outline-secondary" for="cancelApplication">참가 취소</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="receiveOrder(this)" name="btnradio" id="cancelRecruitment" autocomplete="off">
<label class="btn btn-outline-secondary" for="receiveOrder">수령 완료</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="chatRoom(this)" name="btnradio" id="chatRoom" autocomplete="off">
<label class="btn btn-outline-secondary" for="chatRoom">채팅방 참여</label>
</div>
`
)
}
function drawAnyoneButtons(postId){
$('#buttons').append(
`
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" post = "${postId}" onclick="editmenus(this)" name="btnradio" id="editmenus" autocomplete="off">
<label class="btn btn-outline-secondary" for="editmenus">메뉴 수정</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="applyApplication(this)" name="btnradio" id="closeApplication" autocomplete="off">
<label class="btn btn-outline-secondary" for="cancelApplication">참가 신청</label>
</div>
`
)
}
나가기 버튼 연결
//나가기 기능
@DeleteMapping("/posts/exit")
public ApiResponse<Void> exit(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostIdRequest postIdReq
) {
postService.exit(postIdReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "글에서 나가기 되었습니다.");
}
function exit(button){
var postId = $(button).attr("post");
$.ajax({
type: 'PATCH',
url: "/api/v1/posts/exit",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
},
error: function (error,response) {
alert(response.message);
console.error('Error:', error);
}
});
}
수령 완료 버튼 연결
//수령 완료
@DeleteMapping("/posts/received")
public ApiResponse<Void> receiveOrder(
@AuthenticationPrincipal UserDetailsImpl userDetails,
@Valid @RequestBody PostIdRequest postIdReq
) {
postService.receiveOrder(postIdReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "수령완료 처리가 되었습니다.");
}
function receiveOrder(button){
var postId = $(button).attr("post");
$.ajax({
type: 'DELETE',
url: "/api/v1/posts/received",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
},
error: function (error,response) {
alert(response.message);
console.error('Error:', error);
}
});
}
참가신청 버튼 연결
@PostMapping()
public ApiResponse<Void> applyParticipation(
@RequestBody OfferRelatedPostRequest offerRelatedPostReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
offerService.applyParticipation(offerRelatedPostReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "참가신청이 완료되었습니다.");
}
@DeleteMapping()
public ApiResponse<Void> cancelParticipation(
@RequestBody OfferRequest offerReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
offerService.cancelParticipation(offerReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "참가취소가 완료되었습니다.");
}
→ OfferId는 글에서 알 수 없는 부분이라 와이어프레임에서 참가 취소를 요청 조회 페이지에서 하도록 수정함
function drawHostButtons(postId){
$('#buttons').append(
`
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" post = "${postId}" onclick="getOffers(this)" name="btnradio" id="getOffers" autocomplete="off" checked>
<label class="btn btn-outline-secondary" for="getOffers">요청 조회</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="editmenus(this)" name="btnradio" id="editmenus" autocomplete="off">
<label class="btn btn-outline-secondary" for="editmenus">메뉴 수정</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="closeApplication(this)" name="btnradio" id="closeApplication" autocomplete="off">
<label class="btn btn-outline-secondary" for="closeApplication">모집 마감</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="cancelRecruitment(this)" name="btnradio" id="cancelRecruitment" autocomplete="off">
<label class="btn btn-outline-secondary" for="cancelRecruitment">모집 취소</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="completeOrder(this)" name="btnradio" id="completeOrder" autocomplete="off">
<label class="btn btn-outline-secondary" for="completeOrder">주문 완료</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="chatRoom(this)" name="btnradio" id="chatRoom" autocomplete="off">
<label class="btn btn-outline-secondary" for="chatRoom">채팅방 참여</label>
</div>
`
)
}
function drawParticipantButtons(postId){
$('#buttons').append(
`
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" post = "${postId}" onclick="editmenus(this)" name="btnradio" id="editmenus" autocomplete="off">
<label class="btn btn-outline-secondary" for="editmenus">메뉴 수정</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="exit(this)" name="btnradio" id="exit" autocomplete="off">
<label class="btn btn-outline-secondary" for="exit">나가기</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="receiveOrder(this)" name="btnradio" id="cancelRecruitment" autocomplete="off">
<label class="btn btn-outline-secondary" for="receiveOrder">수령 완료</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="chatRoom(this)" name="btnradio" id="chatRoom" autocomplete="off">
<label class="btn btn-outline-secondary" for="chatRoom">채팅방 참여</label>
</div>
`
)
}
function drawAnyoneButtons(postId){
$('#buttons').append(
`
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" post = "${postId}" onclick="getOffers(this)" name="btnradio" id="getOffers" autocomplete="off" checked>
<label class="btn btn-outline-secondary" for="getOffers">요청 조회</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="editmenus(this)" name="btnradio" id="editmenus" autocomplete="off">
<label class="btn btn-outline-secondary" for="editmenus">메뉴 수정</label>
<input type="radio" class="btn-check" post = "${postId}" onclick="applyApplication(this)" name="btnradio" id="closeApplication" autocomplete="off">
<label class="btn btn-outline-secondary" for="cancelApplication">참가 신청</label>
</div>
`
)
}
💡메뉴페이지 만듦
본인 메뉴 조회를 하고 메뉴 삭제/생성 요청을 보내야 하는 페이지임
//자신의 메뉴 조회
@GetMapping("/menus")
public ApiResponse<List<MenuResponse>> getMenus(
@Valid @RequestBody MenuReadRequest menuReadReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
return new ApiResponse<>(HttpStatus.OK.value(), "나의 메뉴 조회",
menuService.getMenus(menuReadReq, userDetails.getUser()));
}
public record MenuResponse(
String menuname,
Integer price
) {
}
id가 안 달려있어서 id추가해줌
→
public record MenuResponse(
Long id,
String menuname,
Integer price
) {
}
service단 함수에서도 수정함
@Override
public List<MenuResponse> getMenus(MenuReadRequest menuReadReq, User user) {
Post post = findPostById(menuReadReq.postId());
List<Menu> menus = menuRepository.findAllByUserAndPost(user, post);
return menus.stream().map(menu -> new MenuResponse(menu.getId() ,menu.getMenuname(), menu.getPrice()))
.toList();
}
// 글에 본인이 주문할 Menu 삭제하기
@DeleteMapping("/menus")
public ApiResponse<Void> deleteMenu(
@Valid @RequestBody MenuDeleteRequest menuDeleteReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
menuService.deleteMenu(menuDeleteReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "메뉴를 삭제했습니다.");
}
// 글에 본인이 주문할 Menu 추가하기
@PostMapping("/menus")
public ApiResponse<Void> createMenu(
@Valid @RequestBody MenuRequest menuReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
menuService.createMenu(menuReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.CREATED.value(), "메뉴를 추가했습니다.");
}
menu.html 만드는데 메뉴 추가를 누르면 메뉴 이름이랑 메뉴 가격 정해지고 추가될 수 있는거 하고싶음
function drawMenus(data) {
data.forEach((menu) =>
$('#menus').append(
`
<div>
<span>${menu.menuname}</span>
<span>${menu.price}</span>
<button class="btn btn-outline-secondary" menuId=${menu.id} onclick="deleteMenu(this)"
type="button">삭제
</button>
</div>
`
))
$('#menus').append(
`
<div id = "addmenu">
<button class="btn btn-outline-secondary" menuId=${menu.id} onclick="dropAddMenu()"
type="button">추가
</button>
</div>
`
)
}
function dropAddMenu() {
$('#addmenu').append(
`<div id = "dropaddmenu">
<div className="input-group">
<span className="input-group-text">메뉴 이름</span>
<input aria-label="메뉴 이름" placeholder="메뉴 이름" className="form-control" id="menuname"
type="text">
<span className="input-group-text">메뉴 가격</span>
<input aria-label="메뉴 가격" placeholder="메뉴 가격" className="form-control" id="menuprice" type="text">
</div>
<button class="btn btn-outline-secondary" onclick="addMenu()"
type="button">추가
</button>
</div>
`
)
}
이렇게 짜고 있었는데
삭제하는거 몰라서 찾아봄
div.remove();
아 근데 삭제 대신 숨겼다 다시 꺼내고 싶어짐
https://hianna.tistory.com/484
<div id="dropaddmenu" visibility="hidden">
<div className="input-group">
<span className="input-group-text">메뉴 이름</span>
<input aria-label="메뉴 이름" placeholder="메뉴 이름" className="form-control" id="menuname"
type="text">
<span className="input-group-text">메뉴 가격</span>
<input aria-label="메뉴 가격" placeholder="메뉴 가격" className="form-control" id="menuprice" type="text">
</div>
<button className="btn btn-outline-secondary" onClick="addMenu()"
type="button">추가
</button>
</div>
function dropAddMenu() {
if ($('#dropaddmenu').style.visibility === 'hidden') {
$('#dropaddmenu').style.visibility = 'visible'
} else {
$('#dropaddmenu').style.visibility = 'hidden'
}
}
그리고 메뉴 추가했을때 페이지 새로고침 하고싶음
메뉴를 추가해봄
public record MenuRequest(
@NotNull
Long postId,
@NotBlank
String name,
@NotNull
Integer price
) {
}
// 글에 본인이 주문할 Menu 추가하기
@PostMapping("/menus")
public ApiResponse<Void> createMenu(
@Valid @RequestBody MenuRequest menuReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
menuService.createMenu(menuReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.CREATED.value(), "메뉴를 추가했습니다.");
}
function addMenu() {
let menuname = $('#menuname').val();
let price = $('#menuprice').val();
let postId = [[${postId}]];
$.ajax({
type: 'POST',
url: "/api/v1/menus",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId,
menuname: menuname,
price: price
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
},
error: function (error, response) {
alert(response.message);
console.error('Error:', error);
}
});
}
메뉴 삭제함
public record MenuDeleteRequest(
@NotNull
Long menuId
){
}
// 글에 본인이 주문할 Menu 삭제하기
@DeleteMapping("/menus")
public ApiResponse<Void> deleteMenu(
@Valid @RequestBody MenuDeleteRequest menuDeleteReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
menuService.deleteMenu(menuDeleteReq, userDetails.getUser());
return new ApiResponse<>(HttpStatus.OK.value(), "메뉴를 삭제했습니다.");
}
<div>
<span>${menu.menuname}</span>
<span>${menu.price}</span>
<button class="btn btn-outline-secondary" menuId=${menu.id} onclick="deleteMenu(this)"
type="button">삭제
</button>
</div>
function deleteMenu(button) {
let menuId = $(button).attr("menuId");
$.ajax({
type: 'DELETE',
url: "/api/v1/menus",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
menuId: menuId
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
},
error: function (error, response) {
alert(response.message);
console.error('Error:', error);
}
});
}
function editmenus(button){
var postId = $(button).attr("post");
window.location.replace(host + `/menus/${postId}`);
}
Post 페이지에 이렇게 달아줌
432:183 Uncaught ReferenceError: host is not defined at editmenus (32:183:29) at HTMLInputElement.onclick (32:1:1)
테스트해봄
→
function editmenus(button){
var postId = $(button).attr("post");
const host = 'http://' + window.location.host;
window.location.replace(host + `/menu/${postId}`);
}
못생기게 뜨는데다가 뭔가 잘못됨
Bean Validation에서 걸러지면 저 오류 뜨던데
🚩문제 : Bean Validation에서 걸림
💡원인 : 그냥 name인데 menuname으로 읽고있었음
function addMenu() {
let name = $('#menuname').val();
let price = $('#menuprice').val();
let postId = [[${postId}]];
$.ajax({
type: 'POST',
url: "/api/v1/menus",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId,
name: name,
price: price
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
},
error: function (error, response) {
alert(response.message);
console.error('Error:', error);
}
});
}
⛳해결 : 그냥 name으로 추가해봄
잘 된다
메뉴 테이블에도 잘 들어가있음
🚩문제 : 메뉴가 안 뜸
get이 안된다고 함
function getData() {
$.ajax({
type: 'GET',
url: `/api/v1/menus`,
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: [[${postId}]]
}),
→
function getData() {
let postId = [[${postId}]]
$.ajax({
type: 'GET',
url: `/api/v1/menus`,
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId
}),
이렇게 분리시켜봄
안 됨
전체글 조회에서는 어떻게 했지?
그건 그냥 href
@GetMapping("/menu/{postId}")
public String menuPage(@PathVariable(name = "postId") Long postId) {
ModelAndView mav = new ModelAndView("postId");
mav.addObject("postId", postId);
return "domain/menu/menu";
}
}
→
@GetMapping("/menu/{postId}")
public String menuPage(
@PathVariable(name = "postId") Long postId,
Model model
) {
Map<String, Long> map = new HashMap<>();
map.put("postId", postId);
model.addAttribute("postId", postId);
model.mergeAttributes(map);
return "domain/menu/menu";
}
근데 여기서 안 받아와져서 그냥 요소에다 만들어서 붙이고 그거 읽어옴
function getData() {
let postId = ${postId}
또 쌍따옴표 이슈인가
let postId = "${postId}";
응 아니었음
걍 요소에 붙이고 그거가지고 할래
<div style="padding:10px;width:1000px; height:max-content">
<div id = "post" post = "${postId}" >id<span th:text="${postId}"></span></div>
function getData() {
let postId = $('#post').attr("post");
$.ajax({
type: 'GET',
url: `/api/v1/menus`,
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: postId
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
drawMenus(response.data);
},
error: function (error) {
console.error('Error:', error);
}
});
}
아니 주소가 왜 이렇게 됨?
🚩문제 : Get할때 JSON 형식으로 Object를 전송하면 url에 이상하게 들어감
Invalid character found in the request target [/api/v1/menus?{%22postId%22:%22${postId}%22} ]. The valid characters are defined in RFC 7230 and RFC 3986
function getData() {
//let postId = $('#post').attr("post");
$.ajax({
type: 'GET',
url: `/api/v1/menus`,
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: [[${postId}]]
}),
success: function (response) {
console.log('Success:', response);
alert(response.message);
drawMenus(response.data);
},
error: function (error) {
console.error('Error:', error);
}
});
}
다시 원래 방식대로 회귀함
let idForPost = [[${postId}]]
java.lang.IllegalArgumentException: Invalid character found in the request target [/api/v1/menus?{%22postId%22:32} ]. The valid characters are defined in RFC 7230 and RFC 3986
아 map이라 저런가 val로 읽어줘야되나
let idForPost = postId.val();
$.ajax({
type: 'GET',
url: `/api/v1/menus`,
dataType: "json",
contentType: 'application/json',
data: JSON.stringify({
postId: idForPost
}),
이렇게 한번 해봄
이제 ajax가 날아가지도 않는다 ㅋㅋㅋㅋ
JavaScript Syntax:
Instead of $('#dropaddmenu').style.visibility, use $('#dropaddmenu').css('visibility') to get and set the visibility.
The same applies to $('#dropaddmenu').style.visibility = 'hidden', replace it with $('#dropaddmenu').css('visibility', 'hidden').
Variable Type Handling:
In the getData function, it seems you're trying to get the value of [[${postId}]].val();. The correct syntax is let idForPost = [[${postId}]];.
@GetMapping("/menu/{postId}")
public String menuPage(
@PathVariable(name = "postId") Long postId,
Model model
) {
model.addAttribute("postId", postId);
return "domain/menu/menu";
}
이렇게 해봄
function getData() {
let idForPost = [[${postId}]];
$.ajax({
이렇게 보내면
/api/v1/menus?{%22postId%22:32}
이렇게 요청이 가는데
/api/v1/menus
와 함께 32 객체를 보내고 싶어
{postId:32} 이렇게
data: {
postId: idForPost
},
이렇게 한번 해봄
이렇게 날아감
⛳해결 : GET요청을 할 때 RequestBody 대신 RequestParam을 씀
GET요청을 할때 RequestBody가 안 먹힘
//자신의 메뉴 조회
@GetMapping("/menus")
public ApiResponse<List<MenuResponse>> getMenus(
@Valid @RequestBody MenuReadRequest menuReadReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
return new ApiResponse<>(HttpStatus.OK.value(), "나의 메뉴 조회",
menuService.getMenus(menuReadReq, userDetails.getUser()));
}
→
this code can’t read /api/v1/menus?{%22postId%22:32}
//자신의 메뉴 조회
@GetMapping("/menus")
public ApiResponse<List<MenuResponse>> getMenus(
@Valid @RequestBody MenuReadRequest menuReadReq,
@AuthenticationPrincipal UserDetailsImpl userDetails
) {
return new ApiResponse<>(HttpStatus.OK.value(), "나의 메뉴 조회",
menuService.getMenus(menuReadReq, userDetails.getUser()));
}
이제 메뉴 추가도 잘 되고
삭제도 잘 된다
💡메뉴 추가하는 부분 접었다 폈다 하는 기능 추가해봄
function dropAddMenu() {
var dropAddMenuElement = $('#dropaddmenu');
if (dropAddMenuElement.css('visibility') === 'hidden') {
dropAddMenuElement.css('visibility', 'visible');
} else {
dropAddMenuElement.css('visibility', 'hidden');
}
}
💡자동 새로고침 기능 추가해봄
이제 자동 새로고침만 해봄
function refresh(){
const host = 'http://' + window.location.host;
window.location.replace(host + `/menu/${postId}`);
}
이걸 넣어봄
그냥 새로고침해야 불러와진다 ㅋㅋ refresh는 안 움직임
refresh →
location.reload();
새로고침 될때마다 나의 메뉴 조회 뜨는거 짜증나서 케이스분류함
if(response.status !== 200){
alert(response.message);
}
잘 된다!
'개발일지' 카테고리의 다른 글
2024-01-19,Today I Learned (0) | 2024.01.20 |
---|---|
2024-01-17, Today I Learned (0) | 2024.01.17 |
2024-01-16, Today I Learned (0) | 2024.01.16 |
2024-01-15, Today I Learned (0) | 2024.01.15 |
2024-01-14, Today I Learned (0) | 2024.01.15 |