Light Blue Pointer
본문 바로가기
개발일지

2024-01-19,Today I Learned

by 개발바닥곰발바닥!!! 2024. 1. 20.

🚀리뷰 페이지 작성

pastOrderList.forEach(order => {
      let menuList = order.menus.map(menu => menu.menuname).join('<br>');
      $('#my-order-info').append(`
         <div class="past-order-pack">
          <div class="past-order">
            <div>가게 이름: ${order.store}</div>
            <div>수령인 이름: ${order.receiverName}</div>
            <div>메뉴
              <div>${menuList}</div>
            </div>
          </div>
            <button type="button" class="btn btn-secondary" id="review-submit" onclick="createReview()">
              리뷰 남기기
            </button>
          </div>
      `);
    });

 

리뷰에 orderId가 필요하니까 그거 달아줌

@Builder
public record OrderResponse (
    Long id,
    String store,
    String receiverName,
    List<MenuResponse> menus

){

}
<button type="button" class="btn btn-secondary" id="review-submit" order = "${order.id} onclick="createReview(this)">
function createReview(button){
    var orderId = $(button).attr("order");
    const host = 'http://' + window.location.host;
    window.location.replace(host + `/menu/${postId}`);
  }

orderId 넣어준다음에 클릭시에 ReviewFrontController 호출함

@Controller
@RequiredArgsConstructor
public class ReviewFrontController {

    @GetMapping("/createreview/{orderId}")
    public String createReviewPage(
        @PathVariable(name = "orderId") Long orderId,
        Model model
    ) {
        model.addAttribute("orderId", orderId);
        return "domain/review/createreview";
    }

}

 

createreview.html 만듦

https://getbootstrap.kr/docs/5.0/forms/checks-radios/

 

체크박스와 라디오버튼

완전히 새로워 진 체크 컴포넌트를 사용해 크로스 브라우저와 크로스 기기로 일관된 체크 박스와 라디오 버튼을 만들 수 있습니다.

getbootstrap.kr

<input type="checkbox" class="btn-check" id="btn-check-outlined" autocomplete="off">
<label class="btn btn-outline-primary" for="btn-check-outlined">Single toggle</label><br>

이거 써봄

 

ReviewEnum 생성함

@Getter
@RequiredArgsConstructor
public enum ReviewEnum {
    //positive
    GOODMANNER("친절하고 매너가 좋아요"),
    GOODTIME("시간 약속을 잘 지켜요"),
    GOODCOMM("소통과 응답이 빨라요"),
    //negative
    BADTIME("약속 시간에 나타나지 않았어요"),
    NOSHOW("아예 나타나지 않았어요"),
    NOMONEY("값을 지불하지 않았어요"),
    BADCOMM("소통과 응답이 느려요"),
    BADMANNER("불친절하고 매너가 좋지 않아요");

    private final String comment;
}
<div style="padding:10px;width:1000px; margin:auto; height:max-content">
    <div>
      <input type="checkbox" class="btn-check" id="goodmanner" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="goodmanner()" for="goodmanner">친절하고 매너가 좋아요</label><br>
      <input type="checkbox" class="btn-check" id="goodtime" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="goodtime()" for="goodtime">시간 약속을 잘 지켜요</label><br>
      <input type="checkbox" class="btn-check" id="goodcomm" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="goodcomm()" for="goodcomm">소통과 응답이 빨라요</label><br>
      <input type="checkbox" class="btn-check" id="badtime" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="badtime()" for="badtime">약속 시간에 나타나지 않았어요</label><br>
      <input type="checkbox" class="btn-check" id="noshow" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="noshow()" for="noshow">아예 나타나지 않았어요</label><br>
      <input type="checkbox" class="btn-check" id="nomoney" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="nomoney()" for="nomoney">값을 지불하지 않았어요</label><br>
      <input type="checkbox" class="btn-check" id="badcomm" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="badcomm()" for="badcomm">소통과 응답이 느려요</label><br>
      <input type="checkbox" class="btn-check" id="badmanner" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="badmanner()" for="badmanner">불친절하고 매너가 좋지 않아요</label><br>
      <button class="btn btn-outline-secondary" menuId=${menu.id} onclick="sendReview()"
              type="button">리뷰 전송
      </button>
    </div>
    <div id="dropaddmenu">
  </div>
</div>
function createReview(button){
    var orderId = $(button).attr("order");
    const host = 'http://' + window.location.host;
    window.location.replace(host + `/review/${orderId}`);
  }
<button id = "${post.id}" post = "${post.id}"  class="btn btn-outline-secondary" onclick="sendData(this)" type="button">조회</button>
              </div>
pastOrderList.forEach(order => {
      let menuList = order.menus.map(menu => menu.menuname).join('<br>');
      $('#my-order-info').append(`
         <div class="past-order-pack">
          <div class="past-order">
            <div>가게 이름: ${order.store}</div>
            <div>수령인 이름: ${order.receiverName}</div>
            <div>메뉴
              <div>${menuList}</div>
            </div>
          </div>
            <button type="button" class="btn btn-secondary" id="review-submit" order = "${order.id} onclick="createReview(this)">
              리뷰 남기기
            </button>
          </div>
      `);
    });

  })
}

function createReview(button){
  var orderId = $(button).attr("order");
  const host = 'http://' + window.location.host;
  window.location.replace(host + `/review/${orderId}`);
}

왜 버튼이 안 눌리지

function createReview(button){
  var orderId = $(button).attr("order");
  const host = 'http://' + window.location.host;
  window.location.replace(host + `/createreview/${orderId}`);
}
<button type="button" class="btn btn-secondary" id="review-submit" order = "${order.id} onclick="createReview(this)">

 

 

🚩문제 : createReview가 안 불리는듯? 인식이 안 됨

왜 no usage로 뜨지?

 

⛳ 문제 해결 : onclick 사이에 "를 추가해줌

<button type="button" class="btn btn-secondary" id="review-submit" order="${order.id}" onclick="createReview(this)">
  리뷰 남기기
</button>

오타 수정하니까 됐다!

페이지가 잘 뜬다

 

