๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ marketing Analytics ๊ณตํ†ต๋ชจ๋“ˆ ์ œ์ž‘๊ธฐ


๊ฐœ์š”
  • Hello Service์˜ ์œ ์ž…/๋™์ž‘ ํ†ต๊ณ„ ๋ชจ๋“ˆ์˜ ๊ณตํ†ตํ™” ์ž‘์—…์ด๋‹ค.
  • Spring AOP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

1. ๊ธฐ์กด js ํ•˜๋“œ์ฝ”๋”ฉ ๋˜์–ด์žˆ๋˜ ํ†ต๊ณ„ ๋กœ์ง SpringAOP ๊ณตํ†ตํ™”

  • ํ†ต๊ณ„ ํ•„์š” ํŽ˜์ด์ง€ ๋‚ด์—์„œ(front > back)

2. Hit์ฒดํฌ ๋™์ž‘ ๋ฐ์ดํ„ฐ ์‚ฝ์ž… ํ›„ ํ”„๋ก์‹œ ๋“ฑ๋ก

  • ์ฟ ํ‚ค ๋ฐ์ดํ„ฐ ํŽ˜์ด์ง€ ๋ณ„ ์ตœ์ดˆ ์ง„์ž… ํ™•์ธ?

3. ์ƒ์„ธ ์ธ์ž… ์ •๋ณด ์ €์žฅ์œผ๋กœ ADMINํ†ต๊ณ„ page์ œ์ž‘


๋ชฉ์ 

  • ๊ธฐ์กด ์™ธ๋ถ€ ์œ ์ž… ํ†ต๊ณ„ ๋กœ์ง์˜ ๋‹จ์  ํ•ด๊ฒฐ.
    1. ํ™•์žฅ์— ๋‹ซํ˜€์žˆ์Œ
    2. ๋””ํ…Œ์ผํ•œ ํ–‰๋™ ์ถ”์  ๋ถˆ๊ฐ€๋Šฅ
    3. ์ค‘๋ณต ์ ‘๊ทผ์ž ์ฒ˜๋ฆฌ๋กœ์ง์˜ ๋ถ€์žฌ


๋ฐ์ดํ„ฐ ๋ชจ๋ธ ๊ตฌ์ƒ

KEY idx hitDate hitCode hitUid pageURL pageType
3 2024-12-10 11-45-12.13 a2FrYW8xc3QK f2843ad6-2de0-48d2-9b5d-3b0eb4f9a4f5 sp/loan GET
2 2024-12-10 12-40-11.22 AAA22dfxdfw2 94107590-2b39-478f-9bb3-32f4a8ef68cb sp/loan/mortgage/notice GET
1 2024-12-09 12-40-11.22 aWfeYW8xc222 3eac413b-a95b-44f8-8f12-32ec4be98e39 sp/marketing/hitTest1 POST


๊ณ ๋ ค์‚ฌํ•ญ


1. ์ถ”์ ์„ ์–ผ๋งˆ๋‚˜ ๋””ํ…Œ์ผํ•˜๊ฒŒ ์ €์žฅํ• ์ง€?

  • ํ•ด๋‹น ์ง„์ž…์‹œ์ ๋ถ€ํ„ฐ ํŠน์ • ๋™์ž‘์— ๋Œ€ํ•œ ๋ชจ๋“  ํƒ€์ž„๋ผ์ธ ๋กœ๊ทธ

2. ๋””ํ…Œ์ผํ•œ ๋กœ๊ทธ์— ๋Œ€ํ•œ ๋ถ€ํ•˜๋ถ„์‚ฐ์€ ์–ด๋–ป๊ฒŒ ํ• ์ง€?

  • ๋ ˆ๋””์Šค ๊ฐ€์šฉ ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•œ ํ•œ๊ณ„๊ฐ’ ์‚ฐ์ •.

3. ์ธ์ž…์‹œ์ ์ด ์•„๋‹Œ ๋™์ž‘์—๋Œ€ํ•œ unique๊ฐ’์„ ์–ด๋–ป๊ฒŒ ์ง€์ •ํ• ์ง€?

  • URL + ํ•จ์ˆ˜๋ช… ์กฐํ•ฉ


Spring AOP ์‚ฌ์šฉ ์ด์œ 


- ๊ด€์‹ฌ์‚ฌ(Aspect)๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ, ๊ฐ ์„œ๋น„์Šค ๋ฉ”์„œ๋“œ์— ๋ฐ˜๋ณตํ•ด์„œ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ๋ณ„๋„์˜ Aspect๋กœ ๊ด€๋ฆฌํ•˜์—ฌ ํ•ต์‹ฌ๋กœ์ง์„ ๊ณตํ†ต์œผ๋กœ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.

