배운 것
@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";
}
느낀 점 / 보완할 점
항상 느끼는 거지만, 이론만 주구장창 보지말고, 직접 타이핑해보는 등, 능동적으로 이해하려는 태도가 더 길러져야 함을 느낀다!
잘못된 정보가 있다면 지적 부탁드려요
'아카이브 > 스프링' 카테고리의 다른 글
스프링의 정석 ( redirect / forward ) (0) | 2021.12.28 |
---|---|
스프링의 정석 ( @GetMapping, @RequestMapping, URL인코딩 ) (0) | 2021.12.27 |
스파르타 코딩클럽 [ 웹개발의 봄, Spring ] - 1주차 (0) | 2021.12.26 |
스프링의 정석 (서블릿과 JSP) (0) | 2021.12.24 |
스프링의 정석 (관심사 분리와 MVC패턴) (0) | 2021.12.24 |