SPRING/INFLEARN

[๊ฐ•์˜] ์Šคํ”„๋ง MVC 2ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ•ต์‹ฌ ๊ธฐ์ˆ  5

ozllzL 2023. 1. 30. 11:46

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2

 

์Šคํ”„๋ง MVC 2ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ™œ์šฉ ๊ธฐ์ˆ  - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋ชจ๋“  ์›น ๊ธฐ์ˆ ์„ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์ดํ•ดํ•˜๊ณ , ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. MVC 2ํŽธ์—์„œ๋Š” MVC 1ํŽธ์˜ ํ•ต์‹ฌ ์›๋ฆฌ์™€ ๊ตฌ์กฐ ์œ„์— ์‹ค๋ฌด ์›น ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋ชจ๋“  ํ™œ์šฉ ๊ธฐ์ˆ ๋“ค์„ ํ•™์Šตํ•  ์ˆ˜ ์žˆ

www.inflearn.com

6. ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ1 - ์ฟ ํ‚ค, ์„ธ์…˜

- ๋กœ๊ทธ์ธ ์š”๊ตฌ ์‚ฌํ•ญ

  • ํ™ˆ ํ™”๋ฉด - ๋กœ๊ทธ์ธ ์ „
    • ํšŒ์› ๊ฐ€์ž…
    • ๋กœ๊ทธ์ธ
  • ํ™ˆ ํ™”๋ฉด - ๋กœ๊ทธ์ธ ํ›„
    • ๋ณธ์ธ ์ด๋ฆ„(๋ˆ„๊ตฌ๋‹˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.)
    • ์ƒํ’ˆ ๊ด€๋ฆฌ
    • ๋กœ๊ทธ ์•„์›ƒ
  • ๋ณด์•ˆ ์š”๊ตฌ์‚ฌํ•ญ
    • ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๋งŒ ์ƒํ’ˆ์— ์ ‘๊ทผํ•˜๊ณ , ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ
    • ๋กœ๊ทธ์ธ ํ•˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ’ˆ ๊ด€๋ฆฌ์— ์ ‘๊ทผํ•˜๋ฉด ๋กœ๊ทธ์ธ ํ™”๋ฉด์œผ๋กœ ์ด๋™
    • ํšŒ์› ๊ฐ€์ž…, ์ƒํ’ˆ ๊ด€๋ฆฌ

- ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

  • ์˜์กด๊ด€๊ณ„๋Š” ๋‹จ๋ฐฉํ–ฅ์œผ๋กœ ํ˜๋Ÿฌ์•ผ ํ•œ๋‹ค
    ๋„๋ฉ”์ธ์ด ๊ฐ€์žฅ ์ค‘์š”ํ•˜๋ฏ€๋กœ ์›น์ด ๋„๋ฉ”์ธ์„ ์ฐธ์กฐํ•˜๋„๋ก ํ•ด์•ผํ•œ๋‹ค.
    ์›น์„ ๋“ค์–ด๋‚ด์„œ ์ฝ”๋“œ๋ฅผ ๋‹ค ๊ฐˆ์•„ ์—Ž์–ด๋„ ๋„๋ฉ”์ธ์—๋Š” ์•„๋ฌด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋„๋ก

- ํšŒ์› ๊ฐ€์ž…

  • ๋กœ๊ทธ์ธ ํผ html ์ถ”๊ฐ€

  • ๋กœ๊ทธ์ธ ๋ ˆํฌ ์ถ”๊ฐ€(List๋ฅผ ์ด์šฉํ•ด ์ž„์‹œ ๋ ˆํฌ, ํ…Œ์ŠคํŠธ์šฉ ๋ฐ์ดํ„ฐ ๋„ฃ๋Š” ์ฝ”๋“œ๋„ ํ•จ๊ป˜)
  • ๋กœ๊ทธ์ธ ์ปจํŠธ๋กค๋Ÿฌ
@Controller
@RequiredArgsConstructor
@RequestMapping("/members")
public class MemberController {
    private final MemberRepository memberRepository;

    @GetMapping("/add")
    public String addForm(@ModelAttribute("member") Member member) {
        return "members/addMemberForm";
    }
    
    @PostMapping("/add")
    public String save(@Valid @ModelAttribute Member member, BindingResult result) {
        if (result.hasErrors()) {
            return "members/addMemberForm";
        }
        memberRepository.save(member);
        return "redirect:/";
    }

- ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ

  • LoginService ๋„๋ฉ”์ธ์— ์ถ”๊ฐ€, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง , ์•„์ด๋”” ๋น„๋ฐ€๋ฒˆํ˜ธ ๋งž๋Š”์ง€ ํ™•์ธ
@Service
@RequiredArgsConstructor
public class LoginService {
    private final MemberRepository memberRepository;

    public Member login(String loginId, String password) {
        return memberRepository.findByLoginId(loginId)
                .filter(m -> m.getPassword().equals(password))
                .orElse(null);
    }
}
  • ๋กœ๊ทธ์ธ ํผ html ์ถ”๊ฐ€

