Publish:

ํƒœ๊ทธ:

์นดํ…Œ๊ณ ๋ฆฌ:

์–ด๋…ธํ…Œ์ด์…˜ ์œ ์ง€์ •์ฑ…

์–ด๋…ธํ…Œ์ด์…˜์„ ์–ธ์ œ๊นŒ์ง€ ์œ ์ง€ํ•  ๊ฒƒ์ธ๊ฐ€

CLASS(default)

1
2
3
4
@Retention(value=RetentionPolicy.CLASS)
public @interface MyAnnotation {
  String value() default "๊ธฐ๋ณธ๊ฐ’์‚ฌ์šฉ";   // ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉํ•˜๋Š” ์ชฝ์—์„œ ๋”ฐ๋กœ ๊ฐ’ ์„ค์ • ์—†์ด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‚ฌ์šฉ.
}

์ปดํŒŒ์ผ ๊ณผ์ •๊นŒ์ง€ ์œ ์ง€ํ•˜๊ฒ ๋‹ค. .class ํŒŒ์ผ์— ์–ด๋…ธํ…Œ์ด์…˜์„ ํฌํ•จํ•œ๋‹ค. ๋ฐ”์ดํŠธ์ฝ”๋“œ๋กœ ์–ด๋…ธํ…Œ์ด์…˜ ํ™•์ธ ๊ฐ€๋Šฅ. ๊ทธ๋Ÿฌ๋‚˜ ๋Ÿฐํƒ€์ž„์— ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋”ฉ๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌํ”Œ๋ ‰์…˜ API๋กœ ์•Œ์•„๋‚ผ ์ˆ˜ ์—†๋‹ค.

SOURCE

1
2
3
4
@Retention(value=RetentionPolicy.SOURCE)
public @interface MyAnnotation {
  String value();
}

์†Œ์Šค ํŒŒ์ผ์—๋งŒ ๋‚จ๊ธด๋‹ค. .class ํŒŒ์ผ์— ํฌํ•จ ์•ˆ๋œ๋‹ค. ์ปดํŒŒ์ผ ์‹œ ์ œ๊ฑฐ๋œ๋‹ค. ๋ฐ”์ดํŠธ์ฝ”๋“œ๋กœ ํ™•์ธ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

RUNTIME

1
2
3
4
@Retention(value=RetentionPolicy.RUNTIME)
public @interface MyAnnotation3 {
  String value();
}

.class ํŒŒ์ผ์—๋„ ํฌํ•จ๋˜๊ณ , ์‹คํ–‰ํ•  ๋•Œ๋„ ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋”ฉ๋œ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ์ •๋ณด๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ์–ด๋…ธํ…Œ์ด์…˜ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ

1
2
3
4
@MyAnnotation
public class MyClass {
  
}
1
2
Class<?> clazz = MyClass.class;
clazz.getAnnotation(MyAnnotation.class);

์–ด๋…ธํ…Œ์ด์…˜ ์ ์šฉ ๋ฒ”์œ„

@Target์„ ์‚ฌ์šฉํ•˜์—ฌ ์• ๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ผ ์ˆ˜ ์žˆ๋Š” ๋ฒ”์œ„๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

์ข…๋ฅ˜ ๋ฒ”์œ„
ElementType.TYPE ํด๋ž˜์Šค, ์ธํ„ฐํŽ˜์ด์Šค์— ๋ถ™์ผ ์ˆ˜ ์žˆ๋‹ค.
ElementType.FIELD ํ•„๋“œ ์„ ์–ธ ์•ž์— ๋ถ™์ธ๋‹ค.
ElementType.METHOD ๋ฉ”์†Œ๋“œ ์„ ์–ธ ์œ„์— ๋ถ™์ธ๋‹ค.
ElementType.LOCAL_VARIABLE ๋กœ์ปฌ ๋ณ€์ˆ˜ ์•ž์— ๋ถ™์ธ๋‹ค.
{ElementType.LOCAL_VARIABLE, ElementType.PARAMETER, ElementType.FIELD} ๋ฐฐ์—ด ํ˜•ํƒœ๋กœ ์—ฌ๋Ÿฌ๊ตฐ๋ฐ์„œ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.
1
2
3
@Target({ElementType.LOCAL_VARIABLE, ElementType.PARAMETER, ElementType.FIELD})
public @interface MyAnnotation {
}

