-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: 사용자가 링크를 등록하면 도메인 정보를 기록한다.
- Loading branch information
Showing
26 changed files
with
632 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
src/main/java/com/seong/shoutlink/domain/domain/Domain.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.seong.shoutlink.domain.domain; | ||
|
||
import lombok.Getter; | ||
|
||
@Getter | ||
public class Domain { | ||
|
||
private Long domainId; | ||
private String rootDomain; | ||
|
||
public Domain(String rootDomain) { | ||
this(null, rootDomain); | ||
} | ||
|
||
public Domain(Long domainId, String rootDomain) { | ||
this.domainId = domainId; | ||
this.rootDomain = rootDomain; | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/main/java/com/seong/shoutlink/domain/domain/repository/DomainEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.seong.shoutlink.domain.domain.repository; | ||
|
||
import com.seong.shoutlink.domain.common.BaseEntity; | ||
import com.seong.shoutlink.domain.domain.Domain; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Table; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Getter | ||
@Entity | ||
@Table(name = "domain") | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class DomainEntity extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long domainId; | ||
private String rootDomain; | ||
|
||
public DomainEntity(String rootDomain) { | ||
this(null, rootDomain); | ||
} | ||
|
||
public DomainEntity(Long domainId, String rootDomain) { | ||
this.domainId = domainId; | ||
this.rootDomain = rootDomain; | ||
} | ||
|
||
public static DomainEntity create(Domain domain) { | ||
return new DomainEntity(domain.getRootDomain()); | ||
} | ||
|
||
public Domain toDomain() { | ||
return new Domain(domainId, rootDomain); | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/java/com/seong/shoutlink/domain/domain/repository/DomainJpaRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.seong.shoutlink.domain.domain.repository; | ||
|
||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface DomainJpaRepository extends JpaRepository<DomainEntity, Long> { | ||
|
||
Optional<DomainEntity> findByRootDomain(String rootDomain); | ||
} |
26 changes: 26 additions & 0 deletions
26
src/main/java/com/seong/shoutlink/domain/domain/repository/DomainRepositoryImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.seong.shoutlink.domain.domain.repository; | ||
|
||
import com.seong.shoutlink.domain.domain.Domain; | ||
import com.seong.shoutlink.domain.domain.service.DomainRepository; | ||
import java.util.Optional; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class DomainRepositoryImpl implements DomainRepository { | ||
|
||
private final DomainJpaRepository domainJpaRepository; | ||
|
||
@Override | ||
public Optional<Domain> findByRootDomain(String rootDomain) { | ||
return domainJpaRepository.findByRootDomain(rootDomain) | ||
.map(DomainEntity::toDomain); | ||
} | ||
|
||
@Override | ||
public Domain save(Domain domain) { | ||
return domainJpaRepository.save(DomainEntity.create(domain)) | ||
.toDomain(); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/java/com/seong/shoutlink/domain/domain/service/DomainRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package com.seong.shoutlink.domain.domain.service; | ||
|
||
import com.seong.shoutlink.domain.domain.Domain; | ||
import java.util.Optional; | ||
|
||
public interface DomainRepository { | ||
|
||
Optional<Domain> findByRootDomain(String rootDomain); | ||
|
||
Domain save(Domain domain); | ||
} |
37 changes: 37 additions & 0 deletions
37
src/main/java/com/seong/shoutlink/domain/domain/service/DomainService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.seong.shoutlink.domain.domain.service; | ||
|
||
import com.seong.shoutlink.domain.domain.Domain; | ||
import com.seong.shoutlink.domain.domain.service.request.UpdateDomainCommand; | ||
import com.seong.shoutlink.domain.domain.service.response.UpdateDomainResponse; | ||
import com.seong.shoutlink.domain.domain.util.DomainExtractor; | ||
import com.seong.shoutlink.domain.exception.ErrorCode; | ||
import com.seong.shoutlink.domain.exception.ShoutLinkException; | ||
import com.seong.shoutlink.domain.link.Link; | ||
import com.seong.shoutlink.domain.link.service.LinkRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class DomainService { | ||
|
||
private final DomainRepository domainRepository; | ||
private final LinkRepository linkRepository; | ||
|
||
@Transactional | ||
public UpdateDomainResponse updateDomain(UpdateDomainCommand command) { | ||
String rootDomain = DomainExtractor.extractRootDomain(command.url()); | ||
Domain domain = domainRepository.findByRootDomain(rootDomain) | ||
.orElseGet(() -> { | ||
Domain newDomain = new Domain(rootDomain); | ||
return domainRepository.save(newDomain); | ||
}); | ||
Link link = linkRepository.findById(command.linkId()) | ||
.orElseThrow(() -> new ShoutLinkException("존재하지 않는 링크입니다.", ErrorCode.NOT_FOUND)); | ||
linkRepository.updateLinkDomain(link, domain); | ||
return new UpdateDomainResponse(domain.getDomainId()); | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
src/main/java/com/seong/shoutlink/domain/domain/service/request/UpdateDomainCommand.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.seong.shoutlink.domain.domain.service.request; | ||
|
||
public record UpdateDomainCommand(Long linkId, String url) { | ||
|
||
} |
5 changes: 5 additions & 0 deletions
5
src/main/java/com/seong/shoutlink/domain/domain/service/response/UpdateDomainResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.seong.shoutlink.domain.domain.service.response; | ||
|
||
public record UpdateDomainResponse(Long domainId) { | ||
|
||
} |
81 changes: 81 additions & 0 deletions
81
src/main/java/com/seong/shoutlink/domain/domain/util/DomainExtractor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package com.seong.shoutlink.domain.domain.util; | ||
|
||
import com.seong.shoutlink.domain.exception.ErrorCode; | ||
import com.seong.shoutlink.domain.exception.ShoutLinkException; | ||
import java.net.URI; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.regex.Pattern; | ||
import lombok.AccessLevel; | ||
import lombok.NoArgsConstructor; | ||
|
||
@NoArgsConstructor(access = AccessLevel.PRIVATE) | ||
public final class DomainExtractor { | ||
|
||
private static final String HTTP = "http"; | ||
private static final Pattern URL_PATTERN = Pattern.compile( | ||
"[-a-zA-Z0-9@:%_\\+.~#?&//=]{2,256}\\.[a-z]{2,4}\\b(\\/[-a-zA-Z0-9가-힣@:%_\\+.~#?&//=]*)?"); | ||
private static final Set<String> SECOND_DOMAIN = new HashSet<>(); | ||
|
||
static { | ||
SECOND_DOMAIN.addAll( | ||
List.of("co", "ne", "or", "re", "pe", "go", "mil", "ac", "hs", "ms", "es", "sc", "kg")); | ||
} | ||
|
||
public static String extractRootDomain(String url) { | ||
checkIsUrlPattern(url); | ||
String fullDomain = removePath(url); | ||
return removeSubDomain(fullDomain); | ||
} | ||
|
||
private static void checkIsUrlPattern(String url) { | ||
if(URL_PATTERN.matcher(url).matches()) { | ||
return; | ||
} | ||
throw new ShoutLinkException("입력값이 URL 형식이 아닙니다.", ErrorCode.ILLEGAL_ARGUMENT); | ||
} | ||
|
||
private static String removePath(String url) { | ||
if(url.startsWith(HTTP)) { | ||
URI uri = URI.create(url); | ||
return uri.getHost(); | ||
} | ||
int firstSlashIndex = url.indexOf("/"); | ||
if(firstSlashIndex == -1) { | ||
return url; | ||
} | ||
return url.substring(0, firstSlashIndex); | ||
} | ||
|
||
private static String removeSubDomain(String fullDomain) { | ||
String[] splitDomain = fullDomain.split("\\."); | ||
if(hasSecondDomain(splitDomain)) { | ||
return makeRootDomain(3, splitDomain); | ||
} else { | ||
return makeRootDomain(2, splitDomain); | ||
} | ||
} | ||
|
||
private static boolean hasSecondDomain(String[] splitDomain) { | ||
int totalDepth = splitDomain.length; | ||
if(totalDepth > 2) { | ||
String secondDomain = splitDomain[totalDepth - 2]; | ||
return SECOND_DOMAIN.stream() | ||
.anyMatch(secondDomain::equals); | ||
} | ||
return false; | ||
} | ||
|
||
private static String makeRootDomain(int rootDomainDepth, String[] splitDomain) { | ||
int totalDepth = splitDomain.length; | ||
StringBuilder domainBuilder = new StringBuilder(); | ||
for (int depth = rootDomainDepth; depth > 0; depth--) { | ||
domainBuilder.append(splitDomain[totalDepth - depth]); | ||
if(depth > 1) { | ||
domainBuilder.append("."); | ||
} | ||
} | ||
return domainBuilder.toString(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
src/main/java/com/seong/shoutlink/domain/link/service/LinkRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,19 @@ | ||
package com.seong.shoutlink.domain.link.service; | ||
|
||
import com.seong.shoutlink.domain.domain.Domain; | ||
import com.seong.shoutlink.domain.link.Link; | ||
import com.seong.shoutlink.domain.link.LinkWithLinkBundle; | ||
import com.seong.shoutlink.domain.link.service.result.LinkPaginationResult; | ||
import com.seong.shoutlink.domain.linkbundle.LinkBundle; | ||
import java.util.Optional; | ||
|
||
public interface LinkRepository { | ||
|
||
Long save(LinkWithLinkBundle linkWithLinkBundle); | ||
|
||
LinkPaginationResult findLinks(LinkBundle linkBundle, int page, int size); | ||
|
||
void updateLinkDomain(Link link, Domain domain); | ||
|
||
Optional<Link> findById(Long linkId); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
src/main/java/com/seong/shoutlink/global/event/DomainEventListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.seong.shoutlink.global.event; | ||
|
||
import com.seong.shoutlink.domain.domain.service.DomainService; | ||
import com.seong.shoutlink.domain.domain.service.request.UpdateDomainCommand; | ||
import com.seong.shoutlink.domain.link.service.event.CreateLinkEvent; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.transaction.annotation.Propagation; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.transaction.event.TransactionalEventListener; | ||
|
||
@RequiredArgsConstructor | ||
public class DomainEventListener { | ||
|
||
private final DomainService domainService; | ||
|
||
@TransactionalEventListener | ||
@Transactional(propagation = Propagation.REQUIRES_NEW) | ||
public void updateDomainInfo(CreateLinkEvent event) { | ||
domainService.updateDomain(new UpdateDomainCommand(event.linkId(), event.url())); | ||
} | ||
} |
Oops, something went wrong.