Project Initialization, Version Management, and Core Scaffold for a Spring Boot Application
This article walks through setting up a Spring Boot project, explains version compatibility between Spring Cloud, Spring Boot, and Kafka, demonstrates common pitfalls, and provides essential scaffold code such as global exception handling, logging, CORS configuration, Swagger setup, and response wrappers.
The guide begins by highlighting the frustration developers face when configuring development environments, especially the challenges of obtaining and activating IDEs like JetBrains, and then shows how to create a new Spring Boot project using the IDE.
It presents the version compatibility matrix between Spring Cloud, Spring Boot, and Kafka, providing URLs to official version tables and illustrating mismatches that can cause runtime errors, such as using an incompatible Kafka client with an older broker.
A real‑world incident is described where a production Kafka server (0.11) conflicted with a client library (3.0.4), leading to an UnsupportedVersionException and emphasizing the importance of aligning versions across environments.
The article then introduces Maven as the tool for managing dependencies and explains Spring Boot's auto‑configuration benefits while noting that dependency conflicts can still arise.
Core scaffold code is provided:
@RestControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(value = {MethodArgumentNotValidException.class})
public ResponseResult
handleValidException(MethodArgumentNotValidException ex, HttpServletResponse httpServletResponse) {
log.error("[GlobalExceptionHandler][handleValidException] 参数校验exception", ex);
return wrapperBindingResult(ex.getBindingResult(), httpServletResponse);
}
private ResponseResult
wrapperBindingResult(BindingResult bindingResult, HttpServletResponse httpServletResponse) {
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());
}
httpServletResponse.setStatus(HttpStatus.BAD_REQUEST.value());
return ResponseResult.failed(ResultCode.FAILED.getCode(), null);
}
} @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));
}
}
} @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);
}
}
@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();
}
} @Data
public class ResponseResult
{
private int code;
private String message;
private T data;
public static
ResponseResult
success(T data) {
ResponseResult
r = new ResponseResult<>();
r.setCode(ResultCode.SUCCESS.getCode());
r.setMessage(ResultCode.SUCCESS.getMessage());
r.setData(data);
return r;
}
public static
ResponseResult
success() { /* ... */ }
public static
ResponseResult
failed(int code, String message) { /* ... */ }
public static boolean isSucceed(ResponseResult response) { return response.getCode() == ResultCode.SUCCESS.getCode(); }
}Additional useful tools are listed, including embedded Redis, embedded MariaDB, in‑memory Kafka via Spring Boot starter, Hutool utilities, MyBatis‑Plus, MapStruct, and Redisson, each with their respective URLs.
The article concludes by reminding readers that while IDE setup can be tedious, mismatched environment versions are an even larger source of wasted time and frustration.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
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.