<div style="padding:10px;width:1000px; margin:auto; height:max-content">
    <div>
      <input type="checkbox" class="btn-check" id="goodmanner" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="goodmanner(this)" for="goodmanner">친절하고 매너가 좋아요</label><br>
      <input type="checkbox" class="btn-check" id="goodtime" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="goodtime(this)" for="goodtime">시간 약속을 잘 지켜요</label><br>
      <input type="checkbox" class="btn-check" id="goodcomm" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="goodcomm(this)" for="goodcomm">소통과 응답이 빨라요</label><br>
      <input type="checkbox" class="btn-check" id="badtime" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="badtime(this)" for="badtime">약속 시간에 나타나지 않았어요</label><br>
      <input type="checkbox" class="btn-check" id="noshow" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="noshow(this)" for="noshow">아예 나타나지 않았어요</label><br>
      <input type="checkbox" class="btn-check" id="nomoney" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="nomoney(this)" for="nomoney">값을 지불하지 않았어요</label><br>
      <input type="checkbox" class="btn-check" id="badcomm" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="badcomm(this)" for="badcomm">소통과 응답이 느려요</label><br>
      <input type="checkbox" class="btn-check" id="badmanner" autocomplete="off">
      <label class="btn btn-outline-primary" onclick="badmanner(this)" for="badmanner">불친절하고 매너가 좋지 않아요</label><br>
      <button class="btn btn-outline-secondary" menuId=${menu.id} onclick="sendReview()"
              type="button">리뷰 전송
      </button>
    </div>
    <div id="dropaddmenu">
  </div>
</div>

이렇게 하고

var goodmanner;
  var goodtime;
  var goodcomm;
  var badtime;
  var noshow;
  var nomoney;
  var badcomm;
  var badmanner;

  function goodmanner(label){
    var checkbox = $('#' + $(label).attr('for'));

    if (checkbox.prop('checked')) {
      goodmanner = true;
    } else {
      goodmanner = false;
    }
  }
  function goodtime(label){
    var checkbox = $('#' + $(label).attr('for'));

    if (checkbox.prop('checked')) {
      goodtime = true;
    } else {
      goodtime = false;
    }
  }
  function goodcomm(label){
    var checkbox = $('#' + $(label).attr('for'));

    if (checkbox.prop('checked')) {
      goodcomm = true;
    } else {
      goodcomm = false;
    }
  }
  function badtime(label){
    var checkbox = $('#' + $(label).attr('for'));

    if (checkbox.prop('checked')) {
      badtime = true;
    } else {
      badtime = false;
    }
  }
  function noshow(label){
    var checkbox = $('#' + $(label).attr('for'));

    if (checkbox.prop('checked')) {
      noshow = true;
    } else {
      noshow = false;
    }
  }
  function nomoney(label){
    var checkbox = $('#' + $(label).attr('for'));

    if (checkbox.prop('checked')) {
      nomoney = true;
    } else {
      nomoney = false;
    }
  }
  function badcomm(label){
    var checkbox = $('#' + $(label).attr('for'));

    if (checkbox.prop('checked')) {
      badcomm = true;
    } else {
      badcomm = false;
    }
  }
  function badmanner(label) {
    var checkbox = $('#' + $(label).attr('for'));

    if (checkbox.prop('checked')) {
      badmanner = true;
    } else {
      badmanner = false;
    }
  }

함수 달아봄

 

이제 리뷰를 보내봄

// 리뷰 작성
    @PostMapping("")
    public ApiResponse<Void> review(
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @RequestBody ReviewRequest reviewReq
    ) {
        reviewService.review(reviewReq, userDetails.getUser());
        return new ApiResponse<>(HttpStatus.OK.value(), "리뷰를 성공적으로 전송했습니다.");
    }

여기로 보내면 됨

public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    boolean goodmanner,
    boolean goodtime,
    boolean goodcomm,
    boolean badtime,
    boolean noshow,
    boolean nomoney,
    boolean badcomm,
    boolean badmanner
) {

}
var checkbox = $('#' + $(label).attr('for'));
->
var checkbox = $(label).attr('for');

 

var goodmanner;
  var goodtime;
  var goodcomm;
  var badtime;
  var noshow;
  var nomoney;
  var badcomm;
  var badmanner;

  function goodmanner(label) {
    var checkbox = $(label).attr('for');

    if (checkbox.prop('checked')) {
      goodmanner = true;
    } else {
      goodmanner = false;
    }
  }

  function goodtime(label) {
    var checkbox = $(label).attr('for');

    if (checkbox.prop('checked')) {
      goodtime = true;
    } else {
      goodtime = false;
    }
  }

  function goodcomm(label) {
    var checkbox = $(label).attr('for');

    if (checkbox.prop('checked')) {
      goodcomm = true;
    } else {
      goodcomm = false;
    }
  }

  function badtime(label) {
    var checkbox = $(label).attr('for');

    if (checkbox.prop('checked')) {
      badtime = true;
    } else {
      badtime = false;
    }
  }

  function noshow(label) {
    var checkbox = $(label).attr('for');

    if (checkbox.prop('checked')) {
      noshow = true;
    } else {
      noshow = false;
    }
  }

  function nomoney(label) {
    var checkbox = $(label).attr('for');

    if (checkbox.prop('checked')) {
      nomoney = true;
    } else {
      nomoney = false;
    }
  }

  function badcomm(label) {
    var checkbox = $(label).attr('for');

    if (checkbox.prop('checked')) {
      badcomm = true;
    } else {
      badcomm = false;
    }
  }

  function badmanner(label) {
    var checkbox = $(label).attr('for');

    if (checkbox.prop('checked')) {
      badmanner = true;
    } else {
      badmanner = false;
    }
  }

저 var들을 sendReview/sendData에서 인식을 못해서 안쪽으로 옮김

function sendReview() {

    let score = $('#customRange').val();

    var goodmanner;
    var goodmannerbox = $(goodmanner).attr('for');
    if (goodmannerbox.prop('checked')) {
      goodmanner = true;
    }

    sendData(score,goodmanner,goodtime,goodcomm,badtime,noshow,nomoney,badcomm,badmanner);
  }

  function sendData(score,goodmanner,goodtime,goodcomm,badtime,noshow,nomoney,badcomm,badmanner){
    let idForOrder = [[${orderId}]];

    $.ajax({
      type: 'POST',
      url: `/api/v1/reviews`,
      dataType: "json",
      contentType: 'application/json',
      data: JSON.stringify({
        orderId: idForOrder,
        score: score,
        goodmanner: goodmanner,
        goodtime: goodtime,
        goodcomm: goodcomm,
        badtime: badtime,
        noshow: noshow,
        nomoney: nomoney,
        badcomm: badcomm,
        badmanner: badmanner
      }),
      success: function (response) {
        console.log('Success:', response);
        alert(response.message);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

 

🚩 문제 : 체크를 

2:106 Uncaught TypeError: checkbox.prop is not a function at badtime (2:106:18) at HTMLLabelElement.onclick (2:41:82) badtime @ 2:106 onclick @ 2:41 2:159 Uncaught TypeError: Cannot read properties of undefined (reading 'prop') at sendReview (2:159:23) at HTMLButtonElement.onclick (2:55:27)

let score = $('#customRange').val();
    
    var goodmannerbox = $('#goodmanner');
    var goodmanner = goodmannerbox.checked;

이렇게 해봄

 

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type boolean from Object value (token JsonToken.START_OBJECT)]

public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    boolean goodmanner,
    boolean goodtime,
    boolean goodcomm,
    boolean badtime,
    boolean noshow,
    boolean nomoney,
    boolean badcomm,
    boolean badmanner
) {

}

Boolean으로 바꿔봄

 

2024-01-19T15:40:21.105+09:00 WARN 13976 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.lang.Boolean from Object value (token JsonToken.START_OBJECT)]

또 똑같은거 뜸

2024-01-19T15:41:10.396+09:00 WARN 13976 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.lang.Boolean from Object value (token JsonToken.START_OBJECT)]

 

