Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 스택
- c언어
- c언어 제어문
- 파이썬 알고리즘 인터뷰
- 백준
- 그리디
- #코린이 #코딩 #할 수 있다
- git오류
- c언어 기본
- 자료구조
- python자료형
- 4장
- 운체 1주차
- Git
- 5장
- 참고X
- git 오류
- python기초
- DP
- 코딩테스트
- git기초
- 도커
- python기본
- 인텔리제이
- 1주차(1)
- Workbench
- 코테
- 인스타
- 최단거리
- 데베시 1주차
Archives
- Today
- Total
하루살이 개발자
[Instagram 클론코딩] 4. 회원정보 수정 본문
회원정보 수정
- PUT 요청
- update.jsp 폼에서 post, get 요청은 가능하지만, PUT은 불가능
- js에서 제출 버튼 클릭시(onclick) update()호출하도록 구현하기
- 회원정보 수정 페이지에 기본 정보가 입력되어 있는 구현임
[프론트]
update.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<!--프로필셋팅 메인-->
<main class="main">
<!--프로필셋팅 섹션-->
<section class="setting-container">
<!--프로필셋팅 아티클-->
<article class="setting__content">
<!--프로필셋팅 아이디영역-->
<div class="content-item__01">
<div class="item__img">
<img src="/upload/${principal.user.profileImageUrl}" onerror="this.src='/images/person.jpeg'" />
</div>
<div class="item__username">
<h2>${principal.user.username}</h2>
</div>
</div>
<!--프로필셋팅 아이디영역end-->
<!--프로필 수정-->
<form id="profileUpdate" onsubmit="update(${principal.user.id}, event)" >
<div class="content-item__02">
<div class="item__title">이름</div>
<div class="item__input">
<input type="text" name="name" placeholder="이름"
value="${principal.user.name}" required="required"/>
</div>
</div>
<div class="content-item__03">
<div class="item__title">유저네임</div>
<div class="item__input">
<input type="text" name="username" placeholder="유저네임"
value="${principal.user.username}" readonly="readonly" />
</div>
</div>
<div class="content-item__04">
<div class="item__title">패스워드</div>
<div class="item__input">
<input type="password" name="password" placeholder="패스워드" required="required"/>
</div>
</div>
<div class="content-item__05">
<div class="item__title">웹사이트</div>
<div class="item__input">
<input type="text" name="website" placeholder="웹 사이트"
value="${principal.user.website}" />
</div>
</div>
<div class="content-item__06">
<div class="item__title">소개</div>
<div class="item__input">
<textarea name="bio" id="" rows="3">${principal.user.bio}</textarea>
</div>
</div>
<div class="content-item__07">
<div class="item__title"></div>
<div class="item__input">
<span><b>개인정보</b></span> <span>비즈니스나 반려동물 등에 사용된 계정인 경우에도
회원님의 개인 정보를 입력하세요. 공개 프로필에는 포함되지 않습니다.</span>
</div>
</div>
<div class="content-item__08">
<div class="item__title">이메일</div>
<div class="item__input">
<input type="text" name="email" placeholder="이메일"
value="${principal.user.email}" readonly="readonly" />
</div>
</div>
<div class="content-item__09">
<div class="item__title">전회번호</div>
<div class="item__input">
<input type="text" name="phone" placeholder="전화번호"
value="${principal.user.phone}" />
</div>
</div>
<div class="content-item__10">
<div class="item__title">성별</div>
<div class="item__input">
<input type="text" name="gender" value="${principal.user.gender}" />
</div>
</div>
<!--제출버튼-->
<div class="content-item__11">
<div class="item__title"></div>
<div class="item__input">
<button>제출</button>
</div>
</div>
<!--제출버튼end-->
</form>
<!--프로필수정 form end-->
</article>
</section>
</main>
<script src="/js/update.js"></script>
<%@ include file="../layout/footer.jsp"%>
upload.js
// (1) 회원정보 수정
function update(userId, event) {
event.preventDefault(); // 폼태그 액션을 막기!!
// header 파일에 제이쿼리 정의함
let data = $("#profileUpdate").serialize(); // key=value
console.log(data);
$.ajax({
type: "put",
url : `/api/user/${userId}`,
data: data,
contentType: "application/x-www-form-urlencoded; charset=utf-8",
dataType: "json"
}).done(res=>{ // HttpStatus 상태코드 200번대
console.log("성공", res);
location.href = `/user/${userId}`;
}).fail(error=>{ // HttpStatus 상태코드 200번대가 아닐 때
if(error.data == null){
alert(error.responseJSON.message);
}else{
alert(JSON.stringify(error.responseJSON.data));
}
});
}
header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<sec:authorize access="isAuthenticated()">
<sec:authentication property="principal" var="principal"/>
</sec:authorize>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Photogram</title>
<!-- 제이쿼리 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- Style -->
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/story.css">
<link rel="stylesheet" href="/css/popular.css">
<link rel="stylesheet" href="/css/profile.css">
<link rel="stylesheet" href="/css/upload.css">
<link rel="stylesheet" href="/css/update.css">
<link rel="shortcut icon" href="/images/insta.svg">
<!-- Fontawesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css" />
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>
<!-- principalId 담아두는 곳 -->
<input type="hidden" id="principalId" value="${principal.user.id}" />
<header class="header">
<div class="container">
<a href="/" class="logo">
<img src="/images/logo.jpg" alt="">
</a>
<nav class="navi">
<ul class="navi-list">
<li class="navi-item"><a href="/">
<i class="fas fa-home"></i>
</a></li>
<li class="navi-item"><a href="/image/popular">
<i class="far fa-compass"></i>
</a></li>
<li class="navi-item"><a href="/user/${principal.user.id}">
<i class="far fa-user"></i>
</a></li>
</ul>
</nav>
</div>
</header>
[백엔드]
UserUpdateDto
package com.cos.photogramstart.web.dto.user;
import javax.validation.constraints.NotBlank;
import com.cos.photogramstart.domain.user.User;
import lombok.Data;
// usernamem, useremail은 수정 불가
// UserApiController
@Data
public class UserUpdateDto {
@NotBlank
private String name; // 필수
@NotBlank
private String password; // 필수
private String website;
private String bio;
private String phone;
private String gender;
// 조금 위함함. 코드 수정이 필요할 예정
// 필수로 받지 않아도 되는 것들이 있으므로 toEntity()로 정의하면 위험함
public User toEntity() {
return User.builder()
.name(name) // 이름을 기재 안했으면 공백으로 값이 전댈되어 문제생김 -> Validation 체크 필요!
.password(password) // 패스워드를 기재 안했으면 공백으로 값이 전달되어 문제생김 -> Validation 체크 필요
.website(website)
.bio(bio)
.phone(phone)
.gender(gender)
.build();
}
}
UserService
package com.cos.photogramstart.service;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import com.cos.photogramstart.domain.subscribe.SubscribeRepository;
import com.cos.photogramstart.domain.user.User;
import com.cos.photogramstart.domain.user.UserRepository;
import com.cos.photogramstart.handler.ex.CustomApiException;
import com.cos.photogramstart.handler.ex.CustomException;
import com.cos.photogramstart.handler.ex.CustomValidationApiException;
import com.cos.photogramstart.web.dto.user.UserProfileDto;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
// 회원정보 수정
@Transactional
public User 회원수정(int id, User user) {
// 1. 영속화
// Optional 기능 1. 무조건 찾았다. 걱정마 get() 2. 못찾았어 익섹션 발동시킬게 orElseThrow()
User userEntity = userRepository.findById(id).orElseThrow(() -> { return new CustomValidationApiException("찾을 수 없는 id입니다.");});
// 2. 영속화된 오브젝트를 수정 - 더티체킹 (업데이트 완료)
userEntity.setName(user.getName());
// 비밀번호 수정시 암호화 해야함
String rawPassword = user.getPassword();
String encPassword = bCryptPasswordEncoder.encode(rawPassword);
userEntity.setPassword(encPassword);
userEntity.setBio(user.getBio());
userEntity.setWebsite(user.getWebsite());
userEntity.setPhone(user.getPhone());
userEntity.setGender(user.getGender());
return userEntity; // 수정된 오브젝트 리턴
} // 더티체킹이 일어나서 업데이트가 완료됨.
}
UserController
package com.cos.photogramstart.web;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import com.cos.photogramstart.config.auth.PrincipalDetails;
import com.cos.photogramstart.service.UserService;
import com.cos.photogramstart.web.dto.user.UserProfileDto;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Controller
public class UserController {
private final UserService userService;
/* 세션정보 찾기를 통해 회원 정보 변경하기!
/auth/login -> username이 존재하면? -> PrincipalDetails에서 세션 저장
-> autnentication에 접근(AuthenticationPrincipal 어노테이션 이용) -> 세션 접근!!
*/
// 회원 정보 변경
// model에 담아서 세션정보 보내기-> pom.xml에서 처리했으므로(시큐리티 태그 라이브러리, header)할 필요 없음!
@GetMapping("/user/{id}/update")
public String updateForm(@PathVariable int id, @AuthenticationPrincipal PrincipalDetails principalDetails) {
// 1. 추천
System.out.println("세션 정보 : "+principalDetails.getUser());
// 2. 비효율
//Authentication auth = SecurityContextHolder.getContext().getAuthentication();
//PrincipalDetails mPrincipalDetails = (PrincipalDetails) auth.getPrincipal();
//System.out.println("직접 찾은 세션 정보 : "+mPrincipalDetails.getUser());
return "user/update";
}
}
* 유효성 검사
ControllerExceptionHandler
package com.cos.photogramstart.handler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import com.cos.photogramstart.handler.ex.CustomApiException;
import com.cos.photogramstart.handler.ex.CustomException;
import com.cos.photogramstart.handler.ex.CustomValidationApiException;
import com.cos.photogramstart.handler.ex.CustomValidationException;
import com.cos.photogramstart.util.Script;
import com.cos.photogramstart.web.dto.CMRespDto;
// 오류 발새 시 낚아채서 응답하기
@RestController
@ControllerAdvice
public class ControllerExceptionHanlder {
// 34강
// 유효성 검사 실패시 처리방법 경우2) ? = CMRespDto
// 어떤 타입을 넣을 지 모르면 <?>
@ExceptionHandler(CustomValidationApiException.class)
public ResponseEntity<?> validationApiException(CustomValidationApiException e) {
return new ResponseEntity<>(new CMRespDto<>(-1, e.getMessage(), e.getErrorMap()), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(CustomApiException.class)
public ResponseEntity<?> apiException(CustomApiException e) {
return new ResponseEntity<>(new CMRespDto<>(-1, e.getMessage(), null), HttpStatus.BAD_REQUEST);
}
}
'Project > Instagram 클론코딩' 카테고리의 다른 글
[Instagram 클론코딩] 4. 구독 (0) | 2022.02.17 |
---|---|
[Instagram 클론코딩] 3. 로그인 (0) | 2022.02.15 |
[Instagram 클론코딩] 2. 회원가입 (0) | 2022.02.14 |
[Instagram 클론코딩] 0. 설계 (0) | 2022.02.14 |