{One-sentence description of what this project does.} Stack: Java {17/21}, Spring Boot {3.x}, {Maven / Gradle}, {PostgreSQL / MySQL / H2} Build: {Maven (mvnw) / Gradle (gradlew)}
# Development
./mvnw spring-boot:run # Run the application
# OR: ./gradlew bootRun
# Building
./mvnw clean package # Build JAR
./mvnw clean package -DskipTests # Build without tests
# OR: ./gradlew clean build
# Testing
./mvnw test # Run all tests
./mvnw test -Dtest=UserServiceTest # Single test class
./mvnw test -Dtest="UserServiceTest#testCreateUser" # Single method
# OR: ./gradlew test --tests UserServiceTest
# Code Quality
./mvnw checkstyle:check # Checkstyle (if configured)
./mvnw spotbugs:check # SpotBugs (if configured)src/main/java/com/{org}/{project}/
├── {Project}Application.java # Main class (@SpringBootApplication)
├── config/ # @Configuration classes
├── controller/ # @RestController classes (HTTP layer)
├── service/ # @Service classes (business logic)
├── repository/ # @Repository interfaces (Spring Data JPA)
├── model/
│ ├── entity/ # @Entity classes (JPA entities)
│ └── dto/ # Request/response DTOs (records)
├── exception/ # Custom exceptions + @ControllerAdvice
└── util/ # Static helpers
src/main/resources/
├── application.yml # Main config (profiles: dev, prod)
└── db/migration/ # Flyway / Liquibase migrations
src/test/java/ # Test classes mirror main structure
- Constructor injection (no
@Autowiredon fields) -- use@RequiredArgsConstructor(Lombok) or explicit constructors - DTOs as Java records:
public record UserResponse(Long id, String name, String email) {} - Service layer owns business logic -- controllers are thin HTTP adapters
- Repository layer: extend
JpaRepository<Entity, ID>, use@Queryfor custom queries - Global exception handling via
@RestControllerAdvice
// Standard controller pattern
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@PostMapping
public ResponseEntity<UserResponse> create(@Valid @RequestBody UserCreateRequest req) {
UserResponse user = userService.create(req);
return ResponseEntity.status(HttpStatus.CREATED).body(user);
}
@GetMapping("/{id}")
public ResponseEntity<UserResponse> getById(@PathVariable Long id) {
return ResponseEntity.ok(userService.getById(id));
}
}@SpringBootTestfor integration tests (loads full context)@WebMvcTest(Controller.class)for controller tests (mock service layer)@DataJpaTestfor repository tests (in-memory DB)- Use
@MockBeanto mock dependencies in Spring tests - Assertions: AssertJ (
assertThat) preferred over JUnitassertEquals - Test naming:
methodName_scenario_expectedResult(e.g.,create_validInput_returnsCreated)
- Java records for DTOs -- not POJOs with getters/setters
finalon injected fields and local variables where possible- No
nullreturns from service methods -- useOptionalor throw exceptions - Logging via SLF4J (
private static final Logger log = LoggerFactory.getLogger(...)) -- noSystem.out.println - Validate request DTOs with
@Validand Bean Validation annotations (@NotBlank,@Email, etc.)
- Do not use field injection (
@Autowiredon fields) -- use constructor injection - Do not put business logic in controllers or repositories -- use services
- Do not return JPA entities from controllers -- map to DTOs
- Do not manually edit Flyway/Liquibase migration files after they have been applied
- Do not add dependencies without asking first -- check if Spring Boot starters cover the need