본문 바로가기

백엔드 개발/SpringMVC

@RequestParam과 컨트롤러 매개변수 깔끔정리하기

1. @RequestParam

(1)@RequestParam 이란? 

요청의 파라미터를 Mapping된 Method의 매개변수와 연결시키는 어노테이션

 

하지만 평소에 우리는 해당 어노테이션을 쓰지 않고 바로 매개변수를 적어도, 매소드가 작동했다. 

그 이유는 @RequestParam 자체가 생략 가능하기 때문이다. 생략해도 Spring FrameWork가 자동으로 요청의 파라미터와 매소드의 매개변수를 연결시켜준다. (default: 쓰인 차례대로 1대1)

(2) 구조 

public String main2(@RequestParam(name="year", requried=false) String year) {...}

// 연결할 매개 변수 옆에다가 쓰고, 
// @RequestParam(name="연결할 요청의 파라미터 name", 필수 입력 여부) 연결한 매개변수의 타입 이름
// ()안의 값은 원하는 것만 써도 문제 없음. 전체 생략해버려도 됨.

 

(3) 코드 리뷰

A. 매개 변수의 타입이 String

 : 형 변환 절차를 걸치지 않는다. 따라서 필수입력만 아니라면 null이 들어오든, ""(공백)이 들어오든 에러가 아니다.

 

a. main 2 부분 

필수 입력이 아니기 때문에, URL 다음에 String Query로 요청의 파라미터 값을 적어주지 않아도 된다.(에러가 아님!)

이때 아예 안 적었을 때와 파라미터 name은 적었는데 value를 적지 않았을 때로 나뉜다. 

requestParam2 year 값에 null이 들어간다.
requestParam2/year year에 공백이 들어간다.

b. main 3 부분 

필수 입력이 참이기 때문에 값이 없으면 에러가 난다. 

requestParam3 year에 null이 들어간다. 값이 없으므로 에러가 난다.

404 에러인 이유는 필수 입력이라는 조건을 클라이언트 쪽에서 지키지 않았기 때문에, 클라이언트 잘못 이라서다.
requestParam3/year year="" , 공백이라도 들어갔다. 
값이 들어갔기에  출력은 이상할 수 있지만 에러는 아니다.

B. 매개 변수 타입이 int인 경우

: String query로 들어오는 값은 무조건 String type이므로 값을 받은 후 int로 형 변환하는 절차를 걸친다. 

  그래서 null이나 ""(공백)이 들어오면 형변환 절차를 거칠 수 없기 때문에 에러가 난다. 

a. main8 부분 

  필수 입력은 아니지만 매개변수의 타입이 int 이므로 받은 파라미터 값에 대한 무조건적인 int 형 변환이 이루어진다. 

따라서 위의 설명과 같이 null이나 ""(공백)이 들어오면 형 변환 자체가 안 되기 때문에 에러가 난다. 

누가 책임을 지는가? 에 따라 에러 메세지가 다름(적으려고 시도 -> 클라이언트가 책임진다는 의지 -> 서버 잘못)

requestParam8 year = null 
500(서버 잘못) 에러가 난다. why? 
일단 필수 입력이 아니기에 값을 안 적은 클라이언트 잘못은 아니다. 
반면 null 값이 들어오면 형변환이 안되서 에러가 뜬다는 걸 알면서도 대처하지 않은 서버 잘못이 된다.
requestParam8/year year=""
400(클라이언트 잘못)에러 why? 
클라이언트가 year를 쓰며 값을 적으려는 시도를 했는데, 기입하는 형식이 잘못된 것이다. 
따라서 클라이언트의 기입 방식이 잘못되었음을 알려주며, 다시 적도록 유도 해야한다. 

그런 의미에서 단순 404 error 페이지를 띄우는 것은 바람직하지 않다. 클라이언트의 올바른 작성을 유도하는 페이지를 따로 작성 해서 띄워야 한다.

** null이나 ""(공백)값이 들어왔을 때 대처 방법

//param (안에 defaultValue를 넣어준다. 이는 null이나 ""이 들어왔을 때 대신 들어가는 값이다.)

	@RequestMapping("/requestParam11")   
	public String main11(@RequestParam(required=false, defaultValue="1") int year) {   
//		http://localhost/ch2/requestParam11        ---->> year=1   
//		http://localhost/ch2/requestParam11?year   ---->> year=1   
		System.out.printf("[%s]year=[%s]%n", new Date(), year);
		return "yoil";
	}

b. main 9 

필수 입력이므로, 무조건 안 적은 클라이언트 잘못이다. 

requestParam9 year = null;
400(클라이언트 잘못)
year의 값이 존재하지 않는다는 에러 뜸
requestParam9/year year=""
400(클라이언트 잘못)
year에 기입한 내용의 형식이 잘못 됐다는 에러 뜸

여기선 필수입력이므로, 클라이언트가 값을 적게 독려하는 페이지를 에러 메세지 대신 올려줘야함.

 

C. 클라이언트가 null이나 ""(공백)을 줬을 때 예외처리

