From 6b3fcf54585705636ac0c295b2e85ebe72f11513 Mon Sep 17 00:00:00 2001 From: kdongd Date: Thu, 16 Apr 2026 16:21:15 +0900 Subject: [PATCH] =?UTF-8?q?##=20shorturl=20MVC=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EC=84=A4=EA=B3=84=20=EB=B0=8F=20=EB=8B=A8=EC=B6=95=20URL=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - shorturl 패키지 내부에서 MVC 구조 설계 - Controller, Service, Repository, View 역할 분리 - Base62 기반 short code 생성 규칙 적용 - HashMap 저장 구조 구현 - 단축 URL 생성 및 원본 URL 조회 흐름 구성 - 패키지 내부 Main/Client 실행 구조 정리 - 불필요한 루트 템플릿 Main 제외 --- src/shorturl/Client.java | 25 +++++++++++ .../controller/ShortUrlController.java | 37 +++++++++++++++++ .../repository/ShortUrlRepository.java | 22 ++++++++++ src/shorturl/service/Base62Converter.java | 19 +++++++++ src/shorturl/service/ShortUrlService.java | 41 +++++++++++++++++++ src/shorturl/view/InputView.java | 18 ++++++++ src/shorturl/view/OutputView.java | 12 ++++++ 7 files changed, 174 insertions(+) create mode 100644 src/shorturl/Client.java create mode 100644 src/shorturl/controller/ShortUrlController.java create mode 100644 src/shorturl/repository/ShortUrlRepository.java create mode 100644 src/shorturl/service/Base62Converter.java create mode 100644 src/shorturl/service/ShortUrlService.java create mode 100644 src/shorturl/view/InputView.java create mode 100644 src/shorturl/view/OutputView.java diff --git a/src/shorturl/Client.java b/src/shorturl/Client.java new file mode 100644 index 0000000..61b9e92 --- /dev/null +++ b/src/shorturl/Client.java @@ -0,0 +1,25 @@ +package shorturl; + +import shorturl.controller.ShortUrlController; +import shorturl.repository.ShortUrlRepository; +import shorturl.service.Base62Converter; +import shorturl.service.ShortUrlService; +import shorturl.view.InputView; +import shorturl.view.OutputView; + +public class Client { + + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + ShortUrlRepository repository = new ShortUrlRepository(); + Base62Converter converter = new Base62Converter(); + ShortUrlService shortUrlService = + new ShortUrlService(repository, converter); + + ShortUrlController shortUrlController = + new ShortUrlController(inputView, outputView, shortUrlService); + + shortUrlController.run(); + } +} diff --git a/src/shorturl/controller/ShortUrlController.java b/src/shorturl/controller/ShortUrlController.java new file mode 100644 index 0000000..5ba8b77 --- /dev/null +++ b/src/shorturl/controller/ShortUrlController.java @@ -0,0 +1,37 @@ +package shorturl.controller; + +import shorturl.service.ShortUrlService; +import shorturl.view.InputView; +import shorturl.view.OutputView; + +public class ShortUrlController { + + private final InputView inputView; + private final OutputView outputView; + private final ShortUrlService shortUrlService; + + public ShortUrlController(InputView inputView, + OutputView outputView, + ShortUrlService shortUrlService) { + this.inputView = inputView; + this.outputView = outputView; + this.shortUrlService = shortUrlService; + } + + public void run() { + while (true) { + String originalUrl = inputView.readOriginalUrl(); + + if (originalUrl.equals("exit")) { + break; + } + + String shortUrl = shortUrlService.createShortUrl(originalUrl); + outputView.printShortUrl(shortUrl); + + String inputShortUrl = inputView.readShortUrl(); + String redirectUrl = shortUrlService.findOriginalUrl(inputShortUrl); + outputView.redirectToOriginalUrl(redirectUrl); + } + } +} diff --git a/src/shorturl/repository/ShortUrlRepository.java b/src/shorturl/repository/ShortUrlRepository.java new file mode 100644 index 0000000..a2d6dc4 --- /dev/null +++ b/src/shorturl/repository/ShortUrlRepository.java @@ -0,0 +1,22 @@ +package shorturl.repository; + +import java.util.HashMap; +import java.util.Map; + +public class ShortUrlRepository { + + private final Map storage = new HashMap<>(); + private int sequence = 1; + + public int nextId() { + return sequence++; + } + + public void save(String shortUrl, String originalUrl) { + storage.put(shortUrl, originalUrl); + } + + public String findByShortUrl(String shortUrl) { + return storage.get(shortUrl); + } +} \ No newline at end of file diff --git a/src/shorturl/service/Base62Converter.java b/src/shorturl/service/Base62Converter.java new file mode 100644 index 0000000..14c6189 --- /dev/null +++ b/src/shorturl/service/Base62Converter.java @@ -0,0 +1,19 @@ +package shorturl.service; + +public class Base62Converter { + + private static final String BASE62 = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + public String encode(int id) { + StringBuilder shortUrl = new StringBuilder(); + + while (id > 0) { + int index = id % 62; + shortUrl.append(BASE62.charAt(index)); + id /= 62; + } + + return shortUrl.reverse().toString(); + } +} diff --git a/src/shorturl/service/ShortUrlService.java b/src/shorturl/service/ShortUrlService.java new file mode 100644 index 0000000..6c62a9e --- /dev/null +++ b/src/shorturl/service/ShortUrlService.java @@ -0,0 +1,41 @@ +package shorturl.service; + +import shorturl.repository.ShortUrlRepository; + +public class ShortUrlService { + + private static final String BASE_URL = "https://short-url.com/"; + + private final ShortUrlRepository repository; + private final Base62Converter converter; + + public ShortUrlService(ShortUrlRepository repository, + Base62Converter converter) { + this.repository = repository; + this.converter = converter; + } + + public String createShortUrl(String originalUrl) { + int id = repository.nextId(); + String shortUrl = converter.encode(id); + + repository.save(shortUrl, originalUrl); + + return BASE_URL + shortUrl; + } + + public String findOriginalUrl(String inputShortUrl) { + String shortUrl = extractShortUrl(inputShortUrl); + String originalUrl = repository.findByShortUrl(shortUrl); + + if (originalUrl == null) { + throw new IllegalArgumentException("해당 URL이 없습니다."); + } + + return originalUrl; + } + + private String extractShortUrl(String inputShortUrl) { + return inputShortUrl.replace(BASE_URL, ""); + } +} \ No newline at end of file diff --git a/src/shorturl/view/InputView.java b/src/shorturl/view/InputView.java new file mode 100644 index 0000000..ed9f6d9 --- /dev/null +++ b/src/shorturl/view/InputView.java @@ -0,0 +1,18 @@ +package shorturl.view; + +import java.util.Scanner; + +public class InputView { + + private final Scanner scanner = new Scanner(System.in); + + public String readOriginalUrl() { + System.out.print("원본 URL 입력 (종료: exit): "); + return scanner.nextLine(); + } + + public String readShortUrl() { + System.out.print("단축 URL 입력: "); + return scanner.nextLine(); + } +} diff --git a/src/shorturl/view/OutputView.java b/src/shorturl/view/OutputView.java new file mode 100644 index 0000000..d3b6043 --- /dev/null +++ b/src/shorturl/view/OutputView.java @@ -0,0 +1,12 @@ +package shorturl.view; + +public class OutputView { + + public void printShortUrl(String shortUrl) { + System.out.println("생성된 단축 URL: " + shortUrl); + } + + public void redirectToOriginalUrl(String originalUrl) { + System.out.println("원본 URL로 리다이렉트: " + originalUrl); + } +}