Spring Boot: Best Practices for AI-Assisted Development
A practical guide for using Claude Code and GitHub Copilot effectively in Spring MVC projects, covering project setup, reusable skills, architecture patterns, and daily workflows.
Content Table
- Purpose
- Audience
- Prerequisites
- Setting Up Your Spring MVC Project for AI
- Spring Official AI Resources
- AI Context Files for Spring Boot Projects
- Spring MVC: Best Practices
- Daily Workflows with AI Assistants
- Tips and Pitfalls
- Spring MVC Specialized Best Practices
- References
Purpose
Spring MVC projects benefit greatly from AI-assisted development, but generic LLM output can produce suboptimal patterns (constructor injection mixed with field injection, @RestControllerAdvice forgotten, test slices misused). This guide solves that problem by configuring Claude Code and GitHub Copilot with Spring MVC-specific context for idiomatic code generation from the start.
By the end of this guide you will have:
- An instruction file tailored to your Spring MVC project
- Reusable skills for common Spring MVC tasks
- Reference architecture snippets that AI assistants can follow
- Practical workflows for daily Spring MVC development
Audience
- Spring MVC developers using AI assistants for development, refactoring, or testing.
- Teams standardizing AI usage across multiple Spring MVC codebases.
Prerequisites
- Java 17+ (21 recommended)
- Maven 3.8+ or Gradle 7.5+
- Spring Boot 3.2+
- Claude Code installed (enterprise access recommended)
- GitHub Copilot enabled in VS Code/IntelliJ
- A working Spring MVC project (new or existing)
Setting Up Your Spring MVC Project for AI
Configure three layers of context before writing prompts.
Layer 1: Project Memory with AGENTS.md
Every modern AI coding assistant supports a project-level context file that provides persistent instructions. This file tells the assistant about your project structure, conventions, and constraints.
AGENTS.md at project root provides persistent context for every session giving project-specific guidance for code completion, chat, and reviews.
See full example: snippets/AGENTS.md
AI Labs: Reusable Skills
Several AI assistants now support a skills concept — reusable Markdown files with structured instructions that the assistant can invoke for specific tasks.
| AI Assistant | Skills Location | File Format | Docs |
|---|---|---|---|
| Claude Code | .claude/skills/<name>/SKILL.md | Markdown with YAML frontmatter | Claude Code Skills |
| Cursor | .cursor/skills/<name>/SKILL.md | Markdown with YAML frontmatter | Cursor Skills |
| GitHub Copilot | .github/skills/<name>.md or .claude/skills/<name>/SKILL.md | Markdown with YAML frontmatter | Copilot Skills |
All three tools use directory-based skills centered on a SKILL.md file with YAML frontmatter and free-form Markdown instructions, so most basic syntax and structure is shared; they use the same open format, making skills directly portable between them.
Store skills in ./skills/<skill-name>/SKILL.md. Ready-to-use skills in snippets/.
Spring Official AI Resources
| Resource | URL | Usage |
|---|---|---|
| Spring AI Reference | docs.spring.io/spring-ai | AI integration patterns |
| Spring Boot AI Guide | spring.io/blog/spring-ai | Official AI development guidance |
| Spring REST Docs | spring.io/projects/spring-restdocs | API documentation patterns |
| SpringDoc OpenAPI | springdoc.org | Auto-generated API docs |
IDE Instructions Files:
| IDE/Tool | File |
|---|---|
| GitHub Copilot | .github/copilot-instructions.md |
| Claude Code | CLAUDE.md |
| Cursor | cursorrules.md |
AI Context Files for Spring Boot Projects
A well-crafted context file is the single most impactful thing you can do for AI-assisted development. It prevents AI assistants from generating outdated patterns and ensures consistency across the project. The content below applies regardless of which tool you use — only the file name and location differ.
| AI Assistant | Context File | Location |
|---|---|---|
| Claude Code | CLAUDE.md | Project root or .claude/ |
| GitHub Copilot | copilot-instructions.md | .github/ |
| Cursor | .cursorrules | Project root |
Spring MVC: Best Practices
Universal Best Practices
Project Structure & Architecture
- Use layered architecture: Controller, Service, Repository.
- Keep controllers thin; delegate logic to services.
- Use interfaces for service/repository layers for testability.
- Organize code by feature/module when possible.
Dependency Injection & Configuration
- Prefer constructor injection for mandatory dependencies.
- Use
@Valueor@ConfigurationPropertiesfor external config. - Avoid field injection except in tests.
- Use stereotypes:
@Component,@Service,@Repository,@Controller. - Keep config in
application.yml/application.propertiesand use profiles.
Data Access
- Use repository interfaces for CRUD/query methods.
- Prefer query methods or
@Queryover native queries. - Use DTOs for API responses, not entities.
Exception Handling
- Use global exception handling (e.g.,
@ControllerAdviceor@RestControllerAdvice). - Return meaningful error messages and HTTP status codes.
Testing
- Use integration tests for end-to-end scenarios.
- Use slice tests for controllers/services/repositories.
- Mock external dependencies.
- Use test profiles and in-memory databases for tests.
Security
- Use Spring Security for authentication/authorization.
- Store secrets in env variables or a secrets manager.
- Use method-level security for fine-grained access control.
Build & Dependency Management
- Use Maven/Gradle for dependencies.
- Keep dependencies up to date; avoid unnecessary libraries.
- Use dependency scopes appropriately.
REST API Design
- Use RESTful conventions for endpoints.
- Validate input with
@Validand constraint annotations. - Document APIs with Swagger/OpenAPI.
Logging & Monitoring
- Use SLF4J with Logback/Log4j2.
- Avoid logging sensitive data.
- Use Actuator for health checks/metrics.
Follow these patterns for this project:
Architecture Patterns and Code Snippets
Controller (thin) -> Service (@Transactional) -> Repository (Spring Data)
Always use:
- Constructor injection
@ValidDTOs@RestControllerAdvice- Test slices (
@WebMvcTest,@DataJpaTest)
Commands:
./mvnw clean test # Unit + integration
./mvnw clean package # Build JAR
./mvnw spring-boot:run # Dev serverService Layer Pattern
@Service
@Transactional
class UserService {
private final UserRepository users;
private final UserMapper mapper;
public UserService(UserRepository users, UserMapper mapper) {
this.users = users;
this.mapper = mapper;
}
public UserResponse create(CreateUserRequest request) {
User user = mapper.toEntity(request);
user = users.save(user);
return mapper.toResponse(user);
}
}Global Exception Handling
@RestControllerAdvice
class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleValidation(
MethodArgumentNotValidException ex) {
// Extract field errors, return 400 with details
}
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(EntityNotFoundException ex) {
return new ErrorResponse("resource.not.found", ex.getMessage());
}
}Test Slice Pattern
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private UserService userService;
@Test
void createUser_validRequest_returns201() throws Exception {
CreateUserRequest request = new CreateUserRequest("John", "john@example.com", "password123");
UserResponse response = new UserResponse("1", "John", "john@example.com");
when(userService.create(request)).thenReturn(response);
mvc.perform(post("/api/v1/users")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").value("1"));
}
}Daily Workflows with AI Assistants
Generating New Feature
/spring-controller OrderController --feature orders
/spring-service OrderService
/spring-test OrderController.javaPrompt example:
Create "orders" feature following CLAUDE.md patterns:
- OrderController with POST /api/v1/orders
- CreateOrderRequest DTO with @Valid
- OrderService with @Transactional
- OrderRepository Spring Data interface
- Full test coverage with correct slicesRefactoring Legacy Code
Refactor UserController from field injection to constructor injection:
- Extract DTOs if using entities directly
- Add @Valid validation
- Add @RestControllerAdvice if missing
- Keep all existing functionalityWriting Tests
/spring-test UserService.java
Additional requirements:
- @ServiceTest slice test
- Mock all repository dependencies
- Test happy path + validation errors
- Test @Transactional rollback scenariosTips and Pitfalls
Do
- Keep CLAUDE.md current - update when adopting Spring AI, GraphQL, etc.
- Use skills for repetitive patterns - controllers/services/tests
- Provide concrete examples - 20-line controller > vague rules
- Specify Spring Boot version - 3.3 patterns differ from 2.x
- Test slices over full integration - faster, more focused tests
Avoid
- Constructor + field injection mix - pick one pattern
- Entities in REST responses - always use DTOs
- No global exception handling -
@RestControllerAdviceessential - Full
@SpringBootTesteverywhere - use slice tests first - Missing
@Transactional- services without transactions fail silently
Spring MVC Specialized Best Practices
- Use MockMvc for controller testing.
- Prefer
@WebMvcTestfor controller slice tests. - Use
@ControllerAdvicefor global exception handling. - Use
@RestControllerfor REST APIs,@Controllerfor MVC views. - Use Spring Data JPA for data access.
- Use
@Transactionalfor service/repository methods that modify data. - Use
@Validfor request validation. - Use
@PreAuthorize/@Securedfor method-level security. - Use
@ModelAttributefor form binding in MVC views. - Use Thymeleaf or JSP for server-side rendering if needed.
- Use
@InitBinderfor custom binding/validation logic. - Use
@ResponseStatusfor custom error responses. - Use
@ExceptionHandlerfor controller-specific error handling. - Use
@PathVariableand@RequestParamfor request data binding. - Use
@SessionAttributesfor session-scoped model attributes. - Use
@CookieValuefor cookie data binding. - Use
@RequestBodyand@ResponseBodyfor JSON/XML APIs.