Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5기 이유정] Shorten-URL 과제 제출합니다. #73

Open
wants to merge 24 commits into
base: letskuku
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6d407d1
init: 초기 환경 세팅
letskuku Dec 11, 2023
3c793ad
feat: BaseEntity 구현
letskuku Dec 14, 2023
d517cd3
feat: Url 엔티티 및 커스텀 예외 구현
letskuku Dec 14, 2023
b814cf1
feat: EncodeType enum 및 커스텀 예외 구현
letskuku Dec 14, 2023
5210ee1
feat: ExceptionController 구현
letskuku Dec 14, 2023
6f18b92
feat: ShortUrlEncoder 인터페이스 생성 및 구현체 구현
letskuku Dec 14, 2023
5d60d96
feat: UrlRepository 생성
letskuku Dec 14, 2023
97730f4
feat: EncodeType에 해당하는 encoder 생성하는 ShortUrlEncoderMapper 구현
letskuku Dec 14, 2023
a5e45ba
feat: UrlService 구현
letskuku Dec 14, 2023
e0b4b3d
feat: 계층 간 데이터 이동 담당하는 dto 구현
letskuku Dec 14, 2023
c60993b
feat: UrlRestController 구현
letskuku Dec 14, 2023
5000fd3
feat: short url 인코딩 결과 형식 수정
letskuku Dec 17, 2023
9b2a411
feat: dto에 builder 추가
letskuku Dec 17, 2023
3747840
feat: thymeleaf로 프론트 구현 및 viewController 구현
letskuku Dec 17, 2023
a118f9e
chore: ExceptionHandler 어노테이션 추가
letskuku Dec 17, 2023
9805d36
refactor: TOKENS_SIZE 상수 초기화 방식 리팩토링
letskuku Dec 17, 2023
43ed06e
refactor: UrlNotFoundException 에러 메시지 수정
letskuku Dec 17, 2023
8719af4
feat: 동일한 original Url에 대한 short Url 인코딩 요청 처리 로직 추가
letskuku Dec 17, 2023
6bfab5f
feat: url 검증 로직 추가 및 커스텀 예외 구현
letskuku Dec 17, 2023
587c537
feat: 커스텀 예외 구현 방식 변경
letskuku Dec 17, 2023
cbc13d5
chore: 필요없는 파일 삭제
letskuku Dec 17, 2023
52234fe
test: EncodeType, Url 테스트 추가
letskuku Dec 17, 2023
802b322
chore: 필요없는 주석 삭제
letskuku Dec 17, 2023
49ca73a
test: UrlService 테스트 추가
letskuku Dec 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: 커스텀 예외 구현 방식 변경
letskuku committed Dec 17, 2023
commit 587c537f7faab9c96551b7978e756182be2a00ed
Original file line number Diff line number Diff line change
@@ -4,7 +4,8 @@
import com.example.urlmanagement.domain.Url;
import com.example.urlmanagement.dto.request.CreateShortUrlRequest;
import com.example.urlmanagement.encoder.ShortUrlEncoder;
import com.example.urlmanagement.exception.UrlNotFoundException;
import com.example.urlmanagement.exception.UrlErrorCode;
import com.example.urlmanagement.exception.UrlException;
import com.example.urlmanagement.mapper.ShortUrlEncoderMapper;
import com.example.urlmanagement.repository.UrlRepository;
import lombok.RequiredArgsConstructor;
@@ -26,7 +27,7 @@ public String createShortUrl(CreateShortUrlRequest createShortUrlRequest) {

if (urlRepository.existsByOriginalUrl(createShortUrlRequest.getOriginalUrl())) {
Url url = urlRepository.findByOriginalUrl(createShortUrlRequest.getOriginalUrl())
.orElseThrow(() -> new UrlNotFoundException(createShortUrlRequest.getOriginalUrl()));
.orElseThrow(() -> new UrlException(UrlErrorCode.URL_NOT_FOUND, createShortUrlRequest.getOriginalUrl()));

return BASE_URL + url.getShortUrl();
}
@@ -46,7 +47,7 @@ public String createShortUrl(CreateShortUrlRequest createShortUrlRequest) {
public String getOriginalUrl(String shortUrl) {

Url url = urlRepository.findByShortUrl(shortUrl)
.orElseThrow(() -> new UrlNotFoundException(shortUrl));
.orElseThrow(() -> new UrlException(UrlErrorCode.URL_NOT_FOUND, shortUrl));
url.increaseRequestCount();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

조회는 빈번하게 일어남으로 동시에 요청이 들어오면 업데이트시 동시성 이슈가 발생할 수 있을 것 같아요.
어떻게 해결할 수 있을 것 같은지 간단한 생각 남겨봐주시면 좋을 것 같아요.


return url.getOriginalUrl();
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.urlmanagement.domain;

import com.example.urlmanagement.exception.EncodeTypeNotFoundException;
import com.example.urlmanagement.exception.UrlErrorCode;
import com.example.urlmanagement.exception.UrlException;

import java.util.Arrays;

@@ -12,7 +13,8 @@ public enum EncodeType {
public static EncodeType getEncodeTypeByName(String name) {
return Arrays.stream(EncodeType.values())
.filter(encodeType -> encodeType.getName().equalsIgnoreCase(name))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

케이스 고려 좋네요 👍
이런 부분이 테스트에 녹여져도 좋은 것 같아요.

.findAny().orElseThrow(() -> new EncodeTypeNotFoundException(name));
.findAny()
.orElseThrow(() -> new UrlException(UrlErrorCode.ENCODE_TYPE_NOT_FOUND, name));
}

private String getName() {
6 changes: 4 additions & 2 deletions src/main/java/com/example/urlmanagement/domain/Url.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.urlmanagement.domain;

import com.example.urlmanagement.exception.InvalidUrlException;
import com.example.urlmanagement.exception.UrlErrorCode;
import com.example.urlmanagement.exception.UrlException;
import com.example.urlmanagement.global.common.BaseEntity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
@@ -48,7 +49,8 @@ private void validateOriginalUrl(String originalUrl) {
try {
new URL(originalUrl);
} catch (MalformedURLException e) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다른 Exception의 경우 그대로 던져질 것 같아서 Exception에 대해선 UrlErrorCode에 별도의 INTERNAL_SERVER_ERROR와 같이 정의해서 던져보는 것도 좋을 것 같아요.

throw new InvalidUrlException(originalUrl);
// throw new InvalidUrlException(originalUrl);
throw new UrlException(UrlErrorCode.INVALID_URL, originalUrl);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.example.urlmanagement.exception;

import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
public enum UrlErrorCode {
ENCODE_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 EncodeType이 존재하지 않습니다."),
URL_NOT_FOUND(HttpStatus.NOT_FOUND, "해당하는 url 정보가 존재하지 않습니다."),
INVALID_URL(HttpStatus.BAD_REQUEST, "올바르지 않은 형식의 URL입니다.");
Comment on lines +8 to +10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나중에 ErrorCode가 HttpStatus에 너무 강결합되지 않는 구조를 고려해봐도 좋을 것 같아요.
별도의 에러코드를 정의하고, ExceptionHandler에서 코드 기반으로 Status를 판단하는것처럼요.


private final HttpStatus errorHttpStatus;
private String errorMessage;

UrlErrorCode(HttpStatus errorHttpStatus, String errorMessage) {
this.errorHttpStatus = errorHttpStatus;
this.errorMessage = errorMessage;
}

public void updateErrorMessage(String wrongInput) {
this.errorMessage = this.errorMessage + " : " + wrongInput;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.urlmanagement.exception;

import lombok.Getter;

@Getter
public class UrlException extends RuntimeException {

private final UrlErrorCode errorCode;

public UrlException(UrlErrorCode urlErrorCode, String wrongInput) {
Comment on lines +8 to +10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrongInput보단 message라고 표현하는게 좋을 것 같네요.

this.errorCode = urlErrorCode;
errorCode.updateErrorMessage(wrongInput);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.example.urlmanagement.presentation;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요건 presentation보단 exception에 대한 설정에 가까운 것 같아요.


import com.example.urlmanagement.exception.EncodeTypeNotFoundException;
import com.example.urlmanagement.exception.InvalidUrlException;
import com.example.urlmanagement.exception.UrlNotFoundException;
import com.example.urlmanagement.exception.UrlException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -13,22 +11,10 @@
@RestControllerAdvice
public class ExceptionController {

@ExceptionHandler(EncodeTypeNotFoundException.class)
public ResponseEntity<String> catchEncodeTypeNotFoundException(EncodeTypeNotFoundException e) {
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}

@ExceptionHandler(UrlNotFoundException.class)
public ResponseEntity<String> catchUrlNotFoundException(UrlNotFoundException e) {
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage());
}

@ExceptionHandler(InvalidUrlException.class)
public ResponseEntity<String> catchInvalidUrlException(InvalidUrlException e) {
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
@ExceptionHandler(UrlException.class)
public ResponseEntity<String> catchCustomUrlException(UrlException e) {
log.error(e.getErrorCode().getErrorMessage(), e);
return ResponseEntity.status(e.getErrorCode().getErrorHttpStatus()).body(e.getErrorCode().getErrorMessage());
}

@ExceptionHandler(Exception.class)