위에서 말한 바와 같이, 클라이언트에게 그냥 404 에러 메세지를 띄우면, 그 다음은 어떻게 대처해야할지 클라이언트로서는 대략난감할 것이다. 그래서 에레 메세지 대신 제대로 된 입력을 유도하는 페이지를 대신 띄워서 클라이언트를 독려해야 한다. 

이때 예외 처리 매소드를 이용한다.

// 컨트롤러 클래스 안에 하나의 매소드로서 적어준다. 
// 예외처리 전용 어노테이션을 해준다. ()안에는 어떤 예외에 대한 것인지, 해당 예외의 클래스 파일을 넣는다.
// ()안의 예외가 발생하면, 어노테이션 밑의 매소드가 호출

// 여기선 발생하는 모든 예외에 대해 처리 하기 위해 Exception.class 를 ()안에 넣었다. 
// 따라서 어떤 예외든 yoilError view를 화면에 띄우는 매소드이다.


@Controller
public class RequestParamTest {

    @ExceptionHandler(Exception.class)
	public String catcher(Exception ex) {
		return "yoilError";
	}
    
    /...
}

 

handler 적은 후

2. @RequestMapping 된 매소드의 매개변수들이 너무 많을 때,

     하나의 객체를 써서 묶어 표현하는 예제

// 요청의 파라미터 값을 넣을 객체 Date

package com.fastcampus.ch2;

public class MyDate {
	private int year;
	private int month;
	private int day;
	
	public int getYear() {
		return year;
	}
	public void setYear(int year) {
		this.year = year;
	}
	public int getMonth() {
		return month;
	}
	public void setMonth(int month) {
		this.month = month;
	}
	public int getDay() {
		return day;
	}
	public void setDay(int day) {
		this.day = day;
	}
	@Override
	public String toString() {
		return "MyDate [year=" + year + ", month=" + month + ", day=" + day + "]";
	}
	
	

}

//년월일을 입력하면 요일을 알려주는 프로그램
@Controller
public class YoilTellerMVC4 {


// 예외처리
	@ExceptionHandler(Exception.class)
	public String catcher(Exception ex) {
		ex.printStackTrace();
		return "yoilError";
	}
	
	
	@RequestMapping("/getYoilMVC4")
    
    //Date 객체를 바로 매개변수로 사용. 요청의 파라미터 값을 객체에 넣어주는 것은 Spring이 자동으로 해줌.
		public String main(MyDate date, Model model) {
		
		if(!isVaild(date)) {
			return "yoilError";
		}
		
		char yoil = getYoil(date);
		
        // Model의 Map 장부에 각각 key value로써 적힌다. 
        // 여기서 주의할 점은 Date란 객체 자체가 적힌다는 것이다. 
        // 따라서 View도 Date 객체에서 필요한 변수를 꺼내 쓰도록 수정해줘야 한다.
		model.addAttribute("myDate",date);
		model.addAttribute("yoil", yoil);
		
		return "yoil";
	}
        


// 추가된 함수, Date의 객체에서 변수들을 꺼내, 원래 함수의 매개변수로 집어넣는다. 
// 하청 돌려서 값 얻어냄.
	private boolean isVaild(MyDate date) {
		return isVaild(date.getYear(),date.getMonth(),date.getDay());
	}


	private char getYoil(MyDate date) {
		return getYoil(date.getYear(),date.getMonth(),date.getDay());
	}


	private boolean isVaild(int year, int month, int day) {
		if(year ==-1 || month == -1 || day == -1)
			return false;
		return (1<=month && month<=12) &&(1<=day && day<=31);
	}

	//요일 계산
	private char getYoil(int year, int month, int day) {
		Calendar cal = Calendar.getInstance();
		cal.set(year, month, day);
		
		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		return "일월화수목금토".charAt(dayOfWeek);
	}

}
<%@ page contentType="text/html;charset=utf-8" %>
<html>
<head>
	<title>YoilTellerMVC</title>
</head>
<body>
<h1>year=<%=request.getParameter("year") %> </h1>

<!--JSP 파일도 이 처럼 Date 객체에서 꺼내쓸 수 있게 바뀌어 있음.-->
<h1>${myDate.year}년 ${myDate.month}월 ${myDate.day}일은 ${yoil}요일입니다.</h1>
</body>
</html>

3. 스스로 해보기

(필수 입력 on/off 해서 돌려보기, 예외처리 매소드 만들어보기, 매소드의 매개변수 하나의 객체에 넣고 그 객체를 이용해 매소드 작동시키기)

 

완료

'백엔드 개발 > SpringMVC' 카테고리의 다른 글

회원 가입 화면 작성하기  (0) 2023.03.03
@ModelAttribute 와 WebDataBinder  (0) 2023.03.03
JSP와 서블릿(4)  (0) 2023.03.02
서블릿과 JSP(3)  (0) 2023.03.01
서블릿과 JSP(2) - 서버 안에 저장소에 대하여  (0) 2023.03.01