오늘 종일 나를 괴롭혔던 이놈
415, 400, 500의 오류를 맛보게 해주었다.
결국 근본적인 이유는
json과 파일을 같이 보내려고 했던 시도가 잘 안됐던 것 같다.
<오류가 났던 코드>
const updateData = JSON.stringify({
memberId : memberId,
memberName : memberName,
memberEmail : memberEmail,
memberPassword : memberPassword,
memberPhone : memberPhone,
}
);
const formData = new FormData();
for (let i = 0; i < memberProfile.length; i++) {
formData.append('memberProfile', memberProfile[i]);
}
formData.append('updateData', updateData);
formData.append('memberProfile', memberProfile);
인터넷에 구글링을 해보다가 이렇게 할 수 있겠구나 싶어서 적용 해 봤지만 400, 500 오류가 떴다. 검색해 보니 파일+제이슨스트링 형식이 contentType이 안맞아서 그런 것 같다. 요 formdata를 나중에 더 공부해보면 왜 그런지 알 수 있을까?
결국 해결방법은 다 지우고 form에 id를 줘서 formdata에 보내면 됐던 것이다!
<해결 코드>
update html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<meta charset="UTF-8">
<title>update</title>
</head>
<body>
<form id="updateForm" th:object="${member}" enctype="multipart/form-data">
<input type="hidden" th:field="*{memberId}">
<input type="text" th:field="*{memberName}" placeholder="이름" readonly>
<input type="text" th:field="*{memberEmail}" placeholder="이메일" readonly>
<input type="password" th:field="*{memberPassword}" placeholder="비밀번호입력">
<input type="text" th:field="*{memberPhone}" placeholder="변경할 전화번호" readonly>
<label for="memberProfile">프로필 사진 선택</label>
<input th:class="form-control" type="file" id="memberProfile" name="memberProfile">
<input type="button" value="수정(put)" th:onclick="memberUpdate()">
</form>
</body>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script>
const memberUpdate = () => {
const memberId = document.getElementById('memberId').value;
const memberName = document.querySelector('#memberName').value;
const memberEmail = $('#memberEmail').val();
const memberPassword = $('#memberPassword').val();
const memberPhone = $('#memberPhone').val();
const memberProfile = document.getElementById('memberProfile').value;
console.log(memberId,memberName,memberEmail,memberPassword,memberPhone,memberProfile);
const reqUrl = "/member/" +memberId;
const data = $('#updateForm')[0];
const formData = new FormData(data);
const pwDB = "[[${member.memberPassword}]]";
if(pwDB == memberPassword){
$.ajax({
type : 'put',
cache: false,
contentType : false,
processData : false,
data : formData,
url : reqUrl,
success : function (){
location.reload()
},error : function (){
alert("요청실패")
}
})}
else {
alert('비밀번호가 틀렸습니다.');
}
};
</script>
</html>
Controller
@PutMapping("/{memberId}")
public ResponseEntity update(@ModelAttribute MemberUpdateDTO memberUpdateDTO)
throws IllegalStateException, IOException {
System.out.println("받아온 것"+ memberUpdateDTO);
ms.update(memberUpdateDTO);
return new ResponseEntity(HttpStatus.OK);
}
그리고 Controller에서 formData는 @RequestBody 로 받아오면 안된다고 한다. json 형식으로 받아올때만 @RequestBody를 쓰고 @ModelAttribute로 받아와야 한다. @RequestBody를 쓰면 이제 415 오류가 뜬다.
serviceImpl - 파일을 파일명으로 변환해줘야겠지요?
@Override
public void update(MemberUpdateDTO memberUpdateDTO) throws IllegalStateException, IOException {
// 프로필 사진 저장하기 파일 -> 이름
MultipartFile m_file = memberUpdateDTO.getMemberProfile();
String m_filename = m_file.getOriginalFilename();
m_filename = System.currentTimeMillis() + "-" + m_filename;
// 파일 저장하기
String savePath = "D:\\development_Phl\\source\\springboot\\MemberBoardProject\\src\\main\\resources\\member_uploadfile\\"+m_filename;
if(!m_file.isEmpty()) {
m_file.transferTo(new File(savePath));
}
memberUpdateDTO.setMemberProfileName(m_filename);
MemberEntity memberEntity = MemberEntity.toMemberUpdateEntity(memberUpdateDTO);
mr.save(memberEntity);
}
UpdateDTO
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MemberUpdateDTO {
private Long memberId;
private String memberEmail;
private String memberPassword;
private String memberName;
private String memberPhone;
private MultipartFile memberProfile;
private String memberProfileName;
}
Entity - 아이디가 같은 곳에 다시 덮어써서 저장하면 끝!
@Entity
@Getter
@Setter
@Table(name = "member_table")
public class MemberEntity extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "member_id")
private Long id;
@Column
private String memberEmail;
@OneToMany(mappedBy = "memberEntity", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<BoardEntity> boardEntityList = new ArrayList<>();
@OneToMany(mappedBy = "memberEntity", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<CommentEntity> commentEntityList = new ArrayList<>();
@Column
private String memberPassword;
@Column
private String memberName;
@Column
private String memberPhone;
@Column
private String memberProfileName;
public static MemberEntity toMemberEntitySave(MemberSaveDTO memberSaveDTO){
MemberEntity memberEntity = new MemberEntity();
memberEntity.setMemberEmail(memberSaveDTO.getMemberEmail());
memberEntity.setMemberPhone(memberSaveDTO.getMemberPhone());
memberEntity.setMemberName(memberSaveDTO.getMemberName());
memberEntity.setMemberPassword(memberSaveDTO.getMemberPassword());
memberEntity.setMemberProfileName(memberSaveDTO.getMemberProfileName());
return memberEntity;
}
public static MemberEntity toMemberUpdateEntity(MemberUpdateDTO memberUpdateDTO){
MemberEntity memberEntity = new MemberEntity();
memberEntity.setId(memberUpdateDTO.getMemberId());
memberEntity.setMemberName(memberUpdateDTO.getMemberName());
memberEntity.setMemberEmail(memberUpdateDTO.getMemberEmail());
memberEntity.setMemberPassword(memberUpdateDTO.getMemberPassword());
memberEntity.setMemberPhone(memberUpdateDTO.getMemberPhone());
memberEntity.setMemberProfileName(memberUpdateDTO.getMemberProfileName());
return memberEntity;
}