ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Spring Boot快速入门与实战指南

Spring Boot快速入门与实战指南 1. Spring Boot 快速入门指南作为一名Java开发者我深知Spring Boot在现代Web开发中的重要性。Spring Boot通过简化配置和提供开箱即用的功能极大地提高了开发效率。本文将分享我在实际项目中使用Spring Boot的经验从环境搭建到核心功能实现带你快速掌握这个强大的框架。2. 环境准备与项目创建2.1 开发环境配置在开始Spring Boot项目前确保你的开发环境已准备就绪JDK 1.8或更高版本Spring Boot 2.x推荐使用JDK 1.8Spring Boot 3.x需要JDK 17Maven 3.3或Gradle 6.x用于项目依赖管理IDE选择IntelliJ IDEA推荐、Eclipse或VS Code提示使用IntelliJ IDEA Ultimate版可以获得更好的Spring Boot支持包括自动配置提示和可视化依赖分析。2.2 创建Spring Boot项目创建Spring Boot项目有多种方式这里介绍最常用的两种2.2.1 使用Spring Initializr创建访问 start.spring.io选择项目配置Project: Maven ProjectLanguage: JavaSpring Boot: 选择稳定版本Group: 你的组织域名如com.exampleArtifact: 项目名称添加依赖根据需求选择如Web、JPA等点击Generate下载项目压缩包2.2.2 使用IDE创建以IntelliJ为例打开IntelliJ选择New Project选择Spring Initializr填写项目基本信息选择需要的依赖点击Finish完成创建创建完成后项目结构应如下src/ ├── main/ │ ├── java/ │ │ └── com/example/demo/ │ │ └── DemoApplication.java │ └── resources/ │ ├── static/ │ ├── templates/ │ └── application.properties └── test/2.3 热部署配置开发过程中频繁重启应用很耗时配置热部署可以显著提高效率添加devtools依赖到pom.xmldependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-devtools/artifactId optionaltrue/optional /dependency配置application.properties# 启用热部署 spring.devtools.restart.enabledtrue # 设置监听目录 spring.devtools.restart.additional-pathssrc/main/java # 排除静态资源目录 spring.devtools.restart.excludestatic/**IDE设置IntelliJ打开设置CtrlAltS搜索Compiler勾选Build project automatically在Advanced Settings中勾选Allow auto-make to start even if developed application is currently running注意事项热部署对静态资源修改即时生效但对Java类修改需要触发编译CtrlF9。某些复杂配置修改可能仍需完整重启。3. Spring Boot核心功能实现3.1 控制器(Controller)开发控制器是处理HTTP请求的核心组件Spring Boot提供了两种主要注解Controller传统MVC控制器通常返回视图名称RestControllerREST风格控制器直接返回数据JSON/XML3.1.1 基本控制器示例RestController RequestMapping(/api) public class HelloController { GetMapping(/hello) public String sayHello() { return Hello, Spring Boot!; } GetMapping(/user/{id}) public User getUser(PathVariable Long id) { User user new User(); user.setId(id); user.setName(张三); user.setEmail(zhangsanexample.com); return user; } }3.1.2 请求参数处理Spring Boot提供了多种参数绑定方式RequestParam获取查询参数GetMapping(/search) public String search(RequestParam String keyword) { return Searching for: keyword; }PathVariable获取路径变量GetMapping(/users/{userId}) public String getUser(PathVariable Long userId) { return User ID: userId; }RequestBody获取请求体通常为JSONPostMapping(/users) public User createUser(RequestBody User user) { // 保存用户逻辑 return user; }ModelAttribute绑定表单数据PostMapping(/register) public String register(ModelAttribute User user) { // 注册逻辑 return redirect:/success; }经验分享对于复杂对象Spring Boot会自动进行类型转换。如果遇到转换问题可以自定义Converter或使用JsonFormat等注解处理特定格式。3.2 路由与请求映射Spring Boot提供了丰富的请求映射注解注解HTTP方法说明GetMappingGET获取资源PostMappingPOST创建资源PutMappingPUT更新资源DeleteMappingDELETE删除资源PatchMappingPATCH部分更新资源RequestMapping任意通用映射需指定method属性3.2.1 高级路由配置RestController RequestMapping(/api/v1) public class AdvancedController { // 组合路径 GetMapping(/users/{id}/orders) public ListOrder getUserOrders(PathVariable Long id) { // 实现逻辑 } // 多条件映射 GetMapping(value /search, params {keyword, page}) public PageResult search(RequestParam String keyword, RequestParam int page) { // 搜索逻辑 } // 内容协商 GetMapping(value /data, produces { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) public Data getData() { // 返回数据Spring会根据Accept头决定格式 } }注意事项路径设计应遵循RESTful原则使用名词复数形式表示资源HTTP方法表示操作。避免在URL中使用动词如/getUsers。3.3 文件上传处理Spring Boot简化了文件上传处理通过MultipartFile接口即可轻松实现3.3.1 基础文件上传首先配置上传限制application.properties# 单个文件大小限制 spring.servlet.multipart.max-file-size10MB # 总请求大小限制 spring.servlet.multipart.max-request-size100MB # 文件存储位置可选 file.upload-dir/tmp/uploads/实现上传控制器RestController public class FileUploadController { Value(${file.upload-dir}) private String uploadDir; PostMapping(/upload) public String handleFileUpload(RequestParam(file) MultipartFile file) { try { // 确保目录存在 File uploadPath new File(uploadDir); if (!uploadPath.exists()) { uploadPath.mkdirs(); } // 生成唯一文件名 String fileName UUID.randomUUID() _ file.getOriginalFilename(); File dest new File(uploadDir fileName); // 保存文件 file.transferTo(dest); return 文件上传成功: fileName; } catch (IOException e) { return 文件上传失败: e.getMessage(); } } }3.3.2 多文件上传PostMapping(/multi-upload) public ListString handleMultipleUpload(RequestParam(files) MultipartFile[] files) { return Arrays.stream(files) .map(this::handleFileUpload) .collect(Collectors.toList()); }实战技巧文件存储应考虑分布式场景可以使用云存储服务如阿里云OSS、AWS S3对于大文件上传考虑实现分片上传文件类型应做校验防止恶意文件上传文件名应做处理避免路径遍历攻击3.4 拦截器(Interceptor)实现拦截器是Spring MVC的重要组件用于预处理和后处理请求3.4.1 自定义拦截器创建拦截器类public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 在控制器方法执行前调用 String token request.getHeader(Authorization); if (!isValidToken(token)) { response.sendError(HttpStatus.UNAUTHORIZED.value(), 无效的认证信息); return false; // 中断请求 } return true; // 继续执行 } Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // 控制器方法执行后视图渲染前调用 } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 请求完成后调用用于资源清理 } private boolean isValidToken(String token) { // 实现token验证逻辑 return true; } }注册拦截器Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()) .addPathPatterns(/api/**) // 拦截路径 .excludePathPatterns(/api/login); // 排除路径 } }3.4.2 拦截器常见应用场景认证和授权检查请求日志记录跨域处理性能监控参数预处理注意事项拦截器中不要进行耗时操作否则会影响请求响应时间。对于复杂业务逻辑建议使用过滤器(Filter)或切面(AOP)实现。4. RESTful API设计与实现4.1 RESTful设计原则RESTful是目前主流的API设计风格遵循以下原则资源导向URI指向资源而不是动作统一接口使用标准HTTP方法GET/POST/PUT/DELETE等无状态每个请求包含完整上下文服务端不保存会话状态可缓存响应应明确是否可缓存分层系统客户端不需要知道是否直接连接最终服务器按需代码可选服务器可以临时扩展功能4.2 Spring Boot实现RESTful API4.2.1 资源控制器示例RestController RequestMapping(/api/users) public class UserController { Autowired private UserService userService; GetMapping public ListUser getAllUsers() { return userService.findAll(); } GetMapping(/{id}) public ResponseEntityUser getUserById(PathVariable Long id) { return userService.findById(id) .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } PostMapping public ResponseEntityUser createUser(Valid RequestBody User user) { User savedUser userService.save(user); URI location ServletUriComponentsBuilder .fromCurrentRequest() .path(/{id}) .buildAndExpand(savedUser.getId()) .toUri(); return ResponseEntity.created(location).body(savedUser); } PutMapping(/{id}) public ResponseEntityUser updateUser(PathVariable Long id, Valid RequestBody User user) { if (!userService.existsById(id)) { return ResponseEntity.notFound().build(); } user.setId(id); return ResponseEntity.ok(userService.save(user)); } DeleteMapping(/{id}) public ResponseEntityVoid deleteUser(PathVariable Long id) { userService.deleteById(id); return ResponseEntity.noContent().build(); } }4.2.2 响应状态码规范使用适当的HTTP状态码200 OK成功GET请求201 Created成功POST请求204 No Content成功DELETE请求400 Bad Request客户端错误401 Unauthorized未认证403 Forbidden无权限404 Not Found资源不存在500 Internal Server Error服务器错误最佳实践使用ResponseEntity可以灵活控制响应状态和头信息。对于复杂API建议定义统一的响应格式。4.3 API文档生成(Swagger)Swagger可以自动生成API文档方便前后端协作4.3.1 Swagger集成步骤添加依赖dependency groupIdio.springfox/groupId artifactIdspringfox-swagger2/artifactId version2.9.2/version /dependency dependency groupIdio.springfox/groupId artifactIdspringfox-swagger-ui/artifactId version2.9.2/version /dependency配置类Configuration EnableSwagger2 public class SwaggerConfig { Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage(com.example.demo)) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title(示例API文档) .description(Spring Boot示例项目API文档) .version(1.0) .build(); } }解决Spring Boot 2.6兼容问题application.propertiesspring.mvc.pathmatch.matching-strategyant_path_matcher访问文档http://localhost:8080/swagger-ui.html4.3.2 Swagger注解增强使用Swagger注解可以让文档更完善Api(tags 用户管理) RestController RequestMapping(/api/users) public class UserController { ApiOperation(获取用户列表) GetMapping public ListUser getAllUsers() { // 实现 } ApiOperation(根据ID获取用户) ApiImplicitParam(name id, value 用户ID, required true, dataType long) GetMapping(/{id}) public User getUserById(PathVariable Long id) { // 实现 } ApiOperation(创建用户) ApiResponses({ ApiResponse(code 201, message 用户创建成功), ApiResponse(code 400, message 无效的输入) }) PostMapping public ResponseEntityUser createUser(RequestBody Valid User user) { // 实现 } }注意事项生产环境应禁用Swagger UI可以通过置springfox.documentation.swagger-ui.enabledfalse实现。5. 数据持久化与MyBatis-Plus集成5.1 MyBatis-Plus简介MyBatis-Plus是MyBatis的增强工具在MyBatis基础上只做增强不做改变无侵入只做增强不做改变引入它不会对现有工程产影响损耗小启动即会自动注入基本CRUD性能基本无损耗强大的CRUD操作内置通用Mapper、通用Service支持Lambda形式调用通过Lambda表达式方便的编写各类查询条件支持主键自动生成支持多达4种主键策略内置分页插件基于MyBatis物理分页开发者无需关心具体操作5.2 MyBatis-Plus集成步骤5.2.1 添加依赖!-- MyBatis-Plus -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3/version /dependency !-- 数据库驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- 连接池 -- dependency groupIdcom.alibaba/groupId artifactIddruid-spring-boot-starter/artifactId version1.2.16/version /dependency5.2.2 数据源配置application.properties# 数据源配置 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver spring.datasource.urljdbc:mysql://localhost:3306/springboot_demo?useSSLfalseserverTimezoneUTCcharacterEncodingutf8 spring.datasource.usernameroot spring.datasource.password123456 spring.datasource.typecom.alibaba.druid.pool.DruidDataSource # MyBatis-Plus配置 mybatis-plus.mapper-locationsclasspath:mapper/*.xml mybatis-plus.type-aliases-packagecom.example.demo.entity mybatis-plus.configuration.map-underscore-to-camel-casetrue mybatis-plus.configuration.log-implorg.apache.ibatis.logging.stdout.StdOutImpl5.2.3 启用Mapper扫描在主应用类上添加MapperScan注解SpringBootApplication MapperScan(com.example.demo.mapper) public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }5.3 基础CRUD操作5.3.1 实体类定义Data TableName(user) public class User { TableId(type IdType.AUTO) private Long id; private String username; private String password; private String email; TableField(create_time) private LocalDateTime createTime; TableField(update_time) private LocalDateTime updateTime; TableLogic private Integer deleted; }注解说明TableName指定表名TableId主键注解type指定主键策略TableField字段注解指定数据库列名TableLogic逻辑删除标记5.3.2 Mapper接口public interface UserMapper extends BaseMapperUser { // 自定义方法 Select(SELECT * FROM user WHERE email #{email}) User findByEmail(String email); }BaseMapper已提供常用方法insert(T entity)deleteById(Serializable id)updateById(T entity)selectById(Serializable id)selectList(Wrapper queryWrapper)等等...5.3.3 Service层示例Service public class UserService { Autowired private UserMapper userMapper; public User findById(Long id) { return userMapper.selectById(id); } public ListUser findAll() { return userMapper.selectList(null); } public int save(User user) { if (user.getId() null) { return userMapper.insert(user); } else { return userMapper.updateById(user); } } public int deleteById(Long id) { return userMapper.deleteById(id); } }5.3.4 条件构造器使用MyBatis-Plus提供了强大的条件构造器// 查询名字包含张且年龄小于30的用户 QueryWrapperUser queryWrapper new QueryWrapper(); queryWrapper.like(username, 张) .lt(age, 30) .orderByDesc(create_time); ListUser users userMapper.selectList(queryWrapper); // Lambda方式 LambdaQueryWrapperUser lambdaQuery Wrappers.lambdaQuery(); lambdaQuery.like(User::getUsername, 张) .lt(User::getAge, 30) .orderByDesc(User::getCreateTime); ListUser users userMapper.selectList(lambdaQuery);5.4 高级特性5.4.1 分页查询配置分页插件Configuration public class MyBatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }使用分页GetMapping(/users) public PageUser getUsersByPage( RequestParam(defaultValue 1) int pageNum, RequestParam(defaultValue 10) int pageSize) { PageUser page new Page(pageNum, pageSize); return userMapper.selectPage(page, null); }5.4.2 逻辑删除配置application.propertiesmybatis-plus.global-config.db-config.logic-delete-fielddeleted mybatis-plus.global-config.db-config.logic-delete-value1 mybatis-plus.global-config.db-config.logic-not-delete-value0实体类添加注解TableLogic private Integer deleted;删除操作会自动变为更新userMapper.deleteById(1L); // 实际执行: UPDATE user SET deleted1 WHERE id1 AND deleted05.4.3 自动填充实体类标记需要填充的字段TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime;实现MetaObjectHandlerComponent public class MyMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, updateTime, LocalDateTime.class, LocalDateTime.now()); } }经验分享MyBatis-Plus虽然强大但复杂查询仍建议使用XML或注解方式实现。对于关联查询可以考虑使用TableField(existfalse)标注非数据库字段然后手动处理关联数据。6. 项目结构与最佳实践6.1 推荐项目结构src/main/java/ └── com.example.demo ├── config/ # 配置类 ├── controller/ # 控制器 ├── service/ # 业务服务 │ ├── impl/ # 服务实现 ├── dao/ # 数据访问层 ├── entity/ # 实体类 ├── dto/ # 数据传输对象 ├── vo/ # 视图对象 ├── util/ # 工具类 ├── exception/ # 异常处理 └── DemoApplication.java # 启动类6.2 最佳实践建议分层清晰严格遵循Controller-Service-Dao分层接口与实现分离Service层定义接口impl包下放实现统一返回格式定义通用的Response对象全局异常处理使用ControllerAdvice统一处理异常参数校验使用Validated和javax.validation约束日志规范使用SLF4J记录关键操作日志配置管理不同环境使用不同配置文件application-dev.yml等API版本控制URI中体现版本如/api/v1/users6.3 常见问题解决循环依赖问题避免A依赖BB又依赖A的情况使用Lazy延迟加载重构代码提取公共逻辑到第三类事务失效场景确保方法为public自调问题同类中方法调用异常类型不正确默认只回滚RuntimeException解决方案检查Transactional配置必要时使用编程式事务性能优化建议合理使用二级缓存N1查询问题使用BatchSize或join查询解决大结果集使用分页频繁查询考虑使用Redis缓存跨域问题解决Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(*) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*) .maxAge(3600); } }7. 进阶功能与扩展7.1 缓存集成Spring Boot提供了简单的缓存抽象添加依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-cache/artifactId /dependency启用缓存SpringBootApplication EnableCaching public class DemoApplication { // ... }使用缓存Service public class UserService { Cacheable(value users, key #id) public User findById(Long id) { return userMapper.selectById(id); } CachePut(value users, key #user.id) public User save(User user) { userMapper.insert(user); return user; } CacheEvict(value users, key #id) public void deleteById(Long id) { userMapper.deleteById(id); } }7.2 定时任务启用定时任务SpringBootApplication EnableScheduling public class DemoApplication { // ... }创建定时任务Component public class ScheduledTasks { private static final Logger log LoggerFactory.getLogger(ScheduledTasks.class); Scheduled(fixedRate 5000) public void reportCurrentTime() { log.info(当前时间{}, LocalDateTime.now()); } Scheduled(cron 0 0 12 * * ?) public void dailyTask() { log.info(执行每日任务...); } }7.3 异步处理启用异步SpringBootApplication EnableAsync public class DemoApplication { // ... }使用异步方法Service public class AsyncService { Async public CompletableFutureString doTask() { // 模拟耗时操作 try { Thread.sleep(5000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return CompletableFuture.completedFuture(任务完成); } }调用异步方法GetMapping(/async) public CompletableFutureString asyncTask() { return asyncService.doTask(); }7.4 安全控制(Spring Security)添加依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-security/artifactId /dependency基础配置Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers(/, /home).permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage(/login) .permitAll() .and() .logout() .permitAll(); } Bean Override public UserDetailsService userDetailsService() { UserDetails user User.withDefaultPasswordEncoder() .username(user) .password(password) .roles(USER) .build(); return new InMemoryUserDetailsManager(user); } }提示生产环境应使用更安全的方式存储密码如BCryptPasswordEncoder并考虑使用JWT等无状态认证方式。8. 项目打包与部署8.1 打包Spring Boot应用使用Maven打包mvn clean package打包结果普通JAR包含项目代码依赖需要单独配置可执行JAR默认包含所有依赖可直接运行8.2 运行应用直接运行JARjava -jar your-application.jar指定配置文件java -jar your-application.jar --spring.profiles.activeprod自定义JVM参数java -Xms256m -Xmx1024m -jar your-application.jar8.3 生产环境建议监控与管理添加Spring Boot Actuator依赖配置适当的健康检查和指标收集性能调优合理设置JVM内存参数根据硬件配置调整线程池大小启用GZIP压缩部署方式直接运行JAR适合小型应用部署到Tomcat等Servlet容器使用Docker容器化部署Docker部署示例FROM openjdk:17-jdk-slim VOLUME /tmp COPY target/*.jar app.jar ENTRYPOINT [java,-jar,/app.jar]构建并运行docker build -t springboot-app . docker run -d -p 8080:8080 --name myapp springboot-app9. 开发工具与实用技巧9.1 开发工具推荐IDEIntelliJ IDEAUltimate版最佳Eclipse with Spring Tools SuiteVS Code with Java扩展API测试PostmanInsomniaSwagger UI数据库工具DBeaverDataGripMySQL Workbench其他工具Lombok减少样板代码MapStruct对象映射JUnit 5单元测试9.2 实用技巧快速创建REST控制器 在IntelliJ中可以右键点击类名 - New - REST Controller快速生成模板代码属性提示 在application.properties中输入spring.会触发自动补全显示所有可用配置条件化Bean 使用Conditional系列注解根据条件创建Bean如Bean ConditionalOnProperty(name feature.enabled, havingValue true) public FeatureService featureService() { return new FeatureServiceImpl(); }环境感知配置Value(${app.timeout:30}) // 默认值30 private int timeout; Autowired private Environment env; public void someMethod() { String value env.getProperty(some.key); }配置元数据 创建META-INF/spring-configuration-metadata.json文件可以为自定义属性添加文档和提示9.3 测试策略单元测试SpringBootTest class UserServiceTest { Autowired private UserService userService; Test void testFindById() { User user userService.findById(1L); assertNotNull(user); } }Mock测试ExtendWith(MockitoExtension.class) class UserServiceUnitTest { Mock private UserRepository userRepository; InjectMocks private UserService userService; Test void testFindById() { when(userRepository.findById(1L)).thenReturn(Optional.of(new User())); User user userService.findById(1L); assertNotNull(user); } }Web层测试SpringBootTest(webEnvironment WebEnvironment.RANDOM_PORT) class UserControllerTest { LocalServerPort private int port; Autowired private TestRestTemplate restTemplate; Test void testGetUser() { ResponseEntityUser response restTemplate.getForEntity( http://localhost: port /api/users/1, User.class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } }测试切片WebMvcTest只测试Web层DataJpaTest只测试JPA组件JsonTest只测试JSON序列化10. 性能优化与问题排查10.1 性能监控添加Actuator依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency配置application.propertiesmanagement.endpoints.web.exposure.includehealth,info,metrics,prometheus management.metrics.export.prometheus.enabledtrue常用监控端点/actuator/health应用健康状态/actuator/metrics性能指标/actuator/prometheusPrometheus格式指标10.2 常见性能问题数据库连接池配置spring.datasource.druid.initial-size5 spring.datasource.druid.min-idle5 spring.datasource.druid.max-active20 spring.datasource.druid.max-wait60000 spring.datasource.druid.time-between-eviction-runs-millis60000 spring.datasource.druid.min-evictable-idle-time-millis300000 spring.datasource.druid.test-while-idletrue spring.datasource.druid.test-on-borrowfalse spring.datasource.druid.test-on
返回列表