var goodmanner;
    var goodmannerbox = $('#goodmanner');
    if(goodmannerbox.checked){
      goodmanner = true;
    }

이렇게 바꿔봄

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.lang.Boolean from Object value (token JsonToken.START_OBJECT)]

 

function sendReview() {

    let score = $('#customRange').val();

    var goodmanner;
    var goodmannerbox = $('#goodmanner');
    if(goodmannerbox.checked){
      goodmanner = "true";
    }

이렇게 바꿔봄

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type java.lang.Boolean from Object value (token JsonToken.START_OBJECT)]

 

 

public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    boolean goodmanner,
    boolean goodtime,
    boolean goodcomm,
    boolean badtime,
    boolean noshow,
    boolean nomoney,
    boolean badcomm,
    boolean badmanner
) {

}

다시바꿔봄

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type boolean from Object value (token JsonToken.START_OBJECT)]

 

if(goodmannerbox.checked){
      goodmanner = true;
    }else{
      goodmanner = false;
    }

이렇게 해봄

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type boolean from Object value (token JsonToken.START_OBJECT)]

상관없었음

 

와 왜 안될까 하고 코드보면서 멍때리는데 깨달음이 찾아옴

package com.moayo.moayoeats.backend.domain.review.dto.request;

import com.moayo.moayoeats.backend.domain.score.entity.ScoreEnum;

public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    boolean goodmanner,
    boolean goodtime,
    boolean goodcomm,
    boolean badtime,
    boolean noshow,
    boolean nomoney,
    boolean badcomm,
    boolean badmanner
) {

}

문제는 다른데 있었다!!!

js파일 백날 들여다봐도 안됨

왜냐면 문제는 Spring측에 있으니까

Getter도 Setter도 Constructor도 안달려있는데 어떻게 변환시키냐고요 ㅋㅋㅋ

 

package com.moayo.moayoeats.backend.domain.review.dto.request;

import com.moayo.moayoeats.backend.domain.score.entity.ScoreEnum;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    boolean goodmanner,
    boolean goodtime,
    boolean goodcomm,
    boolean badtime,
    boolean noshow,
    boolean nomoney,
    boolean badcomm,
    boolean badmanner
) {

}

두개 달아줬다

아니 에러남

레코드는 애초에 포함이야

 

You expect a boolean from your @RequestBody Boolean vote however JSON sends text. You can either use the Payload class as suggested already but you can also simply change your controller to expect a String like this @RequestBody String vote and convert that string into boolean using Boolean.valueOf(vote) to be able to use it where you need it.

라고 하길래 귀찮아서 int로 바꿔주고 0이랑 1넣음

 

public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    Integer goodmanner,
    Integer goodtime,
    Integer goodcomm,
    Integer badtime,
    Integer noshow,
    Integer nomoney,
    Integer badcomm,
    Integer badmanner
) {

}
var goodmanner;
    var goodmannerbox = $('#goodmanner');
    if(goodmannerbox.checked){
      goodmanner = 1;
    }else{
      goodmanner = 0;
    }

 

아 근데 내가 귀찮아서 goodmanner까지만 해놔서 그랬던거면 어떡하지 ㅋㅋ

sendData(score,goodmanner,goodtime,goodcomm,badtime,noshow,nomoney,badcomm,badmanner);

와 노가다했더니 이제 됨

function sendReview() {

    let score = $('#customRange').val();

    var goodmanner;
    var goodmannerbox = $('#goodmanner');
    if(goodmannerbox.checked){
      goodmanner = 1;
    }else{
      goodmanner = 0;
    }
    var goodtime;
    var goodtimebox = $('#goodtime');
    if(goodtimebox.checked){
      goodtime = 1;
    }else{
      goodtime = 0;
    }
    var goodcomm;
    var goodcommbox = $('#goodcomm');
    if(goodcommbox.checked){
      goodcomm = 1;
    }else{
      goodcomm = 0;
    }
    var badtime;
    var badtimebox = $('#goodcomm');
    if(badtimebox.checked){
      badtime = 1;
    }else{
      badtime = 0;
    }
    var noshow;
    var noshowbox = $('#goodcomm');
    if(noshowbox.checked){
      noshow = 1;
    }else{
      noshow = 0;
    }
    var nomoney;
    var nomoneybox = $('#goodcomm');
    if(nomoneybox.checked){
      nomoney = 1;
    }else{
      nomoney = 0;
    }
    var badcomm;
    var badcommbox = $('#goodcomm');
    if(badcommbox.checked){
      badcomm = 1;
    }else{
      badcomm = 0;
    }
    var badmanner;
    var badmannerbox = $('#goodcomm');
    if(badmannerbox.checked){
      badmanner = 1;
    }else{
      badmanner = 0;
    }

    sendData(score,goodmanner,goodtime,goodcomm,badtime,noshow,nomoney,badcomm,badmanner);
  }

  function sendData(score,goodmanner,goodtime,goodcomm,badtime,noshow,nomoney,badcomm,badmanner){
    let idForOrder = [[${orderId}]];

    $.ajax({
      type: 'POST',
      url: `/api/v1/reviews`,
      dataType: "json",
      contentType: 'application/json',
      data: JSON.stringify({
        orderId: idForOrder,
        score: score,
        goodmanner: goodmanner,
        goodtime: goodtime,
        goodcomm: goodcomm,
        badtime: badtime,
        noshow: noshow,
        nomoney: nomoney,
        badcomm: badcomm,
        badmanner: badmanner
      }),
      success: function (response) {
        console.log('Success:', response);
        alert(response.message);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

 

 

근데 내가 바보짓했다는 생각을 지울수가 없음

값을 안 보내놓고 그냥 goodtime:goodtime으로 지정하고 있어서 그랬던거같은데…

다시 되돌리고 해봄

public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    Integer goodmanner,
    Integer goodtime,
    Integer goodcomm,
    Integer badtime,
    Integer noshow,
    Integer nomoney,
    Integer badcomm,
    Integer badmanner
) {

}

package com.moayo.moayoeats.backend.domain.review.dto.request;

import com.moayo.moayoeats.backend.domain.score.entity.ScoreEnum;

public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    boolean goodmanner,
    boolean goodtime,
    boolean goodcomm,
    boolean badtime,
    boolean noshow,
    boolean nomoney,
    boolean badcomm,
    boolean badmanner
) {

}

 

 

private void updateReview(ReviewRequest reviewReq, User receiver) {

        List<Review> reviews = reviewRepository.findAllByUser(receiver);
        List<Review> updated = new ArrayList<>();

        if (reviewReq.goodmanner()==1) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODMANNER, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.goodcomm()==1) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODCOMM, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.goodtime()==1) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODTIME, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badtime()==1) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADTIME, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.noshow()==1) {
            Review review = findReviewByContent(reviews, ReviewEnum.NOSHOW, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.nomoney()==1) {
            Review review = findReviewByContent(reviews, ReviewEnum.NOMONEY, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badcomm()==1) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADCOMM, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badmanner()==1) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADMANNER, receiver);
            review.increaseCount();
            updated.add(review);
        }
        reviewRepository.saveAll(updated);
    }