์–ด๋–ป๊ฒŒ ์ž์‹ ์˜ ๋ฉ”์ธ ํ…Œ์ด๋ธ”์„ ์ฐพ์„๊ฒƒ์ธ๊ฐ€?

    1. ๋‚œ์ˆ˜ ์ƒ์„ฑ ํ›„ ๋ฌผ๊ณ ์žˆ๊ธฐโ˜‘
    1. IP๋กœ ์ถ”์ 

Path๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ์ฃผ์ง€ ์•Š์•˜์„ ๋•Œ, ์ฟ ํ‚ค๊ฐ€ ๋“ฑ๋ก๋˜์ง€ ์•Š๋Š” ์ด์œ  Pasted image 20241224144309.png

์ฟ ํ‚ค๊ฐ€ ํ•„์š”ํ•œ ํŽ˜์ด์ง€์˜ ๊ฒฝ๋กœ๊ฐ€ ๊ธฐ๋ณธ path์™€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ(redirect url ์ด SP_MARKETING_HIT_TEST1 ์˜ ํ•˜์œ„ url์ผ ๊ฒฝ์šฐ) ์—๋Š” ๋ช…์‹œ์ ์œผ๋กœ ํ‘œ์‹œํ•  ํ•„์š”๊ฐ€ ์—†์ง€๋งŒ,

ํ˜„์žฌ๋Š” ํ•˜์œ„ URL์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฝ๋กœ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.



AOP์—์„œ Front-end ๋‹จ์˜ ํŠน์ • ๋™์ž‘ ํ•„ํ„ฐ๋ง ํ•˜๊ธฐ

Pointcut ๊ฐ์ฒด์— ๋™์ ์œผ๋กœ enum์—์„œ ๋ฏธ๋ฆฌ ์„ ์–ธํ•œ ๊ฐ’ execution์œผ๋กœ ์‚ฝ์ž…ํ•˜๊ธฐ

(์ดํ›„ ADMIN ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด enum๊ฐ์ฒด -> DB ๋ฐ์ดํ„ฐํ™” )

๊ธฐ์กด

Pasted image 20241226111559.png

DB

Pasted image 20250102160223.png



@Pointcut ์–ด๋…ธํ…Œ์ด์…˜์€ ์ปดํŒŒ์ผ ์‹œ์ ์— ๊ณ ์ •๋œ ๋ฌธ์ž์—ด๋กœ ์ •์˜๋œ ํฌ์ธํŠธ์ปท ํ‘œํ˜„์‹์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ ๋ฐฉ์‹

  • ์žฅ์ :
    • ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜๊ณ  ์ฝ๊ธฐ ์‰ฝ๋‹ค.
    • Spring์˜ AOP ์ธํ”„๋ผ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์„œ๋“œ ์ธํ„ฐ์…‰์…˜์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹จ์ :
    - ํฌ์ธํŠธ์ปท ์กฐ๊ฑด์€ ์ปดํŒŒ์ผ ์‹œ์ ์— ๊ณ ์ •๋œ๋‹ค.
    - ๋ณต์žกํ•œ ์กฐ๊ฑด์ด๋‚˜ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ์กฐ๊ฑด์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์–ด๋ ต๋‹ค.
    
    -> @Pointcut ๋“ฑ์˜ ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” Bean๊ฐ์ฒด๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์— ์ฐพ์•„๋‚ด์–ด ํ”„๋ก์‹œ๋ฅผ ๊ฐ์‹ผ๋‹ค.

ํ”„๋ก์‹œ ๊ธฐ๋ฐ˜ ๋™์  ํฌ์ธํŠธ์ปท ์ƒ์„ฑ๋ฐฉ์‹

  • ๋™์  ์ƒ์„ฑ:
    • ๋Ÿฐํƒ€์ž„์— ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํฌ์ธํŠธ์ปท๊ณผ ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ๋™์ ์œผ๋กœ ์ ์šฉ.
    • StaticMethodMatcherPointcut ๋˜๋Š” DynamicMethodMatcherPointcut์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Ÿฐํƒ€์ž„ ์กฐ๊ฑด ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฉ”์„œ๋“œ ๋งค์นญ.
  • ์žฅ์ :
    • ๋Ÿฐํƒ€์ž„ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ํฌ์ธํŠธ์ปท ์ƒ์„ฑ ๊ฐ€๋Šฅ.
    • ๋ณต์žกํ•œ ์กฐ๊ฑด๊ณผ ๋™์  ํ•„ํ„ฐ๋ง์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์šฉ์ด.
    • Spring AOP๊ฐ€ ์•„๋‹Œ ์ˆœ์ˆ˜ Java ํ”„๋ก์‹œ ๋ฐฉ์‹๋„ ์ง€์›.
  • ๋‹จ์ :
    • ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ง€๊ณ  ์ถ”๊ฐ€ ๊ตฌํ˜„์ด ํ•„์š”.
    • Spring AOP์™€ ๋™์ผํ•œ ์ˆ˜์ค€์˜ ๊ฐ„๊ฒฐ์„ฑ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์Œ.