์–ด๋…ธํ…Œ์ด์…˜ ํ™œ์šฉ

RetentionPolicy.RUNTIME ์œ ์ง€ ์ •์ฑ…์„ ๊ฐ€์ง„ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ™œ์šฉํ•˜๋ฉด ์‹คํ–‰์ค‘์ธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํŠน์ • ์ •๋ณด๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ๋กœ๊ทธ์ธํ•œ ์œ ์ €์˜ ์„ธ์…˜(httpSession) ์ฒดํฌ๋ฅผ ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.

์œ ์ € ์„ธ์…˜ ์ •๋ณด ํ™•์ธ

1
2
3
4
5
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {

}

์šฐ์„  ์–ด๋…ธํ…Œ์ด์…˜์„ ์ •์˜ํ•œ๋‹ค. ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์„ ํŒŒ๋ผ๋ฏธํ„ฐ ์•ž์— ๋ถ™์ผ ์ˆ˜ ์žˆ๋„๋ก @Target์„ ์ง€์ •ํ•˜๊ณ , ๋Ÿฐํƒ€์ž„ ์‹œ์—๋„ ๋ฉ”๋ชจ๋ฆฌ ์ƒ์— ์–ด๋…ธํ…Œ์ด์…˜ ์ •๋ณด๊ฐ€ ์œ ์ง€๋˜๋„๋ก @Retention ๋ฒ”์œ„๋ฅผ ์ง€์ •ํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ์–ด๋…ธํ…Œ์ด์…˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•ด ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๋„˜์–ด์˜ค๋Š” DTO(Data Transfer Object) ๊ฐ์ฒด๋ฅผ ๊ฒ€์ฆํ•˜๊ฒŒ ๋œ๋‹ค.

HandlerMethodArgumentResolver

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
@RequiredArgsConstructor
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

    private final HttpSession httpSession;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // ํŒŒ๋ผ๋ฏธํ„ฐ์— LoginUser ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์–ด ์žˆ๋Š”๊ฐ€?
        boolean isLoginUserAnnotation = parameter.getParameterAnnotation(LoginUser.class) != null;
        // ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์ด SessionUser ์ธ๊ฐ€?
        /* if(parameter.getParameterType == LoginUser.class) {return true} */
        boolean isUserClass = SessionUser.class.equals(parameter.getParameterType());
        // ๋‘˜๋‹ค ์ฐธ์ผ ๊ฒฝ์šฐ true ๋ฐ˜ํ™˜
        return isLoginUserAnnotation && isUserClass;
    }

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

        // ์œ„ supportsParameter ๋ฉ”์†Œ๋“œ true ์ด๋ฉด ์‹คํ–‰
        return httpSession.getAttribute("user");
    }
}

HandlerMethodArgumentResolver๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ์ปจํŠธ๋กค๋Ÿฌ ์ง„์ž… ์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „์ฒ˜๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์œ„ ์ฝ”๋“œ์—์„œ๋Š” ์œ ์ € ์ •๋ณด๋ฅผ ๋ฐ›๋Š” DTO ๊ฐ์ฒด์˜ ์–ด๋…ธํ…Œ์ด์…˜ ํƒ€์ž…์„ ํ™•์ธํ•˜๊ณ , ๋ฉ”์†Œ๋“œ์˜ ํ˜„์žฌ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์ด SessionUser์ธ์ง€ ํ™•์ธํ•œ๋‹ค. ๋งจ์œ„์—์„œ ์ •์˜ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์˜ ๊ทœ์น™์— ๋งž๋Š”์ง€ ๋‹ค์‹œ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค. supportsParameter๊ฐ€ true ๋ฅผ ๋ฆฌํ„ดํ•˜๊ฒŒ๋˜๋ฉด, resolveArgument์—์„œ ์‹ค์ œ ์„ธ์…˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