  • ๋กœ๊ทธ์ธ ํผ dto ์ถ”๊ฐ€
  • ๋กœ๊ทธ์ธ Controller
@Slf4j
@Controller
@RequiredArgsConstructor
public class LoginController {
    private final LoginService loginService;
    @GetMapping("/login")
    public String loginForm(@ModelAttribute("loginForm") LoginForm form) {
        return "login/loginForm";
    }

    @PostMapping("/login")
    public String login(@Valid @ModelAttribute LoginForm form, BindingResult
            bindingResult) {
        if (bindingResult.hasErrors()) {
            return "login/loginForm";
        }
        Member loginMember = loginService.login(form.getLoginId(),
                form.getPassword());
        log.info("login? {}", loginMember);
        if (loginMember == null) {
            bindingResult.reject("loginFail", "์•„์ด๋”” ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
            return "login/loginForm";
        }
        //๋กœ๊ทธ์ธ ์„ฑ๊ณต ์ฒ˜๋ฆฌ TODO
        return "redirect:/";
    }

 

- ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌํ•˜๊ธฐ - ์ฟ ํ‚ค ์‚ฌ์šฉ

๋กœ๊ทธ์ธ -> ๋กœ๊ทธ์ธ ์„ฑ๊ณต

           <- ์ฟ ํ‚ค ๋งŒ๋“ค์–ด์„œ ๋ณด๋‚ด์คŒ

๋ชจ๋“  ์š”์ฒญ์— ์ฟ ํ‚ค ์ž๋™ ํฌํ•จ

์ฟ ํ‚ค์—๋Š” ์˜์†, ์„ธ์…˜ ์ฟ ํ‚ค๊ฐ€ ์žˆ๋Š”๋ฐ ๋กœ๊ทธ์ธ์€ ๋ธŒ๋ผ์šฐ์ € ์ข…๋ฃŒ ์‹œ๊นŒ์ง€๋งŒ ์œ ์ง€๋˜๋ฉด ๋˜๋ฏ€๋กœ ์„ธ์…˜ ๋ฐฉ์‹์„ ์„ ํƒํ•œ๋‹ค.

@PostMapping("/login")
public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult
, HttpServletResponse response) {
    if (bindingResult.hasErrors()) {
        return "login/loginForm";
    }
    Member loginMember = loginService.login(form.getLoginId(),
            form.getPassword());
    log.info("login? {}", loginMember);
    if (loginMember == null) {
        bindingResult.reject("loginFail", "์•„์ด๋”” ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        return "login/loginForm";
    }
    
    //๋กœ๊ทธ์ธ ์„ฑ๊ณต ์ฒ˜๋ฆฌ
    Cookie idCookie = new Cookie("memberId",
            String.valueOf(loginMember.getId()));
    response.addCookie(idCookie);

    return "redirect:/";
}


@PostMapping("/logout")
public String logout(HttpServletResponse response) {
    expireCookie(response, "memberId");
    return "redirect:/";
}
private void expireCookie(HttpServletResponse response, String cookieName) {
    Cookie cookie = new Cookie(cookieName, null);
    cookie.setMaxAge(0);
    response.addCookie(cookie);
}

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ

home์—์„œ๋„ ๋กœ๊ทธ์ธ์ด ์œ ์ง€๋  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค๊ธฐ/ ๋กœ๊ทธ์•„์›ƒ ๋งŒ๋“ค๊ธฐ

@GetMapping("/")
public String homeLogin(@CookieValue(name = "memberId", required = false) Long memberId, Model model) {
    if (memberId == null) {
        return "home";
    }

    //๋กœ๊ทธ์ธ
    Member loginMember = memberRepository.findById(memberId);
    if (loginMember == null) {
        return "home";
    }
    model.addAttribute("member", loginMember);
    return "loginHome";
}

๋กœ๊ทธ์ธ ํ›„์—๋Š” ํ™ˆ ํ™”๋ฉด์ด ์ด๋ ‡๊ฒŒ ๋ฐ”๋€Œ๋ฉฐ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๊ป๋‹ค๊ฐ€ ์ผœ๋ฉด ์‚ฌ๋ผ์ง„๋‹ค.

 

- ์ฟ ํ‚ค์™€ ๋ณด์•ˆ ๋ฌธ์ œ

์ฟ ํ‚ค๋Š” ์‚ฌ์‹ค ํด๋ผ์ด์–ธํŠธ์—์„œ ์ž„์˜๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค -> ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋“ค์˜ ๊ฐœ์ธ์ •๋ณด๊ฐ€ ๋‹ค ํ„ธ๋ฆฐ๋‹ค

ํ•ด์ปค๊ฐ€ ์ฟ ํ‚ค๋ฅผ ํ›”์ณ์„œ ์•…์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค

-> ๋Œ€์•ˆ

์ฟ ํ‚ค์— ์‹œ๊ฐ„์ œํ•œ์„ ์ค€๋‹ค

์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ์ž„์˜์˜ ํ† ํฐ์„ ์ค€๋‹ค

ํ•ดํ‚น์ด ์˜์‹ฌ๋˜๋Š” ๊ฒฝ์šฐ ์ฟ ํ‚ค๋ฅผ ์ง์ ‘ ์ œ๊ฑฐํ•œ๋‹ค

 

- ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌํ•˜๊ธฐ - ์„ธ์…˜ ๋™์ž‘ ๋ฐฉ์‹

์ฟ ํ‚ค์˜ ์ค‘์š”ํ•œ ์ •๋ณด๋ฅผ ๋ณด๊ด€ํ•˜๊ณ  ์—ฐ๊ฒฐ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ• : ์„ธ์…˜

์ฟ ํ‚ค ๊ฐ’์„ ๋ณ€์กฐ - ์˜ˆ์ƒ ๋ถˆ๊ฐ€๋Šฅํ•œ ๋ณต์žกํ•œ ์„ธ์…˜ id

ํ„ธ๋ ค๋„ ๋ณต์žกํ•˜๋ฏ€๋กœ ์•Œ๊ธฐ ์–ด๋ ต๋‹ค

 

- ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌํ•˜๊ธฐ - ์„ธ์…˜ ์ง์ ‘ ๋งŒ๋“ค๊ธฐ

@Component
public class SessionManager {
    public static final String SESSION_COOKIE_NAME = "mySessionId";
    private Map<String, Object> sessionStore = new ConcurrentHashMap<>();
    /**
     * ์„ธ์…˜ ์ƒ์„ฑ
     */
    public void createSession(Object value, HttpServletResponse response) {
        //์„ธ์…˜ id๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ๊ฐ’์„ ์„ธ์…˜์— ์ €์žฅ
        String sessionId = UUID.randomUUID().toString();
        sessionStore.put(sessionId, value);
        //์ฟ ํ‚ค ์ƒ์„ฑ
        Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
        response.addCookie(mySessionCookie);
    }
    /**
     * ์„ธ์…˜ ์กฐํšŒ
     */
    public Object getSession(HttpServletRequest request) {
        Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
        if (sessionCookie == null) {
            return null;
        }
        return sessionStore.get(sessionCookie.getValue());
    }
    /**
     * ์„ธ์…˜ ๋งŒ๋ฃŒ
     */
    public void expire(HttpServletRequest request) {
        Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
        if (sessionCookie != null) {
            sessionStore.remove(sessionCookie.getValue());
        }
    }
    
    private Cookie findCookie(HttpServletRequest request, String cookieName) {
        if (request.getCookies() == null) {
            return null;
        }
        return Arrays.stream(request.getCookies())
                .filter(cookie -> cookie.getName().equals(cookieName))
                .findAny()
                .orElse(null);
    }
class SessionManagerTest {
    SessionManager sessionManager = new SessionManager();

    @Test
    void sessionTest() {

        //์„ธ์…˜ ์ƒ์„ฑ
        //ํ…Œ์ŠคํŠธ์šฉ ๊ฐ€์งœ Mock ์ œ๊ณต
        MockHttpServletResponse response = new MockHttpServletResponse();
        Member member = new Member();
        sessionManager.createSession(member, response);

        //์š”์ฒญ์— ์‘๋‹ต ์ฟ ํ‚ค ์ €์žฅ
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setCookies(response.getCookies());

        //์„ธ์…˜ ์กฐํšŒ
        Object result = sessionManager.getSession(request);
        assertThat(result).isEqualTo(member);
        
        //์„ธ์…˜ ๋งŒ๋ฃŒ
        sessionManager.expire(request);
        Object expired = sessionManager.getSession(request);
        assertThat(expired).isNull();
    }

Key : UUID

Value : member id๋กœ  

UUID๋ฅผ ํ†ตํ•ด member id์— ์ ‘๊ทผ

 

- ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌํ•˜๊ธฐ - ์ง์ ‘ ๋งŒ๋“  ์„ธ์…˜ ์ ์šฉ

@PostMapping("/login")
public String loginV2(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response) {
    if (bindingResult.hasErrors()) {
        return "login/loginForm";
    }

    Member loginMember = loginService.login(form.getLoginId(),
            form.getPassword());
    log.info("login? {}", loginMember);

    if (loginMember == null) {
        bindingResult.reject("loginFail", "์•„์ด๋”” ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        return "login/loginForm";
    }

    //๋กœ๊ทธ์ธ ์„ฑ๊ณต ์ฒ˜๋ฆฌ
    sessionManager.createSession(loginMember, response);

    return "redirect:/";
}
@PostMapping("/logout")
public String logoutV2(HttpServletRequest request) {
    sessionManager.expire(request);
    return "redirect:/";
}
@GetMapping("/")
public String homeLoginV2(HttpServletRequest request, Model model) {
    Member member = (Member)sessionManager.getSession(request);

    if (member == null) {
        return "home";
    }

    //๋กœ๊ทธ์ธ
    model.addAttribute("member", member);
    return "loginHome";
}

sessionManager๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ชจ๋‘ ์ˆ˜์ •ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ์ผ์ผํžˆ ๊ฐœ๋ฐœํ•ด์•ผ ๋˜๋Š” ์„ธ์…˜์„ ์„œ๋ธ”๋ฆฟ์—์„œ ์ง€์›ํ•ด์ค€๋‹ค.

์ฟ ํ‚ค๊ฐ€ ์ €์žฅ๋œ ๋ชจ์Šต

- ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌํ•˜๊ธฐ - ์„œ๋ธ”๋ฆฟ HTTP ์„ธ์…˜1

๊ธฐ๋ณธ์œผ๋กœ ๋‚ด์žฅ๋œ ๊ธฐ๋Šฅ ์‚ฌ์šฉ

@PostMapping("/login")
public String loginV3(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletRequest request) {
    if (bindingResult.hasErrors()) {
        return "login/loginForm";
    }

    Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
    log.info("login? {}", loginMember);

    if (loginMember == null) {
        bindingResult.reject("loginFail", "์•„์ด๋”” ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        return "login/loginForm";
    }

    //๋กœ๊ทธ์ธ ์„ฑ๊ณต ์ฒ˜๋ฆฌ
    //์„ธ์…˜์ด ์žˆ์œผ๋ฉด ์žˆ๋Š” ์„ธ์…˜ ๋ฐ˜ํ™˜, ์—†์œผ๋ฉด ์‹ ๊ทœ ์„ธ์…˜ ์ƒ์„ฑ
    HttpSession session = request.getSession();
    //์„ธ์…˜์— ๋กœ๊ทธ์ธ ํšŒ์› ์ •๋ณด ๋ณด๊ด€
    session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);

    return "redirect:/";
}

request.getSession(), (true)  -> ์„ธ์…˜์ด ์žˆ์œผ๋ฉด ์„ธ์…˜ ๋ฐ˜ํ™˜, ์—†์œผ๋ฉด ์ƒ์„ฑ

                                   (false) -> ์žˆ์œผ๋ฉด ๋˜‘๊ฐ™์ด, ์—†์œผ๋ฉด null

@PostMapping("/logout")
public String logoutV3(HttpServletRequest request) {
    HttpSession session = request.getSession(false);
    if (session != null) {
        session.invalidate();
    }
    return "redirect:/";
}
@GetMapping("/")
public String homeLoginV3(HttpServletRequest request, Model model) {
    HttpSession session = request.getSession(false);
    if(session == null)
        return "home";


    Member loginMember = (Member)session.getAttribute(SessionConst.LOGIN_MEMBER);

    if (loginMember == null) {
        return "home";
    }

    //๋กœ๊ทธ์ธ
    model.addAttribute("member", loginMember);
    return "loginHome";
}

JSESSIONID๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ฟ ํ‚ค๊ฐ€ ์ ์ ˆํ•˜๊ฒŒ ์ƒ์„ฑ๋œ๋‹ค

- ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌํ•˜๊ธฐ - ์„œ๋ธ”๋ฆฟ HTTP ์„ธ์…˜2

  • @SessionAttribute
@GetMapping("/")
public String homeLoginV3Spring(
        @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model model) {

    if (loginMember == null) {
        return "home";
    }

    //๋กœ๊ทธ์ธ
    model.addAttribute("member", loginMember);
    return "loginHome";
}

@SessionAttribute๋กœ ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

์„ธ์…˜์„ ์ฐพ์•„์˜จ๋‹ค(์ƒ์„ฑํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค.)

 

  • TrakingModes

์ฟ ํ‚ค๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, URL์„ ์ด์šฉํ•ด์„œ ์œ ์ง€์‹œํ‚จ๋‹ค. ์ฒ˜์Œ์— ํŒ๋‹จ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ธฐ ๋•Œ๋ฌธ

์ง€์ €๋ถ„ํ•˜๋‹ค.

์ด๋ฅผ ๋„๋Š” ๋ฐฉ๋ฒ•์€

server.servlet.session.tracking-modes=cookie

๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋Œ ์ˆ˜ ์žˆ๋‹ค. 

 

- ์„ธ์…˜ ์ •๋ณด์™€ ํƒ€์ž„์•„์›ƒ ์„ค์ •

@Slf4j
@RestController
public class SessionInfoController {
    
    @GetMapping("/session-info")
    public String sessionInfo(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return "์„ธ์…˜์ด ์—†์Šต๋‹ˆ๋‹ค.";
        }
        
        //์„ธ์…˜ ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ
        session.getAttributeNames().asIterator()
                .forEachRemaining(name -> log.info("session name={}, value={}",
                        name, session.getAttribute(name)));
        log.info("sessionId={}", session.getId());
        log.info("maxInactiveInterval={}", session.getMaxInactiveInterval());
        log.info("creationTime={}", new Date(session.getCreationTime()));
        log.info("lastAccessedTime={}", new
                Date(session.getLastAccessedTime()));
        log.info("isNew={}", session.isNew());
        return "์„ธ์…˜ ์ถœ๋ ฅ";
    }
}

 

์„ธ์…˜์˜ ์ •๋ณด๋“ค์„ ๋ณธ๋‹ค.

์„ธ์…˜์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒ์„ ์ง์ ‘ ํ˜ธ์ถœํ•  ๋•Œ๋งŒ ์‚ญ์ œ๋œ๋‹ค.

ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ์šฉ์ž๋“ค์€ ์ด๋ฅผ ์„ ํƒํ•˜์ง€ ์•Š๊ณ , HTTP๋Š” ๋น„์—ฐ๊ฒฐ์„ฑ์ด๋ฏ€๋กœ ์„œ๋ฒ„ ์ž…์žฅ์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์ข…๋ฃŒํ•œ ๊ฒƒ์ธ์ง€ ์•„๋‹Œ์ง€ ์ธ์‹ํ•  ์ˆ˜ ์—†๋‹ค.

์„œ๋ฒ„์—์„œ ์„ธ์…˜ ๋ฐ์ดํ„ฐ๋ฅผ ์–ธ์ œ ์‚ญ์ œํ•ด์•ผ๋ ๊นŒ? - ์ผ๋‹จ ๋ฌดํ•œ์ •์€ ์•ˆ๋จ, ๋ณด์•ˆ์ƒ/ ๋ฉ”๋ชจ๋ฆฌ์ƒ 

๋ฉ”๋ชจ๋ฆฌ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์šฐ๋‘๋‘ ์Œ“์ด๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋งค์šฐ ๋†’๋‹ค.

-> ์„ธ์…˜์—์„  ์ตœ์†Œํ•œ์˜ ๋ฐ์ดํ„ฐ๋งŒ ๋ณด๊ด€ํ•ด์•ผํ•œ๋‹ค.

-> ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋ฒ„์— ์ตœ๊ทผ์— ์š”์ฒญํ•œ ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ 30๋ถ„์„ ์œ ์ง€ํ•ด์ฃผ๋ฉด ์–ด๋–จ๊นŒ?

  • ๊ธ€๋กœ๋ฒŒ์„ค์ •
server.servlet.session.timeout=60
  • ์„ธ์…˜ ๋‹จ์œ„๋กœ ์„ค์ •
session.setMaxInactiveInterval(1800);
  • ์„ธ์…˜ ํƒ€์ž„์•„์›ƒ ๋ฐœ์ƒ

์„ธ์…˜ ํƒ€์ž„์•„์›ƒ ์‹œ๊ฐ„์€ ํ•ด๋‹น ์„ธ์…˜๊ณผ ๊ด€๋ จ๋œ JSESSIONID๋ฅผ ์ „๋‹ฌํ•˜๋Š” HTTP  ์š”์ฒญ์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ดˆ๊ธฐํ™”์‹œํ‚จ๋‹ค.

LastAccessedTime(session.getLastAccessedTime()) ์ดํ›„๋กœ timeout ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด WAS๊ฐ€ ๋‚ด๋ถ€์—์„œ ํ•ด๋‹น ์„ธ์…˜์„ ์ œ๊ฑฐ

 

7. ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ2 - ํ•„ํ„ฐ, ์ธํ„ฐ์…‰ํ„ฐ

- ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ - ์†Œ๊ฐœ

URL๋กœ ๋ง‰ ์—ฌ๊ธฐ์ €๊ธฐ ๋“ค์–ด๊ฐˆ ์ˆ˜ ์žˆ์œผ๋ฉด ๋กœ๊ทธ์ธ ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด ์•ˆ๋˜๋Š” ๊ณณ๊นŒ์ง€ ๋“ค์–ด๊ฐ€์ง„๋‹ค = ๋ฌธ์ œ

์ด๋ฅผ 

 

ํ•„ํ„ฐ : ์„œ๋ธ”๋ฆฟ์ด

์ธํ„ฐ์…‰ํ„ฐ : ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ

 

๋กœ๊ทธ์ธ ์—ฌ๋ถ€ ์ฒดํฌ๋ฅผ ๋งค api ํ˜ธ์ถœ ๋•Œ๋งˆ๋‹ค ํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ณ„๋กœ๋‹ค.

์ด๋Ÿฐ ๊ณตํ†ต๊ด€์‹ฌ์‚ฌ๋Š” ์Šคํ”„๋ง AOP๋กœ๋„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์›น๊ณผ ๊ด€๋ จํ•œ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋Š” ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ, ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.(HttpServletRequest๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ)

 

์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ : ์„œ๋ธ”๋ฆฟ์ด ์ง€์›ํ•˜๋Š” ์ˆ˜๋ฌธ์žฅ

URL ํŒจํ„ด๋ณ„๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Œ(/* = ๋ชจ๋“  ์š”์ฒญ)

 

ํ•„ํ„ฐ ํ๋ฆ„

HTTP ์š”์ฒญ -> WAS -> ํ•„ํ„ฐ -> ์„œ๋ธ”๋ฆฟ -> ์ปจํŠธ๋กค๋Ÿฌ

 

ํ•„ํ„ฐ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„, ๋“ฑ๋กํ•˜๋ฉด

์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋กœ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•จ.

init(): ํ•„ํ„ฐ ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.
doFilter(): ๊ณ ๊ฐ์˜ ์š”์ฒญ์ด ์˜ฌ ๋•Œ ๋งˆ๋‹ค ํ•ด๋‹น ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. ํ•„ํ„ฐ์˜ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.
destroy(): ํ•„ํ„ฐ ์ข…๋ฃŒ ๋ฉ”์„œ๋“œ, ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ ํ˜ธ์ถœ๋œ๋‹ค.

 

- ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ - ์š”์ฒญ ๋กœ๊ทธ

@Slf4j
public class LogFilter implements Filter {

    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("log filter init");
    }

    //HTTP ์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
        String uuid = UUID.randomUUID().toString();
        try {
            log.info("REQUEST [{}][{}]", uuid, requestURI);
            chain.doFilter(request, response);
        } catch (Exception e) {
            throw e;
        } finally {
            log.info("RESPONSE [{}][{}]", uuid, requestURI);
        }
    }

    @Override
    public void destroy() {
        log.info("log filter destroy");
    }
}


ServletRequest request ๋Š” HTTP ์š”์ฒญ์ด ์•„๋‹Œ ๊ฒฝ์šฐ๊นŒ์ง€ ๊ณ ๋ คํ•ด์„œ ๋งŒ๋“  ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. HTTP๋ฅผ
์‚ฌ์šฉํ•˜๋ฉด HttpServletRequest httpRequest = (HttpServletRequest) request; ์™€ ๊ฐ™์ด ๋‹ค์šด ์ผ€์ŠคํŒ… ํ•˜๋ฉด ๋œ๋‹ค.

 

String uuid = UUID.randomUUID().toString();
HTTP ์š”์ฒญ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ์š”์ฒญ๋‹น ์ž„์˜์˜ uuid ๋ฅผ ์ƒ์„ฑํ•ด๋‘”๋‹ค.

 

chain.doFilter(request, response);
๋‹ค์Œ ํ•„ํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ํ•„ํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ํ•„ํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ์„œ๋ธ”๋ฆฟ์„ ํ˜ธ์ถœํ•œ๋‹ค.
๋งŒ์•ฝ ์ด ๋กœ์ง์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ง„ํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

@Configuration
public class WebConfig {
    @Bean
    public FilterRegistrationBean logFilter() {
        FilterRegistrationBean<Filter> filterRegistrationBean 
                = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new LogFilter());
        //ํ•„ํ„ฐ๋Š” ์ฒด์ธ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ˆœ์„œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ๋‚ฎ์„ ์ˆ˜๋ก ๋จผ์ € ๋™์ž‘ํ•œ๋‹ค.
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }
}

 

- ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ - ์ธ์ฆ ์ฒดํฌ

@Slf4j
public class LoginCheckFilter implements Filter {

    //ํ’€์–ด์ค„ url ๋ฆฌ์ŠคํŠธ
    private static final String[] whitelist = {"/", "/members/add", "/login", "/logout","/css/*"};

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        try {
            log.info("์ธ์ฆ ์ฒดํฌ ํ•„ํ„ฐ ์‹œ์ž‘ {}", requestURI);

            if (isLoginCheckPath(requestURI)) {
                log.info("์ธ์ฆ ์ฒดํฌ ๋กœ์ง ์‹คํ–‰ {}", requestURI);
                HttpSession session = httpRequest.getSession(false);

                if (session == null ||
                        session.getAttribute(SessionConst.LOGIN_MEMBER) == null) {
                    log.info("๋ฏธ์ธ์ฆ ์‚ฌ์šฉ์ž ์š”์ฒญ {}", requestURI);

                    //๋กœ๊ทธ์ธ์œผ๋กœ redirect
                    httpResponse.sendRedirect("/login?redirectURL=" +
                            requestURI);
                    return; //์—ฌ๊ธฐ๊ฐ€ ์ค‘์š”, ๋ฏธ์ธ์ฆ ์‚ฌ์šฉ์ž๋Š” ๋‹ค์Œ์œผ๋กœ ์ง„ํ–‰ํ•˜์ง€ ์•Š๊ณ  ๋!
                }
            }
            
            chain.doFilter(request, response);
        } catch (Exception e) {
            throw e; //์˜ˆ์™ธ ๋กœ๊น… ๊ฐ€๋Šฅ ํ•˜์ง€๋งŒ, ํ†ฐ์บฃ๊นŒ์ง€ ์˜ˆ์™ธ๋ฅผ ๋ณด๋‚ด์ฃผ์–ด์•ผ ํ•จ
        } finally {
            log.info("์ธ์ฆ ์ฒดํฌ ํ•„ํ„ฐ ์ข…๋ฃŒ {}", requestURI);
        }
    }

    /**
     * ํ™”์ดํŠธ ๋ฆฌ์ŠคํŠธ์˜ ๊ฒฝ์šฐ ์ธ์ฆ ์ฒดํฌX
     */
    private boolean isLoginCheckPath(String requestURI) {
        return !PatternMatchUtils.simpleMatch(whitelist, requestURI);
    }
}

webconfig์— ๋“ฑ๋ก

@Bean
public FilterRegistrationBean loginCheckFilter() {
    FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
    filterRegistrationBean.setFilter(new LoginCheckFilter());
    filterRegistrationBean.setOrder(2);
    filterRegistrationBean.addUrlPatterns("/*");
    
    return filterRegistrationBean;
}

-> ์•„๋ฌด๋ฆฌ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋ฅด ๋“ค์–ด๊ฐ€๋ คํ•ด๋„ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ฐ–์— ๋“ค์–ด๊ฐˆ ์ˆ˜ ์—†๋‹ค.

@PostMapping("/login")
public String loginV4(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult,
                      @RequestParam(defaultValue = "/") String redirectURL,
                      HttpServletRequest request) {
    /*์ƒ๋žต*/
    return "redirect:" + redirectURL;
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์›๋ž˜ ๊ฐ€๋ ค๋˜ ํŽ˜์ด์ง€๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.

 

- ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ - ์†Œ๊ฐœ

HTTP ์š”์ฒญ -> WAS -> ํ•„ํ„ฐ -> ์„œ๋ธ”๋ฆฟ -> ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ -> ์ปจํŠธ๋กค๋Ÿฌ

์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ์— ๋น„ํ•ด ์ •๋ฐ€ํ•œ ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค

preHandle 

์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ ์ „์— ํ˜ธ์ถœ๋œ๋‹ค. (๋” ์ •ํ™•ํžˆ๋Š” ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ ํ˜ธ์ถœ ์ „์— ํ˜ธ์ถœ๋œ๋‹ค.)

์˜ˆ์™ธ ๋ฐœ์ƒ ์‹œ์—๋„ ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ ์ „์— ํ˜ธ์ถœ๋œ๋‹ค.
preHandle ์˜ ์‘๋‹ต๊ฐ’์ด true ์ด๋ฉด ๋‹ค์Œ์œผ๋กœ ์ง„ํ–‰ํ•˜๊ณ , false ์ด๋ฉด ๋”๋Š” ์ง„ํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. false
์ธ ๊ฒฝ์šฐ ๋‚˜๋จธ์ง€ ์ธํ„ฐ์…‰ํ„ฐ๋Š” ๋ฌผ๋ก ์ด๊ณ , ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ๋„ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ฆผ์—์„œ 1๋ฒˆ์—์„œ ๋์ด
๋‚˜๋ฒ„๋ฆฐ๋‹ค.


postHandle

์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ ํ›„์— ํ˜ธ์ถœ๋œ๋‹ค. (๋” ์ •ํ™•ํžˆ๋Š” ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ ํ˜ธ์ถœ ํ›„์— ํ˜ธ์ถœ๋œ๋‹ค.)

์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.


afterCompletion

๋ทฐ๊ฐ€ ๋ Œ๋”๋ง ๋œ ์ดํ›„์— ํ˜ธ์ถœ๋œ๋‹ค.

์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ํ˜ธ์ถœ๋œ๋‹ค.

 

- ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ - ์š”์ฒญ ๋กœ๊ทธ

@Slf4j
public class LogInterceptor implements HandlerInterceptor {
    public static final String LOG_ID = "logId";
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        String uuid = UUID.randomUUID().toString();

        request.setAttribute(LOG_ID, uuid);

        //@RequestMapping: HandlerMethod
        //์ •์  ๋ฆฌ์†Œ์Šค: ResourceHttpRequestHandler
        if (handler instanceof HandlerMethod) {
            //ํ˜ธ์ถœํ•  ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ์˜๋ชจ๋“  ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.
            HandlerMethod hm = (HandlerMethod) handler;
        }

        log.info("REQUEST [{}][{}][{}]", uuid, requestURI, handler);
        return true; //false ์ง„ํ–‰X
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle [{}]", modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String requestURI = request.getRequestURI();
        String logId = (String)request.getAttribute(LOG_ID);
        log.info("RESPONSE [{}][{}]", logId, requestURI);
        if (ex != null) {
            log.error("afterCompletion error!!", ex);
        }
    }
}
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor())
                .order(1)
                .addPathPatterns("/**")
                .excludePathPatterns("/css/**", "/*.ico", "/error");
    }

registry.addInterceptor(new LogInterceptor()) : ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ๋“ฑ๋กํ•œ๋‹ค.
order(1) : ์ธํ„ฐ์…‰ํ„ฐ์˜ ํ˜ธ์ถœ ์ˆœ์„œ๋ฅผ ์ง€์ •ํ•œ๋‹ค. ๋‚ฎ์„ ์ˆ˜๋ก ๋จผ์ € ํ˜ธ์ถœ๋œ๋‹ค.
addPathPatterns("/**") : ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์ ์šฉํ•  URL ํŒจํ„ด์„ ์ง€์ •ํ•œ๋‹ค.
excludePathPatterns("/css/**", "/*.ico", "/error") : ์ธํ„ฐ์…‰ํ„ฐ์—์„œ ์ œ์™ธํ•  ํŒจํ„ด์„ ์ง€์ •ํ•œ๋‹ค.

HandlerMethod
ํ•ธ๋“ค๋Ÿฌ ์ •๋ณด๋Š” ์–ด๋–ค ํ•ธ๋“ค๋Ÿฌ ๋งคํ•‘์„ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค. ์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ
@Controller , @RequestMapping ์„ ํ™œ์šฉํ•œ ํ•ธ๋“ค๋Ÿฌ ๋งคํ•‘์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด ๊ฒฝ์šฐ ํ•ธ๋“ค๋Ÿฌ ์ •๋ณด๋กœ
HandlerMethod ๊ฐ€ ๋„˜์–ด์˜จ๋‹ค.


ResourceHttpRequestHandler
@Controller ๊ฐ€ ์•„๋‹ˆ๋ผ /resources/static ์™€ ๊ฐ™์€ ์ •์  ๋ฆฌ์†Œ์Šค๊ฐ€ ํ˜ธ์ถœ ๋˜๋Š” ๊ฒฝ์šฐ
ResourceHttpRequestHandler ๊ฐ€ ํ•ธ๋“ค๋Ÿฌ ์ •๋ณด๋กœ ๋„˜์–ด์˜ค๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž…์— ๋”ฐ๋ผ์„œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 

postHandle, afterCompletion
์ข…๋ฃŒ ๋กœ๊ทธ๋ฅผ postHandle ์ด ์•„๋‹ˆ๋ผ afterCompletion ์—์„œ ์‹คํ–‰ํ•œ ์ด์œ ๋Š”, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ
postHandle ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. afterCompletion ์€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ํ˜ธ์ถœ ๋˜๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค.

 

PathPattern  ๊ณต์‹ ๋ฌธ์„œ

 

PathPattern (Spring Framework 6.0.4 API)

Compare this pattern with a supplied pattern: return -1,0,+1 if this pattern is more specific, the same or less specific than the supplied pattern.

docs.spring.io

 

- ์Šคํ”„๋ง ์ธํ„ฐ์…‰ํ„ฐ - ์ธ์ฆ ์ฒดํฌ

@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        
        String requestURI = request.getRequestURI();
        
        log.info("์ธ์ฆ ์ฒดํฌ ์ธํ„ฐ์…‰ํ„ฐ ์‹คํ–‰ {}", requestURI);
        
        HttpSession session = request.getSession(false);
        
        if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null) {
            log.info("๋ฏธ์ธ์ฆ ์‚ฌ์šฉ์ž ์š”์ฒญ");
            //๋กœ๊ทธ์ธ์œผ๋กœ redirect
            response.sendRedirect("/login?redirectURL=" + requestURI);
            return false;
        }
        return true;
    }
}
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor())
                .order(1)
                .addPathPatterns("/**")
                .excludePathPatterns("/css/**", "/*.ico", "/error");

        registry.addInterceptor(new LoginCheckInterceptor())
                .order(2)
                .addPathPatterns("/**") //๋ชจ๋“  ๊ณณ์— ์ ์šฉ
                .excludePathPatterns(
                        "/", "/members/add", "/login", "/logout",
                        "/css/**", "/*.ico", "/error" //ํ•˜์ง€๋งŒ ์ด๊ฑด ๋นผ
                );
    }