private void updateReview(ReviewRequest reviewReq, User receiver) {

        List<Review> reviews = reviewRepository.findAllByUser(receiver);
        List<Review> updated = new ArrayList<>();

        if (reviewReq.goodmanner()) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODMANNER, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.goodcomm()) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODCOMM, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.goodtime()) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODTIME, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badtime()) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADTIME, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.noshow()) {
            Review review = findReviewByContent(reviews, ReviewEnum.NOSHOW, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.nomoney()) {
            Review review = findReviewByContent(reviews, ReviewEnum.NOMONEY, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badcomm()) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADCOMM, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badmanner()) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADMANNER, receiver);
            review.increaseCount();
            updated.add(review);
        }
        reviewRepository.saveAll(updated);
    }

새로운 문제 발생

아 저 함수들 다 지우고 onclick에서는 안 지워서 저러는거임

 

전송은 되는데 뭐가된거지

안 들어온 거 같은데

14번 Order에 대해서 리뷰를 써봄

Order는 삭제되는데

Review는 안 생김

@Override
    public void review(ReviewRequest reviewReq, User user) {
        Order order = findOrderById(reviewReq.orderId());
        //check if the receiver exists, to clarify that the review hasn't been made, not because the user doesn't exist
        if (!order.getUser().getId().equals(user.getId())) {
            throw new GlobalException(OrderErrorCode.FORBIDDEN_ACCESS);
        }
        User receiver = order.getReceiver();
        checkIfUserExists(receiver.getId());
        updateScore(reviewReq.score(), receiver);
        updateReview(reviewReq, receiver);
        orderRepository.delete(order);
    }
private void updateReview(ReviewRequest reviewReq, User receiver) {

        List<Review> reviews = reviewRepository.findAllByUser(receiver);
        List<Review> updated = new ArrayList<>();

        if (reviewReq.goodmanner()) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODMANNER, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.goodcomm()) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODCOMM, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.goodtime()) {
            Review review = findReviewByContent(reviews, ReviewEnum.GOODTIME, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badtime()) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADTIME, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.noshow()) {
            Review review = findReviewByContent(reviews, ReviewEnum.NOSHOW, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.nomoney()) {
            Review review = findReviewByContent(reviews, ReviewEnum.NOMONEY, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badcomm()) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADCOMM, receiver);
            review.increaseCount();
            updated.add(review);
        }
        if (reviewReq.badmanner()) {
            Review review = findReviewByContent(reviews, ReviewEnum.BADMANNER, receiver);
            review.increaseCount();
            updated.add(review);
        }
        reviewRepository.saveAll(updated);
    }

 

 

Score도 들어가는지 모르겠음

private Review findReviewByContent(List<Review> reviews, ReviewEnum content, User user) {
        //get Review when exists, make a new one when not
        for (Review review : reviews) {
            if (review.getContent().equals(content)) {
                reviews.remove(review);
                return review;
            }
        }
        return new Review(user, content);
    }

없으면 만들어야 되는데

저게 다 동작이 안 하는건