-> ํ•ด๋‹น ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ ์šฉํ•˜๊ณ  ์‹ถ์€ Bean๊ฐ์ฒด์— ๋งค๋ฒˆ ์ƒ์„ฑ(๋“ฑ๋ก)ํ•ด์ฃผ์–ด์•ผ ํ•จ.




customAdvisor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์  ํฌ์ธํŠธ์ปท ์ƒ์„ฑํ•˜๊ธฐ

import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AopConfig {

    @Bean
    public Pointcut customPointcut() {
        return new CustomPointcut();
    }

    @Bean
    public CustomAdvice customAdvice() {
        return new CustomAdvice();
    }

    @Bean
    public DefaultPointcutAdvisor customAdvisor(Pointcut customPointcut, CustomAdvice customAdvice) {
        return new DefaultPointcutAdvisor(customPointcut, customAdvice);
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator proxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }
}

์œ„ ์ฝ”๋“œ์˜ DefaultAdvisorAutoProxyCreator๊ฐ์ฒด๊ฐ€ ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” ๋นˆ์— ๋Œ€ํ•ด ์ž๋™์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ Advice๋ฅผ ์ ์šฉํ•œ๋‹ค.

  • @Pointcut ๋ฐฉ์‹๊ณผ ๋™์ผํ•œ ๋™์ž‘:
    • Spring ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๋ชจ๋“  ๋นˆ์— ๋Œ€ํ•ด ์กฐ๊ฑด์„ ํ‰๊ฐ€ํ•˜๊ณ  ํ”„๋ก์‹œ๋ฅผ ์ž๋™ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ํ”„๋ก์‹œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์„ ์–ธํ•  ํ•„์š” ์—†์Œ:
    • ProxyFactory์ฒ˜๋Ÿผ ์ˆ˜๋™์œผ๋กœ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.
  • ์œ ์—ฐ์„ฑ๊ณผ ํšจ์œจ์„ฑ ํ–ฅ์ƒ:
    • Spring AOP ์ธํ”„๋ผ๋ฅผ ํ™œ์šฉํ•˜๋ฏ€๋กœ, ๊ด€๋ฆฌ๊ฐ€ ์šฉ์ดํ•˜๊ณ  ๋Ÿฐํƒ€์ž„ ์„ฑ๋Šฅ์ด ๊ฐœ์„ ๋ฉ๋‹ˆ๋‹ค.



DefaultAdvisorAutoProxyCreator๋Š” ์–ด๋–ป๊ฒŒ customAdvisor์˜ ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” ๋นˆ์„ ์ฐพ๋‚˜?

  • BeanPostProcessor:
    • DefaultAdvisorAutoProxyCreator๋Š” Spring์˜ BeanPostProcessor๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค์ด๋‹ค.
    • Spring ์ปจํ…Œ์ด๋„ˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก๋œ ๋ชจ๋“  BeanPostProcessor๋ฅผ ์ž๋™์œผ๋กœ ํ˜ธ์ถœํ•˜์—ฌ ๋นˆ์˜ ์ดˆ๊ธฐํ™” ์ „ํ›„ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
    • ์ด๋ฅผ ํ†ตํ•ด, Spring AOP๋Š” ๋นˆ ์ƒ์„ฑ ๋‹จ๊ณ„์—์„œ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์กฐ๊ฑด์— ๋งž๋Š” ๋นˆ์— ๋Œ€ํ•ด ์–ด๋“œ๋ฐ”์ด์ €๋ฅผ ์ ์šฉ.
  • Advisor ํƒ์ƒ‰:
    • DefaultAdvisorAutoProxyCreator๋Š” Spring ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก๋œ ๋ชจ๋“  Advisor๋ฅผ ์ž๋™์œผ๋กœ ํƒ์ƒ‰ํ•œ๋‹ค.
    • ์ด๋Š” DefaultAdvisorAutoProxyCreator๊ฐ€ BeanFactory๋ฅผ ํ†ตํ•ด ์ปจํ…Œ์ด๋„ˆ์˜ ๋ชจ๋“  Advisor ํƒ€์ž… ๋นˆ์„ ์กฐํšŒํ•˜๊ธฐ ๋•Œ๋ฌธ.
    • ํƒ์ƒ‰๋œ Advisor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ๋นˆ์˜ ๋ฉ”์„œ๋“œ์™€ ํฌ์ธํŠธ์ปท ์กฐ๊ฑด์„ ๋งค์นญ.
  • Advisor์™€ ๋นˆ์˜ ๋งค์นญ:
    • ๋นˆ์ด ์ƒ์„ฑ๋  ๋•Œ, DefaultAdvisorAutoProxyCreator๋Š” ํ•ด๋‹น ๋นˆ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ์–ด๋–ค Advisor์˜ ํฌ์ธํŠธ์ปท ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š”์ง€ ํ‰๊ฐ€.
    • ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋ฉด, ํ•ด๋‹น ๋นˆ์„ ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ๊ฐ์‹ธ๊ณ , ์–ด๋“œ๋ฐ”์ด์Šค๋ฅผ ์—ฐ๊ฒฐ.