์ฝ”๋“œ๊ฐ€ ์„œ๋ธ”๋ฆฟ์— ๋น„ํ•ด์„œ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค

ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๋ฉด ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ž

 

- ArgumentResolver ํ™œ์šฉ

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Login {
}

@Target(ElementType.PARAMETER) : ํŒŒ๋ผ๋ฏธํ„ฐ์—๋งŒ ์‚ฌ์šฉ
@Retention(RetentionPolicy.RUNTIME) : ๋ฆฌํ”Œ๋ ‰์…˜ ๋“ฑ์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋Ÿฐํƒ€์ž„๊นŒ์ง€ ์• ๋…ธํ…Œ์ด์…˜ ์ •๋ณด๊ฐ€ ๋‚จ์•„์žˆ์Œ

@GetMapping("/")
public String homeLoginV3ArgumentResolver(@Login Member loginMember, Model model) {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    resolvers.add(new LoginMemberArgumentResolver());
}

 

@Slf4j
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        log.info("supportsParameter ์‹คํ–‰");
        boolean hasLoginAnnotation =
                parameter.hasParameterAnnotation(Login.class);
        boolean hasMemberType =
                Member.class.isAssignableFrom(parameter.getParameterType());
        return hasLoginAnnotation && hasMemberType;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {

        log.info("resolveArgument ์‹คํ–‰");

        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
        HttpSession session = request.getSession(false);

        if (session == null) {
            return null;
        }

        return session.getAttribute(SessionConst.LOGIN_MEMBER);
    }
}

๊ฒฐ๊ณผ๋Š” ๋™์ผํ•˜๊ฒŒ, ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Œ