Server/Spring

Spring - 컨트롤러(Controller) 구현

JaeHoney 2021. 1. 1. 20:49

GET / POST 방식 구현

@Controller
public class RegisterController {

	@PostMapping("/submitReg") // GetMapping("/submitReg")
	public String register() {
		return "submitReg";
	}
}

POST 방식으로 통신하려면 @PostMapping을 사용하고 GET 방식은 @GetMapping을 사용합니다. 각각 작성하면 전송 방식에 따라 다른 메서드가 처리하게 구현할 수도 있습니다 (메서드 이름은 경로와 상관없기 때문). 전송 방식에 상관없이 지정한 경로와 일치하는 요청을 처리하고 싶다면 @RequestMapping을 사용합니다.

 

+스프링 4.2 버전 까지는 @RequestMapping의 method 속성을 이용해서 전송 방식을 지정합니다.

<body>
	<form action="register" method="post">
	... 내용
	</form>
</body>
    

서버에게 폼을 보낼 때는 method 방식을 post/get로 지정해줘야 됩니다. action에는 폼 데이터를 전송할 url을 위치시킵니다. 폴더 관리나 상황에 따라 위와 달라질 수 있습니다.

 

요청 파라미터 사용

<input type="text" name="id">

어떤 페이지에서 id를 입력하고 그 값을 서버에서 가져와 처리하고 싶을 땐 아래와 같은 방법들이 있습니다.

// 1번 방법
@PostMapping("/submitReg") // GetMapping("/submitReg")
public String register(HttpServletRequest request) {
	String userId = request.getParameter("id");
	// ...생략
    	return "submitReg";
}

HttpServletRequest의 getParameter() 메서드를 이용해서 파라미터 값을 직접 구할 수 있습니다.

// 2번 방법
@PostMapping("/submitReg")
public String register(
	@RequestParam(value = "id", require = "true") String userId,
	Model model) {
		// ...생략
        	return "submitReg";
}

요청 파라미터가 많지 않다면 @RequestParam 애노테이션을 이용해서 간단하게 값을 구할 수도 있습니다. 기본 데이터 타입 및 Wrapper 타입으로 타입 변환도 지원합니다.

 

두 가지 방식 다 http://주소/submitReg?id=ㅇㅇㅇ 이라는 요청이 오면 ㅇㅇㅇ값을 userId라는 변수 / 파라미터에 넣어서 사용합니다.

 

@requestParam는 value와 require 외에도 defaultValue라는 속성이 있는데, 요청 파라미터가 값이 없을 때 지정한 기본값으로 설정합니다. 

 

커맨드 객체

@PostMapping("/submitReg") 
public String register(HttpServletRequest request) {
	String id = request.getParameter("id");
    	String pwd = request.getParameter("pwd");
    	String pwdCheck = request.getParameter("pwdCheck");
    	String email = request.getParameter("email");
        
        RegisterRequest reg = new RegisterRequest();
        reg.setId(id);
        reg.setPwd(pwd);
        reg.setEmail(email);
	// ...생략
    	return "submitReg";
}

요청 파라미터를 위 방식으로 구할 때 작동은 정상적으로 하지만, 파라미터 개수가 증가함에 따라 코드가 길어지고 유지보수가 힘들어집니다. 그래서 스프링은 커맨드(command) 객체를 제공합니다.

@Controller
public class RegisterController {

    // ...생략

    @PostMapping("/submitReg")
    public String handleSubmit(RegisterRequest regReq) {
        memberRegisterService.register(reqReq);
        return "submitReg";
    }

}

스프링 MVC는 매핑 메서드의 파라미터 타입 클래스에 있는 Setter 메서드들을 이용해서 email, id, pwd, pwdCheck 요청 파라미터의 값을 커맨드 객체에 복사한 후, 파라미터 객체로 전달합니다. 따라서, 파라미터로 생성한 regReq 객체는 필드값으로 요청 파라미터들을 가지고 있는 상태가 됩니다.

public class RegisterRequest {