if (reviewReq.goodmanner()) {

이거부터 동작을 안 했기 때문인거 같음

 

포스트맨으로 테스트해봄

16번으로 테스트해봄

{
    "orderId" : 16,
    "score" : "FIVE",
    "goodmanner" : true,
    "goodtime" : true
}
{
    "status": 200,
    "message": "리뷰를 성공적으로 전송했습니다.",
    "data": null
}

일단 Order는 성공적으로 사라지고

Review도 생김ㅜㅜ

 

boolean대신 그냥 int를 보내봄

package com.moayo.moayoeats.backend.domain.review.dto.request;

import com.moayo.moayoeats.backend.domain.score.entity.ScoreEnum;

public record ReviewRequest(
    Long orderId,
    ScoreEnum score,
    Integer goodmanner,
    Integer goodtime,
    Integer goodcomm,
    Integer badtime,
    Integer noshow,
    Integer nomoney,
    Integer badcomm,
    Integer badmanner
) {

}
function sendReview() {

    let score = $('#customRange').val();
    let scoreEnum;
    if(score === 1){
      scoreEnum = "ONE"
    }else if(score === 2){
      scoreEnum = "TWO"
    }else if(score === 3){
      scoreEnum = "THREE"
    }else if(score === 4){
      scoreEnum = "FOUR"
    }else if(score === 5){
      scoreEnum = "FIVE"
    }

    var goodmanner;
    var goodmannerbox = $('#goodmanner');
    if(goodmannerbox.checked){
      goodmanner = 1;
    }else{
      goodmanner = 0;
    }
    var goodtime;
    var goodtimebox = $('#goodtime');
    if(goodtimebox.checked){
      goodtime = 1;
    }else{
      goodtime = 0;
    }
    var goodcomm;
    var goodcommbox = $('#goodcomm');
    if(goodcommbox.checked){
      goodcomm = 1;
    }else{
      goodcomm = 0;
    }
    var badtime;
    var badtimebox = $('#goodcomm');
    if(badtimebox.checked){
      badtime = 1;
    }else{
      badtime = 0;
    }
    var noshow;
    var noshowbox = $('#goodcomm');
    if(noshowbox.checked){
      noshow = 1;
    }else{
      noshow = 0;
    }
    var nomoney;
    var nomoneybox = $('#goodcomm');
    if(nomoneybox.checked){
      nomoney = 1;
    }else{
      nomoney = 0;
    }
    var badcomm;
    var badcommbox = $('#goodcomm');
    if(badcommbox.checked){
      badcomm = 1;
    }else{
      badcomm = 0;
    }
    var badmanner;
    var badmannerbox = $('#goodcomm');
    if(badmannerbox.checked){
      badmanner = 1;
    }else{
      badmanner = 0;
    }

    sendData(scoreEnum,goodmanner,goodtime,goodcomm,badtime,noshow,nomoney,badcomm,badmanner);
  }

  function sendData(score,goodmanner,goodtime,goodcomm,badtime,noshow,nomoney,badcomm,badmanner){
    let idForOrder = [[${orderId}]];

    $.ajax({
      type: 'POST',
      url: `/api/v1/reviews`,
      dataType: "json",
      contentType: 'application/json',
      data: JSON.stringify({
        orderId: idForOrder,
        score: score,
        goodmanner: goodmanner,
        goodtime: goodtime,
        goodcomm: goodcomm,
        badtime: badtime,
        noshow: noshow,
        nomoney: nomoney,
        badcomm: badcomm,
        badmanner: badmanner
      }),
      success: function (response) {
        console.log('Success:', response);
        alert(response.message);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

 

다시 해봄

2024-01-19T16:26:57.703+09:00 ERROR 32796 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.NullPointerException: Cannot invoke "com.moayo.moayoeats.backend.domain.score.entity.ScoreEnum.getScore()" because "score" is null] with root cause

java.lang.NullPointerException: Cannot invoke "com.moayo.moayoeats.backend.domain.score.entity.ScoreEnum.getScore()" because "score" is null
at com.moayo.moayoeats.backend.domain.score.entity.Score.update(Score.java:44) ~[main/:na]

 

 

private void updateScore(ScoreEnum scoreEnum, User user) {
        Score score = findScoreByUser(user);
        score.update(scoreEnum);//->이게 에러가 남
        scoreRepository.save(score);
    }
private Score findScoreByUser(User user) {
        return scoreRepository.findByUser(user).orElse(new Score(user));
    }
public void update(ScoreEnum score){
        this.total += score.getScore();
        this.count++;
    }

ScoreEnum이 왜 null인데요

아 0이라 안 넣어줬나봄

 

let score = $('#customRange').val();
    let scoreEnum;
    if(score === 1){
      scoreEnum = "ONE"
    }else if(score === 2){
      scoreEnum = "TWO"
    }else if(score === 3){
      scoreEnum = "THREE"
    }else if(score === 4){
      scoreEnum = "FOUR"
    }else if(score === 5){
      scoreEnum = "FIVE"
    }
<label for="customRange" class="form-label">점수</label>
    <input type="range" class="form-range" min="0" max="5" id="customRange">

min 0 → min 1

다시 해봄

java.lang.NullPointerException: Cannot invoke "com.moayo.moayoeats.backend.domain.score.entity.ScoreEnum.getScore()" because "score" is null at com.moayo.moayoeats.backend.domain.score.entity.Score.update(Score.java:44) ~[main/:na]

또 이러네

let score = $('#customRange').val();
    let scoreEnum;
    if(score === 1){
      scoreEnum = "ONE"
    }else if(score === 2){
      scoreEnum = "TWO"
    }else if(score === 3){
      scoreEnum = "THREE"
    }else if(score === 4){
      scoreEnum = "FOUR"
    }else if(score === 5){
      scoreEnum = "FIVE"
    }

이게 안 되는 거 같음

 

// Convert the string to a number
score = parseInt(score, 10);

이렇게 해주던가

아니면 그냥 ==으로 비교해야한다고 함

 

let score = $('#customRange').val();
    let scoreEnum;
    if(score == 1){
      scoreEnum = "ONE"
    }else if(score == 2){
      scoreEnum = "TWO"
    }else if(score == 3){
      scoreEnum = "THREE"
    }else if(score == 4){
      scoreEnum = "FOUR"
    }else if(score == 5){
      scoreEnum = "FIVE"
    }

이렇게 해봄

아니 리뷰가 안 생겨요…..

이게 Spring측에서 타입변환 오류가 생기진 않으니까 프론트 문제라고 예측해봄

var goodmanner;
    var goodmannerbox = $('#goodmanner');
    if(goodmannerbox.is(':checked')){
      goodmanner = 1;
    }else{
      goodmanner = 0;
    }
    var goodtime;
    var goodtimebox = $('#goodtime');
    if(goodtimebox.is(':checked')){
      goodtime = 1;
    }else{
      goodtime = 0;
    }
    var goodcomm;
    var goodcommbox = $('#goodcomm');
    if(goodcommbox.is(':checked')){
      goodcomm = 1;
    }else{
      goodcomm = 0;
    }
    var badtime;
    var badtimebox = $('#goodcomm');
    if(badtimebox.is(':checked')){
      badtime = 1;
    }else{
      badtime = 0;
    }
    var noshow;
    var noshowbox = $('#goodcomm');
    if(noshowbox.is(':checked')){
      noshow = 1;
    }else{
      noshow = 0;
    }
    var nomoney;
    var nomoneybox = $('#goodcomm');
    if(nomoneybox.is(':checked')){
      nomoney = 1;
    }else{
      nomoney = 0;
    }
    var badcomm;
    var badcommbox = $('#goodcomm');
    if(badcommbox.is(':checked')){
      badcomm = 1;
    }else{
      badcomm = 0;
    }
    var badmanner;
    var badmannerbox = $('#goodcomm');
    if(badmannerbox.is(':checked')){
      badmanner = 1;
    }else{
      badmanner = 0;
    }

이렇게 해봄

 

User 2 로 로그인해서 해봄

 

🚩문제 : 리뷰를 작성해도 db에 저장되지 않음

Order 5번에 대해서

리뷰를 날려봐도 db에 저장되지 않음

 

const is_checked = checkbox.checked;

.checked를 써봄

 

var goodmanner;
    var goodmannerbox = $('#goodmanner');
    if(goodmannerbox.checked){
      goodmanner = 1;
    }else{
      goodmanner = 0;
    }
    var goodtime;
    var goodtimebox = $('#goodtime');
    if(goodtimebox.checked){
      goodtime = 1;
    }else{
      goodtime = 0;
    }
    var goodcomm;
    var goodcommbox = $('#goodcomm');
    if(goodcommbox.checked){
      goodcomm = 1;
    }else{
      goodcomm = 0;
    }
    var badtime;
    var badtimebox = $('#goodcomm');
    if(badtimebox.checked){
      badtime = 1;
    }else{
      badtime = 0;
    }
    var noshow;
    var noshowbox = $('#goodcomm');
    if(noshowbox.checked){
      noshow = 1;
    }else{
      noshow = 0;
    }
    var nomoney;
    var nomoneybox = $('#goodcomm');
    if(nomoneybox.checked){
      nomoney = 1;
    }else{
      nomoney = 0;
    }
    var badcomm;
    var badcommbox = $('#goodcomm');
    if(badcommbox.checked){
      badcomm = 1;
    }else{
      badcomm = 0;
    }
    var badmanner;
    var badmannerbox = $('#goodcomm');
    if(badmannerbox.is(':checked')){
      badmanner = 1;
    }else{
      badmanner = 0;
    }

아니 지금보니 다 goodcomm으로 된것도 있어서 수정함

 

리뷰를 보내보았다

Score는 이제 잘 들어감

Review는 들어가지지 않는다

NOTIME count가 생성되지 않음

function sendReview() {

    let score = $('#customRange').val();
    let scoreEnum;
    if(score == 1){
      scoreEnum = "ONE"
    }else if(score == 2){
      scoreEnum = "TWO"
    }else if(score == 3){
      scoreEnum = "THREE"
    }else if(score == 4){
      scoreEnum = "FOUR"
    }else if(score == 5){
      scoreEnum = "FIVE"
    }

    var goodmanner;
    var goodmannerbox = $('#goodmanner');
    if(goodmannerbox.prop('checked')){
      goodmanner = 1;
    }else{
      goodmanner = 0;
    }
    var goodtime;
    var goodtimebox = $('#goodtime');
    if(goodtimebox.prop('checked')){
      goodtime = 1;
    }else{
      goodtime = 0;
    }
    var goodcomm;
    var goodcommbox = $('#goodcomm');
    if(goodcommbox.prop('checked')){
      goodcomm = 1;
    }else{
      goodcomm = 0;
    }
    var badtime;
    var badtimebox = $('#goodcomm');
    if(badtimebox.prop('checked')){
      badtime = 1;
    }else{
      badtime = 0;
    }
    var noshow;
    var noshowbox = $('#goodcomm');
    if(noshowbox.prop('checked')){
      noshow = 1;
    }else{
      noshow = 0;
    }
    var nomoney;
    var nomoneybox = $('#goodcomm');
    if(nomoneybox.prop('checked')){
      nomoney = 1;
    }else{
      nomoney = 0;
    }
    var badcomm;
    var badcommbox = $('#goodcomm');
    if(badcommbox.prop('checked')){
      badcomm = 1;
    }else{
      badcomm = 0;
    }
    var badmanner;
    var badmannerbox = $('#goodcomm');
    if(badmannerbox.prop('checked')){
      badmanner = 1;
    }else{
      badmanner = 0;
    }

    sendData(scoreEnum,goodmanner,goodtime,goodcomm,badtime,noshow,nomoney,badcomm,badmanner);
  }

이렇게 하고

const goodmannerbox = document.getElementById('goodmanner');
var goodmanner = goodmannerbox.checked ? 1 : 0;

const goodtimebox = document.getElementById('goodtime');
var goodtime = goodtimebox.checked ? 1 : 0;

const goodcommbox = document.getElementById('goodcomm');
var goodcomm = goodcommbox.checked ? 1 : 0;

const badtimebox = document.getElementById('badtime');
var badtime = badtimebox.checked ? 1 : 0;

const noshowbox = document.getElementById('noshow');
var noshow = noshowbox.checked ? 1 : 0;

const nomoneybox = document.getElementById('nomoney');
var nomoney = nomoneybox.checked ? 1 : 0;

const badcommbox = document.getElementById('badcomm');
var badcomm = badcommbox.checked ? 1 : 0;

const badmannerbox = document.getElementById('badmanner');
var badmanner = badmannerbox.checked ? 1 : 0;

이렇게 바꿔봄

 

const goodmannerbox = document.getElementById('goodmanner');
var goodmanner = goodmannerbox.checked ? 1 : 0;

const goodtimebox = document.getElementById('goodtime');
var goodtime = goodtimebox.checked ? 1 : 0;

const goodcommbox = document.getElementById('goodcomm');
var goodcomm = goodcommbox.checked ? 1 : 0;

const badtimebox = document.getElementById('badtime');
var badtime = badtimebox.checked ? 1 : 0;

const noshowbox = document.getElementById('noshow');
var noshow = noshowbox.checked ? 1 : 0;

const nomoneybox = document.getElementById('nomoney');
var nomoney = nomoneybox.checked ? 1 : 0;

const badcommbox = document.getElementById('badcomm');
var badcomm = badcommbox.checked ? 1 : 0;

const badmannerbox = document.getElementById('badmanner');
var badmanner = badmannerbox.checked ? 1 : 0;

이렇게 바꿔봄

다시 해봄

잘 들어왔다

 

 

전체글 페이지 만들어봄

// 모든 글 조회하기
    @GetMapping("/posts")
    public ApiResponse<List<BriefPostResponse>> getPosts(
        @AuthenticationPrincipal UserDetailsImpl userDetails) {
        return new ApiResponse<>(HttpStatus.OK.value(), "모든 글 조회에 성공했습니다.",
            postService.getPosts(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()));
    }
public record PostCategoryRequest(@NotNull @Category String category) {

}
function getDataByCategory(categoryEnum){
    let category = categoryEnum;
    
    $.ajax({
      type: 'GET',
      url: `/api/v1/posts/category`,
      dataType: "json",
      contentType: 'application/json',
      data: JSON.stringify({
        category: category
      }),
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

이렇게 해봄

저거 누르면 새로 결과 받아와서 화면에 출력할건데 그럼 기존 결과는 삭제해야하지 않나 싶어서 remove함수 알아봄

https://developer.mozilla.org/en-US/docs/Web/API/Element/remove

근데 이거 말고 child들을 다 remove하고 싶음

https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild

<div id="parent">
  <div id="child"></div>
</div>
const parent = document.getElementById("parent");
const child = document.getElementById("child");
const throwawayNode = parent.removeChild(child);

근데 나는 child가 여러갠데?

To remove all children from an element:

const element = document.getElementById("idOfParent");
while (element.firstChild) {
  element.removeChild(element.firstChild);
}

이렇게 해 봄

function removeAllPosts(){
    const element = document.getElementById("posts");
    while (element.firstChild) {
      element.removeChild(element.firstChild);
    }
  }
function all(){
    removeAllPosts();
    getData();
  }

전체를 고르면 다 지우고 새로 출력하게 해봄

function burger(){
    removeAllPosts();
    getDataByCategory("BURGER");
  }

이렇게 해봄

나머지도 똑같이 함

//글 검색하기
    @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()));
    }
public record PostSearchRequest(
    @NotNull(message = "검색어를 입력하세요.")
    String keyword
) {

}

저거 누르면 새로 결과 받아와서 화면에 출력할건데 그럼 기존 결과는 삭제해야하지 않나 싶어서 remove함수 알아봄

검색 입력 input과 버튼이 달린 부트스트랩 찾아다가 만듦

<div class="input-group mb-3">
      <input aria-describedby="button-addon2" aria-label="keyword" class="form-control" id="keyword" placeholder="검색어"
             type="text">
      <button class="btn btn-outline-secondary" onclick="search()" id="search" type="button">검색</button>
    </div>
function search(){
    var keyword = $('#keyword').val();

    removeAllPosts();
    getDataByKeyword(keyword);
  }

  function getDataByKeyword(keyword){
    var keyword = keyword;

    $.ajax({
      type: 'GET',
      url: `/api/v1/posts/search`,
      dataType: "json",
      contentType: 'application/json',
      data: JSON.stringify({
        keyword: keyword
      }),
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

일단 해봤음

성공했는데 저장된 글 데이터가 하나도 없어서 화면에 출력은 안 됨

 

🚩 문제 : ajax GET을 할때 RequestBody로 Object를 보낼 수 없음

검색을 시도해봤더니

이게 또 뜸

java.lang.IllegalArgumentException: Invalid character found in the request target [/api/v1/posts/category?{%22category%22:%22BURGER%22} ]. The valid characters are defined in RFC 7230 and RFC 3986 주소 안에 저 %22가 대체 뭐란말임

data: {
        keyword: keyword
      },

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.moayo.moayoeats.backend.global.dto.ApiResponse<java.util.List<com.moayo.moayoeats.backend.domain.post.dto.response.BriefPostResponse>> com.moayo.moayoeats.backend.domain.post.controller.PostController.searchPost(com.moayo.moayoeats.backend.global.security.UserDetailsImpl,com.moayo.moayoeats.backend.domain.post.dto.request.PostSearchRequest)]

글 하나 만들어봤더니 그건 잘 뜸

카테고리 한식 눌렀더니 이거 뜸

java.lang.IllegalArgumentException: Invalid character found in the request target [/api/v1/posts/category?{%22category%22:%22KOREAN%22} ]. The valid characters are defined in RFC 7230 and RFC 3986

 

검색버튼 눌러봤더니 그건 이거 뜸

2024-01-19T20:43:50.924+09:00 WARN 29456 --- [nio-8080-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.moayo.moayoeats.backend.global.dto.ApiResponse<java.util.List<com.moayo.moayoeats.backend.domain.post.dto.response.BriefPostResponse>> com.moayo.moayoeats.backend.domain.post.controller.PostController.searchPost(com.moayo.moayoeats.backend.global.security.UserDetailsImpl,com.moayo.moayoeats.backend.domain.post.dto.request.PostSearchRequest)]

 

 

스택오버플로우의 어떤 사람이

Did you mean: URL2 = JSON.stringify(URL), and then URL2 = encodeURI(JSON.stringify(URL2))

이거 해보라고 함

function getDataByCategory(categoryEnum) {
    let category = categoryEnum;
    let URL = JSON.stringify({
          category: category
        })
    let categoryUrl= encodeURI(JSON.stringify(URL))

    $.ajax({
      type: 'GET',
      url: `/api/v1/posts/category?${categoryUrl}`,
      dataType: "json",
      contentType: 'application/json',
      data: {},
      /*
      JSON.stringify({
        category: category
      }),*/
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

이거 해봄

2024-01-19T20:54:15.791+09:00 WARN 14536 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.moayo.moayoeats.backend.global.dto.ApiResponse<java.util.List<com.moayo.moayoeats.backend.domain.post.dto.response.BriefPostResponse>> com.moayo.moayoeats.backend.domain.post.controller.PostController.getPostsByCategory(com.moayo.moayoeats.backend.global.security.UserDetailsImpl,com.moayo.moayoeats.backend.domain.post.dto.request.PostCategoryRequest)]

안 됨…

아예 객체 취급을 안 해줌

https://stackoverflow.com/questions/46251131/invalid-character-found-in-the-request-target-in-spring-boot

이사람의 문제 나와 동일하다

According to https://tomcat.apache.org/tomcat-8.5-doc/config/systemprops.html, requestTargetAllow is deprecated. For me, the other solutions presented here did not work either. According to the Tomcat documentation I found a way to set the property relaxedQueryChars instead:

@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
        @Override
        public void customize(Connector connector) {
            connector.setProperty("relaxedQueryChars", "|{}[]");
        }
    });
    return factory;
}

18

For a Spring Boot application, just add to properties file:

server.tomcat.relaxed-query-chars=|,{,},[,]

There is also the following key: server.tomcat.relaxed-path-chars

@Configuration
public class WebServerConfig {

    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
            @Override
            public void customize(Connector connector) {
                connector.setProperty("relaxedQueryChars", "|{}[]");
            }
        });
        return factory;
    }
}

한번 이렇게 해봄

44.858+09:00 WARN 33020 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.moayo.moayoeats.backend.global.dto.ApiResponse<java.util.List<com.moayo.moayoeats.backend.domain.post.dto.response.BriefPostResponse>> com.moayo.moayoeats.backend.domain.post.controller.PostController.getPostsByCategory(com.moayo.moayoeats.backend.global.security.UserDetailsImpl,com.moayo.moayoeats.backend.domain.post.dto.request.PostCategoryRequest)]

024-01-19T21:11:18.234+09:00 WARN 33020 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public com.moayo.moayoeats.backend.global.dto.ApiResponse<java.util.List<com.moayo.moayoeats.backend.domain.post.dto.response.BriefPostResponse>> com.moayo.moayoeats.backend.domain.post.controller.PostController.searchPost(com.moayo.moayoeats.backend.global.security.UserDetailsImpl,com.moayo.moayoeats.backend.domain.post.dto.request.PostSearchRequest)]

