본문 바로가기

Spring

[Spring] Spring HTTP 기반 데이터 요청 (HttpServletRequest, @RequestParam, Command Object)

 

[해당 포스트는 개인적으로 공부를 하고 차후에 참고용으로 하고자 작성한 것입니다.
따라서 잘못된 부분이나 부족한 부분이 있을 수 있기에 참고하시기 바랍니다.]

로그인이나 회원가입, 게시글 등록 등 View에서 사용자가 데이터를 입력하여 Server에 저장하고자 할 때 데이터를 추출할 수 있어야 한다. 이러한 처리를 위해 Spring에선 HTTP Servlet을 통해 HTTP 요청을 처리한다.

Client가 HTTP 요청을 하면 Spring은 Servlet을 통해 HTTP 요청을 인식하여 Controller에게 작업을 할당시켜준다. Controller는 HTTP 요청 중 데이터 전송이 있으면 이를 받아와 Service에게 넘겨주어 DB와 통신을 하게 된다. 이후 DB 결과를 Model을 이용하여 View에게 넘겨준다.

이러한 일련의 작업을 통해 Spring은 최종 View를 Client에게 넘겨주고 HTTP Request 작업이 끝나게 된다.

 

이번 포스팅에선 HTTP Request가 발생했을 때 Client의 데이터를 추출하는 방법에 대해 알아보도록 하자.

 

HttpRequestServlet

HTTP Servlets을 위한 요청 정보를 제공하기 위해 ServletRequest를 상속한다.

ServletRequest 객체는 Parameter 이름과 값, Attributes 그리고 Input Stream을 포함한 데이터를 제공하는데, Client 요청 정보를 Servlet에게 제공하기 위해 객체를 정의해야 한다. 
이후 Servlet Container는 HttpServletRequest 객체를 생성하고 Servlet의 Service 메서드에게 인자로서 전달한다.

 

아래의 예제는 Login을 하기 위한 Java 코드이다.

 

@RequestMapping(value="/memLogin", method=RequestMethod.POST)
public String memLogin(Model model, HttpServletRequest request) {
		
	String memId = request.getParameter("memId");
	String memPw = request.getParameter("memPw");
		
	Member member = service.memberSearch(memId, memPw);
		
	try {
		model.addAttribute("memId", member.getMemId());
		model.addAttribute("memPw", member.getMemPw());
	} catch (Exception e) {
		e.printStackTrace();
	}
    
	return "memLoginOk";
}

 

HttpServletRequest는 Interface Type이기 때문에 Method 인자를 통해 사용가능하다.

ServletRequest를 상속받았기에 addAttribute Method를 사용 가능하며 JSP나 HTTP로 넘어온 데이터의 Name을 통해 데이터를 가져올 수 있다.

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Login</h1>
	<form action="/app/member/memLogin" method="post">
		ID : <input type="text" name="memId" ><br>
		PW : <input type="password" name="memPw" ><br>
		<input type="submit" value="Login" >
	</form>
	<a href="/app/resources/html/memJoin.html">JOIN</a> &nbsp;&nbsp; <a href="/app/resources/html/index.html">MAIN</a>
</body>
</html>

 

HTTP에서 2개의 Input Tag를 생성하여 이름을 memId, memPw를 지정한다.

action은 memLogin Controller에게 POST 방식으로 전송한다.

Controller는 ServletRequest의 getParameter를 호출하여 데이터를 가져와 처리하게 된다.

 

@RequestParam

Spring MVC에서 단일 파라미터를 쉽게 가져올 수 있는 방법 중 하나가 RequestParam Annotation을 사용하는 것이다.

RequestParam은 하나이상의 Type을 지정할 수 있으며 파라미터 방식으로 사용된다.

 

@RequestMapping(value="/memLogin", method=RequestMethod.POST)
public String memLogin(Model model, @RequestParam("memId") String memId,
		@RequestParam("memPw") String memPw) {
			
	Member member = service.memberSearch(memId, memPw);
			
	try {
		model.addAttribute("memId", member.getMemId());
		model.addAttribute("memPw", member.getMemPw());
	} catch (Exception e) {
		e.printStackTrace();
	}
    
	return "memLoginOk";
}

 

이번 예제에선 HTTPRequestServlet Interface를 사용하지 않고 @RequestParam으로 HTTP 요청 값을 받아왔다.

RequstParam에서 사용할 수 있는 Type은 다음과 같다.

 

@RequestParam(value="value", required=boolean type, defaultValue="default Value") 

 

RequestParam Type으로 HTTP 요청 Value를 지정할 수 있는데, 해당 Value를 기반으로 데이터를 가져올 수 있다. 가져온 데이터는 우측에 지정된 파라미터에 저장된다.

 

추가적인 Type으론 requireddefaultValue가 존재한다.

required가 true일 경우 HTTP 요청으로부터 무조건 값이 넘어와야 한다. false일 경우 값이 넘어오지 않아도 된다. 해당 Type을 지정하지 않을 경우 default로 true가 된다. 따라서 @RequestParam에서 지정한 Value가 존재하지 않을 경우, BadRequest로 HTTP 4** Error 가 발생할 수 있으니 오타가 나지 않도록 해야 한다.

 

