Stats
Actions
Tags
From nation-of-elites
Java Spring Boot patterns, dependency injection, REST APIs, JPA/Hibernate, and enterprise Java development best practices
How this skill is triggered — by the user, by Claude, or both
Slash command
/nation-of-elites:java-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- Building Spring Boot microservices
java-expert - Primary user for Java developmentbackend-developer - Backend development with Java/Springapi-architect - REST API design with Spring Boot// Controller Layer
@RestController
@RequestMapping("/api/posts")
public class PostController {
private final PostService postService;
@Autowired
public PostController(PostService postService) {
this.postService = postService;
}
@GetMapping
public ResponseEntity<Page<PostDTO>> getPosts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size
) {
Pageable pageable = PageRequest.of(page, size);
return ResponseEntity.ok(postService.findAll(pageable));
}
@PostMapping
public ResponseEntity<PostDTO> createPost(@Valid @RequestBody CreatePostRequest request) {
PostDTO post = postService.create(request);
return ResponseEntity.status(HttpStatus.CREATED).body(post);
}
}
// Service Layer
@Service
@Transactional
public class PostService {
private final PostRepository postRepository;
private final PostMapper postMapper;
public PostDTO create(CreatePostRequest request) {
Post post = postMapper.toEntity(request);
Post saved = postRepository.save(post);
return postMapper.toDTO(saved);
}
@Transactional(readOnly = true)
public Page<PostDTO> findAll(Pageable pageable) {
return postRepository.findAll(pageable)
.map(postMapper::toDTO);
}
}
// Repository Layer
public interface PostRepository extends JpaRepository<Post, Long> {
@Query("SELECT p FROM Post p WHERE p.status = :status")
Page<Post> findByStatus(@Param("status") PostStatus status, Pageable pageable);
@Query("SELECT p FROM Post p JOIN FETCH p.author WHERE p.id = :id")
Optional<Post> findByIdWithAuthor(@Param("id") Long id);
}
@Entity
@Table(name = "posts")
@EntityListeners(AuditingEntityListener.class)
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 255)
private String title;
@Column(columnDefinition = "TEXT")
private String content;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private PostStatus status = PostStatus.DRAFT;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User author;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments = new ArrayList<>();
@CreatedDate
@Column(nullable = false, updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
// Getters, setters, equals, hashCode
}
@Mapper(componentModel = "spring")
public interface PostMapper {
@Mapping(target = "authorName", source = "author.name")
@Mapping(target = "commentsCount", expression = "java(post.getComments().size())")
PostDTO toDTO(Post post);
@Mapping(target = "id", ignore = true)
@Mapping(target = "createdAt", ignore = true)
@Mapping(target = "updatedAt", ignore = true)
Post toEntity(CreatePostRequest request);
}
public record PostDTO(
Long id,
String title,
String content,
PostStatus status,
String authorName,
Integer commentsCount,
LocalDateTime createdAt
) {}
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(
ResourceNotFoundException ex
) {
ErrorResponse error = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage(),
LocalDateTime.now()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ValidationErrorResponse> handleValidation(
MethodArgumentNotValidException ex
) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error ->
errors.put(error.getField(), error.getDefaultMessage())
);
return ResponseEntity.badRequest().body(
new ValidationErrorResponse(errors, LocalDateTime.now())
);
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@SpringBootTest
@AutoConfigureMockMvc
class PostControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Test
void shouldCreatePost() throws Exception {
CreatePostRequest request = new CreatePostRequest("Title", "Content");
mockMvc.perform(post("/api/posts")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.title").value("Title"));
}
}
@ExtendWith(MockitoExtension.class)
class PostServiceTest {
@Mock
private PostRepository postRepository;
@InjectMocks
private PostService postService;
@Test
void shouldCreatePost() {
// Arrange
CreatePostRequest request = new CreatePostRequest("Title", "Content");
Post post = new Post();
when(postRepository.save(any(Post.class))).thenReturn(post);
// Act
PostDTO result = postService.create(request);
// Assert
assertNotNull(result);
verify(postRepository).save(any(Post.class));
}
}
npx claudepluginhub advisely/claude-code-agents-team-nation-of-elites --plugin nation-of-elitesCreates bite-sized, testable implementation plans from specs or requirements, with file structure and task decomposition. Activates before coding multi-step tasks.