티스토리 뷰

프로필 유저사진 변경

유저 이미지를 누르면 프로필변경이 뜨고 변경을 눌렀을때 사진 업로드창이 뜨게하기

 

유저프로필 이미지 코드

		<!--유저이미지-->
		<div class="profile-left">
			<div class="profile-img-wrap story-border"
				onclick="popup('.modal-image')">
				<form id="userProfileImageForm">
					<input type="file" name="profileImageFile" style="display: none;"
						id="userProfileImageInput" />
				</form>

				<img class="profile-image" src="#"
					onerror="this.src='/images/person.jpeg'" id="userProfileImage" />
			</div>
		</div>
		<!--유저이미지end-->

만약

<input type="file" name="profileImageFile" style="display: none;" id="userProfileImageInput" />

위에서 display:none를 지운다면?

<input type="file" name="profileImageFile" id="userProfileImageInput" />

위와같은 모습일것이다 그래서 히든을 주고 id를 잘보자

이미지 버튼의 id = userProfileImageInput 로 지정되어있다

 

프로필 사진을 눌렀을때 모달창 html코드 

<!--프로필사진 바꾸기 모달-->
<div class="modal-image" onclick="modalImage()">
	<div class="modal">
		<p>프로필 사진 바꾸기</p>
		<button onclick="profileImageUpload(${dto.user.id},${principal.user.id })">사진 업로드</button>
		<button onclick="closePopup('.modal-image')">취소</button>
	</div>
</div>

사진 업로드를 누르게되면 profileImageUpload가 발생되게 설정되어있다.

 

그렇다면 js파일을 보면

// (4) 유저 프로파일 사진 변경 (완)
function profileImageUpload(pageUserId, principalId) {
	
	$("#userProfileImageInput").click();

	$("#userProfileImageInput").on("change", (e) => {
		let f = e.target.files[0];

		if (!f.type.match("image.*")) {
			alert("이미지를 등록해야 합니다.");
			return;
		}

		// 사진 전송 성공시 이미지 변경
		let reader = new FileReader();
		reader.onload = (e) => {
			$("#userProfileImage").attr("src", e.target.result);
		}
		reader.readAsDataURL(f); // 이 코드 실행시 reader.onload 실행됨.
	});
}

발동되면 아까 위에서 봤던 Id를 가져와 강제로 클릭이벤트를 발생시키고

image파일이 아니면 이미지가 아닐경우 alert로 표시하고 

사진이 정상적으로 올라오면 바뀐사진으로 적용시켜주는 모습이다.

 

그렇다면 데이터를 넣어주기 위해선 일단 form태그를 가져와야한다

enctype은 js에서 설정해줄것이니 안해주어도 괜찮습니다.

 

profile.js

function profileImageUpload

		if (!f.type.match("image.*")) {
			alert("이미지를 등록해야 합니다.");
			return;
		}

		let profileImageForm = $("#userProfileImageForm");

이미지 판별후에 작동되도록 밑에다가 작성

콘솔로 출력해보니

데이터가 0번에 담겨있다 이걸 조심해야한다 그래서 콘솔로 데이터를 출력하는 습관은 좋은 습관이다

위정보 토대로 밑처럼 수정해주자

		if (!f.type.match("image.*")) {
			alert("이미지를 등록해야 합니다.");
			return;
		}

		let profileImageForm = $("#userProfileImageForm")[0];

그럼 밑처럼 form데이터만 깔금하게 가져오는 모습을 볼 수 있다

그럼 폼태그가 필요한게 아니라 우린 폼이 받은 데이터가필요하다

그럼 이렇게 바꿔보자

// FormData 객체를 이용한 form 태그의 필드와 그 값을 나타내는 일련의 key/value 쌍을 담을 수 있다.
let formdata = new Formdata(profileImageForm);

받아온 폼태그를 위와같이 FormData로 변환해주면 key/value값으로 담을 수 있다.

 

이제 ajax로 수정요청을 해보자

		$.ajax({
			type:"put",
			url:`/api/user/${principalId}/profileImageUrl`,
			data:formdata,
			contentType:false, // 기본값을 지정안하면  x-www-from-rulencoded형태이다
			processData:false, // contentType를 false로 줬을때 QueryString 자동 설정됨 해제
			enctype : "multipart/form-data",
			dataType:"json"
		}).done(res=>{
		
			// 사진 전송 성공시 이미지 변경
			let reader = new FileReader();
			reader.onload = (e) => {
				$("#userProfileImage").attr("src", e.target.result);
			}
			reader.readAsDataURL(f); // 이 코드 실행시 reader.onload 실행됨.	
		}).fail(err=>{
			console.log("실패",err)
		});

내가 사진을 전송한다하면 contentType 와 processData는 필수로 false값을 줘야한다 

아까 태그에서 설정하지못한 enctype도 설정해주고

성공했을시 이미지 변경하게

실패했을시 실패와 에러를 콘솔에 출력

 

