@RequestParam 배열 전달 시 자동으로 split 되는 문제

udonehn·2024년 4월 8일
0

배열로 파라미터 전달 방법

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에 대괄호[]는 반드시 적어야 하는 것은 아닙니다.

@RequestParam를 사용한 매핑

스프링의 Controller에서는 다음과 같이 배열 또는 리스트를 사용하여 이를 받습니다.

@PostMapping("/test")
public String result(@RequestParam(name = "test[]") String[] test) {
	// 컨트롤러 코드
}
@PostMapping("/test")
public String result(@RequestParam(name = "test[]") List<String> test) {
	// 컨트롤러 코드
}

이렇게 하면 form 태그에서 test[]를 이름으로 사용하였던 모든 값이 배열 형태로 전달되게 됩니다.

쉼표를 포함하면 자동으로 split되는 문제?

그런데 개발하던 중 한 문장만 보냈는데 두 개의 문장이 전달되어 버리는 문제가 있었습니다. 관련된 문제를 구글링해도 잘 나오지 않아 한참동안 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

배열로 보낸 값을 일반 문자열로 받아본다면, 배열 내 값은 쉼표로 구분된다는 점을 알 수 있었습니다. 이에 관련되어 구글링을 더 해보니 다음 사실을 알 수 있었습니다:

  1. 톰캣은 전달받은 배열 파라미터를 쉼표로 구분한다.
  2. @RequestParam는 쉼표로 구분된 문자열을 배열로 반환한다.

따라서 전달한 문자열 속에 쉼표가 있다면 이를 배열 구분자로 취급해 버릴 수 있습니다.

해결방법

이를 해결하기 위한 해결책 중 하나로 파라미터의 내용을 인코딩하여 전송하는 방법이 있습니다.

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 클래스를 사용하여 디코딩합니다.

profile
안녕하세요. 만나서 반갑습니다.

0개의 댓글

관련 채용 정보