주석으로 처리된 모델앤뷰 보다 스트링으로 많이쓴다.
// @GetMapping("/auth/login")
// public ModelAndView login() {
// ModelAndView modelAndView = new ModelAndView();
// modelAndView.setViewName("auth/login");
// return modelAndView;
// }
@GetMapping("/auth/login")
public String login() {
return "auth/login";
}
// @GetMapping("/auth/join")
// public ModelAndView join() {
// ModelAndView modelAndView = new ModelAndView();
// modelAndView.setViewName("auth/join");
// return modelAndView;
// }
@GetMapping("/auth/join")
public String join() {
return "auth/join";
}
// @GetMapping("/auth/logout")
// public ModelAndView logout(HttpSession session) {
// session.invalidate();
// ModelAndView modelAndView = new ModelAndView();
// // 다른 페이지로 이동하겠다..
// modelAndView.setViewName("redirect:/auth/login");
// return modelAndView;
// }
@GetMapping("/auth/logout")
public String logout(){
return "redirect:/auth/login";
}
@ExceptionHandler는 Controller계층에서 발생하는 에러를 잡아서 메서드로 처리해주는 기능이다.
Service, Repository에서 발생하는 에러는 제외한다.
여러개의 Exception 처리 중 @RestControllerAdvice를 사용할 것이다.
@RestControllerAdvice는 @ControllerAdvice와 @ResponseBody을 가지고 있다.
@Controller처럼 작동하며 @ResponseBody를 통해 객체를 리턴할 수 있다.
@RestControllerAdvice 인터페이스
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ControllerAdvice
@ResponseBody
public @interface RestControllerAdvice {
// ...
}
@ControllerAdvice vs @RestControllerAdvice
@ControllerAdvice는 @Componenet 어노테이션을 가지고 있어 컴포넌트 스캔을 통해 스프링 빈으로 등록된다.
@RestControllerAdvice는 @Controlleradvice와 @ResponseBody 어노테이션으로 이루어져있고 HTML 뷰 보다는 Response body로 값을 리턴할 수 있다.
주석으로 처리하고 에러로 처리해서 던짐
public ResponseEntity<?> join(ReqJoinDTO dto) {
// 회원가입 정보 입력했는지 확인
if(
dto.getUser().getId() == null ||
dto.getUser().getId().equals("") ||
dto.getUser().getPassword() ==null ||
dto.getUser().getPassword().equals("")
){
//처리하기 귀찮으니까 에러를 만들어서 던진 것
throw new BadRequestException("아이디나 비밀번호를 입력해주세요");
// return new ResponseEntity<>(
// ResponseDTO.builder()
// .code(1)
// .message("아이디나 비밀번호를 입력해주세요")
// .build(),
// HttpStatus.BAD_REQUEST
// );
}
// 리파지토리에서 아이디로 유저 찾기
Optional<UserEntity> userEntityOptional = userRepository.findById(dto.getUser().getId());
// optional - null 체크 하기위해서 쓴다
// 있으면 (이미 존재하는 아이디입니다.) 메시지 리턴
if(userEntityOptional.isPresent()){
throw new BadRequestException("이미 존재하는 아이디입니다.");
// return new ResponseEntity<>(
// ResponseDTO.builder()
// .code(1)
// .message("이미 존재하는 아이디입니다.")
// .build(),
// HttpStatus.BAD_REQUEST
// );
}
입력안했으니까 에러난다.

폴더구조
@RestControllerAdvice로 처리한다.
package com.example.my.common.exception.handler;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.example.my.common.dto.ResponseDTO;
import com.example.my.common.exception.BadRequestException;
@RestControllerAdvice
// Rest방식으로 에러 처리
public class RestExceptionHandler {
// 처리할 에러를 특정함
@ExceptionHandler(BadRequestException.class)
public ResponseEntity<?> handleBadRequestException(Exception exception) {
return new ResponseEntity<>(ResponseDTO.builder()
.code(1)
.message(exception.getMessage())
.build(), HttpStatus.BAD_REQUEST);
}
}
실행하면 에러가 터졌을 때 특정 처리한다.
모든에러를 처리한다.
(주석으로 설명)
@RestControllerAdvice
// Rest방식으로 에러 처리
public class RestExceptionHandler {
// 처리할 에러를 특정함
@ExceptionHandler(BadRequestException.class)
public ResponseEntity<?> handleBadRequestException(Exception exception) {
exception.printStackTrace();
return new ResponseEntity<>(ResponseDTO.builder()
.code(1)
.message(exception.getMessage())
.build(), HttpStatus.BAD_REQUEST);
}
// 모든 에러를 처리할 때
// 이렇게 하면 찾아내기 어려움
// class별로 에러를 처리하는게 나음
@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleException(Exception exception){
exception.printStackTrace();// 콘솔창에 에러를 뿌려주고 화면에 뿌려줌(하고 싶으면 하고)
return new ResponseEntity<>(ResponseDTO.builder()
.code(1)
.message(exception.getMessage())
.build(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
실행하면
콘솔창에서도
gradle의 디펜덴시에 붙여준다.
implementation 'org.springframework.boot:spring-boot-starter-validation'
유효성 검사가 필요한 Request 객체에 Validation 어노테이션을 사용해 유효성 검사를 적용할 수 있다.

참고자료
Validation에 대해
주석으로 설명~~
@PostMapping("/join")
// 체크를 하겠다는 것 - @Valid
public ResponseEntity<?> join(@Valid @RequestBody ReqJoinDTO dto) {
// 서비스에서 회원가입하기
return authServiceApiV1.join(dto);
}
public class ReqJoinDTO {
@NotNull(message = "유저 정보를 입력해주세요.")
private User user;
실행하면 이렇게 message에 유저 정보를 입력해주세요라는 글이 보인다.
AuthServiceApiV1에서 원래는 이렇게 null을 설정해서 하나하나 다 적어야 했는데
if(
dto.getUser().getId() == null ||
dto.getUser().getId().equals("") ||
dto.getUser().getPassword() ==null ||
dto.getUser().getPassword().equals("")
){
ReqJoinDTO에 이렇게 간단히 할 수 있음
public class ReqJoinDTO {
@Valid
@NotBlank(message = "유저 정보를 입력해주세요.")
private User user;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public static class User {
@NotBlank(message = "아이디를 입력해주세요")
@Size(min = 4, message = "아이디는 4자 이상 입력해주세요.")
private String id;
@NotBlank(message = "비밀번호를 입력해주세요")
@Pattern(regexp = "^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[@#$%^&+=])(?=\\S+$).{8,16}$", message = "비밀번호 양식에 맞추어서 입력해주세요.")
private String password;
}
}
public ResponseEntity<?> login(ReqLoginDTO dto, HttpSession session) {
// 유효성체크
// if(
// dto.getUser().getId() == null ||
// dto.getUser().getId().equals("") ||
// dto.getUser().getPassword() ==null ||
// dto.getUser().getPassword().equals("")
// ){
// throw new BadRequestException("아이디나 비밀번호를 입력해주세요");
// // return new ResponseEntity<>(
// // ResponseDTO.builder()
// // .code(1)
// // .message("아이디나 비밀번호를 입력해주세요")
// // .build(),
// // HttpStatus.BAD_REQUEST
// // );
// }
// 리파지토리에서 아이디로 삭제되지 않은 유저 찾기
Optional<UserEntity> userEntityOptional = userRepository.findByIdAndDeleteDateIsNull(dto.getUser().getId());
실행해서 message에 보면 양식을 똑바로 입력하라고 나온다.
에러가 한개가 아니라 여러개가 나온거 그래서 다찾아서 뿌려주면 좋으니까 만들어준다.
@ExceptionHandler(BindException.class)
public ResponseEntity<?> handleBindException(BindException bindException){
for (FieldError fieldError : bindException.getBindingResult().getFieldErrors()) {
System.out.println(fieldError.getField());
System.out.println(fieldError.getDefaultMessage());
}
return null;
}
실행해보면 에러 처리가 되었고
콘솔창에서는 메세지가 뜬다.
에러가 몇개가 들어오든 다 처리 가능하다.
public class RestExceptionHandler {
@ExceptionHandler(BindException.class)
public ResponseEntity<?> handleBindException(BindException bindException){
HashMap<String, String> errorMap = new HashMap<>();
for (FieldError fieldError : bindException.getBindingResult().getFieldErrors()) {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("요청 데이터를 확인해주세요")
.data(errorMap)
.build(),
HttpStatus.BAD_REQUEST
);
}
다시 실행해보면 잘나온다.
로그인도 해준다!!
유효성체크도 주석처리해줌..(위에서 함)
@PostMapping("/login")
public ResponseEntity<?> login(@Valid @RequestBody ReqLoginDTO dto, HttpSession session) {
// 서비스에서 로그인하기
return authServiceApiV1.login(dto, session);
}
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class ReqLoginDTO {
@Valid
@NotNull(message = "유저 정보를 입력해주세요")
private User user;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public static class User {
@NotBlank(message = "아이디를 입력해주세요")
private String id;
@NotBlank(message = "비밀번호를 입력해주세요")
private String password;
}
}
실행하면 로그인도 잘된다.

이게 AOP라고 한다.