HTTP 통신에서 파라미터 값을 배열로 전달하고 싶다면 HTML form 태그의 name 속성을 같은 이름으로 작성합니다.
<form action="/test" method="GET">
<input type="text" name="test[]" value="test1"> Tag 1<br>
<input type="text" name="test[]" value="test2"> Tag 2<br>
<input type="text" name="test[]" value="test3"> Tag 3<br>
<input type="submit" value="Submit">
</form>
name에 대괄호[]는 반드시 적어야 하는 것은 아닙니다.
스프링의 Controller에서는 다음과 같이 배열 또는 리스트를 사용하여 이를 받습니다.
@PostMapping("/test")
public String result(@RequestParam(name = "test[]") String[] test) {
// 컨트롤러 코드
}
@PostMapping("/test")
public String result(@RequestParam(name = "test[]") List<String> test) {
// 컨트롤러 코드
}
이렇게 하면 form 태그에서 test[]
를 이름으로 사용하였던 모든 값이 배열 형태로 전달되게 됩니다.
그런데 개발하던 중 한 문장만 보냈는데 두 개의 문장이 전달되어 버리는 문제가 있었습니다. 관련된 문제를 구글링해도 잘 나오지 않아 한참동안 console.log()
와 System.out.println()
을 찍어보던 중 원인을 찾을 수 있었습니다.
앞선 예시 코드를 form에서는 여전히 배열처럼 전송하지만, Controller에서는 일반 문자열처럼 매핑한다면 어떻게 될까요?
@PostMapping("/test")
public String result(@RequestParam(name = "test[]") String test) {
System.out.println("test = " + test);
}
실행 결과:
test = test1, test2, test3
배열로 보낸 값을 일반 문자열로 받아본다면, 배열 내 값은 쉼표로 구분된다는 점을 알 수 있었습니다. 이에 관련되어 구글링을 더 해보니 다음 사실을 알 수 있었습니다:
따라서 전달한 문자열 속에 쉼표가 있다면 이를 배열 구분자로 취급해 버릴 수 있습니다.
이를 해결하기 위한 해결책 중 하나로 파라미터의 내용을 인코딩하여 전송하는 방법이 있습니다.
function encodingText() {
var testTexts = document.getElementsByName("test[]");
for (var i = 0; i < testTexts.length; i++) {
testTexts[i].value = encodeURIComponent(testTexts[i].value);
}
}
encodeURIComponent()
는 , ? &
와 같은 특수 문자를 인코딩하여 전송하기 때문에 안전하게 전송할 수 있습니다. 또한 Spring에서의 쉼표 문제뿐만 아니라 본래 함수 목적으로, 특수문자와 예약문자를 포함한 문자열을 안전한 URL로 변환할 수 있습니다.
Java에서는 다음과 같이 디코딩합니다.
@PostMapping("/test")
public String result(@RequestParam(name = "test[]") List<String> test) {
List<String> decodedStrings = new ArrayList<>();
for (String encodedString : test) {
try {
decodedStrings.add(URLDecoder.decode(encodedString, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
// 이후 디코딩된 텍스트 사용 코드. . .
}
URLDecoder
클래스를 사용하여 디코딩합니다.