java.util.Date
> java.util.Calendar
> java.time(org.joda.time)
LocalDate currentDate = LocalDate.now();
LocalDate targetDate = LocalDate.of(2020,03,03);
LocalTime currentTime = LocalTime.now();
LocalTime targetTime = LocalTime.of(14,22,33,22);
// 끝에 4번째 매개변수는 nanoSecond로 Optional이다.
// 14:22:33.0000022
LocalDateTime currentDateTime = LocalDateTime.now();
LocalDateTime targetDateTime = LocalDateTime.of(2019, 11, 12, 12, 32,22,3333);
// second,nanoSecond 매개변수는 필수가 아닌 선택
// 2020-03-03T14:32:22.000003333
@DateTimeFormat
어노테이션으로 스트링값을 DATETIME 포맷으로 변환하여 쉽게 객체에 입력 가능
아래의 코드는 "2020030314"의 문자열을 "2020년 3월 3일 14시" 값을 가지는 LocalDateTime 객체로 변환해준다.
public class DateCommand {
@DateTimeFormat(pattern = "yyyyMMddHH")
private LocalDateTime from;
@DateTimeFormat(pattern = "yyyyMMddHH")
private LocalDateTime to;
}
만약 패턴에 맞지 않는 String을 입력 시 에러가 발생한다.
이런 형식에 대한 변환 처리는 WebDataBinder
가 맡는다.
WebDataBinder
는 이러한 날짜 변환 처리, 요청 파라미터-커맨드 객체 사이의 변환 처리 등 다양한 변환 처리를 한다.
이 처리는 직접 하지 않고, DefaultFormattingConversionService
에 역할을 위임하여 처리한다.
특정 id값에 대한 요청을 할 때 두 가지 방식으로 id 값을 넘길 수 있다.
이러한 방식은 REST API에 대한 이해를 통해 알 수 있다. 두 방식은 어디에 어떤 데이터(명사)를 요청하는 것인지 명확하게 정의하기 위해 사용한다.
어떤 자원(데이터)의 위치를 특정해서 보여줘야 할 경우 Path variable을 쓰고, 정렬하거나 필터해서 보여줘야 할 경우에 Query parameter를 쓴다.
아래는 그 예시로, 전체 리스트나 리스트 중 특정 부분을 필터링 할 경우 Query String을 쓰고, 특정 id값만 조회할 때 Path Variable을 쓰기로 약속하여 사용한다.
/users # Fetch a list of users
/users?occupation=programer # Fetch a list of programer user
/users/123 # Fetch a user who has id 123
위와 같은 방식으로 어디에 어떤 데이터(명사)를 요청하는 것인지 명확하게 정의하게 되고, 어떤 행위를 할 지는 GET, POST, PUT, DELETE 같은 메소드들을 통해 정의한다.
Path Variable 값을 처리하기는 쉽다. 요청 Mapping Url에 {name}형식으로 지정을 하고, 메소드 파라미터에 @PathVariable("name")
으로 정의를 해주면된다. 기본적으로 String으로 받지만, 아래와 같은 경우 Long으로 자동 형변환을 해준다.
@GetMapping("/members/{id}")
public String profile(@PathVariable("id") Long memId, Model model) {
System.out.Pringln(memId);
Member member = memberDao.selectById(memId);
}
@ExceptinalHandler
어노테이션을 적용한 메서드를 통해 컨트롤러에서 익셉션을 처리할 수 있다.
@Controller
public class MemberDetailController {
...(생략)
@ExceptionHandler(TypeMismatchException.class)
public String handleTypeMismatchException() {
return "member/invalidId";
}
@ExceptionHandler(MemberNotFoundException.class)
public String handleNotFoundException() {
return "member/noMember";
}
}
메소드 단에 어노테이션을 적용시키고 어노테이션의 파라미터로 적용할 익셉션을 넣으면 된다. 위 코드는 Long 형식을 받아야하는데 형 변환이 불가능한 "a" 같은 String 값이 들어올 경우 TypeMismatch 익셉션과, Member를 찾을 수 없을 경우의 익셉션을 처리한 코드이다.
Validator나, 인터셉터 처럼 컨트롤러 범위를 지정하여 적용할 수 있다.
이 경우 클래스를 만들고 어노테이션을 적용해 범위를 지정하여 공통 익셉션을 처리할 수 있다.
@ControllerAdvice("spring") // 범위 지정
public class CommonExceptionHandler {
@ExceptionHandler(RuntimeException.class)
public String handleRuntimeException() {
return "error/commonException";
}
}
범위는 @ControllerAdvice
어노테이션의 파라미터에 패키지를 지정해주면 된다.
컨트롤러별 지정 익셉션 처리, 공통 익셉션 처리에 따라 익셉션이 중복되는 경우가 발생할 수 있다. 이 경우 아래의 순서를 따라 먼저 찾아지는 익셉션 처리를 진행한다.
@EceptionHandler
메서드 중 해당 익셉션을 처리할 수 있는 메서드 검색@ControllerAdvice
클래스에 위치한 @ExceptionHandler
메서드를 검색즉 컨트롤러 범위 -> 공통 범위 순으로 찾게 된다.
@ResponseStatus
어노테이션을 통해 원래 에러에 해당하는 상태코드와 이유를 원하는 상태코드와 이유로 변경할 수 있다.
에러 뿐만 아니라 Http 통신 모두에 사용 가능하다.
@Controller
public class MemberDetailController {
...(생략)
@ExceptionHandler(TypeMismatchException.class)
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "My DataFormat Exception")
public String handleTypeMismatchException() {
return "member/invalidId";
}
@ExceptionHandler(MemberNotFoundException.class)
public String handleNotFoundException() {
return "member/noMember";
}
}