0. 컨트롤러 매개변수

@RequestParam : 매개변수가 기본형, Stirng은 생략O ( 생략되어있음 )

@ModelAttribute : 매개변수가 참조형은 생략O ( 생략되어있음 )

 


 

1. @RequestParam

@RequestParam : 요청파라미터를 매개변수에 연결할 때 사용

기억
@RequestParam 의 required =true로 파라마미터 필수입력 일 때반드시 예외처리 해야함
required =false로  파라미터 필수입력이 아닐때에는 defaultValue="1" 를 작성해야함

파라미터가 필수인데 파라미없이 요청했으니, 클라이언트에러 400번대

 

파라미터를 주긴줬으니 "" 빈문자열로 잘못주어 클라이언트 에러

 


map에 들어온 값을, MyDate객체와 어떻게 연결하여 셋팅하는지 예제

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");

		// map의 담긴 값(year,month, day)을        Mydate객체와 어떻게 연결(바인딩)해주는지??????
		// dataBind 이라는 메서드가 그작업 을 한다.
	
		
		
		// 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
	}
}


2. @ModelAttribute

적용대상을 Model의 속성으로 자동 추가해주는 어노테이션 ( Model에 자동저장해주는 어노테이션 )
① 매개변수에 적용 O
② 반환타입 적용 O
※ 저장시 별도 지정해주지 않으면 key의 첫글자는 소문자로 저장됨.

내부적으로
1. 컨트롤러메서드 중에 @ModelAttribute가 있는지 검색하여 모두 호출
2. 호출 후 Model에 저장

즉, @ModelAttribute 붙이기만 하면 별도 호출 및 저장(addAttribute) 할 필요가 없다.


3. WebDataBinder

@Controller
public class YoilTellerMVC6 {
	@ExceptionHandler(Exception.class)
	public String catcher(Exception ex, BindingResult result) {
		System.out.println("[BindingResult] : " + result);		
		FieldError error = result.getFieldError();
		System.out.println("[Code] : " + error.getCode());		
		System.out.println("[Field] : " + error.getField());		
		System.out.println("[DefaultMessage] : " + error.getDefaultMessage());		
		//ex.printStackTrace();
		
		return "yoilError";
	}
	
	@RequestMapping("/getYoilMVC6")
	public String main(MyDate date, Model model)  {	
		// 1. 유효성검사
		if(!isValid(date))
			return "yoilError";
		return "yoil";  //ch2/src/main/webapp/WEB-INF/views/yoil.jsp
	}

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

	private boolean isValid(MyDate date) {
		return isValid(date.getYear(),  date.getMonth(), date.getDay());
	}
	
	private boolean isValid(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 - 1, day);
		
		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		return " 일월화수목금토".charAt(dayOfWeek);
	}
}


 

데이터를 전송시 ASCII 가 아닌 것들(한글 등)은 URL인코딩되어 전송된다.

 


회원가입 화면작성

<c:url>은 ① Context root 자동추가
                ② Session id 자동추가

 


 

 

 

 

 

 

 

 

 

 

 


참고 :

남궁성, 스프링의 정석

+ Recent posts