Required request body is missing:

하 모르겠다

아까도 그랬는데 POST는 json형식으로 잘 되는데 get은 안 돼서

Q. 왜 안되지? POST는 왜 되는거지?

그냥 requestParam으로 수정해야할 거 같음

https://www.baeldung.com/spring-request-param

 

⛳ 해결 : Get method RequestBody에서 RequestParam 방식으로 모두 변경함

@Override
    public List<BriefPostResponse> searchPost(String keyword, User user) {
        //get all posts filtered by search keyword
        List<Post> posts = postRepository.findPostByStoreContaining(keyword)
            .orElse(null);
        //List<Post> -> List<BriefPostResponse>
        return postsToBriefResponses(posts);
    }

String keyword로 다 변경함

//글 검색하기
    @GetMapping("/posts/search")
    public ApiResponse<List<BriefPostResponse>> searchPost(
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @RequestParam String keyword
    ) {
        return new ApiResponse<>(HttpStatus.OK.value(), "검색 결과",
            postService.searchPost(keyword, userDetails.getUser()));
    }
@Override
    public List<BriefPostResponse> searchPost(String keyword, User user) {
        //get all posts filtered by search keyword
        List<Post> posts = postRepository.findPostByStoreContaining(keyword)
            .orElse(null);
        //List<Post> -> List<BriefPostResponse>
        return postsToBriefResponses(posts);
    }
