Loading...

Spring/Blog-V1 / / 2022. 3. 18. 22:38

스프링 36강. 스프링 json 파싱 @RequestBody

반응형

유저 수정 메서드에서만 스프링 기본 파싱 전략을 바꿔야 한다.

유저 수정은 자바스크립트 fetch 함수를 통해 json으로 데이터를 받을 것이기 때문에

스프링이 데이터 받을 때 json으로 파싱 할 수 있도록 기본 파싱 전략을 변경해줘야 한다.

 


 

@RequestBody는 json으로 파싱 해주는 어노테이션이다.

 

RequestBody와 ResponseBody를 붙이면 Raw 하게 버퍼로 읽고 쓰겠다는 말이다.

날 것 그대로!

 

RequestBody를 안 붙이면 request.getParameter가 발동하여

x-www-form-urlencoded 타입만 파싱 하기 때문이다.

 

만약 (@RequestBody String user) 스트링 타입으로 받는다면

json이 스트링 타입으로 들어올 것이다.

이 타입을 User 오브젝트로(User user) 바꾸는 순간 RequestBody 기본 파싱 전략 발동하게 된다.

문자열이면 그냥 그대로 문자열로 읽고, 오브젝트면 제이슨을 오브젝트로 파싱 해준다.

 

RequestBody의 기본 파싱 전략 : json

 

{"password":"1234", "email":"ssar@nate.com"}

이렇게 데이터가 json으로 들어왔을 때

User 오브젝트로 받으면 password와 email을 제외한 다른 컬럼들은 null이 들어온다.

좋은 방법이 아니다.

 

이때는 통신을 위한 DTO(Data Transfer Object)를 하나 만들어야 한다.

package site.metacoding.dbproject.web.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Data
public class ResponseDto<T> {
    private Integer code; // -1 통신 실패 1 통신 성공
    private String msg;
    // 응답의 body 데이터
    private T data; // 데이터 타입이 결정되지 않았다
}

 

 

 

@PutMapping("/s/user/{id}")
public @ResponseBody ResponseDto<String> update(@PathVariable int id, @RequestBody User user) {
    // 보안의 문제
    // 유효성 검사 하기(수십개... 엄청 많겠지?)
    User principal = (User) session.getAttribute("principal");

    // 1. 인증 체크
    if (principal == null) {
        return new ResponseDto<String>(-1, "인증안됨", null);
    }

    // 2. 권한 체크
    if (principal.getId() != id) {
        return new ResponseDto<String>(-1, "권한없음", null); // http 상태코드 403 함께 리턴
    }

    User userEntity = userService.유저수정(id, user); // 세션에는 아직도 원래 비밀번호, 이메일로 저장되어있음 -> 변경해주자

    session.setAttribute("principal", userEntity); // 세션 변경 - 덮어쓰기!!

    return new ResponseDto<String>(1, "통신성공", null);
}

 

인증 체크, 권한 체크가 끝나면 더티 체킹을 해야 한다.

 

@Transactional
public User 유저수정(Integer id, User user) {
    // 1. 영속화(를 시켜야 변경감지하여 더티체킹 가능)
    Optional<User> userOp = userRepository.findById(id);

    if (userOp.isPresent()) { // 영속화 됨
        User userEntity = userOp.get();
        userEntity.setPassword(user.getPassword());
        userEntity.setEmail(user.getEmail());

        return userEntity;
    }

    return null;
} // 2. 트랜잭션 종료 + 영속화 되어있는 것들 전부 더티체킹 (변경감지해서 DB에 flush) -> UPDATE

 

아직 수정 완료 뷰를 만들어주지 않았으니까 포스트맨으로 테스트해보자.

 

포스트맨으로 로그인을 먼저 해야 세션 아이디가 생성된다.

 

 

 

updateForm.mustache 뷰를 만들어주자.

fetch( ) 함수를 통해 put 요청을 할 것이다.

 

{{> /layout/header}}

<!-- 컨테이너 시작 -->
<div class="container mt-3">
  <!-- container, mt-3은 css 클래스임!! -->

  <!-- 회원수정 폼 시작 -->
  <!-- 폼 태그는 put, delete 요청을 할 수 없다. 그래서 자바스크립트로 제어해야 한다. -->
  <form>
    <input type="hidden" id="id" value="{{principal.id}}">
    <div class="mb-3 mt-3">
      <input type="text" class="form-control" value="{{principal.username}}" id="username" readonly> 
      <!--username readonly-->
    </div>
    <div class="mb-3">
      <input type="password" class="form-control" value="{{principal.password}}" id="password" required>
    </div>
    <div class="mb-3">
      <input type="email" class="form-control" value="{{principal.email}}" id="email" required>
    </div>

    <button type="button" class="btn btn-secondary" id="btn-update">수정완료</button>
  </form>
  <!-- 회원수정 폼 끝 -->

</div>
<!-- 컨테이너 끝 -->

<!-- html문서에서 자바스크립트는 여기에 적는다 -->
<script>

  // 클래스 안에 있으면 메서드, 독립적인 것(1급 객체)은 함수
  async function update() {

    // 1. jquery로 password, email 찾아서 자바스크립트 오브젝트로 만들기
    let userUpdate = {
      password: $("#password").val(),
      email: $("#email").val()
    }

    console.log("userUpdate : " + userUpdate);

    // 2. 자바스크립트 오브젝트를 json으로 변환하기

    let userJson = JSON.stringify(userUpdate);
    console.log("userJson : " + userJson);

    // 다시 자바스크립트 오브젝트로 변환
    // let userObject = JSON.parse(userJson);

    // 3. fetch 요청하기
    let id = $("#id").val();
    let response = await fetch("/s/user/" + id, {
      
      // (1) content-type을 json으로 설정하기
      headers: {
        'Content-Type': 'application/json;charset=utf-8'
      },
      // (2) put 메서드로 변경하기
      method: 'PUT',
      // (3) body 데이터 실어 보내기
      body: userJson
    });

    console.log("response : " + response);

    let responseObject = await response.json();

    console.log("responseObject.code : " + responseObject.code);

    // (4) ResponseDto로 응답받아서 code가 1이면 alert창으로 수정 성공 띄우기
    if(responseObject.code == 1) {
      alert("수정이 정상적으로 완료되었습니다.")

      // (5) 수정 성공 메시지 이후에 / 메인 화면으로 이동하기 - location.href = "/"
      location.href = "/s/user/" + id;
    } else {
      alert("통신에 실패하였습니다. : " + responseObject.msg);
    }

    
  }

  $("#btn-update").click((event) => {
    update();
  })
  
</script>

{{> /layout/footer}}

 

자바스크립트에 머스태치 문법을 섞지 말자!!

 

자바스크립트의 중괄호는 오브젝트이다.

 

fetch 중괄호에 담을 수 있는 키 값들은

api 문서를 확인해야 한다.

 

지금 우리가 사용한 method, body, headers가 가장 기본적인 키 값들이다.

 

get요청일 때는 다른 키값들은 필요 없다!

 

 

[출처]

 

https://cafe.naver.com/metacoding

 

메타코딩 : 네이버 카페

코린이들의 궁금증

cafe.naver.com

메타 코딩 유튜브

https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

 

메타코딩

문의사항 : getinthere@naver.com 인스타그램 : https://www.instagram.com/meta4pm 깃헙 : https://github.com/codingspecialist 유료강좌 : https://www.easyupclass.com

www.youtube.com

 

 

반응형