Full-Stack Enterprise Application Showcase
This project implements a robust REST and MVC architecture using JPA/Hibernate for data persistence, Jakarta Validation for security, and Spring Services for transactional business logic.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
# Server Port
server.port=8080
# Database Configuration (H2 In-Memory)
spring.datasource.url=jdbc:h2:mem:bookingdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
# Hibernate properties
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
@Entity
@Table(name = "bookings")
public class Booking {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull(message = "Resource must be selected")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "resource_id")
private Resource resource;
@NotNull(message = "Client must be assigned")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "client_id")
private Client client;
@Future(message = "Start date must be in the future")
@NotNull(message = "Start date is required")
private LocalDateTime startTime;
@Column(nullable = false)
private String status = "PENDING";
}
@Entity
@Table(name = "clients")
public class Client {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank(message = "Company/Client name is required")
private String name;
@Email(message = "Invalid email format")
@NotBlank(message = "Email is required")
private String email;
@OneToMany(mappedBy = "client", cascade = CascadeType.ALL)
private List<Booking> bookings = new ArrayList<>();
}
package com.booking.repository;
import com.booking.model.Booking;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
@Repository
public interface BookingRepository extends JpaRepository<Booking, Long> {
List<Booking> findByStatus(String status);
List<Booking> findByResourceIdAndStartTimeAfter(
Long resourceId, LocalDateTime time);
}
@Service
public class BookingService {
private final BookingRepository repository;
public BookingService(BookingRepository repository) {
this.repository = repository;
}
@Transactional
public Booking createBooking(Booking booking) {
if (!isResourceAvailable(booking.getResource(),
booking.getStartTime())) {
throw new ResourceConflictException("Resource taken!");
}
return repository.save(booking);
}
}
@Controller
public class WebController {
private final BookingService bookingService;
public WebController(BookingService bookingService) {
this.bookingService = bookingService;
}
@GetMapping("/dashboard")
public String showDashboard(Model model) {
// Zasilenie modelu listą z bazy danych
model.addAttribute("bookings", bookingService.findAllBookings());
// Wyrenderowanie widoku
return "dashboard";
}
}
<tbody>
<tr th:each="booking : ${bookings}">
<td class="text-muted" th:text="'#BK-' + ${booking.id}">#BK-101</td>
<td class="fw-bold" th:text="${booking.resource.name}">Resource Name</td>
<td th:text="${booking.client.name}">Client Name</td>
<td th:text="${#temporals.format(booking.startTime, 'yyyy-MM-dd HH:mm')}">Date</td>
<td>
<span class="badge"
th:classappend="${booking.status == 'CONFIRMED' ? 'bg-success' : 'bg-warning text-dark'}"
th:text="${booking.status}">STATUS</span>
</td>
<td><button class="btn btn-sm btn-outline-secondary">Edit</button></td>
</tr>
</tbody>
Below is a static rendering of the Thymeleaf dashboard template. It utilizes responsive Bootstrap 5 utility classes, metric cards, and a data table, styled to match the dark Camel Linen aesthetic.
| ID | Resource | Client | Date | Status | Action |
|---|---|---|---|---|---|
| #BK-101 | Conference Room A | TechCorp Inc. | 2026-08-10 10:00 | CONFIRMED | |
| #BK-102 | Projector 4K | Startup LLC | 2026-08-11 14:00 | PENDING | |
| #BK-103 | Server Rack 04 | Internal IT | 2026-08-09 08:00 | CANCELLED |