$.ajax({
      type: 'GET',
      url: `/api/v1/posts/search?keyword=${keyword}`,
      dataType: "json",
      contentType: 'application/json',
      data: {},
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });

이걸로 해보기

잘 됨

카테고리도 바꿔봄

//글 카테고리별 조회
    @GetMapping("/posts/category")
    public ApiResponse<List<BriefPostResponse>> getPostsByCategory(
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @RequestParam CategoryEnum category
    ) {
        return new ApiResponse<>(HttpStatus.OK.value(), "글 카테고리별 조회에 성공했습니다.",
            postService.getPostsByCategory(category, userDetails.getUser()));
    }
@Override
    public List<BriefPostResponse> getPostsByCategory(CategoryEnum category,
        User user) {
        List<Post> posts;
        if (category.equals(CategoryEnum.ALL.toString())) {
            posts = findAll();
        } else {
            posts = postRepository.findAllByCategoryEquals(category.toString()).orElse(null);
        }
        return postsToBriefResponses(posts);
    }

Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter 'category' for method parameter type CategoryEnum is not present]

아 html바꾸는거 까먹음

function getDataByCategory(categoryEnum) {
    let category = categoryEnum;

    $.ajax({
      type: 'GET',
      url: `/api/v1/posts/category?category=${category}`,
      dataType: "json",
      contentType: 'application/json',
      data:{},
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

org.hibernate.query.QueryArgumentException: Argument [BURGER] of type [java.lang.String] did not match parameter type [com.moayo.moayoeats.backend.domain.post.entity.CategoryEnum

function getDataByCategory(categoryEnum) {
    let category = categoryEnum;

    $.ajax({
      type: 'GET',
      url: `/api/v1/posts/category`,
      dataType: "json",
      contentType: 'application/json',
      data:{category:category},
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

이렇게 해봄

org.hibernate.query.QueryArgumentException: Argument [CHICKEN] of type [java.lang.String] did not match parameter type [com.moayo.moayoeats.backend.domain.post.entity.CategoryEnum (n/a)] at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:85) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final] at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:32) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final] at org.hibernate.query.internal.QueryParameterBindingImpl.validate(QueryParameterBindingImpl.java:362) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final] at org.hibernate.query.internal.QueryParameterBindingImpl.setBindValue(QueryParameterBindingImpl.java:137) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final] at org.hibernate.query.spi.AbstractCommonQueryContract.setParameter(AbstractCommonQueryContract.java:1047) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final] at org.hibernate.query.spi.AbstractSelectionQuery.setParameter(AbstractSelectionQuery.java:966) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final] at org.hibernate.query.sqm.internal.QuerySqmImpl.setParameter(QuerySqmImpl.java:1324) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final] at org.hibernate.query.sqm.internal.QuerySqmImpl.setParameter(QuerySqmImpl.java:140) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]

