[Java] ์ด๋ ธํ ์ด์ (annotation)์ ํ์ฉํด ์ธ์ ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
ํ๊ทธ: Java
์นดํ ๊ณ ๋ฆฌ: Java
์ด๋ ธํ ์ด์ ์ ์ง์ ์ฑ
์ด๋ ธํ ์ด์ ์ ์ธ์ ๊น์ง ์ ์งํ ๊ฒ์ธ๊ฐ
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 ์ ๋ฑ๋กํด ์ฌ์ฉํ ์๋ ์๋ค.
๋๊ธ๋จ๊ธฐ๊ธฐ