I leaned/스프링,스프링부트

@RequestParam과 @ModelAttribute

윤재에요 2023. 5. 19. 17:56

@RequestParam

  • 어노테이션 생략 가능
  • 요처으이 파라미터를 연결할 매개변수에 붙이는 애너테이션
  • required: 필수여부를 설정할 수 있음 필수가 아니라면 null로 받아오고(url?year까지 입력하면 빈문자열로 받아옴), 필수인데 안넣으면 400 에러를 반환한다. default는 false
  • defaultValue : 기본값을 설정해줄 수 있다. required가 false일 때 아무 입력을 안주면 null로 들어온다. 이것을 Int등으로 형변환시 에러가 난다(500번대,서버잘못). 이를 방지하기 위해 기본값을 설정해줄 수 있다. 또는 required를 true로 설정한다.
@Controller
public class RequestParamTest {
    @RequestMapping("/requestParam2")
    //	public String main2(@RequestParam(name="year", required=false) String year) {   // 아래와 동일 
        public String main2(String year) {   
    //		http://localhost/ch2/requestParam2         ---->> year=null
    //		http://localhost/ch2/requestParam2?year    ---->> year=""
            System.out.printf("[%s]year=[%s]%n", new Date(), year);
            return "yoil";
        }
        
    @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";
	}
}
  • 객체에 담아서 요청을 받을 때
    • 클래스를 만들어서 데이터를 받아올 수 있다.
    • 파라미터의 변수명으로 MyDate필드에 맞춰서 대입해줌
    • Jsp에서는 year,date등을 myDate.year등으로 수정해줘야 함
@Controller
public class RequestParamTest {
    @RequestMapping("/requestParam2")
    public String main2(MyDate date) {   
			블라블라
        }

아래는 대입해주는 로직을 보기위한 예시

public class SetterCall {
	public static void main(String[] args) throws Exception{
		Map<String, String> map = new HashMap<>();
		map.put("year", "2021");
		map.put("month", "10");
		map.put("day", "1");
		
		Class<?> type = Class.forName("com.fastcampus.ch2.MyDate");

		// MyDate인스턴스를 생성하고, map의 값으로 초기화한다. 
		Object obj = dataBind(map, type);
		System.out.println("obj="+obj); // obj=[year=2021, month=10, day=1]
	} // main

	private static Object dataBind(Map<String, String> map, Class<?> clazz) throws Exception {
		// 1. MyDate인스턴스 생성
//		Object obj = clazz.newInstance(); // deprecated method
		Object obj = clazz.getDeclaredConstructor().newInstance(new Object[0]);

		// 2. MyDate인스턴스의 setter를 호출해서, map의 값으로 MyDate를 초기화
		// 	 2-1. MyDate의 모든 iv를 돌면서 map에 있는지 찾는다.
		// 	 2-2. 찾으면, 찾은 값을 setter로 객체에 저장한다.
		Field[] ivArr = clazz.getDeclaredFields();
		
		for(int i=0;i<ivArr.length;i++) {
			String name = ivArr[i].getName();
			Class<?>  type = ivArr[i].getType();
			
			// map에 같은 이름의 key가 있으면 가져와서 setter호출 
			Object value = map.get(name); // 못찾으면 value의 값은 null
			Method method = null;
			
			try {   // map에 iv와 일치하는 키가 있을 때만, setter를 호출
				if(value==null) continue;
				
				method = clazz.getDeclaredMethod(getSetterName(name), type); // setter의 정보 얻기	
				System.out.println("method="+method);
				method.invoke(obj, convertTo(value, type)); // obj의 setter를 호출
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		
		System.out.println(Arrays.toString(ivArr));
		
		return obj;
	}

	private static Object convertTo(Object value, Class<?> type) {
		// value의 타입과 type의 타입이 같으면 그대로 반환
		if(value==null || type==null || type.isInstance(value))
			return value;
		
		// value의 타입과 type이 다르면, 변환해서 반환
		if(String.class.isInstance(value) && type==int.class) // String -> int
			return Integer.valueOf(""+value);

		return value;
	}

	// iv의 이름으로 setter의 이름을 만들어서 반환하는 메서드("day" -> "setDay")
	private static String getSetterName(String name) {
//		return "set"+name.substring(0,1).toUpperCase()+name.substring(1);
		return "set" + StringUtils.capitalize(name); // org.springframework.util.StringUtils
	}
}

/*
[실행결과]
method=public void com.fastcampus.ch2.MyDate.setYear(int)
method=public void com.fastcampus.ch2.MyDate.setMonth(int)
method=public void com.fastcampus.ch2.MyDate.setDay(int)
[private int com.fastcampus.ch2.MyDate.year, private int com.fastcampus.ch2.MyDate.month, private int com.fastcampus.ch2.MyDate.day]
obj=[year=2021, month=10, day=1]
 */

 

 

@ModelAttribute

  • 적용 대상을 Model의 속성으로 자동 추가해주는 애너테이션
  • 반환 타입 도는 컨트롤러 메서드의 매개변수에 적용가능
  • 아래 첫번째 코드에서 반환타입에 @ModelAttribute("키") 애너테이션을 붙이면 해당키에 호출결과가 담김("yoil":"월")
  • 아래 두번째 코드에서) @ModelAttribute("키")를 써주면 model에 키로 저장함, 안적으면 MyDate의 첫글자를 소문자로 바꿔서 저장함
  • m.addAttribute를 안해줘도 됨
  • 기본형이나 String은 model에 저장안해도 사용가능함(${param.파라미터이름})

 

WebDataBinder

  • 타입변환: 요청에 담긴 데이터 타입과 우리가 사용하는 데이터타입을 맞추어 준다.,결과및 에러를 BindingResult에 저장
  • 데이터검증: validation, ex) 날짜는 1~31가능 34입력들어오면 에러, 결과및 에러를 BindingResult에 저장
  • BindingResult는 바인딩할 객체 바로 뒤에 와야함

 

댓글수0