Backend Development 7 min read

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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Master Advanced Spring Boot: Date Params, Conditional Controllers & Async Timeouts

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>
backendJavaValidationSpring BootDateTimeControllerasync
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.