<< All versions
Skill v1.0.1
currentAutomated scan100/100rohitg00/awesome-claude-code-toolkit/springboot-patterns
1 files
──Details
PublishedMay 20, 2026 at 01:31 PM
Content Hashsha256:8745017bb4d4e8eb...
Git SHAebdf1d596d2c
Bump Typepatch
──Files
Files (1 file, 5.1 KB)
SKILL.md5.1 KBactive
SKILL.md · 162 lines · 5.1 KB
version: "1.0.1" name: springboot-patterns description: Spring Boot patterns including JPA repositories, REST controllers, layered services, and configuration
Spring Boot Patterns
Layered Architecture
src/main/java/com/example/app/config/ # @Configuration beanscontroller/ # @RestController (thin, delegates to service)service/ # @Service (business logic)repository/ # @Repository (data access via JPA)model/entity/ # @Entity JPA classesdto/ # Request/response DTOsmapper/ # MapStruct or manual mappingexception/ # @ControllerAdvice, custom exceptionssecurity/ # SecurityFilterChain, JWT filters
Controllers handle HTTP concerns. Services contain business logic. Repositories handle persistence.
REST Controller
java
@RestController@RequestMapping("/api/v1/orders")@RequiredArgsConstructorpublic class OrderController {private final OrderService orderService;@GetMappingpublic Page<OrderResponse> list(@RequestParam(defaultValue = "0") int page,@RequestParam(defaultValue = "20") int size) {return orderService.findAll(PageRequest.of(page, size));}@PostMapping@ResponseStatus(HttpStatus.CREATED)public OrderResponse create(@Valid @RequestBody CreateOrderRequest request) {return orderService.create(request);}@GetMapping("/{id}")public OrderResponse getById(@PathVariable UUID id) {return orderService.findById(id);}}
JPA Entity and Repository
java
@Entity@Table(name = "orders")@Getter @Setter @NoArgsConstructorpublic class Order {@Id@GeneratedValue(strategy = GenerationType.UUID)private UUID id;@ManyToOne(fetch = FetchType.LAZY)@JoinColumn(name = "customer_id", nullable = false)private Customer customer;@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)private List<OrderItem> items = new ArrayList<>();@Enumerated(EnumType.STRING)private OrderStatus status = OrderStatus.PENDING;@CreationTimestampprivate Instant createdAt;}public interface OrderRepository extends JpaRepository<Order, UUID> {@Query("SELECT o FROM Order o JOIN FETCH o.items WHERE o.customer.id = :customerId")List<Order> findByCustomerWithItems(@Param("customerId") UUID customerId);@EntityGraph(attributePaths = {"customer", "items"})Optional<Order> findWithDetailsById(UUID id);}
Service Layer
java
@Service@Transactional(readOnly = true)@RequiredArgsConstructorpublic class OrderService {private final OrderRepository orderRepository;private final OrderMapper orderMapper;private final EventPublisher eventPublisher;public OrderResponse findById(UUID id) {Order order = orderRepository.findWithDetailsById(id).orElseThrow(() -> new ResourceNotFoundException("Order", id));return orderMapper.toResponse(order);}@Transactionalpublic OrderResponse create(CreateOrderRequest request) {Order order = orderMapper.toEntity(request);order = orderRepository.save(order);eventPublisher.publish(new OrderCreatedEvent(order.getId()));return orderMapper.toResponse(order);}}
Global Exception Handler
java
@RestControllerAdvicepublic class GlobalExceptionHandler {@ExceptionHandler(ResourceNotFoundException.class)@ResponseStatus(HttpStatus.NOT_FOUND)public ProblemDetail handleNotFound(ResourceNotFoundException ex) {return ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, ex.getMessage());}@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(HttpStatus.BAD_REQUEST)public ProblemDetail handleValidation(MethodArgumentNotValidException ex) {ProblemDetail detail = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);Map<String, String> errors = ex.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));detail.setProperty("errors", errors);return detail;}}
Anti-Patterns
- Injecting repositories directly into controllers (bypassing service layer)
- Using
FetchType.EAGERon entity relationships by default - Returning JPA entities directly from controllers instead of DTOs
- Missing
@Transactional(readOnly = true)on read-only service methods - Catching generic
Exceptioninstead of specific types - Hardcoding configuration values instead of using
@Valueor@ConfigurationProperties
Checklist
- [ ] Controllers are thin and delegate to services
- [ ] All JPA relationships use
FetchType.LAZYby default - [ ] DTOs used for request/response, never raw entities
- [ ]
@Transactionalapplied at service level with correct read/write scoping - [ ] Validation annotations (
@Valid,@NotNull,@Size) on request DTOs - [ ] Global exception handler returns
ProblemDetail(RFC 7807) - [ ] Entity graphs or
JOIN FETCHused to avoid N+1 queries - [ ] Integration tests use
@SpringBootTestwith test containers