Master Advanced Spring Boot: Date Params, Conditional Controllers & Async Timeouts
Learn how to elegantly process Java 8 date parameters, register custom converters, conditionally enable controllers, apply unified API prefixes, perform service‑layer validation, and control asynchronous request timeouts in Spring Boot 3.2.5 using annotations, configuration files, and programmatic WebMvcConfigurer techniques.
1. Elegant Date Parameter Handling
Spring MVC automatically converts many data types, including Java 8 date types. Example:
<code>@GetMapping("/date")
public Object date(@RequestParam(value = "start")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
LocalDateTime start) {
return start;
}</code>Request example:
If repeatedly adding the annotation feels cumbersome, you can register a custom converter.
<code>public class LocalDateTimeConverter implements Converter<String, LocalDateTime> {
private final DateTimeFormatter formatter;
public LocalDateTimeConverter(String pattern) {
this.formatter = DateTimeFormatter.ofPattern(pattern);
}
public LocalDateTime convert(String source) {
if (source == null || source.isEmpty()) {
return null;
}
return LocalDateTime.parse(source, formatter);
}
}</code>Register the converter in the container:
<code>@Component
public class DateConfigure implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new LocalDateTimeConverter("yyyy-MM-dd HH:mm:ss"));
}
}</code>2. Programmatic Control of Controller Activation
You can enable a controller only when a specific property is true using Spring’s conditional annotations:
<code>@ConditionalOnExpression("#{${pack.controller.user.enabled} == true}")
@RestController
@RequestMapping("/users")
public class UserController {}
</code>When pack.controller.user.enabled=true in the environment, UserController becomes active.
Alternatively, use an interceptor to reject requests:
<code>public class ConditionalRejectionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestUri = request.getRequestURI();
if (shouldReject(requestUri)) {
response.setStatus(HttpStatus.NOT_FOUND.value());
return false;
}
return true;
}
private boolean shouldReject(String requestUri) {
return requestUri.startsWith("/users");
}
}
</code>3. Unified API Prefix for Controllers
Goal: prepend /api to all controller paths, e.g., /api/customer , /api/orders .
Method 1: YAML configuration
<code>spring:
mvc:
servlet:
path: /api
# or
server:
servlet:
context-path: /api
</code>Method 2: Java configuration
<code>@Configuration
public class PrefixConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
}
}
</code>4. Service‑Layer Parameter Validation with Annotations
Validation can also be performed in the service layer by injecting Validator :
<code>private final Validator validator;
public ValidationService(Validator validator) {
this.validator = validator;
}
public User save(User user) {
Set<ConstraintViolation<User>> validate = this.validator.validate(user);
System.err.println(validate);
return user;
}
</code>Example output shows violations such as “姓名必须填写” (name required) and “年龄不能小于1” (age must be greater than 0). You can also place @Validated on the class and handle violations globally.
5. Controlling Asynchronous Endpoint Timeouts
Common async return types are @Async with CompletableFuture , Callable , or DeferredResult . Example using Callable :
<code>@GetMapping("")
public Callable<String> index() throws InterruptedException {
return new Callable<String>() {
@Override
public String call() throws Exception {
// Simulate delay
Thread.sleep(5000);
return "Pack Async Task";
}
};
}
</code>Configure timeout via YAML:
<code>spring:
mvc:
async:
request-timeout: 3000
</code>Or programmatically:
<code>@Component
public class TimeoutConfig implements WebMvcConfigurer {
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(1000);
}
}
</code>Register a timeout interceptor to return a default response when a timeout occurs:
<code>@Bean
TimeoutCallableProcessingInterceptor timeoutInterceptor() {
return new TimeoutCallableProcessingInterceptor() {
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
return "超时";
}
};
}
</code>Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.