문제 상황
프로필 이미지를 업로드한 후 <img> 태그의 src로 해당 경로 요청했을 때, 한글이 깨지는 현상이 발생.
연두.png라는 사진 파일을 프로필 이미지로 업로드했고, DB에도 한글로 잘 데이터가 들어가 있는 것을 확인했다. 프로필에서 사용할 수 있는 DTO를 model에 담아서 jsp에 전달해 주는 Controller 로직을 작성했다.
// UserController.java
@GetMapping("/user/{pageUserId}")
public String profile(@PathVariable int pageUserId, Model model, @AuthenticationPrincipal PrincipalUserDetails principal) {
UserProfileDto dto = userService.UserProfile(pageUserId, principal.getUser().getId());
model.addAttribute("dto", dto);
return "user/profile";
}
dto에 담겨있는 데이터 중에서 필자는 dto.user.profileImageUrl을 JSP에서 사용하고자 한다.
// profile.jsp
<img class="profile-image" src="/upload/${dto.user.profileImageUrl}" onerror="this.src='/images/person.jpeg'" id="userProfileImage" />
위처럼 <img>의 src 요청을 보냈더니 콘솔에서 오류가 발생했다. 오류 내용은 아래와 같다.
요청을 원했던 URL
http://localhost:8080/upload/{UUID}_연두.png
실제로 요청된 URL
http://localhost:8080/upload/{UUID}_%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%83%E1%85%AE.png
찾아보니 실제로 요청된 URL은 "연두"라는 한글을 UTF-8 방식으로 인코딩한 후 요청을 보낸 것으로 확인했다. 그럼 내가 원하는 정보는 실제로 요청된 URL에서 "%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%83%E1%85%AE" 이 부분을 다시 UTF-8로 디코딩해서 "연두"로 요청해야 하는 건가...?
해결 사항
근본적인 해결 사항은 아니기 때문에 설정을 건드는 부분은 구글링을 통해서 찾아보시기 바랍니다. 웬만한 키워드로는 다 검색해 본 거 같습니다. "jsp img src 한글 깨짐", "jsp url encoding setting"과 같은 키워드를 통해서 StackOverFlow도 찾아보고 했지만, 대부분 Tomcat 설정 파일을 건드는 방식을 설명했던 거 같아서 아직 시도해보지는 못했습니다. jstl을 이용한 태그도 대부분 사용해 봤지만 통하지 않았습니다.
저는 이렇게 생각을 전환해 봤습니다. "http://localhost:8080/upload/{UUID}_연두.png" 이렇게 요청이 들어가면 한글 부분은 인코딩 되어서 "http://localhost:8080/upload/{UUID}_%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%83%E1%85%AE.png" 실제로는 이렇게 요청이 간다.
그럼 애초에 사진 파일을 저장할 때 UTF-8로 파일명을 인코딩해서 업로드를 진행하면 되지 않을까? 예를 들어 "연두.png"라는 파일을 업로드하고 싶다면 인코딩을 해서 "%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%83%E1%85%AE.png"로 사진 파일을 저장한 후에 DB에도 해당 인코딩된 정보를 저장합니다.
그리고 "http://localhost:8080/upload/{UUID}_%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%83%E1%85%AE.png" 에 요청을 해버리면 되지 않을까?라는 생각으로 코드를 작성해 봤습니다.
가장 먼저 프로필 사진을 저장하는 로직을 가지고 있는 Service 로직을 변경했습니다.
// UserService.java
@Transactional
public User profileImageUrlUpdate(int principalId, MultipartFile profileImageFile) {
UUID uuid = UUID.randomUUID();
String originalName = profileImageFile.getOriginalFilename();
String imageFileName = uuid + "_" + originalName;
...
}
기존 로직은 위와 같습니다. 사진 파일명이 동일한 문제를 발생시키지 않기 위해서 UUID를 생성해 줬고, 실제 파일의 이름을 받아왔습니다. "연두.png"라면 originalName은 "연두.png"가 될 것입니다. 그러고 나서 imageFileName에 UUID와 originalName을 언더바(_)로 구분하여 저장했습니다.
최종적으로 폴더에 저장되는 이름은 {UUID}_연두.png 입니다. 여기서 originalName 밑에 UTF-8 방식으로 인코딩하는 코드를 더 추가해 줬습니다.
import java.net.URLEncoder;
@Transactional
public User profileImageUrlUpdate(int principalId, MultipartFile profileImageFile) {
UUID uuid = UUID.randomUUID();
String originalName = profileImageFile.getOriginalFilename();
try {
originalName = URLEncoder.encode(originalName, "UTF-8");
} catch (UnsupportedEncodingException exception) {
throw new CustomApiException(exception.getMessage());
}
String imageFileName = uuid + "_" + originalName;
...
}
URLEncoder를 사용해 "연두.png"를 "%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%83%E1%85%AE.png"으로 인코딩하여 저장했습니다. 아래는 폴더에 업로드된 사진 파일입니다.
이제 기존 JSP 코드 그대로 요청을 해봅시다.
원하는 이미지 파일이 잘 가져와지는 것을 볼 수 있습니다. 원래는 JSP와 SpringBoot의 원리를 바탕으로 한 번 해결법을 찾아보려 했지만 로직을 변경해서도 해결할 수 있을 거 같다는 생각에 한 번 도전해 봤습니다.
물론 효율적이고 좋은 방법은 아닐지 모르지만 많은 자료를 구글링 해보는 과정에서 조금이라도 배움을 얻었다고 생각합니다. 구글링 하면서 찾은 사이트인데 원하는 방식으로 직접 인코딩, 디코딩해볼 수 있는 사이트를 아래 달아두겠습니다. 사용하기 괜찮은 거 같습니다!
URL Encode and Decode - Online
Encode to URL-encoded format or decode from it with various advanced options. Our site has an easy to use online tool to convert your data.
www.urlencoder.org
'🧑🏻💻 Dev > 오류해결' 카테고리의 다른 글
Mustache 사용해서 html 파일 읽을 때 한글 깨짐 (0) | 2023.06.08 |
---|---|
[오류해결] IntelliJ 커스텀 properties 자동완성 안되는 오류 (0) | 2023.04.27 |
[오류해결] No serializer found for class (InvalidDefinitionException) (0) | 2023.04.20 |
[오류해결] 로컬에 있는 이미지 파일 JSP에서 사용하기 (0) | 2023.03.02 |
[MAC M1] MariaDB ERROR 2002 (HY000): Can't connect to local server through socket '/tmp/mysql.sock' 해결 (3) | 2023.02.28 |