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 | 31 | 
                            Tags
                            
                        
                          
                          - 참고X
- python자료형
- 최단거리
- git 오류
- 스택
- python기초
- 도커
- 코딩테스트
- 파이썬 알고리즘 인터뷰
- Workbench
- 데베시 1주차
- 그리디
- git오류
- 운체 1주차
- 4장
- python기본
- c언어 제어문
- c언어
- 인텔리제이
- c언어 기본
- #코린이 #코딩 #할 수 있다
- 코테
- git기초
- Git
- 5장
- 1주차(1)
- 백준
- 자료구조
- 인스타
- DP
                            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 | 
 
                   
                   
                  