diff --git a/src/main/java/com/daangn/survey/SurveyApplication.java b/src/main/java/com/daangn/survey/SurveyApplication.java index a9df4dc..ed01f64 100644 --- a/src/main/java/com/daangn/survey/SurveyApplication.java +++ b/src/main/java/com/daangn/survey/SurveyApplication.java @@ -11,12 +11,14 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +@EnableAsync @RestController @SpringBootApplication @EnableJpaAuditing diff --git a/src/main/java/com/daangn/survey/common/util/shorturl/UrlController.java b/src/main/java/com/daangn/survey/common/util/shorturl/UrlController.java index dc1da6c..a01d291 100644 --- a/src/main/java/com/daangn/survey/common/util/shorturl/UrlController.java +++ b/src/main/java/com/daangn/survey/common/util/shorturl/UrlController.java @@ -5,6 +5,8 @@ import com.daangn.survey.common.util.shorturl.component.UrlConvertService; import com.daangn.survey.common.util.shorturl.model.dto.ShortUrlResponse; import com.daangn.survey.common.util.shorturl.model.dto.ShortUrlResult; +import com.daangn.survey.core.log.annotation.UserLogging; +import com.daangn.survey.core.log.model.LogType; import com.daangn.survey.third.karrot.KarrotApiUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -13,13 +15,17 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; +import javax.servlet.http.HttpServletRequest; + @Tag(name = "단축 URL") +@Slf4j @Controller @RequiredArgsConstructor public class UrlController { @@ -33,15 +39,9 @@ public class UrlController { @Value("${mudda.short-url}") private String shortUrl; - // 이거 안 사용할 거 같은데 아닌가? - @GetMapping("/daangn/short-url/convert") - @ResponseBody - public ShortUrlResult convertShortUrl(@RequestParam(defaultValue = "") String urlStr) { - return urlConverter.getShortenUrl(urlStr.trim(), null); - } - + @UserLogging(type = LogType.SHORT_URL) @GetMapping("/scheme/redirect") - public String redirectToOriginUrl(@RequestParam String url) { + public String redirectToOriginUrl(@RequestParam String url, HttpServletRequest request) { return "redirect:" + urlConverter.getShortenUrl(url.trim(), null).getShortUrl().getSchemeUrl(); } diff --git a/src/main/java/com/daangn/survey/common/util/shorturl/model/entity/ShortUrl.java b/src/main/java/com/daangn/survey/common/util/shorturl/model/entity/ShortUrl.java index cf6d3b2..e37bf3a 100644 --- a/src/main/java/com/daangn/survey/common/util/shorturl/model/entity/ShortUrl.java +++ b/src/main/java/com/daangn/survey/common/util/shorturl/model/entity/ShortUrl.java @@ -47,4 +47,11 @@ public void addReqCount(){ public void setShortUrl(String url){ this.shortUrl = url; } + + public Long resolveSurveyId(){ + int startIndex = this.originUrl.lastIndexOf('/'); + int lastIndex = this.originUrl.lastIndexOf('?'); + + return Long.parseLong(this.originUrl.substring(startIndex + 1, lastIndex)); + } } diff --git a/src/main/java/com/daangn/survey/common/util/shorturl/repository/UrlRepository.java b/src/main/java/com/daangn/survey/common/util/shorturl/repository/UrlRepository.java index 4eb1a58..fbf0599 100644 --- a/src/main/java/com/daangn/survey/common/util/shorturl/repository/UrlRepository.java +++ b/src/main/java/com/daangn/survey/common/util/shorturl/repository/UrlRepository.java @@ -8,4 +8,5 @@ public interface UrlRepository extends JpaRepository { ShortUrl findFirstByShortUrlOrOriginUrlOrderByCreatedAt(String shortUrl, String originUrl); boolean existsByShortUrlOrOriginUrl(String shortUrl, String originUrl); + ShortUrl findShortUrlByShortUrl(String shortUrl); } diff --git a/src/main/java/com/daangn/survey/core/aop/LogEventAspect.java b/src/main/java/com/daangn/survey/core/aop/LogEventAspect.java new file mode 100644 index 0000000..5657080 --- /dev/null +++ b/src/main/java/com/daangn/survey/core/aop/LogEventAspect.java @@ -0,0 +1,56 @@ +package com.daangn.survey.core.aop; + +import com.daangn.survey.core.log.annotation.UserLogging; +import com.daangn.survey.core.log.model.LogEvent; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; + +@Slf4j +@Component +@Aspect +public class LogEventAspect implements ApplicationEventPublisherAware { + private ApplicationEventPublisher eventPublisher; + + @Pointcut("@annotation(userLogging)") + public void pointcut(UserLogging userLogging) { + } + + @AfterReturning(pointcut = "pointcut(userLogging)") + public void afterReturning(JoinPoint joinPoint, UserLogging userLogging){ + + switch (userLogging.type()){ + case SHORT_URL: + String referer = null; + String userAgent = null; + String url = null; + + for(Object arg : joinPoint.getArgs()){ + if(arg instanceof HttpServletRequest) { + HttpServletRequest request = (HttpServletRequest) arg; + referer = request.getHeader("referer"); + userAgent = request.getHeader("user-agent"); + } + if(arg instanceof String){ + url = (String) arg; + } + } + + eventPublisher.publishEvent(new LogEvent(url, userAgent, referer)); + break; + + } + } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.eventPublisher = applicationEventPublisher; + } +} \ No newline at end of file diff --git a/src/main/java/com/daangn/survey/core/log/LogRepository.java b/src/main/java/com/daangn/survey/core/log/LogRepository.java new file mode 100644 index 0000000..a713faf --- /dev/null +++ b/src/main/java/com/daangn/survey/core/log/LogRepository.java @@ -0,0 +1,15 @@ +package com.daangn.survey.core.log; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.stereotype.Repository; + +@RequiredArgsConstructor +@Repository +public class LogRepository { + private final MongoTemplate mongoTemplate; + + public void saveUserLog(Object log){ + mongoTemplate.save(log); + } +} diff --git a/src/main/java/com/daangn/survey/core/log/annotation/UserLogging.java b/src/main/java/com/daangn/survey/core/log/annotation/UserLogging.java new file mode 100644 index 0000000..88ff9ad --- /dev/null +++ b/src/main/java/com/daangn/survey/core/log/annotation/UserLogging.java @@ -0,0 +1,14 @@ +package com.daangn.survey.core.log.annotation; + +import com.daangn.survey.core.log.model.LogType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface UserLogging { + LogType type(); +} \ No newline at end of file diff --git a/src/main/java/com/daangn/survey/core/log/component/LogEventHandler.java b/src/main/java/com/daangn/survey/core/log/component/LogEventHandler.java new file mode 100644 index 0000000..fb9e369 --- /dev/null +++ b/src/main/java/com/daangn/survey/core/log/component/LogEventHandler.java @@ -0,0 +1,35 @@ +package com.daangn.survey.core.log.component; + +import com.daangn.survey.common.util.shorturl.model.entity.ShortUrl; +import com.daangn.survey.common.util.shorturl.repository.UrlRepository; +import com.daangn.survey.core.log.LogRepository; +import com.daangn.survey.core.log.model.LogEvent; +import com.daangn.survey.core.log.model.ShortUrlLog; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; + +@RequiredArgsConstructor +@Component +public class LogEventHandler { + + private final LogRepository logRepository; + private final UrlRepository urlRepository; + + @Async + @EventListener + public void log(LogEvent event) { + ShortUrl shortUrl = urlRepository.findShortUrlByShortUrl(event.getUrl()); + + logRepository.saveUserLog(new ShortUrlLog( + shortUrl.resolveSurveyId(), + event.getUrl(), + event.getUserAgent(), + event.getReferer() + )); + } +} diff --git a/src/main/java/com/daangn/survey/core/log/model/LogEvent.java b/src/main/java/com/daangn/survey/core/log/model/LogEvent.java new file mode 100644 index 0000000..11d739c --- /dev/null +++ b/src/main/java/com/daangn/survey/core/log/model/LogEvent.java @@ -0,0 +1,12 @@ +package com.daangn.survey.core.log.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class LogEvent { + private String url; + private String userAgent; + private String referer; +} diff --git a/src/main/java/com/daangn/survey/core/log/model/LogType.java b/src/main/java/com/daangn/survey/core/log/model/LogType.java new file mode 100644 index 0000000..496d33e --- /dev/null +++ b/src/main/java/com/daangn/survey/core/log/model/LogType.java @@ -0,0 +1,13 @@ +package com.daangn.survey.core.log.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum LogType { + SHORT_URL("ShortUrl"), + ; + + private String type; +} diff --git a/src/main/java/com/daangn/survey/core/log/model/ShortUrlLog.java b/src/main/java/com/daangn/survey/core/log/model/ShortUrlLog.java new file mode 100644 index 0000000..f0dcf75 --- /dev/null +++ b/src/main/java/com/daangn/survey/core/log/model/ShortUrlLog.java @@ -0,0 +1,29 @@ +package com.daangn.survey.core.log.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.mongodb.core.mapping.Document; + +import javax.persistence.EnumType; +import javax.persistence.Enumerated; + +@AllArgsConstructor +@Getter @Setter +@Document(collection = "userLogs") +public class ShortUrlLog { + @Enumerated(EnumType.STRING) + private LogType logType; + private Long surveyId; + private String url; + private String userAgent; + private String referer; + + public ShortUrlLog(Long surveyId, String url, String userAgent, String referer) { + this.logType = LogType.SHORT_URL; + this.surveyId = surveyId; + this.url = url; + this.userAgent = userAgent; + this.referer = referer; + } +} diff --git a/src/main/java/com/daangn/survey/mongo/MongoRepository.java b/src/main/java/com/daangn/survey/mongo/MongoRepository.java index e9f51c0..9f7741a 100644 --- a/src/main/java/com/daangn/survey/mongo/MongoRepository.java +++ b/src/main/java/com/daangn/survey/mongo/MongoRepository.java @@ -2,8 +2,8 @@ import com.daangn.survey.mongo.aggregate.AggregationAnswerMongo; import com.daangn.survey.mongo.aggregate.AggregationQuestionMongo; -import com.daangn.survey.mongo.aggregate.SurveyResponseCountMongo; import com.daangn.survey.mongo.aggregate.AggregationResponseSetMongo; +import com.daangn.survey.mongo.aggregate.SurveyResponseCountMongo; import com.daangn.survey.mongo.aggregate.individual.IndividualResponseMongo; import com.daangn.survey.mongo.response.ResponseMongo; import com.daangn.survey.mongo.survey.SurveyMongo; @@ -18,7 +18,6 @@ import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.stereotype.Repository; -import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.stream.Collectors;