	private String email;
	private String pwd;
	private String pwdCheck;
	private String id;

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getPwdCheck() {
		return pwdCheck;
	}

	public void setPwdCheck(String pwdCheck) {
		this.pwdCheck = pwdCheck;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
}

파라미터인 RegisterRequest 클래스입니다. 커맨드객체를 사용할 때는 Setter 메서드와 Getter 메서드를 구현해야하고 속성들의 이름과 메서드들의 이름을 주의해서 사용해야합니다. (직접 작동시키지 않고 스프링에서 관리해주기 때문) 

<h1>${registerRequest.Email}</h1>

JSP에서 커맨드 객체를 꺼내서 사용하려면 위와 같이 ${}안에 커맨드 객체의 속성값을 사용하면됩니다. 커맨드 객체의 이름은 클래스명에서 첫글자만 소문자로 해서 생성됩니다.

<input type="text" name="email" id="email" value="${registerRequest.email}

위 형식을 사용하면, 회원가입이 실패했을 때 입력했던 내용들이 날라가지 않도록 할 수 있습니다. (제출하면서 입력했던 내용을 커맨드 객체에 넣었고, 다시 페이지가 로드 하면 그것을 다시 불러옴)

@Controller
public class RegisterController {

    private MemberRegisterService memberRegisterService;

    public void setMemberRegisterService(
        MemberRegisterService memberRegisterService) {
            this.memberRegisterService = memberRegisterService;
    })

    @PostMapping("/submitReg")
    public String handleSubmit(RegisterRequest regReq) {
        memberRegisterService.regist(regReq); // DB에 입력(회원 가입)
        return "submitReg";
    }

}

회원가입을 위한 MemberRegisterService라는 클래스와 regist 메서드를 만들었습니다(생략). /submitReg로 POST 요청이 들어올 때 regist 메서드가 실행됩니다. 이 때 요청 파라미터들을 필드로 가진 커맨드객체 regReq를 인자로 사용합니다. 

 

스프링 MVC가 제공하는 커스텀 태그를 이용한 커맨드 객체

<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
    <title>회원가입</title>
</head>
<body>
    <h2>회원 정보 입력</h2>
    <form:form action="submitReg" modelAttribute="registerRequest">
    <p>
        <label>이메일:<br>
        <form:input path="email" />
        </label>
    </p>
    <p>
        <label>비밀번호:<br>
        <form:password path="pwd" />
        </label>
    </p>
    <input type="submit" value="가입 완료">
    </form:form>
</body>
</html>

2번째 줄에 <%$ taglib prefix="form" uri... %>는  스프링 MVC가 제공하는 커스텀 폼 태그를 사용하기 위한 디렉티브를 설정하는 코드입니다.

 

<form:form>은 HTML의 <form>태그를 커스텀한 태그입니다. 차이점은 modelAttribute 속성에서 사용할 커맨드 객체를의 이름을 입력합니다. 기본 값은 "command"입니다.

 

<form:input>은 HTML의 <input>태그를 커스텀한 태그입니다. path에 커맨드 객체의 속성의 이름을 입력합니다. 그러면, <input id="[속성명]" name="[속성명]" type="text" value="[속성값]" />과 같은 결과를 얻게 됩니다.

<form:password>는 <input>태그의 type값이 "password"입니다.

@Controller
public class RegisterController {

    // ...생략

    @GETMapping("/register")
    public String handleRegister(Model model) {
        model.addAttribute("registerRequest", new RegisterRequest());
        return "register";
    }
    
}

<form:form>같은 커스텀 태그를 사용하려면 그 시점에 커맨드 객체가 존재해야 합니다. 따라서, 매핑할 때 Model을 만들어서 속성으로 커맨드객체를 추가해야 정상적으로 동작합니다.

@Controller
public class RegisterController {

    // ...생략

    @GETMapping("/register")
    public String handleRegister(RegisterRequest registerRequest) {
        return "register";
    }
    
}

Model에 직접 커맨드 객체를 추가하는 것이 아닌 커맨드 객체를 파라미터로 사용하는 방법도 있습니다.