Spring Boot Project Initialization, Version Management, and Common Backend Utilities Tutorial
This article walks through creating a Spring Boot project, handling version compatibility between Spring Cloud, Spring Boot, and Kafka, demonstrates common Maven configurations, provides global exception handling and logging aspects, and lists useful backend tools such as embedded Redis, MyBatis‑Plus, and Redisson.
In this tutorial, a senior architect explains the pain points of environment setup and demonstrates how to quickly create a Spring Boot project using an IDE.
After project creation, the article shows the version compatibility matrix between Spring Cloud and Spring Boot ( https://spring.io/projects/spring-cloud ) and between Spring Boot and Kafka ( https://spring.io/projects/spring-kafka ), highlighting a real‑world mismatch where the Kafka broker version (0.11) does not support the client’s idempotent mode, causing an UnsupportedVersionException .
The author then introduces Maven as a dependency management tool ( https://maven.apache.org/index.html ) and presents a basic Maven dependency snippet for Spring Kafka:
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>Next, the article provides a global exception handler using @RestControllerAdvice and Lombok’s @Slf4j , with a method to handle MethodArgumentNotValidException and a helper to format validation errors.
@RestControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(value = {MethodArgumentNotValidException.class})
public ResponseResult
handleValidException(MethodArgumentNotValidException ex, HttpServletResponse response) {
log.error("[GlobalExceptionHandler][handleValidException] 参数校验exception", ex);
return wrapperBindingResult(ex.getBindingResult(), response);
}
private ResponseResult
wrapperBindingResult(BindingResult bindingResult, HttpServletResponse response) {
StringBuilder errorMsg = new StringBuilder();
for (ObjectError error : bindingResult.getAllErrors()) {
if (error instanceof FieldError) {
errorMsg.append(((FieldError) error).getField()).append(": ");
}
errorMsg.append(error.getDefaultMessage() == null ? "" : error.getDefaultMessage());
}
response.setStatus(HttpStatus.BAD_REQUEST.value());
return ResponseResult.failed(ResultCode.FAILED.getCode(), null);
}
}A logging aspect is also shown, which intercepts all controller methods to log request URLs and parameters before execution and logs the response after returning.
@Aspect
@Slf4j
@Component
public class WebLogAspect {
@Pointcut("@within(org.springframework.stereotype.Controller) || @within(org.springframework.web.bind.annotation.RestController)")
public void cutController() {}
@Before("cutController()")
public void doBefore(JoinPoint point) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String url = request.getRequestURL().toString();
List
list = Lists.newArrayList();
for (Object object : point.getArgs()) {
if (object instanceof MultipartFile || object instanceof HttpServletRequest || object instanceof HttpServletResponse || object instanceof BindingResult) {
continue;
}
list.add(object);
}
log.info("请求 uri:[{}],params:[{}]", url, StringUtils.join(list, ","));
}
@AfterReturning(returning = "response", pointcut = "cutController()")
public void doAfterReturning(Object response) {
if (response != null) {
log.info("请求返回result:[{}]", JSONUtil.toJsonStr(response));
}
}
}Cross‑origin resource sharing (CORS) configuration is provided via a @Configuration class that registers a CorsFilter allowing all origins, headers, and methods.
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Lists.newArrayList("*"));
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}Swagger configuration for API documentation is also included.
@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Bean
public Docket docket() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.enable(true)
.select()
.apis(RequestHandlerSelectors.basePackage("com.vines.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("项目描述")
.description("基础服务项目描述")
.contact(new Contact("作者", "作者URL", "作者Email"))
.version("1.0")
.build();
}
}The article defines a generic ResponseResult wrapper class with static factory methods for success and failure responses.
@Data
public class ResponseResult
{
private int code;
private String message;
private T data;
public static
ResponseResult
success(T data) { ... }
public static
ResponseResult
success() { ... }
public static
ResponseResult
failed(int code, String message) { ... }
public static boolean isSucceed(ResponseResult responseResult) { ... }
}Finally, the author lists several useful backend tools with their URLs: embedded Redis ( https://github.com/kstyrc/embedded-redis ), embedded MariaDB ( https://github.com/mariadb ), embedded Kafka starter, Hutool ( https://hutool.cn/ ), MyBatis‑Plus ( https://baomidou.com/ ), MapStruct ( https://mapstruct.org/ ), and Redisson ( https://github.com/redisson/redisson ).
The article concludes with a reminder that environment configuration is often the most time‑consuming part of development and invites readers to discuss and share their experiences.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
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.