본문 바로가기
아카이브/스프링

스프링의 정석 (@RequestParam, @ModelAttribute)

by nineteen 2021. 12. 27.
반응형

배운 것

@RequestParam

@ModelAttribute

WebDataBinder

  ㅇ BindingResult  

  ㅇ FieldError

 

내용 정리

 

@RequestParam

 

 

매개변수에 @RequestParam을 붙이면 해당 매개변수를 요청할 때 필수로 입력(required=true)해줘야 함

@Controller
public class YoilTellerMVC {	
	// 예외처리 메소드
	@ExceptionHandler(Exception.class)
	public String catcher(Exception e) {
		e.printStackTrace();
		return "yoilError";
	}
	
	@RequestMapping("/getYoilMVC") 
	// @RequestParam을 붙여서 매개변수 값을 필수로 입력하게 만듦, 입력안하면 -> 에러
	public String main(@RequestParam(required=true) int year, 
			@RequestParam(required=true) int month, 
			@RequestParam(required=true) int day, Model model) throws IOException {
	
		// 유효성 검사
		if(!isValid(year, month, day)) {
			return "yoilError";
		}
				
		// 2. 작업, 요일 계산
		char yoil = getYoil(year, month, day);
		
		// 계산한 결과를 Model에 저장
		// Model에 저장한 결과가 View(yoil.jsp)로 전달
		model.addAttribute("year", year);
		model.addAttribute("month", month);
		model.addAttribute("day", day);
		model.addAttribute("yoil", yoil);
		
		// 출력 결과를 보여줄 jsp파일로 이용해서 작업결과를 보여주라는 의미
		// 3. 출력관심사를 분리함
		return "yoil"; // /WEB-INF/views/yoil.jsp
	}

	private boolean isValid(int year, int month, int day) {
		return true;
	}

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

required=true이면 예외처리를 해주어야 한다

 

required=true인데 값을 주지 않으면 400번대 에러가 발생

 

 

 

매개변수에 @RequestParam을 붙이고 필수 입력(required=false)이 아니면 기본값(defaultValue)을 지정해주어야 함

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

required=false이면 defalutValue값을 주어야 함

 

 

required=false인데 defalutValue를 주지 않으면 500번대 에러 발생

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

null값을 String -> int형으로 변환하라고 했기 때문에 500번대 에러가 발생한 것

 

만약, 변환없이 String형이었다면 에러는 발생하지 않지만 null값을 받게 됨

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

 

 

 

 

 

@ModelAttribute

    - 적용 대상을 Model에 자동 저장해주는 애너테이션

    - 매개변수, 메서드 반환타입에 적용 가능

 

 

메서드 반환타입에 @ModelAttribute를 적용했을 시, Model에 어떻게 저장이 될까?

    - 키 : @ModelAttribute()

    - 값 : 반환결과

private @ModelAttribute("yoil") char getYoil(MyDate mydate) {
		return getYoil(mydate.getYear(), mydate.getMonth(), mydate.getDay());
	}

키 : yoil, 값 : getYoil()메소드 반환결과가 바로 Model에 저장이 됨

 

 

메서드 반환타입에 적용한 @ModelAttribute 애너테이션으로 인해 이 메서드는 자동으로 호출이 됨

알아서 호출되고 작업결과를 알아서 Model에 저장하기 때문에 우리가 메소드를 임의로 호출하고, 작업 결과를 Model에 저장하지 않아도 됨 ( 생략 가능! )

 

 

매개변수에 @ModelAttribute를 적용하면?

@RequestMapping("/getYoilMVC5")
	public String main(@ModelAttribute MyDate date, Model model) throws IOException {
    		...
	}

MyDate타입에 @ModelAttribute애너테이션이 붙어있다.

이렇게 매개변수에 적용하면, Model에 자동으로 저장이 된다.

 

 

기존에 처리 방식은 1. 입력을 받고, 2. 작업을 처리해 Model에 저장하고, 3. 출력을 하는 순으로 진행이 됐었다.

하지만 @ModelAttribute으로 인해 Model에 저장해야하는 부분이 생략 가능하다

@RequestMapping("/getYoilMVC6")
	public String main(@ModelAttribute MyDate date, Model model) throws IOException {
		// 유효성 검사
		if(!isValid(date)) {
			return "yoilError";
		}
				
		// 2. 작업, 요일 계산
		char yoil = getYoil(date);
		
		// 계산한 결과를 Model에 저장
		// Model에 저장한 결과가 View(yoil.jsp)로 전달
		model.addAttribute("myDate", date);
		model.addAttribute("yoil", yoil);
		
		// 출력 결과를 보여줄 jsp파일로 이용해서 작업결과를 보여주라는 의미
		// 3. 출력관심사를 분리함
		return "yoil"; // /WEB-INF/views/yoil.jsp
	}

이렇게 처리했었는데,

 

 

 

@RequestMapping("/getYoilMVC6")
	// 1. 입력
	// @ModelAttribute 생략가능 (참조형)
	public String main(MyDate mydate, Model m) {
		// 유효성 검사
		if(!isValid(mydate))
			return "yoilError";
		
		// 3. 출력
		return "yoil";
	}

2. 작업 처리 부분을 생략할 수 있게 되었다.

-> @ModelAttribute로 작업 처리, 작업 결과를 Model에 저장하는 코드를 간소화할 수 있게 되었다.

 

 

Controller 메소드의 매개변수 타입이 기본형, String일 때는, @RequestParam이 생략되어 있고,

참조형일 때는, @ModelAttribute가 생략되어 있다.

 

//	public String main2(@RequestParam(name="year", required=false) String year) {   // 아래와 동일 
	public String main2(String year) {
    		...
    }

 

 

// public String main(@ModelAttribute MyDate mydate) {  // 아래와 동일
public String main(MyDate mydate) {
		...
}

 

 

 

WebDataBinder

    - 매개변수로 들어온 값들을 자동으로 타입변환 해줌 ex) String -> int

    - 타입 변환 후에 데이터 검증을 함

 

ㅇ 요청으로 들어온 값과 매개변수의 타입이 일치하지 않으면?

    - 타입을 변환하고 결과/에러를 BindingResult에 저장

    - 변환 후에 데이터 검증, 결과/에러를 BindingResult에 저장

    - WebDataBinder가 바인딩한 결과를 BindingResult에 담고 Controller에 넘겨 준다

    - Controller는 작업 결과를 가지고 어떤 에러가 있는지 알 수 있음

// 예외처리 메소드
	@ExceptionHandler(Exception.class)
	public String catcher(Exception e, BindingResult result) {
		System.out.println("result:"+result);
		e.printStackTrace();
        // BindingResult를 이용해 FieldError객체를 얻을 수 있음
        // 이 객체를 통해 에러에 대한 상세정보를 알 수 있음
		FieldError error = result.getFieldError();
		System.out.println("field:"+error.getField());
		System.out.println("code:"+error.getCode());
		System.out.println("msg:"+error.getDefaultMessage());
		return "yoilError";
	}

 

 

 

 

 

 

느낀 점 / 보완할 점

항상 느끼는 거지만, 이론만 주구장창 보지말고, 직접 타이핑해보는 등, 능동적으로 이해하려는 태도가 더 길러져야 함을 느낀다!

 

 

 

 

잘못된 정보가 있다면 지적 부탁드려요