WebConfig

1
2
3
4
5
6
7
8
9
10
11
12
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
  private final LoginUserArgumentResolver loginUserArgumentResolver;
  private final UserAgentArgumentResolver userAgentArgumentResolver;

  @Override
  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    resolvers.add(loginUserArgumentResolver);
    resolvers.add(userAgentArgumentResolver);
  }
}

์œ„์—์„œ ์ •์˜ํ•œ HandlerMethodArgumentResolver๊ตฌํ˜„์ฒด๋ฅผ ์•ฑ ์‹œ์ž‘ ์‹œ ์ธ์‹ํ•˜๊ธฐ ์œ„ํ•ด WebMvcConfigurer์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด ๋„ฃ์–ด์ค€๋‹ค.

IndexController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RequiredArgsConstructor
@Controller
public class IndexController {

  private final PostsService postsService;
  private final HttpSession httpSession;  // ์ด์ œ ์„ธ์…˜์—์„œ ๋ฐ”๋กœ ๊บผ๋‚ด์ง€ ์•Š๊ณ  ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•ด ๊บผ๋‚ธ๋‹ค.

  @GetMapping("/")
  public String index(Model model, @LoginUser SessionUser user, @UserInfo String useragent) {
    model.addAttribute("posts", postsService.findAllDesc());
    // ๋กœ๊ทธ์ธํ•œ ์œ ์ € ์„ธ์…˜ ๊ฐ€์ ธ์˜ค๊ธฐ
    //  -> ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜(LoginUserArgumentResolver) ์œผ๋กœ ๋ณ€๊ฒฝ ์‹œ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ „๋‹ฌ๋˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ์—์„œ(user) ๋ชจ๋‘ ๊ฒ€์ฆ์ด ๋๋‚œ ์ƒํƒœ๋กœ ๊ฐ€์ ธ์˜ด.
    //     - ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์„ธ์…˜์—์„œ ๊ฐ€์ ธ์˜ด(resolveArgument ๋ฉ”์†Œ๋“œ ๋ฆฌํ„ด ๋ถ€๋ถ„. httpsession.getAttribute)
    //     - ์ •์˜ํ•œ ์–ด๋…ธํ…Œ์ด์…˜์ด ๋ถ™์–ด์žˆ๋Š”์ง€ / ํƒ€์ž… ์ฒดํฌ.

    //        SessionUser user = (SessionUser) httpSession.getAttribute("user");

    if (user != null) {
      model.addAttribute("userName", user.getName());
    }
    model.addAttribute("userAgent", useragent);
    return "index";
  }

๋กœ๊ทธ์ธ ํ•œ ์œ ์ €๊ฐ€ ์ธ๋ฑ์Šค ํŽ˜์ด์ง€ ์ ‘๊ทผ ์‹œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์–ด๋…ธํ…Œ์ด์…˜์œผ๋กœ ์„ธ์…˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

1
2
3
  ... 
HttpServletRequest req = (HttpServletRequest) webRequest.getNativeRequest();
req.getHeader("User-Agent");

์„ธ์…˜ ์ •๋ณด๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ ‘์† ์ •๋ณด ๋“ฑ์„ ๊ฐ€์ ธ์˜ค๋Š” ์ฝ”๋“œ๋ฅผ resolver ์— ๋“ฑ๋กํ•ด ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

reference

๋ฐฉ๋ฌธํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๋Œ“๊ธ€,์ง€์ ,ํ”ผ๋“œ๋ฐฑ ์–ธ์ œ๋‚˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค๐Ÿ˜Š

๐Ÿ˜€

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