개발 무지렁이

[Error] jQuery AJAX를 통해 전송한 데이터를 Controller에서 인식하지 못하는 경우 본문

Backend/Error

[Error] jQuery AJAX를 통해 전송한 데이터를 Controller에서 인식하지 못하는 경우

Gaejirang-e 2023. 9. 2. 16:10

🎃 Required request parameter 'excludedItemId' for method

📜 script.js

  $(".check-box").change(function() {
    let cur = $(this).data("id");
    let checkbox = ".check-box-" + cur;
    if(!$(checkbox).is(":checked")) { //체크 풀었을 때
      console.log("excluded: ", cur); //체크가 안된 itemId를 감지
      $.ajax({
        url: "/sm/c/api/v1",
        type: "POST",
        data: JSON.stringify({ "excludedItemId" : cur}),
        contentType: "application/json",
        success: function(result) {
        $("#std-parents").html(result);
        },
        error: function(xhr, err, status) {
        console.log(xhr.responseText);
        alert(err + "이(가) 발생했습니다: " + status);
        }
      });
  }
🦉 코드 해석
: (체크박스에 변화가 생겼을 때) 그 중 체크를 풀었을 때,
해당 태그의 data-id 속성에 넣어준 을 가져와서 /sm/c/api/v1으로 json 데이터를 전송하려했다.

❓ contentType="application/json"을 설정하는 이유
대부분의 브라우저는 contentType의 default가 application/x-www-form-urlencoded로 설정되어 있고,
이는 URL 인코딩된 폼데이터 형식을 나타낸다. 따라서 요청본문서버에서 JSON 형식으로 파싱하길 바라기 때문에
이같이 설정해준다.
(폼데이터 형식은, 파일 업로드와 같은 복잡한 데이터를 처리할 때 유용하다)

❓ JSON.stringify()를 사용하는 이유
Javascript 객체를 JSON 문자열로 변환하는 메서드인데, 이 변환을 해야 서버에서 JSON 형식으로 쉽게 파싱할 수 있다.
또한, JSON 문자열로 변환하면 데이터가 문자열로 인코딩되어 특수문자나 스크립트를 포함한 데이터가 안전하게 전달된다.
이 메서드를 사용하지 않고, contentType="application/json"으로 설정했을 경우,
요청된 데이터가 JSON 형식으로 전송되지 않는다.
이 때, 브라우저는 객체를 문자열로 변환하고, 요청 본문에 넣어서 전달하는데,
서버는 이 데이터를 일반 텍스트로 처리하게 된다. 일반 텍스트로 수신한 데이터를 JSON형식으로 파싱하기 어렵기 때문에
서버에서 요청 데이터를 정상적으로 처리하지 못할 수 있다.

🎲 [error code]Controller.java

  @PostMapping("/sm/c/api/v1")
    public String addUnchecked(@RequestParam String excludedItemId, HttpSession session) { // excludedItemId 인식x
    cart_log.info("excludedItemId: " + Long.valueOf(excludedItemId));
    // ..생략..
    return "redirect:/sm/c/api/get";
  }  
🦉 문제 코드
: 어떻게 받아야할지 잘 모르겠어서 일단 @RequestParam으로 받아봤지만, 인식을 못한다.

🎲 [error code2]Controller.java

  @PostMapping("/sm/c/api/v1")
    public String addUnchecked(@RequestParam Map<String,Integer> requestData, HttpSession session) {
      int excludedItemId = (Integer)requestData.get("excludedItemId");
    cart_log.info("excludedItemId: " + Long.valueOf(excludedItemId));
    // ..생략..
    return "redirect:/sm/c/api/get";
  }  
🦉 문제 코드
: key-value로 구성된 json 형식의 데이터를 받기위해, Map으로 받아야하나 싶어 Map으로 받아봤지만,
해당 값에는 null이 들어온다.(jQuery AJAX로 보낸 데이터를 받지 못했다.)
근데, 생각을 해보니 @RequestParam파라미터 값(ex ?username=woo&age=20)을 받을 때
사용하는 어노테이션이니 Http 요청 메시지의 본문을 받는 현재 상황에서는 잘못된 접근이다.

🪄 Controller.java

  @PostMapping("/sm/c/api/v1")
    public String addUnchecked(@RequestBody Map<String, Object> requestData, HttpSession session) {
    int excludedItemIdInt = (Integer)requestData.get("excludedItemId");
    long excludedItemId = Long.valueOf(excludedItemIdInt);
    cart_log.info("excludedItemId: " + Long.valueOf(excludedItemId));

    //HashSet에 uncheck된 itemId 담기
    Set<Long> excludedSet = (HashSet<Long>)session.getAttribute("excludedSet");
    excludedSet = cartService.checkValid(excludedSet);
    excludedSet.add(excludedItemId);
    //세션에 업데이트된 HashSet 저장
    session.setAttribute("excludedSet", excludedSet);

    return "redirect:/sm/c/api/get";
  }
🦉 오류 해결 코드
: 다음과 같이 @RequestBody라는 어노테이션이 있었고,
이는 요청본문을 Map자료구조로 자동변환한다. 이때 Map 자료구조의 value타입은 Object로 명시해놨는데,
@RequestBody가 이미 데이터 값에 맞는 타입으로 자동변환 했기 때문에, 해당 타입으로 캐스팅해서 써야한다.
(현재 전송한 데이터 excludedItemId는 숫자타입이므로 (Integer)로 캐스팅해서 써야한다.)
이렇게 했을 때, 전송한 데이터를 얻을 수 있었다.
Comments