본문 바로가기

🧑🏻‍💻 Dev/오류해결

[오류해결] JSP img GET 요청 시 한글 깨짐

문제 상황

프로필 이미지를 업로드한 후 <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"으로 인코딩하여 저장했습니다. 아래는 폴더에 업로드된 사진 파일입니다.

{UUID}_%E1%84%8B%E1%85%A7%E1%86%AB%E1%84%83%E1%85%AE.png 으로 저장된 사진 파일

이제 기존 JSP 코드 그대로 요청을 해봅시다.

프로필 사진이 변경된 모습

원하는 이미지 파일이 잘 가져와지는 것을 볼 수 있습니다. 원래는 JSP와 SpringBoot의 원리를 바탕으로 한 번 해결법을 찾아보려 했지만 로직을 변경해서도 해결할 수 있을 거 같다는 생각에 한 번 도전해 봤습니다. 

 

물론 효율적이고 좋은 방법은 아닐지 모르지만 많은 자료를 구글링 해보는 과정에서 조금이라도 배움을 얻었다고 생각합니다. 구글링 하면서 찾은 사이트인데 원하는 방식으로 직접 인코딩, 디코딩해볼 수 있는 사이트를 아래 달아두겠습니다. 사용하기 괜찮은 거 같습니다!

 

https://www.urlencoder.org/

 

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