diff --git a/.gitignore b/.gitignore
index 9f11b75..e5a4ede 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
.idea/
+build
+.gradle
diff --git a/.gradle/7.5.1/checksums/checksums.lock b/.gradle/7.5.1/checksums/checksums.lock
deleted file mode 100644
index a03e8ed..0000000
Binary files a/.gradle/7.5.1/checksums/checksums.lock and /dev/null differ
diff --git a/.gradle/7.5.1/checksums/md5-checksums.bin b/.gradle/7.5.1/checksums/md5-checksums.bin
deleted file mode 100644
index a9dfcd7..0000000
Binary files a/.gradle/7.5.1/checksums/md5-checksums.bin and /dev/null differ
diff --git a/.gradle/7.5.1/checksums/sha1-checksums.bin b/.gradle/7.5.1/checksums/sha1-checksums.bin
deleted file mode 100644
index 1fa5fcd..0000000
Binary files a/.gradle/7.5.1/checksums/sha1-checksums.bin and /dev/null differ
diff --git a/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock b/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock
deleted file mode 100644
index 09280f7..0000000
Binary files a/.gradle/7.5.1/dependencies-accessors/dependencies-accessors.lock and /dev/null differ
diff --git a/.gradle/7.5.1/dependencies-accessors/gc.properties b/.gradle/7.5.1/dependencies-accessors/gc.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/.gradle/7.5.1/executionHistory/executionHistory.bin b/.gradle/7.5.1/executionHistory/executionHistory.bin
deleted file mode 100644
index 955abc9..0000000
Binary files a/.gradle/7.5.1/executionHistory/executionHistory.bin and /dev/null differ
diff --git a/.gradle/7.5.1/executionHistory/executionHistory.lock b/.gradle/7.5.1/executionHistory/executionHistory.lock
deleted file mode 100644
index 9323e89..0000000
Binary files a/.gradle/7.5.1/executionHistory/executionHistory.lock and /dev/null differ
diff --git a/.gradle/7.5.1/fileChanges/last-build.bin b/.gradle/7.5.1/fileChanges/last-build.bin
deleted file mode 100644
index f76dd23..0000000
Binary files a/.gradle/7.5.1/fileChanges/last-build.bin and /dev/null differ
diff --git a/.gradle/7.5.1/fileHashes/fileHashes.bin b/.gradle/7.5.1/fileHashes/fileHashes.bin
deleted file mode 100644
index e958afe..0000000
Binary files a/.gradle/7.5.1/fileHashes/fileHashes.bin and /dev/null differ
diff --git a/.gradle/7.5.1/fileHashes/fileHashes.lock b/.gradle/7.5.1/fileHashes/fileHashes.lock
deleted file mode 100644
index 8ca5f3d..0000000
Binary files a/.gradle/7.5.1/fileHashes/fileHashes.lock and /dev/null differ
diff --git a/.gradle/7.5.1/fileHashes/resourceHashesCache.bin b/.gradle/7.5.1/fileHashes/resourceHashesCache.bin
deleted file mode 100644
index 73577d1..0000000
Binary files a/.gradle/7.5.1/fileHashes/resourceHashesCache.bin and /dev/null differ
diff --git a/.gradle/7.5.1/gc.properties b/.gradle/7.5.1/gc.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
deleted file mode 100644
index 555ade8..0000000
Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
deleted file mode 100644
index 79c6d9f..0000000
--- a/.gradle/buildOutputCleanup/cache.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-#Thu Apr 11 12:53:51 GMT+04:00 2024
-gradle.version=7.5.1
diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin
deleted file mode 100644
index 580bcee..0000000
Binary files a/.gradle/buildOutputCleanup/outputFiles.bin and /dev/null differ
diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe
deleted file mode 100644
index 6368ebf..0000000
Binary files a/.gradle/file-system.probe and /dev/null differ
diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/build.gradle b/build.gradle
index 3cae2d7..8e37491 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,6 +12,13 @@ repositories {
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
+ implementation(group: 'com.h2database', name: 'h2', version: '2.1.214')
+
+ testImplementation(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '3.2.4')
+ implementation(group: 'org.springframework.boot', name: 'spring-boot-starter', version: '3.2.4')
+ implementation(group: 'org.springframework.boot', name: 'spring-boot-starter-jetty', version: '3.2.4')
+ implementation(group: 'org.springframework.boot', name: 'spring-boot-starter-web-services', version: '3.2.4')
+ implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '3.2.4'
}
test {
diff --git a/build/classes/java/main/org/example/Main.class b/build/classes/java/main/org/example/Main.class
deleted file mode 100644
index fb64510..0000000
Binary files a/build/classes/java/main/org/example/Main.class and /dev/null differ
diff --git a/build/classes/java/main/org/example/database/Database.class b/build/classes/java/main/org/example/database/Database.class
deleted file mode 100644
index 46c1bbf..0000000
Binary files a/build/classes/java/main/org/example/database/Database.class and /dev/null differ
diff --git a/build/classes/java/main/org/example/exception/UnknownShortLinkException.class b/build/classes/java/main/org/example/exception/UnknownShortLinkException.class
deleted file mode 100644
index 5a091dd..0000000
Binary files a/build/classes/java/main/org/example/exception/UnknownShortLinkException.class and /dev/null differ
diff --git a/build/classes/java/main/org/example/service/MainService.class b/build/classes/java/main/org/example/service/MainService.class
deleted file mode 100644
index 8fd3685..0000000
Binary files a/build/classes/java/main/org/example/service/MainService.class and /dev/null differ
diff --git a/build/classes/java/main/org/example/service/MainServiceImpl.class b/build/classes/java/main/org/example/service/MainServiceImpl.class
deleted file mode 100644
index 89d029b..0000000
Binary files a/build/classes/java/main/org/example/service/MainServiceImpl.class and /dev/null differ
diff --git a/build/classes/java/test/org/example/service/MainServiceTest.class b/build/classes/java/test/org/example/service/MainServiceTest.class
deleted file mode 100644
index 0d03df1..0000000
Binary files a/build/classes/java/test/org/example/service/MainServiceTest.class and /dev/null differ
diff --git a/build/reports/tests/test/classes/org.example.service.MainServiceTest.html b/build/reports/tests/test/classes/org.example.service.MainServiceTest.html
deleted file mode 100644
index b338007..0000000
--- a/build/reports/tests/test/classes/org.example.service.MainServiceTest.html
+++ /dev/null
@@ -1,111 +0,0 @@
-
-
-
-
-
-Test results - MainServiceTest
-
-
-
-
-
-
-
MainServiceTest
-
-
-
-
-
-
-
-
-|
-
- |
-
-
- |
-
-
- |
-
-
- |
-
-
-
- |
-
-
- |
-
-
-
-
-
-
-
Tests
-
-
-
-| Test |
-Duration |
-Result |
-
-
-
-| testException() |
-0.039s |
-passed |
-
-
-| testGetLongLink() |
-0.005s |
-passed |
-
-
-| testGetShortLink() |
-0.019s |
-passed |
-
-
-| testUniqueness() |
-3.557s |
-passed |
-
-
-
-
-
-
-
-
diff --git a/build/reports/tests/test/css/base-style.css b/build/reports/tests/test/css/base-style.css
deleted file mode 100644
index 4afa73e..0000000
--- a/build/reports/tests/test/css/base-style.css
+++ /dev/null
@@ -1,179 +0,0 @@
-
-body {
- margin: 0;
- padding: 0;
- font-family: sans-serif;
- font-size: 12pt;
-}
-
-body, a, a:visited {
- color: #303030;
-}
-
-#content {
- padding-left: 50px;
- padding-right: 50px;
- padding-top: 30px;
- padding-bottom: 30px;
-}
-
-#content h1 {
- font-size: 160%;
- margin-bottom: 10px;
-}
-
-#footer {
- margin-top: 100px;
- font-size: 80%;
- white-space: nowrap;
-}
-
-#footer, #footer a {
- color: #a0a0a0;
-}
-
-#line-wrapping-toggle {
- vertical-align: middle;
-}
-
-#label-for-line-wrapping-toggle {
- vertical-align: middle;
-}
-
-ul {
- margin-left: 0;
-}
-
-h1, h2, h3 {
- white-space: nowrap;
-}
-
-h2 {
- font-size: 120%;
-}
-
-ul.tabLinks {
- padding-left: 0;
- padding-top: 10px;
- padding-bottom: 10px;
- overflow: auto;
- min-width: 800px;
- width: auto !important;
- width: 800px;
-}
-
-ul.tabLinks li {
- float: left;
- height: 100%;
- list-style: none;
- padding-left: 10px;
- padding-right: 10px;
- padding-top: 5px;
- padding-bottom: 5px;
- margin-bottom: 0;
- -moz-border-radius: 7px;
- border-radius: 7px;
- margin-right: 25px;
- border: solid 1px #d4d4d4;
- background-color: #f0f0f0;
-}
-
-ul.tabLinks li:hover {
- background-color: #fafafa;
-}
-
-ul.tabLinks li.selected {
- background-color: #c5f0f5;
- border-color: #c5f0f5;
-}
-
-ul.tabLinks a {
- font-size: 120%;
- display: block;
- outline: none;
- text-decoration: none;
- margin: 0;
- padding: 0;
-}
-
-ul.tabLinks li h2 {
- margin: 0;
- padding: 0;
-}
-
-div.tab {
-}
-
-div.selected {
- display: block;
-}
-
-div.deselected {
- display: none;
-}
-
-div.tab table {
- min-width: 350px;
- width: auto !important;
- width: 350px;
- border-collapse: collapse;
-}
-
-div.tab th, div.tab table {
- border-bottom: solid #d0d0d0 1px;
-}
-
-div.tab th {
- text-align: left;
- white-space: nowrap;
- padding-left: 6em;
-}
-
-div.tab th:first-child {
- padding-left: 0;
-}
-
-div.tab td {
- white-space: nowrap;
- padding-left: 6em;
- padding-top: 5px;
- padding-bottom: 5px;
-}
-
-div.tab td:first-child {
- padding-left: 0;
-}
-
-div.tab td.numeric, div.tab th.numeric {
- text-align: right;
-}
-
-span.code {
- display: inline-block;
- margin-top: 0em;
- margin-bottom: 1em;
-}
-
-span.code pre {
- font-size: 11pt;
- padding-top: 10px;
- padding-bottom: 10px;
- padding-left: 10px;
- padding-right: 10px;
- margin: 0;
- background-color: #f7f7f7;
- border: solid 1px #d0d0d0;
- min-width: 700px;
- width: auto !important;
- width: 700px;
-}
-
-span.wrapped pre {
- word-wrap: break-word;
- white-space: pre-wrap;
- word-break: break-all;
-}
-
-label.hidden {
- display: none;
-}
\ No newline at end of file
diff --git a/build/reports/tests/test/css/style.css b/build/reports/tests/test/css/style.css
deleted file mode 100644
index 3dc4913..0000000
--- a/build/reports/tests/test/css/style.css
+++ /dev/null
@@ -1,84 +0,0 @@
-
-#summary {
- margin-top: 30px;
- margin-bottom: 40px;
-}
-
-#summary table {
- border-collapse: collapse;
-}
-
-#summary td {
- vertical-align: top;
-}
-
-.breadcrumbs, .breadcrumbs a {
- color: #606060;
-}
-
-.infoBox {
- width: 110px;
- padding-top: 15px;
- padding-bottom: 15px;
- text-align: center;
-}
-
-.infoBox p {
- margin: 0;
-}
-
-.counter, .percent {
- font-size: 120%;
- font-weight: bold;
- margin-bottom: 8px;
-}
-
-#duration {
- width: 125px;
-}
-
-#successRate, .summaryGroup {
- border: solid 2px #d0d0d0;
- -moz-border-radius: 10px;
- border-radius: 10px;
-}
-
-#successRate {
- width: 140px;
- margin-left: 35px;
-}
-
-#successRate .percent {
- font-size: 180%;
-}
-
-.success, .success a {
- color: #008000;
-}
-
-div.success, #successRate.success {
- background-color: #bbd9bb;
- border-color: #008000;
-}
-
-.failures, .failures a {
- color: #b60808;
-}
-
-.skipped, .skipped a {
- color: #c09853;
-}
-
-div.failures, #successRate.failures {
- background-color: #ecdada;
- border-color: #b60808;
-}
-
-ul.linkList {
- padding-left: 0;
-}
-
-ul.linkList li {
- list-style: none;
- margin-bottom: 5px;
-}
diff --git a/build/reports/tests/test/index.html b/build/reports/tests/test/index.html
deleted file mode 100644
index a2a465e..0000000
--- a/build/reports/tests/test/index.html
+++ /dev/null
@@ -1,133 +0,0 @@
-
-
-
-
-
-Test results - Test Summary
-
-
-
-
-
-
-
Test Summary
-
-
-
-
-
-
-
-|
-
- |
-
-
- |
-
-
- |
-
-
- |
-
-
-
- |
-
-
- |
-
-
-
-
-
-
-
Packages
-
-
-
-| Package |
-Tests |
-Failures |
-Ignored |
-Duration |
-Success rate |
-
-
-
-
-|
-org.example.service
- |
-4 |
-0 |
-0 |
-3.620s |
-100% |
-
-
-
-
-
-
-
-
-
-
diff --git a/build/reports/tests/test/js/report.js b/build/reports/tests/test/js/report.js
deleted file mode 100644
index 83bab4a..0000000
--- a/build/reports/tests/test/js/report.js
+++ /dev/null
@@ -1,194 +0,0 @@
-(function (window, document) {
- "use strict";
-
- var tabs = {};
-
- function changeElementClass(element, classValue) {
- if (element.getAttribute("className")) {
- element.setAttribute("className", classValue);
- } else {
- element.setAttribute("class", classValue);
- }
- }
-
- function getClassAttribute(element) {
- if (element.getAttribute("className")) {
- return element.getAttribute("className");
- } else {
- return element.getAttribute("class");
- }
- }
-
- function addClass(element, classValue) {
- changeElementClass(element, getClassAttribute(element) + " " + classValue);
- }
-
- function removeClass(element, classValue) {
- changeElementClass(element, getClassAttribute(element).replace(classValue, ""));
- }
-
- function initTabs() {
- var container = document.getElementById("tabs");
-
- tabs.tabs = findTabs(container);
- tabs.titles = findTitles(tabs.tabs);
- tabs.headers = findHeaders(container);
- tabs.select = select;
- tabs.deselectAll = deselectAll;
- tabs.select(0);
-
- return true;
- }
-
- function getCheckBox() {
- return document.getElementById("line-wrapping-toggle");
- }
-
- function getLabelForCheckBox() {
- return document.getElementById("label-for-line-wrapping-toggle");
- }
-
- function findCodeBlocks() {
- var spans = document.getElementById("tabs").getElementsByTagName("span");
- var codeBlocks = [];
- for (var i = 0; i < spans.length; ++i) {
- if (spans[i].className.indexOf("code") >= 0) {
- codeBlocks.push(spans[i]);
- }
- }
- return codeBlocks;
- }
-
- function forAllCodeBlocks(operation) {
- var codeBlocks = findCodeBlocks();
-
- for (var i = 0; i < codeBlocks.length; ++i) {
- operation(codeBlocks[i], "wrapped");
- }
- }
-
- function toggleLineWrapping() {
- var checkBox = getCheckBox();
-
- if (checkBox.checked) {
- forAllCodeBlocks(addClass);
- } else {
- forAllCodeBlocks(removeClass);
- }
- }
-
- function initControls() {
- if (findCodeBlocks().length > 0) {
- var checkBox = getCheckBox();
- var label = getLabelForCheckBox();
-
- checkBox.onclick = toggleLineWrapping;
- checkBox.checked = false;
-
- removeClass(label, "hidden");
- }
- }
-
- function switchTab() {
- var id = this.id.substr(1);
-
- for (var i = 0; i < tabs.tabs.length; i++) {
- if (tabs.tabs[i].id === id) {
- tabs.select(i);
- break;
- }
- }
-
- return false;
- }
-
- function select(i) {
- this.deselectAll();
-
- changeElementClass(this.tabs[i], "tab selected");
- changeElementClass(this.headers[i], "selected");
-
- while (this.headers[i].firstChild) {
- this.headers[i].removeChild(this.headers[i].firstChild);
- }
-
- var h2 = document.createElement("H2");
-
- h2.appendChild(document.createTextNode(this.titles[i]));
- this.headers[i].appendChild(h2);
- }
-
- function deselectAll() {
- for (var i = 0; i < this.tabs.length; i++) {
- changeElementClass(this.tabs[i], "tab deselected");
- changeElementClass(this.headers[i], "deselected");
-
- while (this.headers[i].firstChild) {
- this.headers[i].removeChild(this.headers[i].firstChild);
- }
-
- var a = document.createElement("A");
-
- a.setAttribute("id", "ltab" + i);
- a.setAttribute("href", "#tab" + i);
- a.onclick = switchTab;
- a.appendChild(document.createTextNode(this.titles[i]));
-
- this.headers[i].appendChild(a);
- }
- }
-
- function findTabs(container) {
- return findChildElements(container, "DIV", "tab");
- }
-
- function findHeaders(container) {
- var owner = findChildElements(container, "UL", "tabLinks");
- return findChildElements(owner[0], "LI", null);
- }
-
- function findTitles(tabs) {
- var titles = [];
-
- for (var i = 0; i < tabs.length; i++) {
- var tab = tabs[i];
- var header = findChildElements(tab, "H2", null)[0];
-
- header.parentNode.removeChild(header);
-
- if (header.innerText) {
- titles.push(header.innerText);
- } else {
- titles.push(header.textContent);
- }
- }
-
- return titles;
- }
-
- function findChildElements(container, name, targetClass) {
- var elements = [];
- var children = container.childNodes;
-
- for (var i = 0; i < children.length; i++) {
- var child = children.item(i);
-
- if (child.nodeType === 1 && child.nodeName === name) {
- if (targetClass && child.className.indexOf(targetClass) < 0) {
- continue;
- }
-
- elements.push(child);
- }
- }
-
- return elements;
- }
-
- // Entry point.
-
- window.onload = function() {
- initTabs();
- initControls();
- };
-} (window, window.document));
\ No newline at end of file
diff --git a/build/reports/tests/test/packages/org.example.service.html b/build/reports/tests/test/packages/org.example.service.html
deleted file mode 100644
index f22e014..0000000
--- a/build/reports/tests/test/packages/org.example.service.html
+++ /dev/null
@@ -1,103 +0,0 @@
-
-
-
-
-
-Test results - Package org.example.service
-
-
-
-
-
-
-
Package org.example.service
-
-
all > org.example.service
-
-
-
-
-
-
-
-|
-
- |
-
-
- |
-
-
- |
-
-
- |
-
-
-
- |
-
-
- |
-
-
-
-
-
-
-
Classes
-
-
-
-| Class |
-Tests |
-Failures |
-Ignored |
-Duration |
-Success rate |
-
-
-
-|
-MainServiceTest
- |
-4 |
-0 |
-0 |
-3.620s |
-100% |
-
-
-
-
-
-
-
-
diff --git a/build/test-results/test/TEST-org.example.service.MainServiceTest.xml b/build/test-results/test/TEST-org.example.service.MainServiceTest.xml
deleted file mode 100644
index 79b5ccf..0000000
--- a/build/test-results/test/TEST-org.example.service.MainServiceTest.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/build/test-results/test/binary/output.bin b/build/test-results/test/binary/output.bin
deleted file mode 100644
index e69de29..0000000
diff --git a/build/test-results/test/binary/output.bin.idx b/build/test-results/test/binary/output.bin.idx
deleted file mode 100644
index f76dd23..0000000
Binary files a/build/test-results/test/binary/output.bin.idx and /dev/null differ
diff --git a/build/test-results/test/binary/results.bin b/build/test-results/test/binary/results.bin
deleted file mode 100644
index 7f5e71f..0000000
Binary files a/build/test-results/test/binary/results.bin and /dev/null differ
diff --git a/build/tmp/compileJava/previous-compilation-data.bin b/build/tmp/compileJava/previous-compilation-data.bin
deleted file mode 100644
index 0826bd6..0000000
Binary files a/build/tmp/compileJava/previous-compilation-data.bin and /dev/null differ
diff --git a/build/tmp/compileTestJava/previous-compilation-data.bin b/build/tmp/compileTestJava/previous-compilation-data.bin
deleted file mode 100644
index 19a83b1..0000000
Binary files a/build/tmp/compileTestJava/previous-compilation-data.bin and /dev/null differ
diff --git a/h2-2.1.214.jar b/h2-2.1.214.jar
new file mode 100644
index 0000000..1d527cb
Binary files /dev/null and b/h2-2.1.214.jar differ
diff --git a/src/main/java/org/example/LinkShortenerApplication.java b/src/main/java/org/example/LinkShortenerApplication.java
new file mode 100644
index 0000000..6a3628a
--- /dev/null
+++ b/src/main/java/org/example/LinkShortenerApplication.java
@@ -0,0 +1,11 @@
+package org.example;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class LinkShortenerApplication {
+ public static void main(String... args) {
+ SpringApplication.run(LinkShortenerApplication.class);
+ }
+}
diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java
deleted file mode 100644
index 689f5c0..0000000
--- a/src/main/java/org/example/Main.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.example;
-
-
-
-import org.example.exception.UnknownShortLinkException;
-import org.example.service.MainService;
-import org.example.service.MainServiceImpl;
-
-import java.util.Scanner;
-
-import static org.example.service.MainServiceImpl.shortLinksDomain;
-
-public class Main {
- public static Scanner sc = new Scanner(System.in);
- public static MainService service = new MainServiceImpl();
- public static void main(String[] args) {
- while (true) {
- printMenu();
-
- String chosenService = sc.nextLine();
-
- if (chosenService.equals("1")) {
- System.out.println("Введите длинную ссылку");
- String longLink = null;
- while (longLink == null) {
- longLink = readAndValidateLongLink();
- }
- String shortLink = service.getShortLink(longLink);
- System.out.println("Короткая ссылка: " + shortLink);
-
- } else if (chosenService.equals("2")) {
- System.out.println("Введите короткую ссылку:");
- String shortLink = null;
- while (shortLink == null) {
- shortLink = readAndValidateShortLink();
- }
- try {
- String longLink = service.getLongLink(shortLink);
- System.out.println("Длинная ссылка: " + longLink);
- } catch(UnknownShortLinkException ex) {
- System.out.println("Данной короткой ссылке не соответствует никакая длинная");
- }
- } else if (chosenService.equals("3")) {
- return;
- } else {
- System.out.println("Выберите валидный вариант");
- }
- }
- }
-
- private static String readAndValidateLongLink() {
- String link = sc.nextLine();
-
- if (link == null || link.isBlank()) {
- System.out.println("Некорректная ссылка, введите ещё раз");
- return null;
- }
-
- return link;
- }
-
- private static String readAndValidateShortLink() {
- String link = sc.nextLine();
- int len = shortLinksDomain.length();
-
- if (link == null || link.length() < len || !shortLinksDomain.equals(link.substring(0, len))) {
- System.out.println("Короткая ссылка должна начинаться с \"" + shortLinksDomain + "\". Введите ссылку ещё раз");
- return null;
- }
-
- return link;
- }
-
-
- private static void printMenu() {
- System.out.println("""
- Выберите действие:
- 1. Укоротить ссылку
- 2. Восстановить длинную ссылку по короткой
- 3. Выйти
- """);
- }
-
-
-}
\ No newline at end of file
diff --git a/src/main/java/org/example/advice/MyControllerAdvice.java b/src/main/java/org/example/advice/MyControllerAdvice.java
new file mode 100644
index 0000000..8923589
--- /dev/null
+++ b/src/main/java/org/example/advice/MyControllerAdvice.java
@@ -0,0 +1,34 @@
+package org.example.advice;
+
+import org.example.exception.BadRepositoryFunctionCallException;
+import org.example.exception.IncorrectLongLinkException;
+import org.example.exception.UnknownShortLinkException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+import java.sql.SQLException;
+
+@ControllerAdvice
+public class MyControllerAdvice {
+ @ExceptionHandler(IncorrectLongLinkException.class)
+ public ResponseEntity handleIncorrectLongLink(IncorrectLongLinkException e) {
+ return new ResponseEntity("Incorrect long link", HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler(UnknownShortLinkException.class)
+ public ResponseEntity handleUnknownShortLink(UnknownShortLinkException e) {
+ return new ResponseEntity("There is no corresponding long link", HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler(BadRepositoryFunctionCallException.class)
+ public ResponseEntity handleBadCall(BadRepositoryFunctionCallException e) {
+ return new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ @ExceptionHandler(SQLException.class)
+ public ResponseEntity handleSQLException(SQLException e) {
+ return new ResponseEntity(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+}
diff --git a/src/main/java/org/example/controller/MainController.java b/src/main/java/org/example/controller/MainController.java
new file mode 100644
index 0000000..a054683
--- /dev/null
+++ b/src/main/java/org/example/controller/MainController.java
@@ -0,0 +1,34 @@
+package org.example.controller;
+
+import org.example.exception.BadRepositoryFunctionCallException;
+import org.example.exception.IncorrectLongLinkException;
+import org.example.exception.UnknownShortLinkException;
+import org.example.service.MainService;
+import org.example.service.MainServiceImpl;
+import org.springframework.web.bind.annotation.*;
+
+import static org.example.service.MainServiceImpl.shortLinksDomain;
+
+@RestController
+@RequestMapping("/url")
+public class MainController {
+ private final MainService mainService;
+ public MainController(MainService mainService) {
+ this.mainService = mainService;
+ }
+ @PostMapping(value = "/create")
+ public String createShortLink(@RequestBody String longLink)
+ throws IncorrectLongLinkException, BadRepositoryFunctionCallException {
+ if(longLink == null || longLink.isBlank())
+ throw new IncorrectLongLinkException();
+
+ return mainService.getShortLink(longLink);
+ }
+
+
+ @GetMapping("/{shortCode}")
+ public String getLongLink(@PathVariable("shortCode") String shortCode)
+ throws UnknownShortLinkException, BadRepositoryFunctionCallException {
+ return mainService.getLongLink(shortLinksDomain + shortCode);
+ }
+}
diff --git a/src/main/java/org/example/dao/entity/LinksEntity.java b/src/main/java/org/example/dao/entity/LinksEntity.java
new file mode 100644
index 0000000..0ee198e
--- /dev/null
+++ b/src/main/java/org/example/dao/entity/LinksEntity.java
@@ -0,0 +1,36 @@
+package org.example.dao.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+
+@Entity(name = "links")
+public class LinksEntity {
+ @Id
+ @Column(name = "SHORT_CODE")
+ private String shortCode;
+ @Column(name = "LONG_LINK")
+ private String longLink;
+
+ public LinksEntity() {}
+ public LinksEntity(String shortCode, String longLink) {
+ this.shortCode = shortCode;
+ this.longLink = longLink;
+ }
+
+ public String getShortCode() {
+ return shortCode;
+ }
+
+ public void setShortCode(String shortCode) {
+ this.shortCode = shortCode;
+ }
+
+ public String getLongLink() {
+ return longLink;
+ }
+
+ public void setLongLink(String longLink) {
+ this.longLink = longLink;
+ }
+}
diff --git a/src/main/java/org/example/dao/repository/LinksRepository.java b/src/main/java/org/example/dao/repository/LinksRepository.java
new file mode 100644
index 0000000..0cebd84
--- /dev/null
+++ b/src/main/java/org/example/dao/repository/LinksRepository.java
@@ -0,0 +1,19 @@
+package org.example.dao.repository;
+
+import org.example.dao.entity.LinksEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface LinksRepository extends JpaRepository {
+ @Query(nativeQuery = true,
+ value = "SELECT LONG_LINK FROM links WHERE SHORT_CODE = :shortCode")
+ List findLongLinksByShortCode(@Param("shortCode") String shortCode);
+ @Query(nativeQuery = true,
+ value = "SELECT SHORT_CODE FROM links WHERE LONG_LINK = :longLink")
+ List findShortCodesByLongLink(@Param("longLink") String longLink);
+}
diff --git a/src/main/java/org/example/dao/repository/OldLinksRepository.java b/src/main/java/org/example/dao/repository/OldLinksRepository.java
new file mode 100644
index 0000000..7aab4cd
--- /dev/null
+++ b/src/main/java/org/example/dao/repository/OldLinksRepository.java
@@ -0,0 +1,49 @@
+package org.example.dao.repository;
+
+import org.example.dao.entity.LinksEntity;
+import org.example.exception.BadRepositoryFunctionCallException;
+import org.springframework.stereotype.Repository;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+@Repository
+public class OldLinksRepository {
+ private final LinksRepository linksRepository;
+
+ public OldLinksRepository(LinksRepository linksRepository) { this.linksRepository = linksRepository; }
+
+ public String getShortCode(String longLink) throws BadRepositoryFunctionCallException {
+ List shortCodes = linksRepository.findShortCodesByLongLink(longLink);
+
+ if (!shortCodes.isEmpty())
+ return shortCodes.get(0);
+
+ throw new BadRepositoryFunctionCallException("Error: long link is not found");
+ }
+
+ public String getLongLink(String shortCode) throws BadRepositoryFunctionCallException {
+ List longLinks = linksRepository.findLongLinksByShortCode(shortCode);
+
+ if(!longLinks.isEmpty())
+ return longLinks.get(0);
+
+ throw new BadRepositoryFunctionCallException("Error: short code is not found");
+ }
+
+ public boolean containsShortCode(String shortCode) {
+ List longLinks = linksRepository.findLongLinksByShortCode(shortCode);
+ return !longLinks.isEmpty();
+ }
+
+ public boolean containsLongLink(String longLink) {
+ List shortCodes = linksRepository.findShortCodesByLongLink(longLink);
+ return !shortCodes.isEmpty();
+ }
+
+ public void addPairOfLinks(String longLink, String shortCode) {
+ linksRepository.save(new LinksEntity(shortCode, longLink));
+ }
+}
diff --git a/src/main/java/org/example/database/Database.java b/src/main/java/org/example/database/Database.java
deleted file mode 100644
index 07f4921..0000000
--- a/src/main/java/org/example/database/Database.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.example.database;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class Database {
- private static final Database instance = new Database();
- private Database() {}
- public static Database getInstance() {
- return instance;
- }
-
- private final Map shortCodes = new HashMap<>(); // key = long link, value = short code (without domain)
- private final Map longLinks = new HashMap<>(); // key = short code, value = long link
-
- public String getShortCode(String longLink) {
- return shortCodes.get(longLink);
- }
-
- public String getLongLink(String shortCode) {
- return longLinks.get(shortCode);
- }
-
- public boolean containsLongLink(String longLink) {
- return shortCodes.containsKey(longLink);
- }
-
- public boolean containsShortCode(String shortCode) {
- return longLinks.containsKey(shortCode);
- }
-
- public void addPairOfLinks(String longLink, String shortCode) {
- longLinks.put(shortCode, longLink);
- shortCodes.put(longLink, shortCode);
- }
-}
diff --git a/src/main/java/org/example/exception/BadRepositoryFunctionCallException.java b/src/main/java/org/example/exception/BadRepositoryFunctionCallException.java
new file mode 100644
index 0000000..fc3f4f4
--- /dev/null
+++ b/src/main/java/org/example/exception/BadRepositoryFunctionCallException.java
@@ -0,0 +1,7 @@
+package org.example.exception;
+
+public class BadRepositoryFunctionCallException extends Exception {
+ public BadRepositoryFunctionCallException() {}
+
+ public BadRepositoryFunctionCallException(String message) {super(message);}
+}
diff --git a/src/main/java/org/example/exception/IncorrectLongLinkException.java b/src/main/java/org/example/exception/IncorrectLongLinkException.java
new file mode 100644
index 0000000..0654815
--- /dev/null
+++ b/src/main/java/org/example/exception/IncorrectLongLinkException.java
@@ -0,0 +1,12 @@
+package org.example.exception;
+
+public class IncorrectLongLinkException extends Exception {
+
+ public IncorrectLongLinkException() {
+ }
+
+ public IncorrectLongLinkException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/org/example/exception/UnknownShortLinkException.java b/src/main/java/org/example/exception/UnknownShortLinkException.java
index 094959f..bc85ac2 100644
--- a/src/main/java/org/example/exception/UnknownShortLinkException.java
+++ b/src/main/java/org/example/exception/UnknownShortLinkException.java
@@ -9,4 +9,4 @@ public UnknownShortLinkException(String message) {
super(message);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/example/jdbc/JdbcUtils.java b/src/main/java/org/example/jdbc/JdbcUtils.java
new file mode 100644
index 0000000..601af32
--- /dev/null
+++ b/src/main/java/org/example/jdbc/JdbcUtils.java
@@ -0,0 +1,22 @@
+package org.example.jdbc;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+@Configuration
+public class JdbcUtils {
+ private static final String DB_URL = "jdbc:h2:~/test";
+ @Bean(value = "connection")
+ public Connection getConnection() {
+ try {
+ return DriverManager.getConnection(DB_URL, "admin", "admin");
+ } catch (Exception ex) {
+ System.out.println("Error occurred while connection to database: " + ex.getMessage());
+ throw new RuntimeException(ex);
+ }
+ }
+}
diff --git a/src/main/java/org/example/service/MainService.java b/src/main/java/org/example/service/MainService.java
index 2a006ab..6de533e 100644
--- a/src/main/java/org/example/service/MainService.java
+++ b/src/main/java/org/example/service/MainService.java
@@ -1,8 +1,9 @@
package org.example.service;
+import org.example.exception.BadRepositoryFunctionCallException;
import org.example.exception.UnknownShortLinkException;
public interface MainService {
- String getShortLink(String longLink);
- String getLongLink(String shortLink) throws UnknownShortLinkException;
+ String getShortLink(String longLink) throws BadRepositoryFunctionCallException;
+ String getLongLink(String shortLink) throws BadRepositoryFunctionCallException, UnknownShortLinkException;
}
diff --git a/src/main/java/org/example/service/MainServiceImpl.java b/src/main/java/org/example/service/MainServiceImpl.java
index c348207..80aaa02 100644
--- a/src/main/java/org/example/service/MainServiceImpl.java
+++ b/src/main/java/org/example/service/MainServiceImpl.java
@@ -1,13 +1,21 @@
package org.example.service;
-import org.example.database.Database;
+import org.example.exception.BadRepositoryFunctionCallException;
import org.example.exception.UnknownShortLinkException;
+import org.example.dao.repository.OldLinksRepository;
+import org.springframework.stereotype.Service;
import java.util.Random;
+@Service
public class MainServiceImpl implements MainService {
public static final int shortLinkLength = 5;
public static final String shortLinksDomain = "localhost:8080/";
+ private final OldLinksRepository linksRepository;
+
+ public MainServiceImpl(OldLinksRepository linksRepository) {
+ this.linksRepository = linksRepository;
+ }
char getSymbol(int code) {
if(code < 26)
@@ -17,30 +25,30 @@ else if(code < 52)
else return (char)(code - 52 + '0');
}
@Override
- public String getShortLink(String longLink) {
- if(Database.getInstance().containsLongLink(longLink))
- return shortLinksDomain + Database.getInstance().getShortCode(longLink);
+ public String getShortLink(String longLink) throws BadRepositoryFunctionCallException {
+ if(linksRepository.containsLongLink(longLink))
+ return shortLinksDomain + linksRepository.getShortCode(longLink);
String shortLink = null;
Random random = new Random();
- while(shortLink == null || Database.getInstance().containsShortCode(shortLink)) {
+ while(shortLink == null || linksRepository.containsShortCode(shortLink)) {
shortLink = "";
for(int i = 0; i < shortLinkLength; i++)
shortLink += getSymbol(random.nextInt(62));
}
- Database.getInstance().addPairOfLinks(longLink, shortLink);
+ linksRepository.addPairOfLinks(longLink, shortLink);
return shortLinksDomain + shortLink;
}
@Override
- public String getLongLink(String shortLink) throws UnknownShortLinkException {
+ public String getLongLink(String shortLink) throws UnknownShortLinkException, BadRepositoryFunctionCallException {
shortLink = shortLink.substring(shortLinksDomain.length(), shortLink.length());
- if(!Database.getInstance().containsShortCode(shortLink))
+ if(!linksRepository.containsShortCode(shortLink))
throw new UnknownShortLinkException("Короткая ссылка не найдена");
- else return Database.getInstance().getLongLink(shortLink);
+ else return linksRepository.getLongLink(shortLink);
}
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..e9b42f4
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,10 @@
+spring:
+ datasource:
+ url: jdbc:h2:~/test
+ username: admin
+ password: admin
+
+logging:
+ level:
+ sql: INFO
+
diff --git a/src/test/java/org/example/controller/MainControllerTest.java b/src/test/java/org/example/controller/MainControllerTest.java
new file mode 100644
index 0000000..999fe4e
--- /dev/null
+++ b/src/test/java/org/example/controller/MainControllerTest.java
@@ -0,0 +1,156 @@
+package org.example.controller;
+
+import org.example.exception.UnknownShortLinkException;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+
+import java.util.HashMap;
+import java.util.Random;
+
+import static org.example.service.MainServiceImpl.shortLinkLength;
+import static org.example.service.MainServiceImpl.shortLinksDomain;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc
+public class MainControllerTest {
+ @Autowired
+ private MockMvc mockMvc;
+ private Random random = new Random();
+
+ @Test
+ void testGetShortLink() throws Exception {
+ String longLink = "";
+
+ for(int i = 0; i < 10; i++)
+ longLink += (char)random.nextInt('a', 'z' + 1);
+
+ MvcResult mvcResult = mockMvc.perform(post("/url/create").content(longLink))
+ .andExpect(status().isOk()).andReturn();
+
+ String shortLink = mvcResult.getResponse().getContentAsString();
+
+ mvcResult = mockMvc.perform(post("/url/create").content(longLink))
+ .andExpect(status().isOk()).andReturn();
+
+ String shortLink2 = mvcResult.getResponse().getContentAsString();
+
+ assert(shortLink.length() == shortLinksDomain.length() + shortLinkLength);
+ assertEquals(shortLink.substring(0, shortLinksDomain.length()), shortLinksDomain);
+ assertEquals(shortLink, shortLink2);
+ }
+
+ /*@Test
+ void testGetShortLink() throws Exception {
+ //given:
+ String longLink = "www.example.com";
+ //when:
+ String shortLink = mainService.getShortLink(longLink);
+ String shortLink2 = mainService.getShortLink(longLink);
+ //then:
+ assert(shortLink.length() == shortLinksDomain.length() + shortLinkLength);
+ assertEquals(shortLink.substring(0, shortLinksDomain.length()), shortLinksDomain);
+ assertEquals(shortLink, shortLink2);
+ }*/
+
+ @Test
+ void testGetLongLink() throws Exception {
+ String longLink = "";
+
+ for(int i = 0; i < 10; i++)
+ longLink += (char)random.nextInt('a', 'z' + 1);
+
+ MvcResult mvcResult = mockMvc.perform(post("/url/create").content(longLink))
+ .andExpect(status().isOk()).andReturn();
+
+ String shortLink = mvcResult.getResponse().getContentAsString();
+
+ mvcResult = mockMvc.perform(get("/url" + shortLink.substring(shortLinksDomain.length() - 1, shortLink.length())))
+ .andExpect(status().isOk()).andReturn();
+
+ String longLink2 = mvcResult.getResponse().getContentAsString();
+ assertEquals(longLink, longLink2);
+ }
+
+ /* @Test
+ void testGetLongLink() throws Exception {
+ //given:
+ String longLink = "www.example.com";
+ //when:
+ String shortLink = mainService.getShortLink(longLink);
+ String longLink2 = mainService.getLongLink(shortLink);
+ //then:
+ assertEquals(longLink, longLink2);
+ }*/
+
+ @Test
+ void testUniqueness() throws Exception {
+ int N = 100000;
+ HashMap map = new HashMap<>();
+
+ for(int i = 0; i < N; i++)
+ {
+ String longLink = "";
+
+ for(int j = 0; j < 3; j++)
+ longLink += (char)random.nextInt('a', 'z' + 1);
+
+ longLink += Integer.toString(i);
+
+ MvcResult mvcResult = mockMvc.perform(post("/url/create").content(longLink))
+ .andExpect(status().isOk()).andReturn();
+
+ String shortLink = mvcResult.getResponse().getContentAsString();
+ map.put(shortLink, i);
+ }
+
+ assertEquals(map.size(), N);
+ }
+
+ /* @Test
+ void testUniqueness() throws Exception {
+ //given:
+ int N = 1000000;
+ HashMap map = new HashMap<>();
+ //when:
+ for(int i = 0; i < N; i++)
+ {
+ String shortLink = mainService.getShortLink(Integer.toString(i));
+ map.put(shortLink, i);
+ }
+ //then:
+ assertEquals(map.size(), N);
+ }*/
+
+ @Test
+ void testLinkNotFound() throws Exception {
+
+ MvcResult mvcResult = mockMvc.perform(get("/url/a"))
+ .andExpect(status().isBadRequest()).andReturn();
+
+ String longLink = mvcResult.getResponse().getContentAsString();
+ assertEquals(longLink, "There is no corresponding long link");
+ }
+
+ /*@Test
+ void testException() throws Exception {
+ //given:
+ String shortLink = shortLinksDomain;
+ //when:
+ boolean exceptionThrown = false;
+ try {
+ String longLink = mainService.getLongLink(shortLink);
+ } catch (UnknownShortLinkException e) {
+ exceptionThrown = true;
+ }
+
+ assert(exceptionThrown);
+ }*/
+}
diff --git a/src/test/java/org/example/service/MainServiceTest.java b/src/test/java/org/example/service/MainServiceTest.java
deleted file mode 100644
index f442a1a..0000000
--- a/src/test/java/org/example/service/MainServiceTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.example.service;
-
-import org.example.exception.UnknownShortLinkException;
-import org.junit.jupiter.api.Test;
-
-import java.util.HashMap;
-
-import static org.example.service.MainServiceImpl.shortLinkLength;
-import static org.example.service.MainServiceImpl.shortLinksDomain;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-public class MainServiceTest {
- private final MainService service = new MainServiceImpl();
-
- @Test
- void testGetShortLink() throws Exception {
- //given:
- String longLink = "www.example.com";
- //when:
- String shortLink = service.getShortLink(longLink);
- String shortLink2 = service.getShortLink(longLink);
- //then:
- assert(shortLink.length() == shortLinksDomain.length() + shortLinkLength);
- assertEquals(shortLink.substring(0, shortLinksDomain.length()), shortLinksDomain);
- assertEquals(shortLink, shortLink2);
- }
-
- @Test
- void testGetLongLink() throws Exception {
- //given:
- String longLink = "www.example.com";
- //when:
- String shortLink = service.getShortLink(longLink);
- String longLink2 = service.getLongLink(shortLink);
- //then:
- assertEquals(longLink, longLink2);
- }
-
- @Test
- void testUniqueness() throws Exception {
- //given:
- int N = 1000000;
- HashMap map = new HashMap<>();
- //when:
- for(int i = 0; i < N; i++)
- {
- String shortLink = service.getShortLink(Integer.toString(i));
- map.put(shortLink, i);
- }
- //then:
- assertEquals(map.size(), N);
- }
-
- @Test
- void testException() throws Exception {
- //given:
- String shortLink = shortLinksDomain;
- //when:
- boolean exceptionThrown = false;
- try {
- String longLink = service.getLongLink(shortLink);
- } catch (UnknownShortLinkException e) {
- exceptionThrown = true;
- }
-
- assert(exceptionThrown);
- }
-}