spring-web by claude-dev-suite/claude-dev-suite
npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill spring-web深度知识:使用
mcp__documentation__fetch_docs并指定技术为spring-web以获取全面的文档。
@RestController
@RequestMapping("/api/v1")
@RequiredArgsConstructor
public class ApiController {
private final RestClient restClient;
@GetMapping("/proxy/{id}")
public ResponseEntity<Resource> proxyRequest(@PathVariable Long id) {
return restClient.get()
.uri("/external/resource/{id}", id)
.retrieve()
.toEntity(Resource.class);
}
}
@Configuration
public class RestClientConfig {
@Bean
public RestClient restClient(RestClient.Builder builder) {
return builder
.baseUrl("https://api.external.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.connectTimeout(Duration.ofSeconds(5))
.readTimeout(Duration.ofSeconds(30))
.build();
}
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
RestClient 是替代 RestTemplate 的新同步 HTTP 客户端。
@Service
@RequiredArgsConstructor
public class UserApiClient {
private final RestClient restClient;
// GET
public UserDto getUser(Long id) {
return restClient.get()
.uri("/users/{id}", id)
.retrieve()
.body(UserDto.class);
}
// POST
public UserDto createUser(CreateUserRequest request) {
return restClient.post()
.uri("/users")
.body(request)
.retrieve()
.body(UserDto.class);
}
// 带错误处理
public UserDto getUserSafe(Long id) {
return restClient.get()
.uri("/users/{id}", id)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, (req, res) -> {
throw new ResourceNotFoundException("User not found: " + id);
})
.body(UserDto.class);
}
}
完整参考:完整的 RestClient 和 WebClient 文档请参阅 http-clients.md。
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
// 创建并返回 Location 头
@PostMapping
public ResponseEntity<UserResponse> create(
@Valid @RequestBody CreateUserRequest req,
UriComponentsBuilder uriBuilder) {
UserResponse created = service.create(req);
URI location = uriBuilder.path("/api/v1/users/{id}")
.buildAndExpand(created.getId()).toUri();
return ResponseEntity.created(location).body(created);
}
// 带 ETag
@GetMapping("/{id}")
public ResponseEntity<UserResponse> get(@PathVariable Long id) {
UserResponse user = service.findById(id);
return ResponseEntity.ok()
.eTag("\"" + user.getVersion() + "\"")
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.body(user);
}
// 无内容
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
service.delete(id);
return ResponseEntity.noContent().build();
}
}
完整参考:关于 ResponseEntity、内容协商和流式处理的完整内容,请参阅 patterns.md。
// 上传
@PostMapping("/upload")
public ResponseEntity<FileResponse> upload(@RequestParam("file") MultipartFile file) {
String fileName = storageService.store(file);
return ResponseEntity.ok(new FileResponse(fileName, file.getSize()));
}
// 下载
@GetMapping("/download/{fileName}")
public ResponseEntity<Resource> download(@PathVariable String fileName) {
Resource resource = storageService.loadAsResource(fileName);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + fileName + "\"")
.body(resource);
}
完整参考:完整的文件操作请参阅 file-handling.md。
@Slf4j
@Component
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
MDC.put("requestId", UUID.randomUUID().toString());
request.setAttribute("startTime", System.currentTimeMillis());
log.info("==> {} {}", request.getMethod(), request.getRequestURI());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
long duration = System.currentTimeMillis() -
(Long) request.getAttribute("startTime");
log.info("<== {} ({} ms)", response.getStatus(), duration);
MDC.clear();
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor).addPathPatterns("/api/**");
}
}
完整参考:关于拦截器、参数解析器、异常处理和测试的完整内容,请参阅 advanced.md。
| 应做 | 不应做 |
|---|---|
| 使用 RestClient 进行同步调用 (Spring 3.2+) | 使用已弃用的 RestTemplate |
| 配置显式超时 | 依赖默认超时 |
| 使用指数退避实现重试 | 无延迟立即重试 |
| 使用拦截器进行集中式日志记录 | 在每个方法中记录日志 |
| 将响应包装在 ResponseEntity 中 | 返回原始对象 |
spring-webflux 技能spring-rest 技能spring-websocket 技能spring-graphql 技能| 反模式 | 问题 | 解决方案 |
|---|---|---|
| 使用 RestTemplate | 已弃用,非类型安全 | 使用 RestClient (同步) 或 WebClient (异步) |
| 未配置超时 | 请求无限期挂起 | 配置连接/读取超时 |
| 流导致内存泄漏 | 流未关闭 | 使用 try-with-resources |
| N+1 HTTP 调用 | 在循环中调用 | 使用批量端点或并行调用 |
| 在 WebFlux 中阻塞 | 在响应式栈中使用 .block() | 保持链式响应式 |
| 问题 | 诊断 | 修复 |
|---|---|---|
| 连接超时 | 检查网络/防火墙 | 配置适当的超时值 |
| SSL 握手失败 | 检查证书 | 正确配置 SSLContext |
| 响应未映射 | 检查 Content-Type | 配置消息转换器 |
| 拦截器未被调用 | 检查注册 | 验证拦截器顺序 |
| 文件上传失败 | 检查大小限制 | 配置 multipart 设置 |
| 文件 | 内容 |
|---|---|
| http-clients.md | RestClient, WebClient, 拦截器 |
| patterns.md | ResponseEntity, 内容协商, 流式处理 |
| file-handling.md | 文件上传, 下载, 存储服务 |
| advanced.md | 参数解析器, HandlerInterceptors, 异常处理, 测试 |
每周安装数
1
代码库
首次出现
3 天前
安全审计
安装于
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1
Deep Knowledge : Use
mcp__documentation__fetch_docswith technology:spring-webfor comprehensive documentation.
@RestController
@RequestMapping("/api/v1")
@RequiredArgsConstructor
public class ApiController {
private final RestClient restClient;
@GetMapping("/proxy/{id}")
public ResponseEntity<Resource> proxyRequest(@PathVariable Long id) {
return restClient.get()
.uri("/external/resource/{id}", id)
.retrieve()
.toEntity(Resource.class);
}
}
@Configuration
public class RestClientConfig {
@Bean
public RestClient restClient(RestClient.Builder builder) {
return builder
.baseUrl("https://api.external.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.connectTimeout(Duration.ofSeconds(5))
.readTimeout(Duration.ofSeconds(30))
.build();
}
}
RestClient is the new synchronous HTTP client replacing RestTemplate.
@Service
@RequiredArgsConstructor
public class UserApiClient {
private final RestClient restClient;
// GET
public UserDto getUser(Long id) {
return restClient.get()
.uri("/users/{id}", id)
.retrieve()
.body(UserDto.class);
}
// POST
public UserDto createUser(CreateUserRequest request) {
return restClient.post()
.uri("/users")
.body(request)
.retrieve()
.body(UserDto.class);
}
// With error handling
public UserDto getUserSafe(Long id) {
return restClient.get()
.uri("/users/{id}", id)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, (req, res) -> {
throw new ResourceNotFoundException("User not found: " + id);
})
.body(UserDto.class);
}
}
Full Reference : See http-clients.md for complete RestClient and WebClient documentation.
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
// Created with Location
@PostMapping
public ResponseEntity<UserResponse> create(
@Valid @RequestBody CreateUserRequest req,
UriComponentsBuilder uriBuilder) {
UserResponse created = service.create(req);
URI location = uriBuilder.path("/api/v1/users/{id}")
.buildAndExpand(created.getId()).toUri();
return ResponseEntity.created(location).body(created);
}
// With ETag
@GetMapping("/{id}")
public ResponseEntity<UserResponse> get(@PathVariable Long id) {
UserResponse user = service.findById(id);
return ResponseEntity.ok()
.eTag("\"" + user.getVersion() + "\"")
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.body(user);
}
// No Content
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
service.delete(id);
return ResponseEntity.noContent().build();
}
}
Full Reference : See patterns.md for ResponseEntity, Content Negotiation, and Streaming.
// Upload
@PostMapping("/upload")
public ResponseEntity<FileResponse> upload(@RequestParam("file") MultipartFile file) {
String fileName = storageService.store(file);
return ResponseEntity.ok(new FileResponse(fileName, file.getSize()));
}
// Download
@GetMapping("/download/{fileName}")
public ResponseEntity<Resource> download(@PathVariable String fileName) {
Resource resource = storageService.loadAsResource(fileName);
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=\"" + fileName + "\"")
.body(resource);
}
Full Reference : See file-handling.md for complete file operations.
@Slf4j
@Component
public class LoggingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
MDC.put("requestId", UUID.randomUUID().toString());
request.setAttribute("startTime", System.currentTimeMillis());
log.info("==> {} {}", request.getMethod(), request.getRequestURI());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
long duration = System.currentTimeMillis() -
(Long) request.getAttribute("startTime");
log.info("<== {} ({} ms)", response.getStatus(), duration);
MDC.clear();
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor).addPathPatterns("/api/**");
}
}
Full Reference : See advanced.md for Interceptors, Argument Resolvers, Exception Handling, and Testing.
| Do | Don't |
|---|---|
| Use RestClient for sync calls (Spring 3.2+) | Use deprecated RestTemplate |
| Configure explicit timeouts | Rely on default timeouts |
| Implement retry with exponential backoff | Retry immediately without delay |
| Use interceptors for centralized logging | Log in each method |
| Wrap responses in ResponseEntity | Return raw objects |
spring-webflux skillspring-rest skillspring-websocket skillspring-graphql skill| Anti-Pattern | Problem | Solution |
|---|---|---|
| Using RestTemplate | Deprecated, not type-safe | Use RestClient (sync) or WebClient (async) |
| No timeout configuration | Requests hang indefinitely | Configure connect/read timeout |
| Memory leak with streams | Stream not closed | Use try-with-resources |
| N+1 HTTP calls | Calls in loop | Use batch endpoints or parallel calls |
| Blocking in WebFlux | .block() in reactive stack | Keep chain reactive |
| Problem | Diagnostic | Fix |
|---|---|---|
| Connection timeout | Check network/firewall | Configure proper timeout values |
| SSL handshake fails | Check certificates | Configure SSLContext properly |
| Response not mapped | Check Content-Type | Configure message converters |
| Interceptor not called | Check registration | Verify interceptor order |
| File upload fails | Check size limits | Configure multipart settings |
| File | Content |
|---|---|
| http-clients.md | RestClient, WebClient, Interceptors |
| patterns.md | ResponseEntity, Content Negotiation, Streaming |
| file-handling.md | File Upload, Download, Storage Service |
| advanced.md | Argument Resolvers, HandlerInterceptors, Exception Handling, Testing |
Weekly Installs
1
Repository
First Seen
3 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1
agent-browser 浏览器自动化工具 - Vercel Labs 命令行网页操作与测试
147,400 周安装
Docnify自动化:通过Rube MCP和Composio工具包实现文档操作自动化
1 周安装
Docmosis自动化集成指南:通过Rube MCP与Composio实现文档生成自动化
1 周安装
Dictionary API自动化教程:通过Rube MCP和Composio实现词典API操作自动化
1 周安装
detrack-automation:自动化追踪技能,集成Claude AI提升开发效率
1 周安装
Demio自动化工具包:通过Rube MCP和Composio实现Demio操作自动化
1 周安装
Deel自动化工具:通过Rube MCP与Composio实现HR与薪资操作自动化
1 周安装