======= 회원정보 수정하기 =======
회원 정보 페이지를 달라고 요청하는 거니까
주소에 /api를 붙이지 않는다.
좀 특이한 건 그냥 페이지 요청이 아니라
데이터를 넣어서 페이지 달라고 요청한다.
제일 쉬운 방법은 DB에서 id로 SELECT 해서 모델에 담으면 되는데
앱까지 같은 서버로 제공한다면 fetch를 사용해야 한다.
공통적으로!!
원래는 findById( ) 메서드를 요청하면 Optional<User> 타입을 리턴해줘서
isPresent( )로 안에 값이 있으면 return userOp.get( ) 하고,
값이 없으면 null을 리턴하는데
null이 리턴되면 결국 머스태치에서 터지게 된다.
뷰 랜더링 할 때!
null을 리턴하는 것은 위험하다.
내가 직접 강제로 Exception을 터뜨려줘야 한다.
throw new RuntimeException("아이디를 찾을 수 없습니다.");
강제로 Exception을 터뜨리는 것을 throw라고 한다.
강제로 터진 이 Exception을 에러 핸들러가 낚아챌 것이다.
내가 메세지도 넣어줄 수 있다.
@Transactional
public User 회원수정(Integer id, UpdateDto updateDto) {
// UPDATE user SET password = ?, email = ?, address = ? WHERE id = ?
Optional<User> userOp = userRepository.findById(id); // 영속화 (DB의 row를 영속성 컨텍스트에 옮김)
if (userOp.isPresent()) {
// 영속화된 오브젝트 수정
User userEntity = userOp.get();
userEntity.setPassword(updateDto.getPassword());
userEntity.setEmail(updateDto.getEmail());
userEntity.setAddress(updateDto.getAddress());
return userEntity;
} else {
throw new RuntimeException("회원수정에 실패하였습니다.");
}
} // 트랜잭션이 걸려있으면 @Service가 종료될 때 변경 감지 후 DB에 UPDATE -> 더티체킹
package site.metacoding.blogv2.web.api.dto.user;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UpdateDto {
private String password;
private String email;
private String address;
}
// 유저정보 수정 password, email, address
@PutMapping("/s/api/user/{id}")
public ResponseDto<?> update(@PathVariable Integer id, @RequestBody UpdateDto updateDto, Model model) {
// System.out.println("id : " + id + ", updateDto : " + updateDto);
User userEntity = userService.회원수정(id, updateDto);
return new ResponseDto<>(1, "업데이트 성공", null);
}
{{> /layout/header}}
<!-- 컨테이너 시작 -->
<div class="container mt-3">
<!-- 회원수정 폼 시작 -->
<form>
<input id="id" type="hidden" value="{{user.id}}">
<div class="mb-3 mt-3">
<input id="username" type="text" class="form-control" value="{{user.username}}" readonly>
<!--username readonly-->
</div>
<div class="mb-3">
<input id="password" type="password" class="form-control" value="{{user.password}}" maxlength="12" required>
</div>
<div class="mb-3">
<input id="email" type="email" class="form-control" value="{{user.email}}" maxlength="30" required>
</div>
<div class="mb-3">
<input id="address" type="text" class="form-control" value="{{user.address}}" maxlength="300" required>
</div>
<button id="btn-update" type="button" class="btn btn-primary">수정완료</button>
</form>
<!-- 회원수정 폼 끝 -->
</div>
<!-- 컨테이너 끝 -->
<script src="/js/user.js"></script>
{{> /layout/footer}}
$("#btn-update").click(() => {
update();
});
// 회원정보 수정 함수
async function update() {
let updateDto = {
password: $("#password").val(),
email: $("#email").val(),
address: $("#address").val()
}
let id = $("#id").val();
let response = await fetch(`/s/api/user/${id}`, {
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
method: 'PUT',
body: JSON.stringify(updateDto)
});
let responseParse = await response.json();
// console.log(responseParse);
if (responseParse.code == 1) {
alert("수정이 완료되었습니다.");
location.href = `/s/user/${id}`;
} else {
alert("수정에 실패했습니다.");
}
}
UPDATE시에 영속화가 아닌 직접 네이티브 쿼리를 만들어서 사용해도 된다.
// UPDATE시에 영속화말고 직접 네이티브 쿼리를 짜도됨
@Modifying // 네이티브쿼리로 WRITE 작업을 하려면 이 어노테이션을 붙여줘야함 = executeUpdate()
@Query(value="UPDATE user SET password = :password, email = :email, address= :address WHERE id=:id", nativeQuery = true)
void mUpdate(@Param("password") String password, @Param("email") String email, @Param("address") String address, @Param("id") Integer id);
네이티브 쿼리로 DB에 WRITE 요청을 할 때는
@Modifying 어노테이션을 붙여줘야 한다.
우리가 prepareStatement를 사용할 때와 같이
WRITE 요청에 @Modifying 어노테이션을 붙이는 것은 executeUpdate( )가 실행되는 것과 같고,
SELECT 하는 쿼리는 executeQuery( )가 실행되는 것과 같은 것이다.
[출처]
https://cafe.naver.com/metacoding
메타 코딩 유튜브
https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9