用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/UitbreidenOS/UitKit --skill spring-boot命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
Guidelines and instructions for Agent execution state rollback rules
Guidelines and instructions for Agent execution step counters limits
Guidelines and instructions for Agent execution timeout limits setups
基于 SOC 职业分类
| name | spring-boot |
| description | Spring Boot REST API, JPA repositories, Spring Security JWT, @WebMvcTest, @SpringBootTest, Spring Cloud |
@Async or Spring Eventssrc/
├── main/
│ ├── java/com/example/app/
│ │ ├── AppApplication.java # @SpringBootApplication entry point
│ │ ├── config/ # @Configuration beans
│ │ ├── controller/ # @RestController — HTTP layer only
│ │ ├── service/ # Business logic — @Service
│ │ ├── repository/ # @Repository — data access
│ │ ├── domain/ # @Entity models
│ │ ├── dto/ # Request/response shapes (records)
│ │ ├── exception/ # @ControllerAdvice error handling
│ │ └── security/ # Security config and filters
│ └── resources/
│ ├── application.yml # Base config
│ ├── application-dev.yml # Dev overrides
│ └── application-prod.yml # Prod overrides
└── test/
└── java/com/example/app/
├── controller/ # MockMvc / @WebMvcTest
├── service/ # Unit tests with Mockito
└── integration/ # @SpringBootTest full context
@SpringBootApplication
public class AppApplication {
public static void main(String[] args) {
SpringApplication.run(AppApplication.class, args);
}
}
spring:
application:
name: my-service
datasource:
url: ${DATABASE_URL}
username: ${DB_USER}
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: validate # Never 'create' or 'update' in production
show-sql: false
properties:
hibernate:
format_sql: true
server:
port: ${PORT:8080}
# Custom properties — always use @ConfigurationProperties, never @Value for groups
app:
jwt:
secret: ${JWT_SECRET}
expiration-ms: 86400000
// domain/User.java
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 320)
private String email;
@Column(nullable = false)
private String passwordHash;
@CreationTimestamp
@Column(updatable = false)
private Instant createdAt;
// No-arg constructor required by JPA
protected User() {}
public User(String email, String passwordHash) {
this.email = email;
this.passwordHash = passwordHash;
}
// getters only — no setters on entities
}
// repository/UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
boolean existsByEmail(String email);
// JPQL for complex queries
@Query("SELECT u FROM User u WHERE u.createdAt > :since")
List<User> findRecentUsers(@Param("since") Instant since);
}
@Service
@Transactional(readOnly = true) // Default read-only; override for writes
public class UserService {
private final UserRepository userRepo;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepo, PasswordEncoder passwordEncoder) {
this.userRepo = userRepo;
this.passwordEncoder = passwordEncoder;
}
@Transactional // Override: this method writes
public UserDto createUser(CreateUserRequest request) {
if (userRepo.existsByEmail(request.email())) {
throw new ConflictException("Email already in use");
}
User user = new User(request.email(), passwordEncoder.encode(request.password()));
return UserDto.from(userRepo.save(user));
}
public UserDto getById(Long id) {
return userRepo.findById(id)
.map(UserDto::from)
.orElseThrow(() -> new NotFoundException("User " + id + " not found"));
}
}
@RestController
@RequestMapping("/api/v1/users")
@Validated
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public UserDto createUser(@RequestBody @Valid CreateUserRequest request) {
return userService.createUser(request);
}
@GetMapping("/{id}")
public UserDto getUser(@PathVariable Long id) {
return userService.getById(id);
}
@GetMapping
public Page<UserDto> listUsers(Pageable pageable) {
return userService.findAll(pageable);
}
}
// dto/CreateUserRequest.java
public record CreateUserRequest(
@NotBlank @Email String email,
@NotBlank @Size(min = 8) String password
) {}
// dto/UserDto.java
public record UserDto(Long id, String email, Instant createdAt) {
public static UserDto from(User user) {
return new UserDto(user.getId(), user.getEmail(), user.getCreatedAt());
}
}
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ProblemDetail handleNotFound(NotFoundException ex) {
return ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, ex.getMessage());
}
@ExceptionHandler(ConflictException.class)
@ResponseStatus(HttpStatus.CONFLICT)
public ProblemDetail handleConflict(ConflictException ex) {
return ProblemDetail.forStatusAndDetail(HttpStatus.CONFLICT, ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ProblemDetail handleValidation(MethodArgumentNotValidException ex) {
var detail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "Validation failed");
detail.setProperty("errors", ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.toList());
return detail;
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, JwtAuthFilter jwtFilter) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/**", "/actuator/health").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
// @WebMvcTest — controller slice test (no full context)
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired MockMvc mockMvc;
@MockitoBean UserService userService; // Spring Boot 3.4+: @MockitoBean
@Test
void createUser_returnsCreated() throws Exception {
given(userService.createUser(any())).willReturn(new UserDto(1L, "a@b.com", Instant.now()));
mockMvc.perform(post("/api/v1/users")
.contentType(MediaType.APPLICATION_JSON)
.content("""{"email":"a@b.com","password":"password123"}"""))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.email").value("a@b.com"));
}
}
// @SpringBootTest — full integration test
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Transactional
class UserServiceIntegrationTest {
@Autowired UserService userService;
@Test
void createUser_persistsToDatabase() {
var user = userService.createUser(new CreateUserRequest("a@b.com", "password123"));
assertThat(user.email()).isEqualTo("a@b.com");
assertThat(user.id()).isNotNull();
}
}
# Service discovery with Eureka
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://eureka-server:8761/eureka/
# Config server client
spring:
config:
import: configserver:http://config-server:8888
// Feign client for inter-service calls
@FeignClient(name = "order-service")
public interface OrderClient {
@GetMapping("/api/v1/orders/user/{userId}")
List<OrderDto> getOrdersByUser(@PathVariable Long userId);
}
User: Build a Spring Boot REST API for a product catalogue with CRUD endpoints, PostgreSQL via JPA, bean validation, global error handling, and a @WebMvcTest for the GET endpoint.
Expected output:
Product entity — id, name, price (BigDecimal), stock, createdAtProductDto record + CreateProductRequest record with @NotBlank / @Positive validationProductRepository extends JpaRepository<Product, Long>ProductService — @Transactional(readOnly = true) class-level, @Transactional on writesProductController — CRUD at /api/v1/products, Pageable on GET listGlobalExceptionHandler — NotFoundException → 404, MethodArgumentNotValidException → 400 with field errorsProductControllerTest using @WebMvcTest + @MockitoBean ProductService