안되나봄

function getDataByCategory(categoryEnum) {
    let category = categoryEnum;

    $.ajax({
      type: 'GET',
      url: `/api/v1/posts/category?category=${category}`,
      dataType: "json",
      contentType: 'application/json',
      data:{},
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

ㅈㅈㅇㅈㅇㅈㅁ ㅈㅇ

//글 카테고리별 조회
    @GetMapping("/posts/category")
    public ApiResponse<List<BriefPostResponse>> getPostsByCategory(
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @RequestParam @Category String category
    ) {
        return new ApiResponse<>(HttpStatus.OK.value(), "글 카테고리별 조회에 성공했습니다.",
            postService.getPostsByCategory(category, userDetails.getUser()));
    }

일단 정해진거 해보고 html에서 이상한것도 보내봐야지

org.hibernate.query.QueryArgumentException: Argument [ASIAN] of type [java.lang.String] did not match parameter type [com.moayo.moayoeats.backend.domain.post.entity.CategoryEnum (n/a)] at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:85) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]

at com.moayo.moayoeats.backend.domain.post.service.impl.PostServiceImpl.getPostsByCategory(PostServiceImpl.java:138) ~[main/:na] at com.moayo.moayoeats.backend.domain.post.controller.PostController.getPostsByCategory(PostController.java:78) ~[main/:na]

Optional<List<Post>> findAllByCategoryEquals(String category);

String인데 뭔소리함

@Override
    public List<BriefPostResponse> getPostsByCategory(String category,
        User user) {
        List<Post> posts;
        if (category.equals(CategoryEnum.ALL.toString())) {
            posts = findAll();
        } else {
            posts = postRepository.findAllByCategoryEquals(category).orElse(null);
        }
        return postsToBriefResponses(posts);
    }

이것도 String이고

//글 카테고리별 조회
    @GetMapping("/posts/category")
    public ApiResponse<List<BriefPostResponse>> getPostsByCategory(
        @AuthenticationPrincipal UserDetailsImpl userDetails,
        @RequestParam @Category String category
    ) {
        return new ApiResponse<>(HttpStatus.OK.value(), "글 카테고리별 조회에 성공했습니다.",
            postService.getPostsByCategory(category, userDetails.getUser()));
    }

다 String인데?

근데 Entity에 저장된 타입은 CategoryEnum이라 그 부분 바꿔봄

Optional<List<Post>> findAllByCategoryEquals(CategoryEnum category);
@Override
    public List<BriefPostResponse> getPostsByCategory(String category,
        User user) {
        List<Post> posts;
        CategoryEnum categoryEnum = CategoryEnum.valueOf(category);
        if (category.equals(CategoryEnum.ALL.toString())) {
            posts = findAll();
        } else {
            posts = postRepository.findAllByCategoryEquals(categoryEnum).orElse(null);
        }
        return postsToBriefResponses(posts);
    }

잘 된다

 

이제 @Category 가 되는지 보기 위해 html을 바꿔서 테스트해봄

function getDataByCategory(categoryEnum) {
    let category = categoryEnum;

    $.ajax({
      type: 'GET',
      url: `/api/v1/posts/category?category=${category}`,
      dataType: "json",
      contentType: 'application/json',
      data:{},
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

function getDataByCategory(categoryEnum) {
    let category = categoryEnum;

    $.ajax({
      type: 'GET',
      url: `/api/v1/posts/category?category=test`,
      dataType: "json",
      contentType: 'application/json',
      data:{},
      success: function (response) {
        console.log('Success:', response);

        drawAllPosts(response.data);

      },
      error: function (error) {
        console.error('Error:', error);
      }
    });
  }

카테고리 누를때마다 에러가 뜸!

포스트맨에서도 해봄

localhost:8080/api/v1/posts/category?category=test

이렇게 보내면

403Forbidden

이렇게 뜨고

localhost:8080/api/v1/posts/category?category=ALL

이렇게 보내면 잘 뜸!

{
    "status": 200,
    "message": "글 카테고리별 조회에 성공했습니다.",
    "data": [
        {
            "id": 34,
            "author": "가나다라",
            "address": "37.5675458,126.9714466",
            "store": "1",
            "minPrice": 1,
            "sumPrice": 0,
            "deadline": "2024-01-19T23:42:31"
        }
    ]
}

이건 무슨 에러를 던지는지 뜨지도 않아서 어떻게 Exception 처리해야할지 모르겠다!

→ 🚀issue: 나중에 추가로 해보기!!!

 

 

 

'개발일지' 카테고리의 다른 글

2024-01-18, Today I Learned  (0) 2024.01.18
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