์œ„ ๋ฐฉ๋ฒ•์˜ ๋ฌธ์ œ์ ?

ํด๋ž˜์Šค์— ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด JDK ๋™์  ํ”„๋ก์‹œ, ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†์œผ๋ฉด CGLIB ํ”„๋ก์‹œ

  • ์ด๋ ‡๊ฒŒ ๋งตํ•‘์ด ๋˜์–ด์•ผ ํ•˜๋‚˜, ์ด๋ฅผ ๋™์ ์œผ๋กœ ํƒ์ง€ํ•˜์ง€ ๋ชปํ•œ๋‹ค.
/*  
 * EnableAspectJAutoProxy > ํ”„๋ก์‹œ ์ ์šฉ์‹œ ์ธํ„ฐํŽ˜์ด์Šค/ํด๋ž˜์Šค ์—ฌ๋ถ€ ์ž๋™ ํŒ๋‹จ  
 * ํด๋ž˜์Šค์— ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด JDK ๋™์  ํ”„๋ก์‹œ.  
 * ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์—†์œผ๋ฉด CGLIB ํ”„๋ก์‹œ.  
 * */@Configuration  
@EnableAspectJAutoProxy  
public class AopConfig {  
    @Bean  
    public Pointcut customPointcut() {  
        return new CustomPointcut();  
    }  
  
    @Bean  
    public CustomAdvice customAdvice() {  
        return new CustomAdvice();  
    }  
  
    @Bean  
    public DefaultPointcutAdvisor customAdvisor(Pointcut customPointcut, CustomAdvice customAdvice) {  
        return new DefaultPointcutAdvisor(customPointcut, customAdvice);  
    }  
	/*  
	* @EnableAspectJAutoProxy๋ฅผ ์‚ฌ์šฉํ•ด ๋“ฑ๋กํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถˆํ•„์š”.  
	* */  
	//    @Bean  
	//    public DefaultAdvisorAutoProxyCreator proxyCreator() {  
	//        return new DefaultAdvisorAutoProxyCreator();  
	//    }  
}

@EnableAspectJAutoProxy ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ๋นˆ ์ตœ์ดˆ๋“ฑ๋ก์‹œ ์ž๋™์œผ๋กœ ํŒ๋‹จํ•˜์—ฌ ํ•ด๋‹น ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

StaticMethodMatcherPointcut์—์„œ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ํ˜ธ์ถœ ๊ณ ์œ ์ •๋ณด


ํƒ€๊ฒŸ ํด๋ž˜์Šค / ๋ฉ”์„œ๋“œ๋ช… / ํŒŒ๋ผ๋ฏธํ„ฐ / ์–ด๋…ธํ…Œ์ด์…˜

Method Name: loanerLoginPage javax.servlet.http.HttpServletRequest org.springframework.web.bind.annotation.GetMapping

๋ฉ”์„œ๋“œ ๊ฒ€์ฆ ํฌ์ธํŠธ ์ปท ์ถ”๊ฐ€ ํ›„ ๋นŒ๋“œ ์‹œ๊ฐ„

Pasted image 20241226152219.png


ENUM๊ฐ์ฒด์—, ๊ณ ์œ ํ•œ ์ •๋ณด๋ฅผ ๋„ฃ์–ด์ฃผ๋ฉด ์ž๋™ ์ง‘๊ณ„๊ฐ€ ์‹œ์ž‘๋œ๋‹ค

์ดํ›„ DB์— ๋งตํ•‘ํ•˜์—ฌ admin์—์„œ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌ๋กœ ๋ณ€๊ฒฝ ๋จ.

Pasted image 20241226171158.png

customAdvice์— ๋“ฑ๋ก๋œ invokeํ•จ์ˆ˜๋Š” Pointcut์˜ ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” ๋ฉ”์„œ๋“œ์˜ ์ •๋ณด๋งŒ์„ ๊ฐ€์ ธ์˜จ๋‹ค.


์ผ€์ด์Šค ์ •๋ฆฌ

1. Pointcut์— ์žˆ๋Š” ๋ฉ”์„œ๋“œ์ด๋ฉฐ, "p"ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์žˆ์„๋•Œ,

1.1 ํ˜„์žฌ ์ฟ ํ‚ค์— hitCode / hitUid ๊ฐ€ ์—†์„๋•Œ

  • ์™ธ๋ถ€๋งํฌ ์ตœ์ดˆ์ง„์ž…. hitCode, hitUid ๋ฐœ๊ธ‰ ๋ฐ DB์ €์žฅ

1.2 ํ˜„์žฌ ์ฟ ํ‚ค์— hitCode / hitUid ๊ฐ€ ์žˆ์„๋•Œ

  • ์™ธ๋ถ€๋งํฌ ์žฌ์ง„์ž…. hitCode๋Š” ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ "p"ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์žฌ๋ฐœ๊ธ‰ => hitCode๋Š” ๋งค๋ฒˆ ์žฌ๋ฐœ๊ธ‰ / hitUid๋Š” ์—†์„๋•Œ๋งŒ ๋ฐœ๊ธ‰

