GDSC 웹 5주차 기록

4주차 스터디와 과제를 진행하고 작성한 글입니다.

소스코드는 링크 에 가면 자세히 보실 수 있습니다.


  • 개발(삽질) 순서로 작성됩니다!

status 코드 미적용?

  • 리드님의 스터디 시간때 유저의 회원가입까지 했습니다!
    Response 를 각각 성공과 실패형태로 작성을 했는데요
@Getter
@Setter
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class FailResponse<T> extends BasicResponse{
    private boolean success = false;
    private T data;
    private String  message;


    public FailResponse( String message,T data) {
        this.data = data;
        this.message = message;
    }
}

실패시에 Status Code가 400(BadRequest) 로 기대했지만 포스트맨에서는 200이 찍히는 이슈 발생.. 프론트 입장에서 실패시 200이 온다면 API 요청에 대한 예외처리가 복잡해지기 때문에 status를 변경해줘야 합니다…
왜 안되는지는 모르지만,,, 스프링에서 ResponseEntity라는 걸 지원해줘서 모든 응답을 감싸줬습니다.

//회원가입
@PostMapping("")
public ResponseEntity<BasicResponse> signUp(@RequestBody() UserDto.SignUpRequest user){
    String message = userService.signUp(user);
    if(message.equals("ok")){
        return ResponseEntity.ok(new SuccessResponse<>(new EmptyJsonResponse()));
    }else{
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
        .body(new FailResponse<>(message, new EmptyJsonResponse()));
    }
}

세션 체크

이번에 개발하면서 많이 막혔던 부분.. 중복 로그인을 막거나, 로그인이 꼭 필요한 유저인데 매번 세션에서꺼내서 확인할 수도 없는 부분이고 해서 찾아보던 차에 인터셉터라는걸로 구현을 한다길래 적용했습니다.

//interceptor
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object Handler)
            throws Exception {
                ...
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                    @Nullable ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

인터셉터는 preHandler, postHandler, afterCompletion 3개를 구현하는데 WebMvcConfigurer을 구현한 Config 파일에서 Override로 적용할 수 있었습니다.

public class AuthInterceptor implements HandlerInterceptor {
    private static final String[] ExceptionController =
            {"GET/api/user", "POST/api/user"};

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object Handler)
            throws Exception {

        //path가 중복되는 것은 예외처리로 제외함
        String method = request.getMethod();
        String requestUrl = request.getRequestURI();
        if(Arrays.asList(ExceptionController).contains((method + requestUrl))){
            return true;
        }

        //세션이 있는지 체크 없으면 401 리턴
        HttpSession session = request.getSession();
        Object user = session.getAttribute("sessionId");
         if(ObjectUtils.isEmpty(user)){
             FailResponse fail = new FailResponse<>("로그인이 필요합니다",new EmptyJsonResponse());
             ObjectMapper objectMapper = new ObjectMapper();
             String result = objectMapper.writeValueAsString(fail);
             response.setStatus(401);
             response.setContentType("application/json");
             response.setCharacterEncoding("utf-8");
             response.getWriter().write(result);
             return false;
         }else{
             return true;
         }
    }
  • 실제 구현 코드,.. 실화?
  • 세션이 있어야 하는 컨트롤러에 없으면 로그인이 필요하다는 응답과 401을 보내줍니다..
    컨트롤러에 등록할때는 url로 등록해주기 때문에 같은 url에 다른 메소드가 적용된다면 구분할 수 없어서… 위에서 같은 url에 예외처리를 해줬는데요..
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(new LogInterceptor())
                .addPathPatterns("/**");
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns(AuthUrlList);
    }
  • 같은 방식으로 로그도 구현해봤습니다.

추가 리팩토링 방안

  • 이 글을 작성하면서 잠시 검색해보니 커스텀 어노테이션을 만들어서 컨트롤러 단위로 맵핑하는 코드를 발견.. 추후에 리팩토링 하고싶네요
  • Log를 인터셉터에 구현했는데 filter 레이어에 구현하는게 더 맞는것 같네요 이것도 바꿔야 된다!