Backend/Spring

[Thymeleaf]HTML Form 태그로 서버에 Multipart 형식의 데이터 전송하기(+로그인 인증문제 해결)

Chung-A 2021. 2. 3. 00:33

 

Thymeleaf 로 뷰를 만들다 보면 JavaScript 의 ajax가 아닌 HTML Form태그 만으로 데이터 전송을 해야할 때가 있다.

 

이 때 로그인 인증을 위한 csrf 토큰을 보냄과 동시에 multipart 로 데이터와 이미지를 동시에 보내야 하는 상황이여서 막막했던 차에 좋은 해결 방법을 찾아서 공유한다.

 

우선 소스코드는 아래와 같다.

 

<form name="form" action="url" method="post"
      enctype="multipart/form-data">
    <input type="hidden" name="_csrf" th:value="${_csrf.token}">
    <input type="hidden" name="_csrf_header" th:value="${_csrf.headerName}"/>

    <span>
                    텍스트 <span class="required">*</span>
                </span>
    <input type="text" class="input-field" id="data" name="data"/>

    <span>
                    이미지 <span class="required">*</span>
                </span>
    <input type="file" name="image" id="image" accept="image/*">
    <label>
                <span>
                </span>
        <input type="submit" value="Submit"/>
    </label>
</form>

 

1. 로그인 세션 문제

흔히 웹사이트들은 권한이 필요한 페이지들은 유저들이 로그인 한 정보를 토큰으로 남기고 이 토큰을 같이 전송해서 로그인 한 유저가 보낸 요청이라는 것을 서버에 알린다.

 

ajax 에서는 beforeSend 를 통해 미리 토큰을 보내 해결할 수 있지만 form 태그에서는 어떻게 보낼 지 막막하던 차에

hidden 으로 input 을 넣고 value 를 thymeleaf의 th:value 를 이용하여 토큰을 보내면 해결 된다는 것을 알게 되었다.


2. multipart 전송 문제

데이터를 보낼 때 이미지와 input 데이터를 같이 보낼 때는 form 태그에 enctype="multipart/form-data" 를 넣어주면 된다.

 

이 때 각 input 에서 name 값을 뭘로 설정하였는지가 중요하다.

 


위와 같이 HTML 뷰 코드를 만들었다면 서버에서 데이터를 받아오는 것은 간단하다.

Spring Controller 단에서 보낸 데이터를 받아 올 때는 아래와 같이 어노테이션을 넣어주면 된다.

    @PostMapping(value = "/url")
    public String formData(@ModelAttribute DTO dto, @RequestPart MultipartFile image) {
		...
    }

@ModelAttribute 는 생략 가능하며 DTO 객체 안에 뷰에서 보낼때 사용한 input 필드 name인 data라는 필드가 있다면 값이 자동으로 매핑된다.

 

Multipart로 나눠서 보낸 이미지 데이터의 경우, @RequestPart 로 이미지가 있는 파일을 가져올 수 있다.

 

사실 이 @RequestPart 를 사용하면 Multipart 라는 것 자체가 HTTP Request Body 내부에 여러 part 로 데이터를 영역을 나눠서 넣었다는 의미이기 때문에 변수 명만 맞춰서 적어주면 사진이 여러장이여도, 원하는 데이터를 지정해서 가져올 수 있다.