2. Pointcut์— ์žˆ๋Š” ๋ฉ”์„œ๋“œ์ด๋ฉฐ,"p"ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—†์„๋•Œ,

2.1 ํ˜„์žฌ ์ฟ ํ‚ค์— hitCode / hitUid ๊ฐ€ ๋‘˜๋‹ค ์—†์„๋•Œ

  • ์ผ๋ฐ˜์‚ฌ์šฉ์ž ์ด๋ฉฐ, ์•„๋ฌด๋™์ž‘ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

2.2 ํ˜„์žฌ ์ฟ ํ‚ค์— hitUid ๋˜๋Š” hitUid ๊ฐ€ ์žˆ์„๋•Œ

  • ์™ธ๋ถ€๋งํฌ ์ง„์ž… ํ›„ ๋™์ž‘. ์—†๋Š” ๋…€์„ ์ƒˆ๋กœ ๋ฐœ๊ธ‰ ๋ฐ DB์ €์žฅ

์„œ๋น„์Šค ์ €์žฅ์‹œ ๋™์‹œ์„ฑ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค?
@Override  
@Transactional  
public ResponseModel insertMarketingHitLog(String hitCode, String hitUid, String pageUrl, String pageType){  
    try {  
        Optional<HfMarketingHitLog> existingLog = hfMarketingHitLogRepository.findByHitCodeAndHitUidAndPageUrlAndPageType(hitCode, hitUid, pageUrl, pageType);  
        if (existingLog.isPresent()) {  
            HfMarketingHitLog logToUpdate = existingLog.get();  
            logToUpdate.setUpdateDate(LocalDateTime.now());  
            hfMarketingHitLogRepository.save(logToUpdate);  
            return new ResponseModel(ResponseModel.ResponseStatus.SUCCESS);  
        }  
        HfMarketingHitLog hfMarketingHitLog = HfMarketingHitLog.builder()  
                .hitCode(hitCode)  
                .hitUid(hitUid)  
                .pageUrl(pageUrl)  
                .pageType(pageType)  
                .build();  
        hfMarketingHitLogRepository.save(hfMarketingHitLog);  
        return new ResponseModel(ResponseModel.ResponseStatus.SUCCESS);  
    } catch (Exception e) {  
        return new ResponseModel(ResponseModel.ResponseStatus.FAILED, "๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ");  
    }  
}

์ค‘๋ณต ๋ฐ์ดํ„ฐ ์กฐํšŒ์™€ ์ €์žฅ ์‚ฌ์ด์˜ ํƒ€์ด๋ฐ ์ฐจ์ด

  • ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ(๋˜๋Š” ํŠธ๋žœ์žญ์…˜)๊ฐ€ findByHitCodeAndHitUidAndPageUrlAndPageType ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋™์ผํ•œ ์กฐ๊ฑด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์‹œ์— ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‘ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ชจ๋‘ existingLog.isPresent() ์กฐ๊ฑด์—์„œ false๋ฅผ ํ™•์ธํ•œ ํ›„, ๋™์‹œ์— ์ƒˆ๋กœ์šด HfMarketingHitLog ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ €์žฅํ•˜๋ ค ํ•˜๋ฉด ๋ฐ์ดํ„ฐ ์ค‘๋ณต ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

. Lock์„ ์“ฐ๋ฉด ๋˜๋‚˜, ์ดํ›„ ์—…๋ฐ์ดํŠธ ๋กœ์ง ์‚ญ์ œ(๋กœ๊ทธ ํ…Œ์ด๋ธ”ํ™”) ๋ณ€๊ฒฝ์œผ๋กœ ์ฒ˜๋ฆฌ


๊ฒฐ๊ณผ

Pasted image 20241230135801.png

  • 1์ผ์˜ ์œ ํšจ๊ธฐ๊ฐ„์„ ๊ฐ–๋Š” uid๋ฅผ ๋ฐœ๊ธ‰ํ•˜์—ฌ, ์ธ์ž…์ฝ”๋“œ / Hit๋œ ๊ธฐ๋Šฅ ์ฃผ์†Œ / ์‹œ๊ฐ„ ์„ ์ €์žฅํ•œ๋‹ค.
  • uid๋Š” ์™ธ๋ถ€url๋กœ ์ ‘๊ทผ์‹œ ๋ฐœ๊ธ‰
  • page_url๋Š” ์ฝ”๋“œ์— ๋ฏธ๋ฆฌ ๋“ฑ๋ก / hit_code๋Š” ๋ชจ๋‘(only ์˜๋ฌธ+์ˆซ์ž) ์ˆ˜์šฉ ๊ฐ€๋Šฅ

