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

[Refactor] feat: 전역 예외 처리 추가 및 URL 단축 로직 분리 #22

Merged
merged 9 commits into from
Feb 1, 2025

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package community.whatever.onembackendjava.common.exception;

import community.whatever.onembackendjava.common.exception.notfound.NotFoundShortenUrlException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GlobalExceptionHandler {

@ExceptionHandler(NotFoundShortenUrlException.class)
public ResponseEntity<String> handleNotFoundShortenUrlException(NotFoundShortenUrlException ex) {
return new ResponseEntity<>("단축 URL을 찾지 못했습니다.", HttpStatus.NOT_FOUND);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

문자열을 그대로 내려보내는게 의도된 것일까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

추후 정의되는 예외가 추가됨에 따라, json 형식의 에러 코드와 메시지를 포함한 응답을 생성할 예정입니다.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package community.whatever.onembackendjava.common.exception.notfound;


public class NotFoundShortenUrlException extends RuntimeException {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package community.whatever.onembackendjava.component;

import java.util.Random;
import org.springframework.stereotype.Component;

public class UrlShortener {

private static final Random RANDOM = new Random();

public String shorten() {
return String.valueOf(RANDOM.nextInt(10000));
}

}
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 클래스가 꼭 bean 이어야 할까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

현재 UrlShortenService에서만 사용되기 때문에 빈 등록을 제거하였습니다.

Copy link
Collaborator

Choose a reason for hiding this comment

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

이 클래스가 꼭 객체로서 생성되어야 할까요?

Copy link
Collaborator Author

@seeeeeeong seeeeeeong Feb 1, 2025

Choose a reason for hiding this comment

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

URL 단축 방식이 변경되고 다양한 메서드가 추가될 가능성을 고려하여 객체로 생성하였습니다. 현재는 shorten() 메서드만 사용하기 때문에 객체로 생성하지 않아도 될 것 같아 static 메서드로 변경하였습니다.

UrlShortener 클래스에 shorten() 이외의 여러 가지 메서드가 추가된다면, 객체를 생성할지 말지는 클래스 내에 상태를 가지는지 여부에 따라 판단하는 것이 맞는지 궁금합니다.

Copy link
Collaborator

Choose a reason for hiding this comment

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

현재는 shorten() 메서드만 사용하기 때문에 객체로 생성하지 않아도 될 것 같습니다. 그렇다면 static 메서드로 구현하는 것이 맞을까요?

저는 지금의 상황이면 util 성격으로 간주하여 static method 로 만들 것 같습니다.

UrlShortener 클래스에 shorten() 이외의 여러 가지 메서드가 추가된다면,

미래는 불특정하기에 지금에 맞는 클래스 형태를 권장 합니다.

  • ex) 클래스 안에 메서드를 추가하는게 아니라, provider 를 여러개 만들어서 필요에 따라 사용한다.

객체를 생성할지 말지는 클래스 내에 상태를 가지는지 여부에 따라 판단하는 것이 맞는지 궁금합니다.

이건 질문 이해가 잘 안되네요. 상태 보유 여부를 떠나서 런타임에 dto 외의 객체를 생성하는 케이스는 거의 없지 않나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

객체를 생성할지 말지는 클래스 내에 상태를 가지는지 여부에 따라 판단하는 것이 맞는지 궁금합니다.

제가 이해를 잘못한 것 같습니다. static method로 사용하고 추후 구현에 따라 궁금한 점이 생기면 다시 질문드리겠습니다!

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package community.whatever.onembackendjava.controller;

import community.whatever.onembackendjava.controller.response.GetOriginUrlResponse;
import community.whatever.onembackendjava.controller.request.ShortenUrlRequest;
import community.whatever.onembackendjava.controller.response.ShortenUrlResponse;
import community.whatever.onembackendjava.service.UrlShortenService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UrlShortenController {

private final UrlShortenService urlShortenService;

public UrlShortenController(UrlShortenService urlShortenService) {
this.urlShortenService = urlShortenService;
}

@PostMapping("/shorten-url")
public ShortenUrlResponse createShortenUrl(@RequestBody ShortenUrlRequest request) {
String shortenUrl = urlShortenService.createShortenUrl(request.originUrl());
return new ShortenUrlResponse(shortenUrl);
}

@GetMapping("/shorten-url/{shortenUrlKey}")
public GetOriginUrlResponse getOriginUrlByShortenUrlKey(@PathVariable String shortenUrlKey) {
String originUrl = urlShortenService.getOriginUrlByShortenUrlKey(shortenUrlKey);
return new GetOriginUrlResponse(originUrl);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package community.whatever.onembackendjava.controller.request;

public record ShortenUrlRequest(
String originUrl
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package community.whatever.onembackendjava.controller.response;

public record GetOriginUrlResponse (
String originUrl
){
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

record 클래스를 알고 계신가요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

record가 더 간결하고 가독성이 좋다고 생각되어 변경하였습니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package community.whatever.onembackendjava.controller.response;

public record ShortenUrlResponse (
String shortenUrlKey
){
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package community.whatever.onembackendjava.repository;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.springframework.stereotype.Repository;

@Repository
public class UrlShortenRepository {

private final Map<String, String> shortenUrls = new HashMap<>();

public Optional<String> findByShortenUrlKey(String shortenUrlKey) {
return Optional.ofNullable(shortenUrls.get(shortenUrlKey));
}

public void save(String shortenUrlKey, String originUrl) {
shortenUrls.put(shortenUrlKey, originUrl);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package community.whatever.onembackendjava.service;

import community.whatever.onembackendjava.common.exception.notfound.NotFoundShortenUrlException;
import community.whatever.onembackendjava.component.UrlShortener;
import community.whatever.onembackendjava.repository.UrlShortenRepository;
import org.springframework.stereotype.Service;

@Service
public class UrlShortenService {

private final UrlShortenRepository urlShortenRepository;
private final UrlShortener urlShortener;

public UrlShortenService(UrlShortenRepository urlShortenRepository) {
this.urlShortenRepository = urlShortenRepository;
this.urlShortener = new UrlShortener();
}

public String createShortenUrl(String originUrl) {
String shortenUrlKey = urlShortener.shorten();
urlShortenRepository.save(shortenUrlKey, originUrl);
return shortenUrlKey;
}

public String getOriginUrlByShortenUrlKey(String shortenUrlKey) {
return urlShortenRepository.findByShortenUrlKey(shortenUrlKey)
.orElseThrow(NotFoundShortenUrlException::new);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

import community.whatever.onembackendjava.common.exception.notfound.NotFoundShortenUrlException;
import community.whatever.onembackendjava.service.UrlShortenService;
import java.util.NoSuchElementException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
Expand All @@ -19,17 +20,17 @@ class UrlShortenServiceTest {
void shorten_url을_생성하고_조회한다() {
String expectedOriginUrl = "https://www.google.com";
String key = urlShortenService.createShortenUrl(expectedOriginUrl);
String originUrl = urlShortenService.getOriginUrlByKey(key);
String originUrl = urlShortenService.getOriginUrlByShortenUrlKey(key);

assertThat(originUrl).isEqualTo(expectedOriginUrl);
}

@Test
void 존재하지_않는_key로_조회하면_예외가_발생한다() {
void 존재하지_않는_shorten_url_key로_조회하면_예외가_발생한다() {
String nonExistingKey = "nonExistingKey";

assertThrows(NoSuchElementException.class, () -> {
urlShortenService.getOriginUrlByKey(nonExistingKey);
assertThrows(NotFoundShortenUrlException.class, () -> {
urlShortenService.getOriginUrlByShortenUrlKey(nonExistingKey);
});
}

Expand Down