Merge pull request #20 from Gyubin-Han/feature/url-short
Feat: 단축 URL로 접속 시, 클라이언트 정보 저장 기능 구현
This commit is contained in:
@@ -57,9 +57,13 @@ public class MainController {
|
|||||||
* @param response Re-Direct 응답 처리를 위한 매개변수
|
* @param response Re-Direct 응답 처리를 위한 매개변수
|
||||||
*/
|
*/
|
||||||
@GetMapping("/{shortUrl}")
|
@GetMapping("/{shortUrl}")
|
||||||
public void getShortUrl(@PathVariable(name="shortUrl") String shortUrl, HttpServletResponse response){
|
public void getShortUrl(@PathVariable(name="shortUrl") String shortUrl, HttpServletRequest request, HttpServletResponse response){
|
||||||
|
// 접속 정보들 추출
|
||||||
|
String userAgent=request.getHeader("User-Agent");
|
||||||
|
String userIpAddr=request.getRemoteAddr();
|
||||||
|
|
||||||
// 단축 URL을 통해, 원본 URL을 가져옴.
|
// 단축 URL을 통해, 원본 URL을 가져옴.
|
||||||
String originalUrl=mainService.getOriginalUrl(shortUrl);
|
String originalUrl=mainService.getOriginalUrl(shortUrl,userAgent,userIpAddr);
|
||||||
// 가져온 원본 URL 값을 적잘한 URL이 될 수 있도록 Re-Direct하기 전에 URL-Encoding
|
// 가져온 원본 URL 값을 적잘한 URL이 될 수 있도록 Re-Direct하기 전에 URL-Encoding
|
||||||
String encodeUrl=UriComponentsBuilder.fromUriString(originalUrl).build().encode().toUriString();
|
String encodeUrl=UriComponentsBuilder.fromUriString(originalUrl).build().encode().toUriString();
|
||||||
// Re-Direct 상태 코드 설정
|
// Re-Direct 상태 코드 설정
|
||||||
|
|||||||
28
src/main/java/be/gyu/urlShortener/entity/ClickStat.java
Normal file
28
src/main/java/be/gyu/urlShortener/entity/ClickStat.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package be.gyu.urlShortener.entity;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ClickStat {
|
||||||
|
@Id
|
||||||
|
private Long clickStatId;
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name="url_map_id")
|
||||||
|
private UrlMap urlMap;
|
||||||
|
private LocalDateTime clickStatClickedAt;
|
||||||
|
private String clickStatUserAgent;
|
||||||
|
private String clickStatIpAddr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package be.gyu.urlShortener.repository;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import be.gyu.urlShortener.entity.ClickStat;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ClickStatRepository extends JpaRepository<ClickStat,Long>{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,9 +3,11 @@ package be.gyu.urlShortener.service;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import be.gyu.urlShortener.entity.ClickStat;
|
||||||
import be.gyu.urlShortener.entity.UrlMap;
|
import be.gyu.urlShortener.entity.UrlMap;
|
||||||
import be.gyu.urlShortener.exception.ShortUrlNotFoundException;
|
import be.gyu.urlShortener.exception.ShortUrlNotFoundException;
|
||||||
import be.gyu.urlShortener.exception.UrlValidationFailedException;
|
import be.gyu.urlShortener.exception.UrlValidationFailedException;
|
||||||
|
import be.gyu.urlShortener.repository.ClickStatRepository;
|
||||||
import be.gyu.urlShortener.repository.UrlMapRepository;
|
import be.gyu.urlShortener.repository.UrlMapRepository;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -21,6 +23,8 @@ import io.seruco.encoding.base62.Base62;
|
|||||||
public class MainService {
|
public class MainService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private UrlMapRepository urlMapRepository;
|
private UrlMapRepository urlMapRepository;
|
||||||
|
@Autowired
|
||||||
|
private ClickStatRepository clickStatRepository;
|
||||||
|
|
||||||
// HTTP(S) URL 검증 패턴식
|
// HTTP(S) URL 검증 패턴식
|
||||||
private final String urlRegPattern="^((http|https):\\/\\/)?([a-z0-9-]{2,}\\.[a-z]{2,}|([0-9]{1,3}\\.){3}[0-9]{1,3})[\\w.\\/가-힣\\-\\ ?=&:%0-9A-Fa-f]*";
|
private final String urlRegPattern="^((http|https):\\/\\/)?([a-z0-9-]{2,}\\.[a-z]{2,}|([0-9]{1,3}\\.){3}[0-9]{1,3})[\\w.\\/가-힣\\-\\ ?=&:%0-9A-Fa-f]*";
|
||||||
@@ -89,14 +93,24 @@ public class MainService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 단축 URL로 원본 URL 조회 및 반환 메소드
|
// 단축 URL로 원본 URL 조회 및 반환 메소드
|
||||||
public String getOriginalUrl(String shortUrl){
|
public String getOriginalUrl(String shortUrl, String userAgent, String ipAddr){
|
||||||
Optional<UrlMap> optional=urlMapRepository.findByUrlMapShort(shortUrl);
|
Optional<UrlMap> optional=urlMapRepository.findByUrlMapShort(shortUrl);
|
||||||
|
|
||||||
if(!optional.isPresent()){
|
if(!optional.isPresent()){
|
||||||
throw new ShortUrlNotFoundException();
|
throw new ShortUrlNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
return optional.get().getUrlMapOriginal();
|
// 접속 정보 저장을 위해서 새 엔티티 객체 생성
|
||||||
|
ClickStat clickStat=ClickStat.builder()
|
||||||
|
.clickStatClickedAt(LocalDateTime.now())
|
||||||
|
.urlMap(optional.get())
|
||||||
|
.clickStatUserAgent(userAgent)
|
||||||
|
.clickStatIpAddr(ipAddr)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
clickStatRepository.save(clickStat);
|
||||||
|
|
||||||
|
return clickStat.getUrlMap().getUrlMapOriginal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 단축 URL 생성 메소드 (검증 및 생성)
|
// 단축 URL 생성 메소드 (검증 및 생성)
|
||||||
|
|||||||
Reference in New Issue
Block a user