유저 수정 메서드에서만 스프링 기본 파싱 전략을 바꿔야 한다.
유저 수정은 자바스크립트 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
메타 코딩 유튜브
https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9