defaultValue는 HTTP 요청으로부터 값이 넘어오지 않았을 때 초기화시켜주는 값이 들어간다.

 

Command Object

만약 HTTP 요청으로 넘어오는 데이터가 10개에서 20개를 넘어 100개까지 지정된다고 가정해보자. HttpServletRequest 방식이나 @RequestParam은 100줄이 넘는 코드를 작성해야 하기 때문에 코드가 지저분해진다. 이러한 문제점을 해결하기 위해 Spring에선 Command Object (Command 객체)를 지원한다.

Command Object는 HTTP에서 들어오는 각 속성 값들을 Command 객체에 자동적으로 바인딩하여 처리할 수 있다.

 

다음과 같이 회원가입을 하는 HTML 파일이 존재한다고 하자.

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Member Join</h1>
	<form action="/app/member/memJoin" method="post">
		ID : <input type="text" name="memId" ><br />
		PW : <input type="password" name="memPw" ><br />
		MAIL : <input type="text" name="memMail" ><br />
		PHONE : <input type="text" name="memPhone1" size="5"> -
				<input type="text" name="memPhone2" size="5"> -
				<input type="text" name="memPhone3" size="5"><br />
		<input type="submit" value="Join" >
		<input type="reset" value="Cancel" >
	</form>
	<a href="/app/resources/html/login.html">LOGIN</a> &nbsp;&nbsp; <a href="/app/resources/html/index.html">MAIN</a>
</body>
</html>

 

만약 데이터를 HttpServletRequest 방식으로 데이터를 가져온다면 다음과 같은 코드가 될 것이다.

 

@RequestMapping(value="/memJoin", method=RequestMethod.POST)
public String memJoin(Model model, HttpServletRequest request) {
	String memId = request.getParameter("memId");
	String memPw = request.getParameter("memPw");
	String memMail = request.getParameter("memMail");
	String memPhone1 = request.getParameter("memPhone1");
	String memPhone2 = request.getParameter("memPhone2");
	String memPhone3 = request.getParameter("memPhone3");

	service.memberRegister(memId, memPw, memMail, memPhone1, memPhone2, memPhone3);
	
	model.addAttribute("memId", memId);
	model.addAttribute("memPw", memPw);
	model.addAttribute("memMail", memMail);
	model.addAttribute("memPhone", memPhone1 + " - " + memPhone2 + " - " + memPhone3);
	
	return "memJoinOk";
}

 

불필요하게 코드가 6줄이나 늘어났다.

그러나 Command Object 방식을 사용하면 다음과 같이 처리를 할 수 있다.

 

@RequestMapping(value="/memJoin", method=RequestMethod.POST)
public String memJoin(Member member) {

	service.memberRegister(member.getMemId(), member.getMemPw(),
			member.getMemMail(), member.getMemPhone1(),
			member.getMemPhone2(), member.getMemPhone3());
	
	return "memJoinOk";
}

 

인자로 Binding 시켜줄 객체를 지정 한 번이면 끝이다.

HTTP 요청으로부터 데이터를 가져올 수 있으며 Model에 데이터를 자동으로 저장시켜 HTML로 넘겨줄 수 있다.

Binding 할 땐 Command Object와 요청하는 ID 이름이 서로 같아야 가능하며 Command Object는 Getter / Setter를 지정해야 사용할 수 있다.

 

public class Member {
	private String memId;
	private String memPw;
	private String memMail;
	private String memPhone1;
	private String memPhone2;
	private String memPhone3;

	public String getMemId() {
		return memId;
	}

	public void setMemId(String memId) {
		this.memId = memId;
	}

	public String getMemPw() {
		return memPw;
	}

	public void setMemPw(String memPw) {
		this.memPw = memPw;
	}

	public String getMemMail() {
		return memMail;
	}

	public void setMemMail(String memMail) {
		this.memMail = memMail;
	}

	public String getMemPhone1() {
		return memPhone1;
	}

	public void setMemPhone1(String memPhone1) {
		this.memPhone1 = memPhone1;
	}

	public String getMemPhone2() {
		return memPhone2;
	}

	public void setMemPhone2(String memPhone2) {
		this.memPhone2 = memPhone2;
	}

	public String getMemPhone3() {
		return memPhone3;
	}

	public void setMemPhone3(String memPhone3) {
		this.memPhone3 = memPhone3;
	}
}

 

HTML에서 데이터를 가져올 땐 객체 형태로 값을 호출하면 된다.

 

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h1> Member Join Ok! </h1>
	ID : ${member.memId}<br/>
	PW : ${member.memPw}<br/>
	Mail : ${member.memMail}<br/>
	Phone : ${member.memPhone1} - ${member.memPhone2} - ${member.memPhone3}<br/>
	
	<a href="/app/resources/html/memJoin.html">Go MemberJoin</a>
</body>
</html>