js가 완료되었다면 이제 컨트롤에 요청해야하니 컨트롤에 요청함수를 만들어보자

 

UserApiController.java

@PutMapping("/api/user/{principalId}/profileImageUrl")
public ResponseEntity<?> profileImageUrlUpdate(@PathVariable int principalId, MultipartFile profileImageFile, 
        @AuthenticationPrincipal PrincipalDetails principalDetails){
    User userEntity =  userService.회원프로필사진변경(principalId,profileImageFile);
    principalDetails.setUser(userEntity);
    return new ResponseEntity<>(new CMRespDto<>(1,"프로필사진변경 성공",null),HttpStatus.OK);
}

js에서 명시한대로 요청을 작성해주고 

 

중요한점

form데이터를 받아와 매개변수에서 MultipartFile로 받을땐 input의 name값과 일치해야 매핑이된다.

profile.jsp에서 우리가 가져온 form태그의 file의 name을 보면 profileImageFile라고 지정이되어있는데 

key와 value로 우리가 값을 받아왔으니 key에 name값이 들어가 이름이 다르면 매핑이 안되는건 당연하니 주의하자!

 

서비스 작성

UserService.java

	@Value("${file.path}")
	private String uploadForder;

	@Transactional
	public User 회원프로필사진변경(int principalId, MultipartFile profileImageFile) {
		UUID uuid = UUID.randomUUID(); // uuid
		String imageFileName= uuid +"_"+profileImageFile.getOriginalFilename(); 
		Path imageFilePath = Paths.get(uploadForder+imageFileName);
		try {
			Files.write(imageFilePath, profileImageFile.getBytes());
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		User userEntity = userRepository.findById(principalId).orElseThrow(()->{
			throw new CustomApiException("유저를 찾을 수 없습니다.");
		});
		userEntity.setProfileimageUrl(imageFileName);
		return userEntity; // 더티체킹으로 저장된다.
		
	}

ImageService할때 사용했던 UUID를 가져와 기입해주고 MultipartFile은 파일 그자체이기 때문에 .getFile()없이 바로 getOriginalFilename()를 사용가능한것이다

업로드될 폴더값도 가져오기위해 file.path가 담긴 @Value도 만들어진 모습이다.

findById로 영속성 컨택스트에 저장된 유저의 정보가있을것이고

영속성 컨텍스트에 저장된 유저의 정보를 set으로 바꿔주면 알아서 DB에도 데이터가 변경될것이다

 

이제 jsp에 사진을 출력해보자

<!--유저이미지-->
<div class="profile-left">
    <div class="profile-img-wrap story-border"
        onclick="popup('.modal-image',${dto.user.id},${principal.user.id })">
        <form id="userProfileImageForm">
            <input type="file" name="profileImageFile" style="display: none;"
                id="userProfileImageInput" />
        </form>

        <img class="profile-image" src="/upload/${dto.user.profileimageUrl }"
            onerror="this.src='/images/person.jpeg'" id="userProfileImage" />
    </div>
</div>
<!--유저이미지end-->

dto에 유저의 데이터가 담겨와 프로필페이지를 구성하니 dto.user.profileimageUrl을 불러온다면 성공적으로 불러올것이다

 

/upload/는 한번더 되새길겸 WebMvcConfig.java를 살펴보자

WebMvcConfig.java

package com.cos.photogramstart.config;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer{ // web 설정 파일

	@Value("${file.path}")
	private String uploadFolder;
	
	@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
			WebMvcConfigurer.super.addResourceHandlers(registry);
			
			// C:/study/springboot/workspace/springbootwork/upload/
			registry
			.addResourceHandler("/upload/**") // jsp페이지에서/upload/** 이런 주소패턴이 나오면 발동
			.addResourceLocations("file:///"+uploadFolder)
			.setCachePeriod(60 * 10 * 6)
						// 60초  10분 6 =1시간 
			.resourceChain(true)
			.addResolver(new PathResourceResolver());
		}
}

 

key=value형태와 FormData형태의 차이

 

우리가 유저 정보를 업데이트할때는 

	let data = $("#profileUpdate").serialize();

위와같이 폼의 데이터를 가져와 ajax처리를하였다

 

하지만

위에서 프로필 사진변경할때는 FormData를 이용해서 데이터를 가져왔는데

	
		let profileImageForm = $("#userProfileImageForm")[0];
		let formdata = new FormData(profileImageForm);

 

유저의 정보를 폼에서 가져올때는 사진이없고(file형태가없음) 정수나 스트링값만 가져왔다

하지만 파일을 받아와 데이터를 전송할때는 무조건 FormData형태로 변환한뒤 보내줘야 성공적으로 보낼 수 있다

꼭 사진이있다면 FormData이고 사진이 없이 그냥 정수나 스트링형태는 위처럼 serialize()를 이용하여 key=value값으로 전달하자 

 

더좋은 방법은 json화 시켜 보내면은 좋지만 아직 배우지 않았으니 넘어가도록하자.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/05   »
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
글 보관함