PointCut service ์ƒ์„ฑ์ž ์ฃผ์ž…์œผ๋กœ, DB์—์„œ ๊ฐ’๋กœ๋“œ ํ˜•์‹์œผ๋กœ ๋ณ€๊ฒฝ

Pasted image 20250102160213.png Pasted image 20250102160223.png


ENUM๊ฐ์ฒด์—์„œ DB๋กœ ์ „ํ™˜

  1. enum๊ฐ์ฒด์— ์ •์˜๋œ ๋ฉ”์„œ๋“œ๋ฅผ DB๋กœ ์ „ํ™˜ํ•˜์—ฌ pointcut์—์„œ ํ•ด๋‹น ํด๋ž˜์Šค, ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ ธ์™€ ์กฐ๊ฑด์œผ๋กœ ์ •์˜
  2. ํ•ด๋‹น ์กฐ๊ฑด์— ๋ถ€ํ•ฉํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ”„๋ก์‹œ๋กœ ์ „ํ™˜

๋‹ค์Œ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด DB๋กœ admin๊ณผ app์„ ๋ชจ๋‘ ๊ด€๋ฆฌ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ˆ˜์ •.



๊ณ ๋ฏผ


AOP์œ„๋น™ ๋ฐฉ์‹์„ ํ™œ์šฉํ•ด, ๋™์ ์œผ๋กœ ์›ํ•˜๋Š” ์‹œ๊ฐ„์— Pointcut์— ์กฐ๊ฑด์— ํ•ด๋‹นํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๋‹ค์‹œ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์„๊นŒ? โ†’ ์„œ๋ฒ„๋ฅผ ์žฌ์‹คํ–‰ ํ•˜์ง€์•Š๊ฒŒ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

  • apiํ˜ธ์ถœ์„ ํ†ตํ•ด advice๋‚ด์˜ ๋™์ž‘์€ ๋Ÿฐํƒ€์ž„ ํ™˜๊ฒฝ์—์„œ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

pointcut๋„ ๋Ÿฐํƒ€์ž„์— ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜์ž–์•„? ๋Ÿฐํƒ€์ž„ ์œ„๋น™์ด๋‹ˆ๊นŒ?

  • ๋Ÿฐํƒ€์ž… ์œ„๋น™ ๋ฐฉ์‹์ด๋ผ๊ณ  ํ•˜๋”๋ผ๋„, ๋ณ€๊ฒฝ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ์ปดํŒŒ์ผ ์œ„๋น™ ๋ฐฉ์‹์€ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์›๋ณธ ํด๋ž˜์Šค ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์—ฌ ์ง์ ‘ ์œ„๋น™์„ ํ•˜๋Š” ๋ฐฉ์‹์ด๊ณ , ๋Ÿฐํƒ€์ž„ ์œ„๋น™์€ ๋Ÿฐํƒ€์ž„๋‹จ๊ณ„์—์„œ ์›๋ณธ ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ต์ฒดํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

์ด๋•Œ, ๋Ÿฐํƒ€์ž„๋‹จ๊ณ„ ๋ผ๊ณ  ํ•˜์ง€๋งŒ applicationContext๊ฐ€ bean๋“ค์˜ ์˜์กด์„ฑ์ฃผ์ž…์„ ๋งˆ์น˜๊ธฐ ์ด์ „์— ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค. ์ฆ‰, ์ž„์˜๋กœ ๋‚˜์ค‘์— ๋ณ€๊ฒฝํ•  ์ˆ˜ ๊ฐ€ ์—†๋‹ค๋Š” ๋ง์ด๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, pointcut์—์„œ @Autowired๋ฅผ ํ†ตํ•ด service๋ฅผ ์ฃผ์ž…๋ฐ›์ง€ ๋ชปํ•˜์˜€๋‹ค.

ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€ ์—†์„๊นŒ?

1. appcontext์—์„œ ๋นˆ ์ „์ฒด ์ดˆ๊ธฐํ™”

bean์„ ๋ชจ๋‘ refreshํ•œ๋‹ค๋ฉด ์˜์กด์„ฑ์ด ๊นจ์ง€์ง€ ์•Š๊ณ  ๋Ÿฐํƒ€์ž…ํ™˜๊ฒฝ์—์„œ AOP๋ฅผ ์žฌ์ ์šฉ ํ• ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ?

=> ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ฆฌ๋นŒ๋“œ์™€ ํฐ ์ฐจ์ด๊ฐ€ ์—†๊ณ , ๊ฐ class์— scope๋ฅผ ๋”ฐ๋กœ ์ ์šฉํ•ด์•ผํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ณ ๋ คํ•˜์ง€ ์•Š์•˜๋‹ค.

2. ์›ํ•˜๋Š” bean๊ฐ์ฒด๋งŒ ์ดˆ๊ธฐํ™”

์˜์กด ๊ด€๊ณ„๊ฐ€ ๊นจ์ง€๋Š” ์˜ํ–ฅ๋„๋ฅผ ๊ณ ๋ ค ํ•  ์ˆ˜ ์—†๋‹ค.

