금백조의 개발 블로그

[Spring]Spring에서 PUT, DELETE Method 사용하기 본문

Web/Spring

[Spring]Spring에서 PUT, DELETE Method 사용하기

금백조 2021. 12. 4. 23:09
반응형

서론

 

진행하고 있던 Spring 사이드 프로젝트에서 RESTful 하고 싶은 HTTP API를 만들기 위해 put, delete HTTP Method를 사용하려 했습니다. 단순히 form 태그 안 method 속성을 "put", "delete"로 바꾸고 요청을 시도해보았지만 Controller에 Method 별로 제대로 매핑이 되지 않았습니다. 오늘은 이를 해결한 과정에 대해서 자세히 포스팅하려 합니다.

 

[개발환경]

Spring 4.3.12

openJDK 1.8

 


 

본론

 

HTML form 태그에서는 GET/POST Method만 지원을 합니다. 왜 그런지에 대해서는 아래의 [REST - HTML Form에서 GET/POST만 지원하는 이유] 글에 자세히 나와있기에 링크로 대체하겠습니다.

 

[REST - HTML Form에서 GET/POST만 지원하는 이유]

http://haah.kr/2017/05/23/rest-http-method-in-html-form/

 

REST - HTML Form에서 GET/POST만 지원하는 이유

연재 목록 REST - 긴 여정의 시작 REST - HTML Form에서 GET/POST만 지원하는 이유 REST - 논문(요약) 훑어보기 REST - REST 좋아하시네 REST - Roy가 입을 열다 REST - 당신이 만든 건 REST가 아니지만 괜찮아 REST -

haah.kr

 

따라서 디스패처 서블릿(dispatcher Servlet)이 PUT, DELETE Method를 인식할 수 있도록 Spring Framework의 org.springframework.web.filter 패키지 안에 구현된 HiddenHttpMethodFilter를 사용해야 합니다.

 

[해결책]

 

1. web.xml 에 아래의 코드를 추가하여 HiddenHttpMethodFilter를 활성화합니다.

 

[web.xml]

<!-- HTTP Method Filter -->
 <filter>
    <filter-name>httpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
 </filter>
 <filter-mapping>
    <filter-name>httpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>

 

2.form 태그에서 method 속성을 post 로 하고 form 태그 안 input을 type="hidden" name = "_method"으로 한 후 value 속성에 요청할 HTTP Method를 명시합니다.

 

[example.jsp]

<form id="delete" action="/bulletinboards/newbulletinboard/${bulletinId}" method="post">
 					<input type="hidden" name = "_method" value = "delete"/>
</form>

 

3.Controller에 요청한 HTTP Method가 제대로 매핑되는지 확인합니다.

 

[ExampleController.java]

@PutMapping(value = "/newbulletinboard/{bulletinId}")
	public void updateBulletinboard(Model model, HttpServletRequest req, @PathVariable("bulletinId") String strbulletinId) throws Exception {
		//생략
	}

@DeleteMapping(value = "/newbulletinboard/{bulletinId}")
	public void updateBulletinboard(Model model, HttpServletRequest req, @PathVariable("bulletinId") String strbulletinId) throws Exception {
		//생략
	}

 

form 태그안의 input 태그를 히든으로 하고 name을 _method로 하는 이유?

→ HiddenHttpMethodFilter.class 내부를 디버깅을 해보면 input 태그를 type="hidden" name = "_method" value = "delete"로 한 후 요청하면 doFilterInternal메서드 안에 있는 paramValue에 "delete"가 들어가게 됩니다. 그리고 HttpMethodRequestWrapper 객체를 생성하여 method를 delete로 변경하여 DELETE 요청이 온 것으로 바뀌게 됩니다. 따라서 히든으로 설정한 name이 _"method"인 input 태그의 value 값에 따라 디스패처 서블릿(dispatcher Servlet)에 요청하는 HTTP Method가 결정됩니다.

 

[HiddenHttpMethodFilter.class]

public class HiddenHttpMethodFilter extends OncePerRequestFilter {

	/** Default method parameter: {@code _method} */
	public static final String DEFAULT_METHOD_PARAM = "_method";

	private String methodParam = DEFAULT_METHOD_PARAM;

	/**
	 * Set the parameter name to look for HTTP methods.
	 * @see #DEFAULT_METHOD_PARAM
	 */
	public void setMethodParam(String methodParam) {
		Assert.hasText(methodParam, "'methodParam' must not be empty");
		this.methodParam = methodParam;
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		HttpServletRequest requestToUse = request;

		if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
			String paramValue = request.getParameter(this.methodParam);
			if (StringUtils.hasLength(paramValue)) {
				requestToUse = new HttpMethodRequestWrapper(request, paramValue);
			}
		}

		filterChain.doFilter(requestToUse, response);
	}

	/**
	 * Simple {@link HttpServletRequest} wrapper that returns the supplied method for
	 * {@link HttpServletRequest#getMethod()}.
	 */
	private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {

		private final String method;

		public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
			super(request);
			this.method = method.toUpperCase(Locale.ENGLISH);
		}

		@Override
		public String getMethod() {
			return this.method;
		}
	}

}

 

결론

 

Spring 환경에서 GET, POST Method 이외에 HTTP Method 사용법을 알게 된 좋은 경험이었습니다. 구현된 자세한 소스는 아래 링크에서 확인하실 수 있습니다.

 

https://github.com/GoldSwan/PictureRepository

 

GitHub - GoldSwan/PictureRepository: Web Side Project with Spring

Web Side Project with Spring. Contribute to GoldSwan/PictureRepository development by creating an account on GitHub.

github.com

 

반응형