A student-scoped URL shortener built with Java 17, Spring Boot 3, PostgreSQL, and Thymeleaf.
- Shorten long URLs into compact Base62 codes
- Redirect visitors with
GET /{code}(HTTP 302) - Track click counts on each redirect
- Simple web UI at
/plus a JSON REST API under/api/urls - Flyway-managed database schema
- Java 17+
- Maven 3.9+
- PostgreSQL 14+ (local install or Docker)
- Docker (required only for integration tests via Testcontainers)
Create a PostgreSQL database named urlshortener:
createdb urlshortenerOr run PostgreSQL in Docker:
docker run -d --name urlshortener-db -p 5432:5432 \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=urlshortener \
postgres:16
docker run -d --name urlshortener-db -p 5432:5432 -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=urlshortener postgres:16Default connection settings are in src/main/resources/application.yml:
- URL:
jdbc:postgresql://localhost:5432/urlshortener - Username:
postgres - Password:
postgres
mvn spring-boot:runOpen http://localhost:8080 to use the web UI.
curl -X POST http://localhost:8080/api/urls \
-H "Content-Type: application/json" \
-d "{\"longUrl\":\"https://example.com/very/long/path\"}"Example response:
{
"shortCode": "1",
"shortUrl": "http://localhost:8080/1",
"longUrl": "https://example.com/very/long/path",
"clickCount": 0,
"createdAt": "2026-06-30T12:00:00Z"
}curl http://localhost:8080/api/urls/1curl -I http://localhost:8080/1Returns 302 Found with a Location header pointing to the original URL.
The home page provides:
- A form to paste a long URL
- The generated short link on success
- A Copy button for the short URL
- Inline validation errors for invalid input
flowchart LR
Browser --> HomeController
Client --> UrlApiController
HomeController --> UrlService
UrlApiController --> UrlService
RedirectController --> UrlService
UrlService --> UrlMappingRepository
UrlMappingRepository --> PostgreSQL
Layers:
- Controllers — Thymeleaf page, JSON API, and redirect endpoint
- Service — URL validation, code generation, click tracking
- Repository — Spring Data JPA access to
url_mappings - Flyway — schema migration on startup
- Save the long URL to get an auto-increment
id - Encode
idas Base62 (e.g.1→"1",62→"10") - Store the code in
short_code
The same long URL may receive multiple short codes (no deduplication in this version).
mvn testTests include:
Base62EncoderTest— encode/decode round-tripUrlServiceTest— validation and service logicUrlApiControllerTest— API contract with MockMvcUrlShortenerIntegrationTest— full flow with Testcontainers PostgreSQL
src/main/java/com/example/urlshortener/
├── controller/ HomeController, UrlApiController, RedirectController
├── service/ UrlService
├── repository/ UrlMappingRepository
├── model/ UrlMapping
├── dto/ Request/response records
├── util/ Base62Encoder
├── exception/ Global error handling
└── config/ AppProperties
| Property | Default | Purpose |
|---|---|---|
app.base-url |
http://localhost:8080 |
Prefix used when building shortUrl in API responses |
spring.datasource.* |
local Postgres | Database connection |
- Custom aliases with reserved-word checks
- Link expiration (
expires_at+ HTTP 410) - OpenAPI docs via
springdoc-openapi