=> ์—ฐ๊ด€์„ฑ ์žˆ๋Š” ๋ชจ๋“  ์ฐธ์กฐ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์žฌ์„ค์ •ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งค์šฐ ๋ณต์žกํ•ด์ง„๋‹ค.

3. Filter๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ข…๋‹จ์œผ๋กœ ๋‚˜๋‘๋Š” AOP์—์„œ ํšก๋‹จ์œผ๋กœ ๋‚˜๋ˆ„๋Š” ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•œ๋‹ค๋ฉด ์ ์šฉ ๋ฒ”์œ„๊ฐ€ ์ „์ฒด ๋ฒ”์œ„๋กœ ํ™•์žฅ๋˜์–ด ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ํฌ๊ฒŒ ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ฒฐ๋ก 

  • ์ฐธ์กฐ๋ฅผ ๊ฐฑ์‹ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Java๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ•์ œ๋กœ ์ฐธ์กฐ๋ฅผ ๊ฐฑ์‹ ํ•˜๊ฑฐ๋‚˜, AspectJ์˜ ๋Ÿฐํƒ€์ž„ ์œ„๋น™ ๋ฐฉ์‹์„ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค.
  • ๋”ฐ๋ผ์„œ, ์„œ๋ฒ„ Kill์„ ํ•˜๋Š” ๊ฒƒ๊ณผ ์ง„๋ฐฐ ์—†์œผ๋ฉฐ, ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

+ ์ถ”๊ฐ€์‚ฌํ•ญ

์ด์Šˆ

๋‚ด๋ถ€ํ†ต๊ณ„๊ธฐ๋Šฅ(AOP)์˜ ์ง„์ž…URL์—์„œ ๋„ค์ด๋ฒ„ ์•„๋‚ ๋ฆฌํ‹ฑ์Šค(์™ธ๋ถ€ ํ†ต๊ณ„ ํ”„๋กœ๊ทธ๋žจ)๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด์Šˆ

์›์ธ?

  • ์™ธ๋ถ€ ์œ ์ž…ํ†ต๊ณ„ ํŽ˜์ด์ง€์˜ ์ธ์ž… ์ฃผ์†Œ๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฉ”์ธ ํŽ˜์ด์ง€๊ฐ€ ์•„๋‹Œ, Gate๋ฅผ ๊ฑฐ์ณ์„œ(redirect) ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค.
  • ์ด ๋•Œ, ์ง„์ž… referrer์— ๋ณ€๋™์ด ์ƒ๊ธฐ๋ฉด์„œ ์ง‘๊ณ„๊ฐ€ ๋˜์ง€ ์•Š๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.

ํ•ด๊ฒฐ๋ฒ•?

1. redirect -> ํ•˜์ดํผ๋งํฌ ๊ธฐ๋ฐ˜ Replace๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ?

  • ํ•ด๋‹น ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ, View๋‹จ์„ ์ถ”๊ฐ€ํ•˜์—ฌ replaceํ•œ๋‹ค๋ฉด, ์ฒ˜์Œ ์ง„์ž…์‹œ ๊ฐ–๊ณ  ์žˆ๋Š” referrer๋ฅผ ๋ฌผ๊ณ  ๊ฐˆ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ?
  • redirect๋Œ€์‹  view๋‹จ์„ ํ†ตํ•ด ์ง„์ž…ํ•˜๋„๋ก ๋งŒ๋“  ํ›„, naver์•„๋‚ ๋ฆฌํ‹ฑ์Šค ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
  • ํ•œ๊ณ„ : ์™ธ๋ถ€ ์œ ์ž…์‹œ ๋ถˆํ•„์š”ํ•œ ํŽ˜์ด์ง€ ๋ฐฉ๋ฌธ์ด ์ƒ๊ธฐ๊ฒŒ ๋˜๊ณ , ์œ ์ž…๊ณผ์ •์˜ ์‹œ๊ฐ„์ด ์ฆ๊ฐ€ํ•œ๋‹ค. ๋˜ํ•œ, ํ•ด๋‹น ์˜ค๋ฅ˜๋ฅผ 100% ํ•ด๊ฒฐํ• ์ง€ ๋ฏธ์ง€์ˆ˜

2. ์™ธ๋ถ€์œ ์ž… ํŽ˜์ด์ง€๋ฅผ ์‚ญ์ œํ•˜๊ณ , ๋ฉ”์ธํŽ˜์ด์ง€์—์„œ ๋‚ด๋ถ€ ํ†ต๊ณ„๋กœ ๋ณ€๊ฒฝ

  • ํ•ด๋‹น ๋ฐฉ๋ฒ•์€ ๊ธฐ์กด naver์•„๋‚ ๋ฆฌํ‹ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๋กœ์ง์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ œ์ผ ํ™•์‹คํ•˜๋‹ค.
  • ํ•œ๊ณ„ : ์™ธ๋ถ€์œ ์ž…์ž๊ฐ€ ์•„๋‹Œ, ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ session๋ฐ uid์ฒดํฌ๊ฐ€ ๋“ค์–ด๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€ํ•˜๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค.(DBํ†ต์‹ ์€ X)

