Spring Web MVC Advanced
Deep Knowledge: Use mcp__documentation__fetch_docs with technology: spring-web for comprehensive documentation.
Quick Start
@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 Essentials (Spring 6.1+)
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.
ResponseEntity Quick Patterns
@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.
File Upload/Download Quick Start
// 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.
Interceptors Quick Start
@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.
Best Practices
| 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 |
When NOT to Use This Skill
- Reactive applications - Use
spring-webflux skill
- Basic REST controllers - Use
spring-rest skill
- WebSocket communication - Use
spring-websocket skill
- GraphQL APIs - Use
spring-graphql skill
Anti-Patterns
| 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 |
Quick Troubleshooting
| 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 |
Reference Files
| 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 |
External Documentation
1---2name: spring-web3description: Spring Web MVC advanced for Spring Boot 3.x. Covers RestClient (Spring 6.1+), WebClient, ResponseEntity patterns, interceptors, content negotiation, file upload/download, streaming responses, and custom argument resolvers. USE WHEN: user mentions "spring web", "RestClient", "WebClient", "ResponseEntity", "HTTP client Spring", "file upload", "file download", "streaming response", "HandlerInterceptor", "content negotiation", "argument resolver" DO NOT USE FOR: reactive web stack - use `spring-webflux` skill, REST controller basics - use `spring-rest` skill, WebSocket - use `spring-websocket` skill4---5# Spring Web MVC Advanced67> **Deep Knowledge**: Use `mcp__documentation__fetch_docs` with technology: `spring-web` for comprehensive documentation.89## Quick Start1011```java12@RestController13@RequestMapping("/api/v1")14@RequiredArgsConstructor15public class ApiController {1617 private final RestClient restClient;1819 @GetMapping("/proxy/{id}")20 public ResponseEntity<Resource> proxyRequest(@PathVariable Long id) {21 return restClient.get()22 .uri("/external/resource/{id}", id)23 .retrieve()24 .toEntity(Resource.class);25 }26}2728@Configuration29public class RestClientConfig {3031 @Bean32 public RestClient restClient(RestClient.Builder builder) {33 return builder34 .baseUrl("https://api.external.com")35 .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)36 .connectTimeout(Duration.ofSeconds(5))37 .readTimeout(Duration.ofSeconds(30))38 .build();39 }40}41```4243---4445## RestClient Essentials (Spring 6.1+)4647RestClient is the new synchronous HTTP client replacing RestTemplate.4849```java50@Service51@RequiredArgsConstructor52public class UserApiClient {5354 private final RestClient restClient;5556 // GET57 public UserDto getUser(Long id) {58 return restClient.get()59 .uri("/users/{id}", id)60 .retrieve()61 .body(UserDto.class);62 }6364 // POST65 public UserDto createUser(CreateUserRequest request) {66 return restClient.post()67 .uri("/users")68 .body(request)69 .retrieve()70 .body(UserDto.class);71 }7273 // With error handling74 public UserDto getUserSafe(Long id) {75 return restClient.get()76 .uri("/users/{id}", id)77 .retrieve()78 .onStatus(HttpStatusCode::is4xxClientError, (req, res) -> {79 throw new ResourceNotFoundException("User not found: " + id);80 })81 .body(UserDto.class);82 }83}84```8586> **Full Reference**: See [http-clients.md](http-clients.md) for complete RestClient and WebClient documentation.8788---8990## ResponseEntity Quick Patterns9192```java93@RestController94@RequestMapping("/api/v1/users")95public class UserController {9697 // Created with Location98 @PostMapping99 public ResponseEntity<UserResponse> create(100 @Valid @RequestBody CreateUserRequest req,101 UriComponentsBuilder uriBuilder) {102103 UserResponse created = service.create(req);104 URI location = uriBuilder.path("/api/v1/users/{id}")105 .buildAndExpand(created.getId()).toUri();106107 return ResponseEntity.created(location).body(created);108 }109110 // With ETag111 @GetMapping("/{id}")112 public ResponseEntity<UserResponse> get(@PathVariable Long id) {113 UserResponse user = service.findById(id);114 return ResponseEntity.ok()115 .eTag("\"" + user.getVersion() + "\"")116 .cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))117 .body(user);118 }119120 // No Content121 @DeleteMapping("/{id}")122 public ResponseEntity<Void> delete(@PathVariable Long id) {123 service.delete(id);124 return ResponseEntity.noContent().build();125 }126}127```128129> **Full Reference**: See [patterns.md](patterns.md) for ResponseEntity, Content Negotiation, and Streaming.130131---132133## File Upload/Download Quick Start134135```java136// Upload137@PostMapping("/upload")138public ResponseEntity<FileResponse> upload(@RequestParam("file") MultipartFile file) {139 String fileName = storageService.store(file);140 return ResponseEntity.ok(new FileResponse(fileName, file.getSize()));141}142143// Download144@GetMapping("/download/{fileName}")145public ResponseEntity<Resource> download(@PathVariable String fileName) {146 Resource resource = storageService.loadAsResource(fileName);147 return ResponseEntity.ok()148 .contentType(MediaType.APPLICATION_OCTET_STREAM)149 .header(HttpHeaders.CONTENT_DISPOSITION,150 "attachment; filename=\"" + fileName + "\"")151 .body(resource);152}153```154155> **Full Reference**: See [file-handling.md](file-handling.md) for complete file operations.156157---158159## Interceptors Quick Start160161```java162@Slf4j163@Component164public class LoggingInterceptor implements HandlerInterceptor {165166 @Override167 public boolean preHandle(HttpServletRequest request,168 HttpServletResponse response, Object handler) {169 MDC.put("requestId", UUID.randomUUID().toString());170 request.setAttribute("startTime", System.currentTimeMillis());171 log.info("==> {} {}", request.getMethod(), request.getRequestURI());172 return true;173 }174175 @Override176 public void afterCompletion(HttpServletRequest request,177 HttpServletResponse response,178 Object handler, Exception ex) {179 long duration = System.currentTimeMillis() -180 (Long) request.getAttribute("startTime");181 log.info("<== {} ({} ms)", response.getStatus(), duration);182 MDC.clear();183 }184}185186@Configuration187public class WebConfig implements WebMvcConfigurer {188 @Override189 public void addInterceptors(InterceptorRegistry registry) {190 registry.addInterceptor(loggingInterceptor).addPathPatterns("/api/**");191 }192}193```194195> **Full Reference**: See [advanced.md](advanced.md) for Interceptors, Argument Resolvers, Exception Handling, and Testing.196197---198199## Best Practices200201| Do | Don't |202|----|-------|203| Use RestClient for sync calls (Spring 3.2+) | Use deprecated RestTemplate |204| Configure explicit timeouts | Rely on default timeouts |205| Implement retry with exponential backoff | Retry immediately without delay |206| Use interceptors for centralized logging | Log in each method |207| Wrap responses in ResponseEntity | Return raw objects |208209---210211## When NOT to Use This Skill212213- **Reactive applications** - Use `spring-webflux` skill214- **Basic REST controllers** - Use `spring-rest` skill215- **WebSocket communication** - Use `spring-websocket` skill216- **GraphQL APIs** - Use `spring-graphql` skill217218---219220## Anti-Patterns221222| Anti-Pattern | Problem | Solution |223|--------------|---------|----------|224| Using RestTemplate | Deprecated, not type-safe | Use RestClient (sync) or WebClient (async) |225| No timeout configuration | Requests hang indefinitely | Configure connect/read timeout |226| Memory leak with streams | Stream not closed | Use try-with-resources |227| N+1 HTTP calls | Calls in loop | Use batch endpoints or parallel calls |228| Blocking in WebFlux | .block() in reactive stack | Keep chain reactive |229230---231232## Quick Troubleshooting233234| Problem | Diagnostic | Fix |235|---------|------------|-----|236| Connection timeout | Check network/firewall | Configure proper timeout values |237| SSL handshake fails | Check certificates | Configure SSLContext properly |238| Response not mapped | Check Content-Type | Configure message converters |239| Interceptor not called | Check registration | Verify interceptor order |240| File upload fails | Check size limits | Configure multipart settings |241242---243244## Reference Files245246| File | Content |247|------|---------|248| [http-clients.md](http-clients.md) | RestClient, WebClient, Interceptors |249| [patterns.md](patterns.md) | ResponseEntity, Content Negotiation, Streaming |250| [file-handling.md](file-handling.md) | File Upload, Download, Storage Service |251| [advanced.md](advanced.md) | Argument Resolvers, HandlerInterceptors, Exception Handling, Testing |252253---254255## External Documentation256257- [Spring Web MVC](https://docs.spring.io/spring-framework/reference/web/webmvc.html)258- [RestClient](https://docs.spring.io/spring-framework/reference/integration/rest-clients.html#rest-restclient)259- [WebClient](https://docs.spring.io/spring-framework/reference/web/webflux-webclient.html)