Last active
October 22, 2023 06:00
-
-
Save mayankchoubey/f2f21b9b417fe36cd318fe2707264b0a to your computer and use it in GitHub Desktop.
Spring Boot - URL shortener service in PostgreSQL
This file contains hidden or 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
| server.port=3000 | |
| spring.datasource.url= jdbc:postgresql://localhost:5432/${dbName} | |
| spring.datasource.username= ${dbUser} | |
| spring.datasource.password= ${dbUserPass} | |
| spring.datasource.max-active=10 | |
| spring.datasource.max-idle=10 | |
| spring.datasource.min-idle=10 | |
| spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation= true | |
| spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.PostgreSQLDialect | |
| # Hibernate ddl auto (create, create-drop, validate, update) | |
| spring.jpa.hibernate.ddl-auto= update |
This file contains hidden or 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
| <?xml version="1.0" encoding="UTF-8"?> | |
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
| <modelVersion>4.0.0</modelVersion> | |
| <parent> | |
| <groupId>org.springframework.boot</groupId> | |
| <artifactId>spring-boot-starter-parent</artifactId> | |
| <version>3.1.5</version> | |
| <relativePath/> <!-- lookup parent from repository --> | |
| </parent> | |
| <groupId>com.example</groupId> | |
| <artifactId>demo</artifactId> | |
| <version>0.0.1-SNAPSHOT</version> | |
| <name>demo</name> | |
| <description>URL shortener project for Spring Boot with Virtual threads</description> | |
| <properties> | |
| <java.version>21</java.version> | |
| </properties> | |
| <dependencies> | |
| <dependency> | |
| <groupId>org.springframework.boot</groupId> | |
| <artifactId>spring-boot-starter-web</artifactId> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.postgresql</groupId> | |
| <artifactId>postgresql</artifactId> | |
| <scope>runtime</scope> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.springframework.boot</groupId> | |
| <artifactId>spring-boot-starter-data-jpa</artifactId> | |
| </dependency> | |
| <dependency> | |
| <groupId>com.aventrix.jnanoid</groupId> | |
| <artifactId>jnanoid</artifactId> | |
| <version>2.0.0</version> | |
| </dependency> | |
| <dependency> | |
| <groupId>org.springframework</groupId> | |
| <artifactId>spring-context</artifactId> | |
| <version>6.0.13</version> | |
| </dependency> | |
| </dependencies> | |
| <build> | |
| <plugins> | |
| <plugin> | |
| <groupId>org.springframework.boot</groupId> | |
| <artifactId>spring-boot-maven-plugin</artifactId> | |
| <configuration> | |
| <mainClass>com.example.shorten.UrlShortenerApplication</mainClass> | |
| <layout>JAR</layout> | |
| </configuration> | |
| </plugin> | |
| <plugin> | |
| <groupId>org.apache.maven.plugins</groupId> | |
| <artifactId>maven-compiler-plugin</artifactId> | |
| <version>3.11.0</version> | |
| <configuration> | |
| <release>21</release> | |
| <enablePreview>true</enablePreview> | |
| <compilerArgs>--enable-preview</compilerArgs> | |
| </configuration> | |
| </plugin> | |
| <plugin> | |
| <groupId>org.apache.maven.plugins</groupId> | |
| <artifactId>maven-shade-plugin</artifactId> | |
| <version>3.5.0</version> | |
| <executions> | |
| <execution> | |
| <phase>package</phase> | |
| <goals> | |
| <goal>shade</goal> | |
| </goals> | |
| </execution> | |
| </executions> | |
| </plugin> | |
| <plugin> | |
| <groupId>org.apache.maven.plugins</groupId> | |
| <artifactId>maven-surefire-plugin</artifactId> | |
| <version>3.1.2</version> | |
| <configuration> | |
| <argLine>--enable-preview</argLine> | |
| </configuration> | |
| </plugin> | |
| </plugins> | |
| </build> | |
| <profiles> | |
| <profile> | |
| <id>native</id> | |
| <build> | |
| <plugins> | |
| <plugin> | |
| <groupId>org.graalvm.buildtools</groupId> | |
| <artifactId>native-maven-plugin</artifactId> | |
| <version>0.9.27</version> | |
| <extensions>true</extensions> | |
| <executions> | |
| <execution> | |
| <id>build-native</id> | |
| <goals> | |
| <goal>compile-no-fork</goal> | |
| </goals> | |
| <phase>package</phase> | |
| </execution> | |
| <execution> | |
| <id>test-native</id> | |
| <goals> | |
| <goal>test</goal> | |
| </goals> | |
| <phase>test</phase> | |
| </execution> | |
| </executions> | |
| <configuration> | |
| <!-- ... --> | |
| </configuration> | |
| </plugin> | |
| </plugins> | |
| </build> | |
| </profile> | |
| </profiles> | |
| </project> |
This file contains hidden or 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
| package com.example.shorten; | |
| import java.time.LocalDateTime; | |
| import jakarta.persistence.Entity; | |
| import jakarta.persistence.Table; | |
| import jakarta.persistence.GeneratedValue; | |
| import jakarta.persistence.GenerationType; | |
| import jakarta.persistence.Id; | |
| @Entity | |
| @Table(name = "shortenedurls") | |
| public class ShortenedUrl { | |
| @Id | |
| private String id; | |
| private String srcurl; | |
| private LocalDateTime created; | |
| private LocalDateTime lastaccessed; | |
| public String getId() { | |
| return id; | |
| } | |
| public void setId(String id) { | |
| this.id = id; | |
| } | |
| public String getSrcUrl() { | |
| return srcurl; | |
| } | |
| public void setSrcUrl(String srcUrl) { | |
| this.srcurl = srcUrl; | |
| } | |
| public LocalDateTime getCreated() { | |
| return created; | |
| } | |
| public void setCreated(LocalDateTime created) { | |
| this.created = created; | |
| } | |
| public LocalDateTime getLastAccessed() { | |
| return lastaccessed; | |
| } | |
| public void setLastAccessed(LocalDateTime lastAccessed) { | |
| this.lastaccessed = lastAccessed; | |
| } | |
| } |
This file contains hidden or 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
| package com.example.shorten; | |
| import org.springframework.boot.SpringApplication; | |
| import org.springframework.boot.autoconfigure.SpringBootApplication; | |
| import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer; | |
| import org.springframework.context.annotation.Bean; | |
| import java.util.concurrent.Executors; | |
| @SpringBootApplication | |
| public class UrlShortenerApplication { | |
| public static void main(String[] args) { | |
| SpringApplication.run(UrlShortenerApplication.class, args); | |
| } | |
| @Bean | |
| public TomcatProtocolHandlerCustomizer<?> protocolHandlerVirtualThreadExecutorCustomizer() { | |
| return protocolHandler -> { | |
| protocolHandler.setExecutor(Executors.newVirtualThreadPerTaskExecutor()); | |
| }; | |
| } | |
| } |
This file contains hidden or 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
| package com.example.shorten; | |
| import org.springframework.web.bind.annotation.PostMapping; | |
| import org.springframework.web.bind.annotation.RequestBody; | |
| import org.springframework.http.ResponseEntity; | |
| import org.springframework.http.HttpStatus; | |
| import org.springframework.http.HttpHeaders; | |
| import org.springframework.http.MediaType; | |
| import org.springframework.web.bind.annotation.RestController; | |
| import java.util.Optional; | |
| import javax.print.attribute.standard.MediaTray; | |
| import com.example.shorten.UrlShortenerRequest; | |
| import com.example.shorten.UrlShortenerResponse; | |
| import com.example.shorten.UrlShortenerError; | |
| import com.example.shorten.UrlShortenerService; | |
| import org.springframework.beans.factory.annotation.Autowired; | |
| @RestController | |
| public class UrlShortenerController { | |
| @Autowired | |
| UrlShortenerService shortenerService; | |
| @PostMapping( | |
| value="/shorten", | |
| consumes = MediaType.APPLICATION_JSON_VALUE, | |
| produces = MediaType.APPLICATION_JSON_VALUE) | |
| public ResponseEntity handleRequest(@RequestBody UrlShortenerRequest shortenRequest) { | |
| if(shortenRequest.getSrcUrl() == null) { | |
| return ResponseEntity.badRequest() | |
| .contentType(MediaType.APPLICATION_JSON) | |
| .body(new UrlShortenerError("Parameter 'srcUrl' is missing")); | |
| } | |
| String srcUrl = shortenRequest.getSrcUrl(); | |
| if(srcUrl.length()>250) { | |
| return ResponseEntity.badRequest() | |
| .contentType(MediaType.APPLICATION_JSON) | |
| .body(new UrlShortenerError("Parameter 'srcUrl' must not be more than 250 characters")); | |
| } | |
| if(!(srcUrl.startsWith("http://") || srcUrl.startsWith("https://"))) { | |
| return ResponseEntity.badRequest() | |
| .contentType(MediaType.APPLICATION_JSON) | |
| .body(new UrlShortenerError("Parameter 'srcUrl' must start with http:// or https://")); | |
| } | |
| String shortenedUrl = shortenerService.shorten(srcUrl); | |
| if(shortenedUrl.isEmpty()) { | |
| return ResponseEntity.badRequest() | |
| .contentType(MediaType.APPLICATION_JSON) | |
| .body(new UrlShortenerError("Failed to shorten")); | |
| } | |
| UrlShortenerResponse resp = new UrlShortenerResponse(srcUrl, shortenedUrl); | |
| return ResponseEntity.ok() | |
| .contentType(MediaType.APPLICATION_JSON) | |
| .body(resp); | |
| } | |
| } | |
This file contains hidden or 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
| package com.example.shorten; | |
| public class UrlShortenerError { | |
| private String errMsg; | |
| public UrlShortenerError() { | |
| } | |
| public UrlShortenerError(String errMsg) { | |
| this.errMsg = errMsg; | |
| } | |
| public String getErrMsg() { | |
| return this.errMsg; | |
| } | |
| public void setErrMsg(String errMsg) { | |
| this.errMsg = errMsg; | |
| } | |
| } |
This file contains hidden or 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
| package com.example.shorten; | |
| import org.springframework.data.jpa.repository.JpaRepository; | |
| import com.example.shorten.ShortenedUrl; | |
| public interface UrlShortenerRepository extends JpaRepository<ShortenedUrl, String> { | |
| } |
This file contains hidden or 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
| package com.example.shorten; | |
| public class UrlShortenerRequest { | |
| private String srcUrl; | |
| public String getSrcUrl() { | |
| return this.srcUrl; | |
| } | |
| public void setSrcUrl(String srcUrl) { | |
| this.srcUrl = srcUrl; | |
| } | |
| } |
This file contains hidden or 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
| package com.example.shorten; | |
| public class UrlShortenerResponse { | |
| private String srcUrl; | |
| private String shortenedUrl; | |
| public UrlShortenerResponse() { | |
| } | |
| public UrlShortenerResponse(String srcUrl, String shortenedUrl) { | |
| this.srcUrl = srcUrl; | |
| this.shortenedUrl = shortenedUrl; | |
| } | |
| public String getSrcUrl() { | |
| return this.srcUrl; | |
| } | |
| public void setSrcUrl(String srcUrl) { | |
| this.srcUrl = srcUrl; | |
| } | |
| public String getShortenedUrl() { | |
| return this.shortenedUrl; | |
| } | |
| public void setShortenedUrl(String shortenedUrl) { | |
| this.shortenedUrl = shortenedUrl; | |
| } | |
| } |
This file contains hidden or 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
| package com.example.shorten; | |
| import java.time.LocalDateTime; | |
| import com.aventrix.jnanoid.jnanoid.*; | |
| import com.example.shorten.ShortenedUrl; | |
| import com.example.shorten.UrlShortenerRepository; | |
| import org.springframework.stereotype.Service; | |
| import org.springframework.beans.factory.annotation.Autowired; | |
| @Service | |
| public class UrlShortenerService { | |
| final String baseUrl = "http://test.short/"; | |
| @Autowired | |
| UrlShortenerRepository shortenerRepository; | |
| public String shorten(String srcUrl) { | |
| if(srcUrl.isEmpty()) { | |
| return ""; | |
| } | |
| String urlId = NanoIdUtils.randomNanoId( | |
| NanoIdUtils.DEFAULT_NUMBER_GENERATOR, | |
| NanoIdUtils.DEFAULT_ALPHABET, | |
| 10 | |
| ); | |
| String shortUrl = baseUrl + urlId; | |
| ShortenedUrl shortenedUrl = new ShortenedUrl(); | |
| shortenedUrl.setId(urlId); | |
| shortenedUrl.setSrcUrl(srcUrl); | |
| shortenedUrl.setCreated(LocalDateTime.now()); | |
| shortenedUrl.setLastAccessed(LocalDateTime.now()); | |
| ShortenedUrl savedData = shortenerRepository.save(shortenedUrl); | |
| return savedData.getId().isEmpty() ? "" : shortUrl; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment