Initialise Spring API with ShortLink endpoints

This commit is contained in:
2025-12-22 18:43:19 +00:00
commit 4107d7a248
9 changed files with 236 additions and 0 deletions

3
backend/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
target/
.idea/

50
backend/pom.xml Normal file
View File

@@ -0,0 +1,50 @@
<?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>
<groupId>services.shay</groupId>
<artifactId>halflink</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.0.1</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>3.3.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,21 @@
package services.shay;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class Halflink {
@GetMapping("/")
String home() {
return "Halflink API says hello!";
}
public static void main(String[] args) {
SpringApplication.run(Halflink.class, args);
}
}

View File

@@ -0,0 +1,24 @@
package services.shay.shortlink;
import java.security.SecureRandom;
public class ShortCodeGenerator {
private static final String BASE_58_CHARS = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
private static final SecureRandom RANDOM = new SecureRandom();
public static String generate(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(BASE_58_CHARS.charAt(RANDOM.nextInt(BASE_58_CHARS.length())));
}
return sb.toString();
}
public static String generate() {
return "abc";
// return generate(7);
}
}

View File

@@ -0,0 +1,58 @@
package services.shay.shortlink;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Null;
import java.util.Date;
import java.util.UUID;
@Entity
@Table(name = "shortlink", uniqueConstraints = { @UniqueConstraint(columnNames = { "code" }) })
public class ShortLink {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
@NotNull
private String url;
@NotNull
private String title;
private Date createdAt;
private Integer clicks;
private String code;
protected ShortLink() {}
public ShortLink(String url, String title) {
this.url = url;
this.title = title;
}
@PrePersist
protected void onCreate() {
createdAt = new Date();
clicks = 0;
code = ShortCodeGenerator.generate();
}
public UUID getId() { return id; }
public String getUrl() { return url; }
public String getTitle() { return title; }
public Date getCreatedAt() { return createdAt; }
public Integer getClicks() { return clicks; }
public String getCode() { return code; }
public void setId(UUID id) { this.id = id; }
public void setUrl(String url) { this.url = url; }
public void setTitle(String title) { this.title = title; }
public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
public void setClicks(Integer clicks) { this.clicks = clicks; }
public void setCode(String code) { this.code = code; }
}

View File

@@ -0,0 +1,47 @@
package services.shay.shortlink;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.net.URI;
import java.util.UUID;
@RestController
@RequestMapping("/sl")
public class ShortLinkController {
private final ShortLinkRepository shortLinkRepository;
public ShortLinkController(ShortLinkRepository shortLinkRepository) {
this.shortLinkRepository = shortLinkRepository;
}
@GetMapping("/{code}")
public ResponseEntity<Void> redirectToUrl(@PathVariable String code) {
ShortLink sl = shortLinkRepository.findByCode(code).orElse(null);
if (sl != null) {
sl.setClicks(sl.getClicks() + 1);
shortLinkRepository.save(sl);
return ResponseEntity
.status(HttpStatus.FOUND)
.location(URI.create(sl.getUrl()))
.build();
}
return ResponseEntity.notFound().build();
}
@PostMapping
public ShortLink createShortLink(@Valid @RequestBody ShortLink shortLink) {
ShortLink savedShortLink = shortLinkRepository.save(shortLink);
System.out.println("savedShortLink = " + savedShortLink);
return savedShortLink;
}
@DeleteMapping("/{id}")
public void deleteShortLink(@PathVariable UUID id) {
shortLinkRepository.deleteById(id);
}
}

View File

@@ -0,0 +1,14 @@
package services.shay.shortlink;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
import java.util.UUID;
@Repository
public interface ShortLinkRepository extends JpaRepository<ShortLink, UUID> {
Optional<ShortLink> findByCode(String code);
}

View File

@@ -0,0 +1,8 @@
# Database connection
spring.datasource.url=jdbc:postgresql://localhost:5432/halflink
spring.datasource.username=springchatuser
spring.datasource.password=abcdef
# JPA/Hibernate settings
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

View File

@@ -0,0 +1,11 @@
POST http://localhost:8080/sl
Content-Type: application/json
{
"url": "https://docs.spring.io/spring-security/reference/servlet/authentication/index.html",
"title": "Spring Security Servlet Authentication"
}
###
DELETE http://localhost:8080/sl/a0232bf3-245d-4515-8a8b-c10031d21766