3. ๋„ค์ด๋ฒ„ ์•„๋‚ ๋ฆฌํ‹ฑ์Šค๊ฐ€ ๋ฌผ๊ณ ์žˆ๋Š” Referrer๋ฅผ ์ฐพ์•„ HttpServletResponse์— ํ•จ๊ป˜ ๋‹ด์•„ redirect ํ•˜๊ธฐ.

  • BEST๐Ÿ–
  • ํ•œ๊ณ„ : ๋„ค์ด๋ฒ„ ์•„๋‚ ๋ฆฌํ‹ฑ์Šค์˜ ๋‚ด๋ถ€๋กœ์ง ํŒŒ์•…์ด ๋ถˆ๊ฐ€ํ•จ

- ์„ธ ํ•ด๊ฒฐ๋ฒ• ๋ชจ๋‘ ๋‚ด๋ถ€๋ง/์™ธ๋ถ€๋ง ๋ถ„๋ฆฌ๋กœ ์ธํ•˜์—ฌ ์šด์˜์„œ๋ฒ„์— ๋ฐ˜์˜ ์ „, ํ™•์‹คํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ ์ค‘ํ•œ ์„ ํƒ์ด ํ•„์š”ํ•˜๋‹ค.


๋ฐฉ๋ฒ• 1 ํ•˜์ดํผ๋งํฌ ๊ธฐ๋ฐ˜ Replace๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ

  • ํ˜„์žฌ ๋„ค์ด๋ฒ„์˜ ๋‚ด๋ถ€ ๋กœ์ง ํŒŒ์•…์ด ๋ถˆ๊ฐ€ํ•˜๋‹ˆ, View๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋„ค์ด๋ฒ„ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋ฌผ๊ณ  ๊ฐ€๋Š”์ง€ ๋จผ์ € TESTํ•˜๋„๋ก ํ•˜๊ธฐ
<html xmlns:th="http://www/thymeleaf.org" th:replace="layout/mainLayout :: mainLayout('gate loan')">

<script th:inline="javascript">  
  $(document).ready(function() {  
    location.href = [[${urls.SP_LOAN}]];  
  });  
</script>

mainLayout์„ ์ ์šฉํ•˜์—ฌ ํ•ด๋‹น ํŽ˜์ด์ง€์— default script๋ฅผ ์ ์šฉ์‹œ์ผฐ๋‹ค. ๊ฒฐ๊ณผ๋Š” ์ถ”ํ›„ ๋ชจ๋‹ˆํ„ฐ๋ง ์˜ˆ์ •

=> ์ •์ƒ์ ์œผ๋กœ ์ง‘๊ณ„ ๋˜์—ˆ๋‹ค.


๋ฐฉ๋ฒ• 3 ๋„ค์ด๋ฒ„ ์•„๋‚ ๋ฆฌํ‹ฑ์Šค๊ฐ€ ๋ฌผ๊ณ ์žˆ๋Š” Referrer๋ฅผ ์ฐพ์•„ HttpServletResponse์— ํ•จ๊ป˜ ๋‹ด์•„ redirect ํ•˜๊ธฐ.

Quote

sp/loan๊ธฐ์ค€์œผ๋กœ ๋ ˆํผ๋Ÿฌ๋ฅผ https://www-stg.hellofunding.co.kr/sp/loan/gtLoan?p=Z29vZ2xlMXN0 ์ธ์ž…ํŽ˜์ด์ง€ ์ฃผ์†Œ๋ฅผ ๊ฐ–๊ณ ์žˆ๋Š”๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

2025-02-25 14:34:04 [hello-app-staging-7985c4d74f-47qnx] INFO com.hellofintech.hellofunding.common.interceptor.ServiceHandlerInterceptor[mergeIntoVisitCount:187] - referer = https://www-stg.hellofunding.co.kr/sp/loan/gtLoan?p=Z29vZ2xlMXN0

sp/loan(๋Œ€์ถœํŽ˜์ด์ง€)์—์„œ referrer๋„˜๊ธฐ๊ธฐ

Pasted image 20250226145129.png

ํ™•์ธ ๊ฒฐ๊ณผ์ด๋ฏธ sendRedirect ๋กœ์ง์—์„œ๋„ Header์˜ Referer๋ฅผ ๋ฌผ๊ณ ์žˆ์—ˆ๋‹ค.

์–ด๋– ํ•œ referrer๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ง‘๊ณ„๋ฅผ ํ•˜๋Š”์ง€ ์ •ํ™•ํ•œ ํŒŒ์•…์ด ํ•„์š”ํ•˜๋‹ค.


[๋ถ€๋ก]