remagine
혼자서 웹 서비스 만들어보기 - 4 본문
혼자서 웹 서비스 만들어보기 - 4
https://github.com/remagine/webNovel/tree/develop
한동안 업데이트를 못했지만 조금씩 완성해 가고 있었습니다.ㅠㅠ
만드는 것도 어렵지만, 만든 것을 정리해서 올리는 것도 힘들더라구요.
1. 로그인 체크
사이트를 만들다보면 로그인 해야 볼 수 있는 페이지, 서비스가 많습니다.
요청이 들어올 때 로그인 여부를 체크해야 합니다.
여러가지 방법이 있지만
세션에 저장된 로그인 정보가 있는지 확인하는 법이 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 | @RequestMapping(value = "/mypage/profile") public String profile(Model model, HttpSession session, RedirectAttributes attrs) { Member loginUser = Logics.memberFromSession(session); /*if(null == loginUser){ ViewMessage.error().message("로그인이 필요한 서비스입니다.").register(attrs); return "redirect:/member/login"; }*/ model.addAttribute("member", loginUser); return "/member/mypage/profile"; } | cs |
현재 주석 처리된 부분을
모~~~~~~~든 Controller에 넣어주면 됩니다.
결국 코드가 중복되는 것이 많은 것 입니다.
2. 로그인 체크 인터셉터
인터셉터는 전후처리기의 한 종류라고 보면 좋을 것 같습니다.
컨트롤러가 실행되기 전에 체크해야 할 것들이 있다면 혹은 컨트롤러가 실행 된 후에 할 일이 있다면
사용할 수 있는 방법은 세가지 인 것 같습니다.
Request 는 요청입니다. 클라이언트가 url을 통해 서버(host)에게 요청을 하게 되면, 해당 요청은 미리 Spring Container에 Bean으로 등록된 Controller에 전달이 됩니다. 이 전달되기전에, 혹은 전달 된 후에 접근을 제어하는 친구들이 있습니다.
아래의 순서를 확인해보세요.
1. 브라우저가 요청한다.
2. Filter에 들어온다.
3. Dispatcher Servlet으로 들어온다.
4. Intercepter로 들어온다.
5. Controller로 들어온다.
6. 다시 Intercepter로 들어온다.
7. 다시 Dispatcher Servlet으로 들어온다.
8. 다시 Filter에 들어온다.
9. 브라우저에게 응답한다.
출처: http://cocomo.tistory.com/199 [Cocomo Coding]
전후처리기는 Filter와 DispatcherServlet 그리고 AOP가 있습니다.
이중 인터셉터는 DispatcherServlet에 의해 작동합니다.
그래서 Controller에 전달되기 전,후
View가 User에게 전달되기 전,후
제어가 가능합니다.
3. 실제 코드 적용
먼저 Intercepter 패키지를 만들고
클래스를 만들어봅니다.
1) MemberLoginCheckInterceptor.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | package com.arthur.webnovel.intercepter; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.codec.EncoderException; import org.apache.commons.codec.net.URLCodec; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import com.arthur.webnovel.entity.Member; import com.arthur.webnovel.util.Logics; public class MemberLoginCheckInterceptor extends HandlerInterceptorAdapter { private static Logger log = LoggerFactory.getLogger(MemberLoginCheckInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.debug("handle = {}", handler); if (handler instanceof HandlerMethod) { HandlerMethod hm = (HandlerMethod) handler; MemberRole memberRole = hm.getMethodAnnotation(MemberRole.class); if (memberRole == null) { memberRole = hm.getBeanType().getAnnotation(MemberRole.class); } if (memberRole != null) { HttpSession session = request.getSession(); Member member = Logics.memberFromSession(session); if(null == member){ return gotoLoginPage(request, response); } } } return true; } private final URLCodec codec = new URLCodec("UTF-8"); // immutable and thread-safe public boolean gotoLoginPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { StringBuilder sb = new StringBuilder(); sb.append(request.getServletPath()); String p = request.getPathInfo(); String queryString = request.getQueryString(); String redirectUrl = null; if (StringUtils.isNoneBlank(p)) { sb.append(p); } if (StringUtils.isNoneBlank(queryString)) { sb.append("?").append(queryString); } try { redirectUrl = codec.encode(sb.toString()); } catch (EncoderException e) { log.error("redirectUrl encode error", e); redirectUrl = StringUtils.join(request.getServletPath(), p); } response.sendRedirect("/member/login?redirectUrl=" + redirectUrl); return false; } } | cs |
2) MemberRole.java
1 2 3 4 5 6 7 8 9 10 11 12 13 | package com.arthur.webnovel.intercepter; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MemberRole { boolean optional() default false; } | cs |
처음보는 클래스가 있습니다. @interface입니다.
자바는 1.5버전부터 @을 사용해서 interface를 사용할 수 있다고 합니다.
@Target에서 METHOD는 메소드 위에 정의할 수 있다는 말이고, TYPE은 클래스를 의미합니다.
@Retention에서 RetentionPolicy는 인터페이스가 런타임시, 컴파일시 실행될지를 정의합니다.
MemberLoginCheckInterceptor에서는 preHandle이라는 메소드를 오버라이딩하고 있습니다.
Spring의 Handler는 Controller에게 @MemberRole 어노테이션이 달려있는지 체크해서
달려있을 경우 Session의 회원정보여부를 확인합니다.
확인이 되면 진행이 되고
확인이 안되면 로그인 페이지로 redirect시키는 것이지요.
3. 실제로 적용시키기
1 2 3 4 5 6 7 8 9 10 11 12 13 | @MemberRole @RequestMapping(value = "/mypage/profile") public String profile(Model model, HttpSession session, RedirectAttributes attrs) { Member loginUser = Logics.memberFromSession(session); /*if(null == loginUser){ ViewMessage.error().message("로그인이 필요한 서비스입니다.").register(attrs); return "redirect:/member/login"; }*/ model.addAttribute("member", loginUser); return "/member/mypage/profile"; } | cs |
사용방법은 간단합니다.
로그인 처리를 원하는 Controller에 @MemberRole을 달아주시면 됩니다.
그러나 단점이 하나 있네요.
저는 ViewMessage라는 클래스를 사용해서
redirect시 메시지를 다룰 수 있게 해왔는데요.
현재 적용한 인터셉터를 사용하면 사용할 수가 없습니다.
왜나하면 redirect는 실제로 요청url자체를 바꾸는 명령이고
현재 interceptor에 적용된
response.sendRedirect("/member/login?redirectUrl=" + redirectUrl);
Header에 301로 url을 적용시키는 것입니다.
자세한 내용은 https://blog.outsider.ne.kr/188를 참고하세요
'개인프로젝트 - 웹소설 사이트' 카테고리의 다른 글
혼자서 웹 서비스 만들어보기 - 6 (0) | 2017.06.28 |
---|---|
혼자서 웹 서비스 만들어보기 - 5 (0) | 2017.06.26 |
혼자서 웹 서비스 만들어보기 - 3 (0) | 2017.06.15 |
혼자서 웹 서비스 만들어보기 - 2 (0) | 2017.06.13 |
혼자서 웹 서비스 만들어보기 (0) | 2017.06.12 |