diff --git a/2-x-spring-boot-webflux-handling-errors/pom.xml b/2-x-spring-boot-webflux-handling-errors/pom.xml new file mode 100755 index 00000000..aadde204 --- /dev/null +++ b/2-x-spring-boot-webflux-handling-errors/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + springboot + 2-x-spring-boot-webflux-handling-errors + 0.0.1-SNAPSHOT + 2-x-spring-boot-webflux-handling-errors + + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/Application.java b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/Application.java new file mode 100644 index 00000000..347d4525 --- /dev/null +++ b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/Application.java @@ -0,0 +1,20 @@ +package org.spring.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Spring Boot 应用启动类 + * + */ +// Spring Boot 应用的标识 +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + // 程序启动入口 + // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件 + SpringApplication.run(Application.class,args); + + } +} diff --git a/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalErrorAttributes.java b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalErrorAttributes.java new file mode 100644 index 00000000..c8f7158e --- /dev/null +++ b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalErrorAttributes.java @@ -0,0 +1,32 @@ +package org.spring.springboot.error; + +import org.springframework.boot.web.reactive.error.DefaultErrorAttributes; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.ServerRequest; + +import java.util.Map; + +@Component +public class GlobalErrorAttributes extends DefaultErrorAttributes { + + @Override + public Map getErrorAttributes(ServerRequest request, boolean includeStackTrace) { + Map map = super.getErrorAttributes(request, includeStackTrace); + + if (getError(request) instanceof GlobalException) { + GlobalException ex = (GlobalException) getError(request); + map.put("exception", ex.getClass().getSimpleName()); + map.put("message", ex.getMessage()); + map.put("status", ex.getStatus().value()); + map.put("error", ex.getStatus().getReasonPhrase()); + + return map; + } + + map.put("exception", "SystemException"); + map.put("message", "System Error , Check logs!"); + map.put("status", "500"); + map.put("error", " System Error "); + return map; + } +} diff --git a/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalErrorWebExceptionHandler.java b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalErrorWebExceptionHandler.java new file mode 100644 index 00000000..32e68649 --- /dev/null +++ b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalErrorWebExceptionHandler.java @@ -0,0 +1,47 @@ +package org.spring.springboot.error; + +import org.springframework.boot.autoconfigure.web.ResourceProperties; +import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler; +import org.springframework.boot.web.reactive.error.ErrorAttributes; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.RequestPredicates; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +import java.util.Map; + +@Component +@Order(-2) +public class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler { + + public GlobalErrorWebExceptionHandler(GlobalErrorAttributes g, ApplicationContext applicationContext, + ServerCodecConfigurer serverCodecConfigurer) { + super(g, new ResourceProperties(), applicationContext); + super.setMessageWriters(serverCodecConfigurer.getWriters()); + super.setMessageReaders(serverCodecConfigurer.getReaders()); + } + + @Override + protected RouterFunction getRoutingFunction(final ErrorAttributes errorAttributes) { + return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse); + } + + private Mono renderErrorResponse(final ServerRequest request) { + + final Map errorPropertiesMap = getErrorAttributes(request, false); + + return ServerResponse.status(HttpStatus.BAD_REQUEST) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .body(BodyInserters.fromObject(errorPropertiesMap)); + } + +} diff --git a/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalException.java b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalException.java new file mode 100644 index 00000000..e5e300b6 --- /dev/null +++ b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalException.java @@ -0,0 +1,15 @@ +package org.spring.springboot.error; + +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ResponseStatusException; + +public class GlobalException extends ResponseStatusException { + + public GlobalException(HttpStatus status, String message) { + super(status, message); + } + + public GlobalException(HttpStatus status, String message, Throwable e) { + super(status, message, e); + } +} diff --git a/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/handler/CityHandler.java b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/handler/CityHandler.java new file mode 100644 index 00000000..56d02976 --- /dev/null +++ b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/handler/CityHandler.java @@ -0,0 +1,27 @@ +package org.spring.springboot.handler; + +import org.spring.springboot.error.GlobalException; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +import java.util.Optional; + +@Component +public class CityHandler { + + public Mono helloCity(ServerRequest request) { + return ServerResponse.ok().body(sayHelloCity(request), String.class); + } + + private Mono sayHelloCity(ServerRequest request) { + Optional cityParamOptional = request.queryParam("city"); + if (!cityParamOptional.isPresent()) { + throw new GlobalException(HttpStatus.INTERNAL_SERVER_ERROR, "request param city is ERROR"); + } + + return Mono.just("Hello," + cityParamOptional.get()); + } +} diff --git a/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/router/CityRouter.java b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/router/CityRouter.java new file mode 100644 index 00000000..0cef9af2 --- /dev/null +++ b/2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/router/CityRouter.java @@ -0,0 +1,20 @@ +package org.spring.springboot.router; + +import org.spring.springboot.handler.CityHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.server.RequestPredicates; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; + +@Configuration +public class CityRouter { + + @Bean + public RouterFunction routeCity(CityHandler cityHandler) { + return RouterFunctions.route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), cityHandler::helloCity); + } + +} diff --git a/2-x-spring-boot-webflux-handling-errors/src/main/resources/application.properties b/2-x-spring-boot-webflux-handling-errors/src/main/resources/application.properties new file mode 100644 index 00000000..e69de29b diff --git a/README.md b/README.md index cc17360c..2252e500 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,116 @@ -# springboot-learning-example -spring boot 实践学习案例,是 spring boot 初学者及核心技术巩固的最佳实践。 - -# 推荐 -由于工作原因,我发表原创博客也需要编写的时间。期间很多人私我问题,没有及时得到回复,这里说声抱歉。因此,建一个星球 - -「泥瓦匠BYSocket」和朋友们讨论技术相关的话题,你一起来吧? - -[泥瓦匠BYSocket 星球](https://t.zsxq.com/nMzjqbe "泥瓦匠BYSocket") - -[泥瓦匠BYSocket 星球](https://t.zsxq.com/nMzjqbe "泥瓦匠BYSocket") - -[泥瓦匠BYSocket 星球](https://t.zsxq.com/nMzjqbe "泥瓦匠BYSocket") - -这个星球里面讲深入讨论 Java 、Java EE、Spring Boot 等框架技术及工作经验交流,分享一路技术走来的经验、教训。硬实力软实力、择业、职业规划等。 - -## 计划 -Spring Boot 2.0 最大的热点肯定是 Web Flux。我这边也就开始操刀了... - -Web Flux 努力进行中,尽情期待。唯一文章入口:[GitChat文章地址](http://gitbook.cn/gitchat/author/58968d35f2b669527d7a7c57 "gitchat") - -## Spring For All 社区 -[Spring For All 社区](http://www.spring4all.com/ "spring4all")是新组建的关于 Spring 的纯技术交流社区(涵盖 Spring Boot、Spring Cloud 等内容),集诸多开源爱好者和技术大牛贡献内容和交流问题。我们不夸大、不装逼、做最纯粹的技术分享!!! - -看看我们超强的群众基础,欢迎有兴趣的朋友加入QQ群分享与交流:[点击立即加入](http://www.spring4all.com/about "about") - -## 作者与学习乐园 -源码地址:我的[GitHub地址](https://github.com/JeffLi1993 "GitHub")、[OSCGit地址](https://git.oschina.net/jeff1993/springboot-learning-example "OSCGit")
-作者:[泥瓦匠BYSocket](http://www.bysocket.com/ "泥瓦匠BYSocket")
-关注微信公众号【泥瓦匠BYSokcet】,及时得到技术文章推送
-![公众号](http://www.bysocket.com/wp-content/uploads/2017/01/qrcode_for_gh_cd421e7eb7d6_430.jpg) - -## 一、项目结构 -「Spring Boot 那些事」:[传送门](http://www.bysocket.com/?page_id=1639 "Spring Boot 那些事")
- -### 『 WebFlux 篇 』 - -WebFlux 系类文章入口:[GitChat文章地址](http://gitbook.cn/gitchat/author/58968d35f2b669527d7a7c57 "gitchat") - -- springboot-webflux
-Spring Boot WebFlux 实现 Restful 服务 - - -#### a. 『 基础 - 入门篇 』 -- springboot-helloworld
- [《Spring Boot 之 HelloWorld 详解》](http://www.bysocket.com/?p=1124 "Spring Boot 之 HelloWorld详解")
-- springboot-properties
- [《Spring Boot 之配置文件详解》](http://www.bysocket.com/?p=1786 "Spring Boot 之配置文件详解")
- -#### b. 『 基础 - Web 业务开发篇 』 -- springboot-restful
- [《Springboot 实现 Restful 服务,基于 HTTP / JSON 传输》](http://www.bysocket.com/?p=1627 "Springboot 实现 Restful 服务,基于 HTTP / JSON 传输")
- [《Spring Boot 之 RESRful API 权限控制》](http://www.bysocket.com/?p=1080 "Spring Boot 之 RESRful API 权限控制")
-- springboot-freemarker
-[《Spring Boot 集成 FreeMarker 详解案例》](http://www.bysocket.com/?p=1666 "Spring Boot 集成 FreeMarker 详解案例")
-- springboot-validation-over-json -[《Spring Boot HTTP over JSON 的错误码异常处理》](http://www.bysocket.com/?p=1692 "Spring Boot HTTP over JSON 的错误码异常处理")
- - -#### c. 『 基础 – 数据存储篇 』 -- springboot-mybatis
- [《Springboot 整合 Mybatis 的完整 Web 案例》](http://www.bysocket.com/?p=1610 "Springboot 整合 Mybatis 的完整 Web 案例")
-- springboot-mybatis-annotation
- [《Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例》](http://www.bysocket.com/?p=1811 "Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例")
-- springboot-mybatis-mutil-datasource
- [《Spring Boot 整合 Mybatis 实现 Druid 多数据源详解》](http://www.bysocket.com/?p=1712 "Spring Boot 整合 Mybatis 实现 Druid 多数据源详解")
- - -#### d. 『 基础 – 数据缓存篇 』 -- springboot-mybatis-redis
- [《Spring Boot 整合 Redis 实现缓存操作》](http://www.bysocket.com/?p=1756 "Spring Boot 整合 Mybatis 实现 Druid 多数据源详解")
-- springboot-mybatis-redis-annotation
- [《Spring Boot 注解实现整合 Redis 作为缓存》](http://www.bysocket.com/?p=1756 "Spring Boot 整合 Mybatis 实现 Druid 多数据源详解")
- -#### e. 『 其他篇 』 -- springboot-elasticsearch
- [《Spring Boot 整合 Elasticsearch,实现 function score query 权重分查询》](http://www.bysocket.com/?p=1829 "Spring Boot 整合 Elasticsearch,实现 function score query 权重分查询")
-- springboot-dubbo-server
-- springboot-dubbo-client
-Dubbo 服务提供者工程和 Dubbo 服务消费者工程
- [《Springboot 整合 Dubbo/ZooKeeper 详解 SOA 案例》](http://www.bysocket.com/?p=1681 "Springboot 整合 Dubbo/ZooKeeper 详解 SOA 案例")
- [《Spring Boot 中如何使用 Dubbo Activate 扩展点》](http://www.bysocket.com/?p=1782 "Spring Boot 中如何使用 Dubbo Activate 扩展点")
- - -#### 『 Spring Data ES 篇 』 -- spring-data-elasticsearch-crud
- [《Spring Data Elasticsearch - 基本案例》](http://spring4all.com/article/70 "Spring Data Elasticsearch - 基本案例")
-- spring-data-elasticsearch-query
-spring-data-elasticsearch - 实战案例详解 - -最后,
- - [《Spring Boot教程与Spring Cloud教程》](https://git.oschina.net/didispace/SpringBoot-Learning "Spring Boot教程与Spring Cloud教程")
+### 谢谢赞助的ta们 + + + + + + + +
+ + + + + + + +
+ +**Spring Boot 2.x 系列教程**,spring boot 实践学习案例,是初学者及核心技术巩固的最佳实践。 + +### 一、支持泥瓦匠(了解泥瓦匠:[《泥瓦匠想做一个与众不同的技术"匠" 》](http://t.cn/EazOqCY) http://t.cn/EazOqCY) +1. 拿起微信,关注公众号:「泥瓦匠BYSocket 」。添加我微信:bysocket01,加入纯技术交流群,成长技术 +2. 给教程的开源代码仓库点个 **Star** 吧 + - [GitHub(springboot-learning-example)](https://github.com/JeffLi1993/springboot-learning-example "GitHub(springboot-learning-example)") + - [Gitee(springboot-learning-example)](https://gitee.com/jeff1993/springboot-learning-example "Gitee(springboot-learning-example)") +3. 帮忙分享该系列文章链接给更多的朋友 + +> 如果您对文字类教程不感冒或者想要通过综合案例学习Spring,那么给您推荐这个我觉得目前内容与价格最良心的视频课程:[“玩转Spring全家桶”](https://time.geekbang.org/course/intro/156?code=zqaEuXYpWbKaPeBaJc8GVoYCUHvoGhTlQQ7QZYoWWdI%3D&utm_term=zeusDUJ0V&utm_source=website&utm_medium=bysocket "“玩转Spring全家桶”") + +### 二、系列文章目录 + +#### 『 Spring Boot 2.x 系列教程篇 』 +- [Spring Boot 2.x 系列教程:WebFlux REST API 全局异常处理 Error Handling](https://www.bysocket.com/archives/2272/spring-boot-2-x-%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B%EF%BC%9Awebflux-rest-api-%E5%85%A8%E5%B1%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86-error-handling) +- [Spring Boot 2.x 系列教程:WebFlux 系列教程大纲(一)](https://www.bysocket.com/archives/2290/spring-boot-2-x-%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B%EF%BC%9Awebflux-%E7%B3%BB%E5%88%97%E6%95%99%E7%A8%8B%E5%A4%A7%E7%BA%B2%EF%BC%88%E4%B8%80%EF%BC%89) + +#### 『 基础 - 入门篇 』 +- [Spring Boot 2.0 配置图文教程](https://www.bysocket.com/archives/2135) +- [Spring Boot 2.0 的快速入门(图文教程)](https://www.bysocket.com/archives/2119) +- [Spring Boot 之 HelloWorld 详解](http://www.bysocket.com/?p=1124) +- [Spring Boot 之配置文件详解](http://www.bysocket.com/?p=1786) + +#### 『 基础 - Web 业务开发篇 』 +- [Spring Boot Web 开发注解篇](http://www.bysocket.com/?p=1929) +- [Spring Boot 表单验证篇](http://www.bysocket.com/?p=1942) +- [Spring Boot 2.x 小新功能 – Spring Data Web configuration](http://www.bysocket.com/?p=1950) +- [Spring Boot 实现 Restful 服务,基于 HTTP / JSON 传输](http://www.bysocket.com/?p=1627) +- [Spring Boot 之 RESRful API 权限控制](http://www.bysocket.com/?p=1080) +- [Spring Boot 集成 FreeMarker](http://www.bysocket.com/?p=1666) +- [Spring Boot HTTP over JSON 的错误码异常处理](http://www.bysocket.com/?p=1692) +- Spring Boot 使用 Swagger2 构建 RESRful API 文档 +- Spring Boot 集成 JSP +- Spring Boot 集成 Thymeleaf +- Spring Boot 单元测试的使用 +- Spring Boot 热更新部署 + +#### 『 基础 – 数据存储篇 』 +- [Spring Boot 整合 Mybatis 的完整 Web 案例](http://www.bysocket.com/?p=1610) +- [Spring Boot 整合 Mybatis Annotation 注解案例](http://www.bysocket.com/?p=1811) +- [Spring Boot 整合 Mybatis 实现 Druid 多数据源配置](http://www.bysocket.com/?p=1712) +- Spring Boot 整合使用 JdbcTemplate +- Spring Boot 整合 Spring-data-jpa +- Spring Boot 声明式事务管理 + +#### 『 基础 – 数据缓存篇 』 +- [Spring Boot 整合 Redis 实现缓存操作](http://www.bysocket.com/?p=1756) +- Spring Boot 整合 Redis Annotation 实现缓存操作 +- Spring Boot 整合 MongoDB 实现缓存操作 +- Spring Boot 整合 EhCache 实现缓存操作 + +#### 『 基础 – 日志管理篇 』 +- Spring Boot 默认日志 logback 配置解析 +- Spring Boot 使用 log4j 记录日志 +- Spring Boot 对 log4j 进行多环境不同日志级别的控制 +- Spring Boot 使用 log4j 记录日志到 MongoDB +- Spring Boot 1.5.x 动态修改日志级别 + +#### 『 基础 – 应用篇 』 +- Spring Boot Actuator 监控 +- Spring Boot Web 应用部署 + +#### 『 提升 – 安全控制及权限篇 』 +- Spring Boot 整合 Spring Security +- Spring Boot 整合 Shiro +- Spring Boot 整合 Spring Session + +#### 『 提升 – 中间件篇 』 +- [Spring Boot 2.x :通过 spring-boot-starter-hbase 集成 HBase](https://www.bysocket.com/archives/2162) +- Spring Boot 整合 RabbitMQ +- Spring Boot 整合 Quartz + +#### 『 提升 – 源码篇 』 +- Spring Boot 启动原理解析 + +#### 『 Elasticsearch 篇 』 +- [Spring Boot 整合 Elasticsearch](http://www.bysocket.com/?p=1829) +- [深入浅出 spring-data-elasticsearch 之 ElasticSearch 架构初探(一)](http://www.bysocket.com/?p=1889) +- [深入浅出 spring-data-elasticsearch 系列 – 概述及入门(二)](http://www.bysocket.com/?p=1894) +- [深入浅出 spring-data-elasticsearch – 基本案例详解(三)](http://www.bysocket.com/?p=1899) +- [深入浅出 spring-data-elasticsearch – 实战案例详解(四)](http://www.bysocket.com/?p=1902) + +#### 『 Dubbo 篇 』 +- [Spring Boot 整合 Dubbo/ZooKeeper 详解 SOA 案例](http://www.bysocket.com/?p=1681) +- [Spring Boot 中如何使用 Dubbo Activate 扩展点](http://www.bysocket.com/?p=1782) +- [Spring Boot Dubbo applications.properties 配置清单](http://www.bysocket.com/?p=1805) + +### 三、最后推荐 + +- [我的博客](http://www.bysocket.com "我的博客"):分享学习可落地的技术博文 +- [我的GitHub](https://github.com/JeffLi1993 "我的GitHub"):Follow 下呗 +- [我的Gitee](https://gitee.com/jeff1993 "我的Gitee"):Follow 下呗 +- [Spring问答社区](http://www.spring4all.com/ "Spring问答社区"):如果您有什么问题,可以去这里发帖 + +### 四、我的公号 +关注微信公众号,领取 Java 精选干货学习资料 + + diff --git a/chapter-1-spring-boot-quickstart/pom.xml b/chapter-1-spring-boot-quickstart/pom.xml index b709729a..7e47fc49 100644 --- a/chapter-1-spring-boot-quickstart/pom.xml +++ b/chapter-1-spring-boot-quickstart/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/chapter-1-spring-boot-quickstart/src/main/resources/application.properties b/chapter-1-spring-boot-quickstart/src/main/resources/application.properties index e69de29b..aba2a536 100644 --- a/chapter-1-spring-boot-quickstart/src/main/resources/application.properties +++ b/chapter-1-spring-boot-quickstart/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=-1 \ No newline at end of file diff --git a/chapter-1-spring-boot-quickstart/src/test/java/demo/springboot/QuickStartApplicationTests.java b/chapter-1-spring-boot-quickstart/src/test/java/demo/springboot/QuickStartApplicationTests.java index 5220ed5c..124f83be 100644 --- a/chapter-1-spring-boot-quickstart/src/test/java/demo/springboot/QuickStartApplicationTests.java +++ b/chapter-1-spring-boot-quickstart/src/test/java/demo/springboot/QuickStartApplicationTests.java @@ -1,16 +1,38 @@ package demo.springboot; + import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringRunner.class) -@SpringBootTest +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = QuickStartApplication.class) +@AutoConfigureMockMvc +@TestPropertySource(locations = "classpath:application.properties") public class QuickStartApplicationTests { - @Test - public void contextLoads() { - } + @Autowired + private MockMvc mvc; + + + @Test + public void requestHello_thenStatus200_and_outputHello() throws Exception { + mvc.perform(get("/hello") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_PLAIN)) + .andExpect(content().encoding("UTF-8")) + .andExpect(content().string("Hello,Spring Boot!")); + } } diff --git a/chapter-1-spring-boot-quickstart/src/test/resources/application.properties b/chapter-1-spring-boot-quickstart/src/test/resources/application.properties new file mode 100644 index 00000000..aba2a536 --- /dev/null +++ b/chapter-1-spring-boot-quickstart/src/test/resources/application.properties @@ -0,0 +1 @@ +server.port=-1 \ No newline at end of file diff --git a/chapter-2-spring-boot-config/pom.xml b/chapter-2-spring-boot-config/pom.xml index cc088fc9..e24ffdee 100644 --- a/chapter-2-spring-boot-config/pom.xml +++ b/chapter-2-spring-boot-config/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.1.3.RELEASE @@ -52,7 +52,7 @@ org.springframework.boot spring-boot-maven-plugin - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/chapter-3-spring-boot-web/pom.xml b/chapter-3-spring-boot-web/pom.xml index b40d56f2..780e9ea5 100644 --- a/chapter-3-spring-boot-web/pom.xml +++ b/chapter-3-spring-boot-web/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.1.3.RELEASE diff --git a/chapter-3-spring-boot-web/src/main/java/demo/springboot/domain/Book.java b/chapter-3-spring-boot-web/src/main/java/demo/springboot/domain/Book.java index 29dda95a..3102a87b 100644 --- a/chapter-3-spring-boot-web/src/main/java/demo/springboot/domain/Book.java +++ b/chapter-3-spring-boot-web/src/main/java/demo/springboot/domain/Book.java @@ -60,4 +60,23 @@ public String getIntroduction() { public void setIntroduction(String introduction) { this.introduction = introduction; } + + public Book(Long id, String name, String writer, String introduction) { + this.id = id; + this.name = name; + this.writer = writer; + this.introduction = introduction; + } + + public Book(Long id, String name) { + this.id = id; + this.name = name; + } + + public Book(String name) { + this.name = name; + } + + public Book() { + } } diff --git a/chapter-3-spring-boot-web/src/main/java/demo/springboot/service/BookService.java b/chapter-3-spring-boot-web/src/main/java/demo/springboot/service/BookService.java index 8fb63d13..cd895d72 100644 --- a/chapter-3-spring-boot-web/src/main/java/demo/springboot/service/BookService.java +++ b/chapter-3-spring-boot-web/src/main/java/demo/springboot/service/BookService.java @@ -42,4 +42,18 @@ public interface BookService { * @param id 编号 */ Book findById(Long id); + + /** + * 查找书是否存在 + * @param book + * @return + */ + boolean exists(Book book); + + /** + * 根据书名获取书籍 + * @param name + * @return + */ + Book findByName(String name); } diff --git a/chapter-3-spring-boot-web/src/main/java/demo/springboot/service/impl/BookServiceImpl.java b/chapter-3-spring-boot-web/src/main/java/demo/springboot/service/impl/BookServiceImpl.java index 8d63aafc..18a5cfe4 100644 --- a/chapter-3-spring-boot-web/src/main/java/demo/springboot/service/impl/BookServiceImpl.java +++ b/chapter-3-spring-boot-web/src/main/java/demo/springboot/service/impl/BookServiceImpl.java @@ -2,24 +2,40 @@ import demo.springboot.domain.Book; import demo.springboot.service.BookService; +import demo.springboot.web.BookController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import javax.annotation.PostConstruct; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; /** * Book 业务层实现 - * + *

* Created by bysocket on 27/09/2017. */ @Service public class BookServiceImpl implements BookService { + private static final AtomicLong counter = new AtomicLong(); + + + /** + * 使用集合模拟数据库 + */ + private static List books = new ArrayList<>( + Arrays.asList( + new Book(counter.incrementAndGet(), "book"))); + + // 模拟数据库,存储 Book 信息 // 第五章《数据存储》会替换成 MySQL 存储 - private static Map BOOK_DB = new HashMap<>(); + private static Map BOOK_DB = new HashMap<>(); @Override public List findAll() { @@ -29,23 +45,40 @@ public List findAll() { @Override public Book insertByBook(Book book) { book.setId(BOOK_DB.size() + 1L); - BOOK_DB.put(book.getId(), book); + BOOK_DB.put(book.getId().toString(), book); return book; } @Override public Book update(Book book) { - BOOK_DB.put(book.getId(), book); + BOOK_DB.put(book.getId().toString(), book); return book; } @Override public Book delete(Long id) { - return BOOK_DB.remove(id); + return BOOK_DB.remove(id.toString()); } @Override public Book findById(Long id) { - return BOOK_DB.get(id); + return BOOK_DB.get(id.toString()); + } + + @Override + public boolean exists(Book book) { + return findByName(book.getName()) != null; + } + + @Override + public Book findByName(String name) { + + for (Book book : books) { + if (book.getName().equals(name)) { + return book; + } + } + + return null; } } diff --git a/chapter-3-spring-boot-web/src/main/java/demo/springboot/web/BookController.java b/chapter-3-spring-boot-web/src/main/java/demo/springboot/web/BookController.java index 3f852496..d9069a34 100644 --- a/chapter-3-spring-boot-web/src/main/java/demo/springboot/web/BookController.java +++ b/chapter-3-spring-boot-web/src/main/java/demo/springboot/web/BookController.java @@ -2,8 +2,14 @@ import demo.springboot.domain.Book; import demo.springboot.service.BookService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.util.UriComponentsBuilder; import java.util.List; @@ -16,6 +22,10 @@ @RequestMapping(value = "/book") public class BookController { + + private final Logger LOG = LoggerFactory.getLogger(BookController.class); + + @Autowired BookService bookService; @@ -43,8 +53,20 @@ public Book getBook(@PathVariable Long id) { * 通过 @RequestBody 绑定实体参数,也通过 @RequestParam 传递参数 */ @RequestMapping(value = "/create", method = RequestMethod.POST) - public Book postBook(@RequestBody Book book) { - return bookService.insertByBook(book); + public ResponseEntity postBook(@RequestBody Book book, UriComponentsBuilder ucBuilder) { + + LOG.info("creating new book: {}", book); + + if (book.getName().equals("conflict")){ + LOG.info("a book with name " + book.getName() + " already exists"); + return new ResponseEntity<>(HttpStatus.CONFLICT); + } + + bookService.insertByBook(book); + + HttpHeaders headers = new HttpHeaders(); + headers.setLocation(ucBuilder.path("/book/{id}").buildAndExpand(book.getId()).toUri()); + return new ResponseEntity<>(headers, HttpStatus.CREATED); } /** diff --git a/chapter-3-spring-boot-web/src/test/java/demo/springboot/web/BookControllerTest.java b/chapter-3-spring-boot-web/src/test/java/demo/springboot/web/BookControllerTest.java new file mode 100644 index 00000000..2344ee1d --- /dev/null +++ b/chapter-3-spring-boot-web/src/test/java/demo/springboot/web/BookControllerTest.java @@ -0,0 +1,198 @@ +package demo.springboot.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import demo.springboot.WebApplication; +import demo.springboot.domain.Book; +import demo.springboot.service.BookService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebApplication.class) +@AutoConfigureMockMvc +@TestPropertySource(locations = "classpath:application.properties") +public class BookControllerTest { + + private MockMvc mockMvc; + + @Mock + private BookService bookService; + + @InjectMocks + private BookController bookController; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + mockMvc = MockMvcBuilders + .standaloneSetup(bookController) + //.addFilters(new CORSFilter()) + .build(); + } + + + @Test + public void getBookList() throws Exception { + mockMvc.perform(get("/book") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON_UTF8)) + .andExpect(jsonPath("$", hasSize(0))); + + } + + + @Test + public void test_create_book_success() throws Exception { + + Book book = createOneBook(); + + when(bookService.insertByBook(book)).thenReturn(book); + + mockMvc.perform( + post("/book/create") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(book))) + + .andExpect(status().isCreated()) + .andExpect(header().string("location", containsString("/book/1"))); + } + + + @Test + public void test_create_book_fail_404_not_found() throws Exception { + + Book book = new Book(99L, "conflict"); + + when(bookService.exists(book)).thenReturn(true); + + mockMvc.perform( + post("/book/create") + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(book))) + .andExpect(status().isConflict()); + } + + @Test + public void test_get_book_success() throws Exception { + + Book book = new Book(1L, "测试获取一本书", "strongant作者", "社区 www.spring4all.com 出版社出版"); + + when(bookService.findById(1L)).thenReturn(book); + + mockMvc.perform(get("/book/{id}", 1L)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .andExpect(jsonPath("$.id", is(1))) + .andExpect(jsonPath("$.name", is("测试获取一本书"))); + + verify(bookService, times(1)).findById(1L); + verifyNoMoreInteractions(bookService); + } + + @Test + public void test_get_by_id_fail_null_not_found() throws Exception { + when(bookService.findById(1L)).thenReturn(null); + + //TODO: 查找不到应该抛出 404 状态码, Demo 待优化 + mockMvc.perform(get("/book/{id}", 1L)) + .andExpect(status().isOk()) + .andExpect(content().string("")); + + verify(bookService, times(1)).findById(1L); + verifyNoMoreInteractions(bookService); + } + + @Test + public void test_update_book_success() throws Exception { + + Book book = createOneBook(); + + when(bookService.findById(book.getId())).thenReturn(book); + doReturn(book).when(bookService).update(book); + + mockMvc.perform( + put("/book/update", book) + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(book))) + .andExpect(status().isOk()); + } + + @Test + public void test_update_book_fail_not_found() throws Exception { + Book book = new Book(999L, "测试书名1"); + + when(bookService.findById(book.getId())).thenReturn(null); + + mockMvc.perform( + put("/book/update", book) + .contentType(MediaType.APPLICATION_JSON) + .content(asJsonString(book))) + .andExpect(status().isOk()) + .andExpect(content().string("")); + } + + // =========================================== Delete Book ============================================ + + @Test + public void test_delete_book_success() throws Exception { + + Book book = new Book(1L, "这本书会被删除啦"); + + when(bookService.findById(book.getId())).thenReturn(book); + doReturn(book).when(bookService).delete(book.getId()); + + mockMvc.perform( + delete("/book/delete/{id}", book.getId()) + ).andExpect(status().isOk()); + } + + @Test + public void test_delete_book_fail_404_not_found() throws Exception { + Book book = new Book(1L, "这本书会被删除啦"); + + when(bookService.findById(book.getId())).thenReturn(null); + + mockMvc.perform( + delete("/book/delete/{id}", book.getId())) + .andExpect(status().isOk()); + } + + + public static String asJsonString(final Object obj) { + try { + final ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(obj); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private Book createOneBook() { + Book book = new Book(); + book.setId(1L); + book.setName("测试书名1"); + book.setIntroduction("这是一本 www.spring4all.com 社区出版的很不错的一本书籍"); + book.setWriter("strongant"); + return book; + } +} \ No newline at end of file diff --git a/chapter-3-spring-boot-web/src/test/resources/application.properties b/chapter-3-spring-boot-web/src/test/resources/application.properties new file mode 100644 index 00000000..5ff02851 --- /dev/null +++ b/chapter-3-spring-boot-web/src/test/resources/application.properties @@ -0,0 +1 @@ +server.port=9090 \ No newline at end of file diff --git a/chapter-4-spring-boot-validating-form-input/pom.xml b/chapter-4-spring-boot-validating-form-input/pom.xml index 35ab84c2..ef6e6230 100644 --- a/chapter-4-spring-boot-validating-form-input/pom.xml +++ b/chapter-4-spring-boot-validating-form-input/pom.xml @@ -54,7 +54,6 @@ com.h2database h2 - runtime @@ -71,7 +70,7 @@ org.springframework.boot spring-boot-maven-plugin - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/ValidatingFormInputApplication.java b/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/ValidatingFormInputApplication.java index 1825f04f..c6cb5ac1 100644 --- a/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/ValidatingFormInputApplication.java +++ b/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/ValidatingFormInputApplication.java @@ -1,12 +1,40 @@ package spring.boot.core; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import spring.boot.core.domain.User; +import spring.boot.core.domain.UserRepository; @SpringBootApplication -public class ValidatingFormInputApplication { +public class ValidatingFormInputApplication implements CommandLineRunner { - public static void main(String[] args) { - SpringApplication.run(ValidatingFormInputApplication.class, args); - } + + private Logger LOG = LoggerFactory.getLogger(ValidatingFormInputApplication.class); + + @Autowired + private UserRepository userRepository; + + public static void main(String[] args) { + SpringApplication.run(ValidatingFormInputApplication.class, args); + } + + @Override + public void run(String... args) throws Exception { + User user1 = new User("Sergey", 24, "1994-01-01"); + User user2 = new User("Ivan", 26, "1994-01-01"); + User user3 = new User("Adam", 31, "1994-01-01"); + LOG.info("Inserting data in DB."); + userRepository.save(user1); + userRepository.save(user2); + userRepository.save(user3); + LOG.info("User count in DB: {}", userRepository.count()); + LOG.info("User with ID 1: {}", userRepository.findById(1L)); + LOG.info("Deleting user with ID 2L form DB."); + userRepository.deleteById(2L); + LOG.info("User count in DB: {}", userRepository.count()); + } } diff --git a/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/domain/User.java b/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/domain/User.java index 535d3a58..45d4aaf4 100644 --- a/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/domain/User.java +++ b/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/domain/User.java @@ -79,6 +79,15 @@ public void setBirthday(String birthday) { this.birthday = birthday; } + + public User(String name, Integer age, String birthday) { + this.name = name; + this.age = age; + this.birthday = birthday; + } + + public User() {} + @Override public String toString() { return "User{" + diff --git a/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/web/UserController.java b/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/web/UserController.java index 3eb0360a..8a51c844 100644 --- a/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/web/UserController.java +++ b/chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/web/UserController.java @@ -103,7 +103,7 @@ public String putUser(ModelMap map, /** * 处理 "/users/{id}" 的 GET 请求,用来删除 User 信息 */ - @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) + @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE) public String deleteUser(@PathVariable Long id) { userService.delete(id); diff --git a/chapter-4-spring-boot-validating-form-input/src/main/resources/application.properties b/chapter-4-spring-boot-validating-form-input/src/main/resources/application.properties index 51350c65..1a47991d 100644 --- a/chapter-4-spring-boot-validating-form-input/src/main/resources/application.properties +++ b/chapter-4-spring-boot-validating-form-input/src/main/resources/application.properties @@ -1,2 +1,15 @@ +## 开启 H2 数据库 +spring.h2.console.enabled=true + +## 配置 H2 数据库连接信息 +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + + + ## 是否显示 SQL 语句 -spring.jpa.show-sql=true \ No newline at end of file +spring.jpa.show-sql=true +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.hbm2ddl.auto=create diff --git a/chapter-4-spring-boot-validating-form-input/src/test/java/spring/boot/core/web/UserControllerTest.java b/chapter-4-spring-boot-validating-form-input/src/test/java/spring/boot/core/web/UserControllerTest.java new file mode 100644 index 00000000..08e9af7e --- /dev/null +++ b/chapter-4-spring-boot-validating-form-input/src/test/java/spring/boot/core/web/UserControllerTest.java @@ -0,0 +1,159 @@ +package spring.boot.core.web; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import spring.boot.core.ValidatingFormInputApplication; +import spring.boot.core.domain.User; +import spring.boot.core.service.UserService; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; + +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.beans.HasPropertyWithValue.hasProperty; +import static org.junit.Assert.assertEquals; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ValidatingFormInputApplication.class) +@AutoConfigureMockMvc +@TestPropertySource(locations = "classpath:application.properties") +public class UserControllerTest { + + + @Autowired + private MockMvc mockMvc; + + @Autowired + private UserService userService; + + @Autowired + private ObjectMapper objectMapper; + + @Test + public void getUserList() throws Exception { + mockMvc.perform(get("/users")) + .andExpect(view().name("userList")) + .andExpect(status().isOk()) + .andDo(print()); + } + + private User createUser() { + User user = new User(); + user.setName("测试用户"); + user.setAge(100); + user.setBirthday("1994-01-01"); + return userService.insertByUser(user); + } + + @Test + public void createUserForm() throws Exception { + + mockMvc.perform(get("/users/create")) + .andDo(print()) + .andExpect(view().name("userForm")) + .andExpect(request().attribute("action", "create")) + .andDo(print()) + .andReturn(); + } + + @Test + public void postUser() throws Exception { + User user = createUser(); + assertNotNull(user); + + MultiValueMap parameters = new LinkedMultiValueMap(); + Map maps = objectMapper.convertValue(user, new TypeReference>() { + }); + parameters.setAll(maps); + + mockMvc.perform(post("/users/create").params(parameters)) + .andDo(print()) + .andExpect(status().is(HttpServletResponse.SC_FOUND)) + .andDo(print()) + .andExpect(view().name("redirect:/users/")) + .andDo(print()) + .andReturn(); + } + + @Test + public void getUser() throws Exception { + + MvcResult result= mockMvc.perform(get("/users/update/{id}/", 1)) + .andExpect(status().isOk()) + .andExpect(view().name("userForm")) + .andExpect(MockMvcResultMatchers.model().attributeExists("action")) + .andExpect(model().attribute("user", hasProperty("id", is(1L)))) + .andExpect(model().attribute("user", hasProperty("name", is("Sergey")))) + .andExpect(model().attribute("user", hasProperty("age", is(24)))) + .andExpect(model().attribute("user", hasProperty("birthday", is("1994-01-01")))) + .andReturn(); + + + MockHttpServletResponse mockResponse=result.getResponse(); + assertThat(mockResponse.getContentType()).isEqualTo("text/html;charset=UTF-8"); + + Collection responseHeaders = mockResponse.getHeaderNames(); + assertNotNull(responseHeaders); + assertEquals(2, responseHeaders.size()); + assertEquals("Check for Content-Type header", "Accept-Language", responseHeaders.iterator().next()); + String responseAsString=mockResponse.getContentAsString(); + assertTrue(responseAsString.contains("用户管理")); + } + + @Test + public void putUser() throws Exception { + User user = createUser(); + assertNotNull(user); + + MultiValueMap parameters = new LinkedMultiValueMap(); + Map maps = objectMapper.convertValue(user, new TypeReference>() { + }); + parameters.setAll(maps); + + mockMvc.perform(post("/users/update").params(parameters)) + .andDo(print()) + .andExpect(status().is(HttpServletResponse.SC_FOUND)) + .andDo(print()) + .andExpect(view().name("redirect:/users/")) + .andDo(print()) + .andReturn(); + } + + @Test + public void deleteUser() throws Exception { + mockMvc.perform( MockMvcRequestBuilders.delete("/users/delete/{id}", 1L) ) + .andDo(print()) + .andExpect(status().is(HttpServletResponse.SC_FOUND)) + .andExpect(view().name("redirect:/users/")); + } + + public static byte[] convertObjectToJsonBytes(Object object) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return mapper.writeValueAsBytes(object); + } +} \ No newline at end of file diff --git a/chapter-4-spring-boot-validating-form-input/src/test/resources/application.properties b/chapter-4-spring-boot-validating-form-input/src/test/resources/application.properties new file mode 100644 index 00000000..893718a7 --- /dev/null +++ b/chapter-4-spring-boot-validating-form-input/src/test/resources/application.properties @@ -0,0 +1,14 @@ +## 开启 H2 数据库 +spring.h2.console.enabled=true + +## 配置 H2 数据库连接信息 +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + + +## 是否显示 SQL 语句 +spring.jpa.show-sql=true +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.hbm2ddl.auto=create diff --git a/chapter-6-spring-boot-cache-redis/src/main/resources/static/css/default.css b/chapter-4-spring-boot-validating-form-input/src/test/resources/static/css/default.css similarity index 100% rename from chapter-6-spring-boot-cache-redis/src/main/resources/static/css/default.css rename to chapter-4-spring-boot-validating-form-input/src/test/resources/static/css/default.css diff --git a/chapter-6-spring-boot-cache-redis/src/main/resources/static/images/favicon.ico b/chapter-4-spring-boot-validating-form-input/src/test/resources/static/images/favicon.ico similarity index 100% rename from chapter-6-spring-boot-cache-redis/src/main/resources/static/images/favicon.ico rename to chapter-4-spring-boot-validating-form-input/src/test/resources/static/images/favicon.ico diff --git a/chapter-4-spring-boot-validating-form-input/src/test/resources/templates/userForm.html b/chapter-4-spring-boot-validating-form-input/src/test/resources/templates/userForm.html new file mode 100644 index 00000000..f60c4e0f --- /dev/null +++ b/chapter-4-spring-boot-validating-form-input/src/test/resources/templates/userForm.html @@ -0,0 +1,58 @@ + + + + + + + + + 用户管理 + + + +

+ +
《 Spring Boot 2.x 核心技术实战》第二章快速入门案例
+ + + 用户管理 + + +
+ + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+    + +
+
+
+
+ + \ No newline at end of file diff --git a/chapter-4-spring-boot-validating-form-input/src/test/resources/templates/userList.html b/chapter-4-spring-boot-validating-form-input/src/test/resources/templates/userList.html new file mode 100644 index 00000000..3d680f1b --- /dev/null +++ b/chapter-4-spring-boot-validating-form-input/src/test/resources/templates/userList.html @@ -0,0 +1,46 @@ + + + + + + + + + 用户列表 + + + + +
+ +
《 Spring Boot 2.x 核心技术实战》第二章快速入门案例
+ + + + 用户列表 + + + + + + + + + + + + + + + + + + + +
用户编号名称年龄出生时间管理
删除
+ + +
+ + + \ No newline at end of file diff --git a/chapter-4-spring-boot-web-thymeleaf/pom.xml b/chapter-4-spring-boot-web-thymeleaf/pom.xml index 2d3bfffa..ede4d5fa 100644 --- a/chapter-4-spring-boot-web-thymeleaf/pom.xml +++ b/chapter-4-spring-boot-web-thymeleaf/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.1.3.RELEASE diff --git a/chapter-5-spring-boot-data-jpa/pom.xml b/chapter-5-spring-boot-data-jpa/pom.xml index fd1d2eb9..c8789cc3 100644 --- a/chapter-5-spring-boot-data-jpa/pom.xml +++ b/chapter-5-spring-boot-data-jpa/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT + 2.1.3.RELEASE diff --git a/chapter-5-spring-boot-paging-sorting/pom.xml b/chapter-5-spring-boot-paging-sorting/pom.xml index 77efa6aa..71797fb8 100644 --- a/chapter-5-spring-boot-paging-sorting/pom.xml +++ b/chapter-5-spring-boot-paging-sorting/pom.xml @@ -60,7 +60,7 @@ org.springframework.boot spring-boot-maven-plugin - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/chapter-6-spring-boot-cache-redis/pom.xml b/chapter-6-spring-boot-cache-redis/pom.xml deleted file mode 100644 index 690eb60d..00000000 --- a/chapter-6-spring-boot-cache-redis/pom.xml +++ /dev/null @@ -1,96 +0,0 @@ - - - 4.0.0 - chapter-6-spring-boot-cache-redis - 《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 6 章《数据缓存》Demo - - demo.springboot - chapter-6-spring-boot-cache-redis - 1.0 - jar - - - org.springframework.boot - spring-boot-starter-parent - 2.0.0.BUILD-SNAPSHOT - - - - UTF-8 - UTF-8 - 1.8 - - - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.boot - spring-boot-starter-thymeleaf - - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - - - com.h2database - h2 - runtime - - - - - org.springframework.boot - spring-boot-starter-cache - - - - - org.springframework.boot - spring-boot-starter-redis - - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/libs-snapshot - - true - - - - - diff --git a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/WebApplication.java b/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/WebApplication.java deleted file mode 100644 index 7b7d2209..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/WebApplication.java +++ /dev/null @@ -1,18 +0,0 @@ -package demo.springboot; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cache.annotation.EnableCaching; - -/** - * Spring Boot 应用启动类 - * - * Created by bysocket on 30/09/2017. - */ -@SpringBootApplication -@EnableCaching -public class WebApplication { - public static void main(String[] args) { - SpringApplication.run(WebApplication.class, args); - } -} diff --git a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/domain/Book.java b/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/domain/Book.java deleted file mode 100644 index 5ce99aa6..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/domain/Book.java +++ /dev/null @@ -1,69 +0,0 @@ -package demo.springboot.domain; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import java.io.Serializable; - -/** - * Book 实体类 - * - * Created by bysocket on 30/09/2017. - */ -@Entity -public class Book implements Serializable { - - /** - * 编号 - */ - @Id - @GeneratedValue - private Long id; - - /** - * 书名 - */ - private String name; - - /** - * 作者 - */ - private String writer; - - /** - * 简介 - */ - private String introduction; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getWriter() { - return writer; - } - - public void setWriter(String writer) { - this.writer = writer; - } - - public String getIntroduction() { - return introduction; - } - - public void setIntroduction(String introduction) { - this.introduction = introduction; - } -} diff --git a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/domain/BookRepository.java b/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/domain/BookRepository.java deleted file mode 100644 index e0796e01..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/domain/BookRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package demo.springboot.domain; - -import org.springframework.data.jpa.repository.JpaRepository; - -/** - * Book 数据持久层操作接口 - * - * Created by bysocket on 09/10/2017. - */ -public interface BookRepository extends JpaRepository { -} diff --git a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/service/BookService.java b/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/service/BookService.java deleted file mode 100644 index d2323b90..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/service/BookService.java +++ /dev/null @@ -1,45 +0,0 @@ -package demo.springboot.service; - -import demo.springboot.domain.Book; - -import java.util.List; - -/** - * Book 业务接口层 - * - * Created by bysocket on 30/09/2017. - */ -public interface BookService { - /** - * 获取所有 Book - */ - List findAll(); - - /** - * 新增 Book - * - * @param book {@link Book} - */ - Book insertByBook(Book book); - - /** - * 更新 Book - * - * @param book {@link Book} - */ - Book update(Book book); - - /** - * 删除 Book - * - * @param id 编号 - */ - Book delete(Long id); - - /** - * 获取 Book - * - * @param id 编号 - */ - Book findById(Long id); -} diff --git a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/service/impl/BookServiceImpl.java b/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/service/impl/BookServiceImpl.java deleted file mode 100644 index d2b957eb..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/service/impl/BookServiceImpl.java +++ /dev/null @@ -1,59 +0,0 @@ -package demo.springboot.service.impl; - -import demo.springboot.domain.Book; -import demo.springboot.domain.BookRepository; -import demo.springboot.service.BookService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.annotation.CacheConfig; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.CachePut; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.stereotype.Service; - -import java.util.List; - -/** - * Book 业务层实现 - * - * Created by bysocket on 30/09/2017. - */ -@Service -@CacheConfig(cacheNames = "books") -public class BookServiceImpl implements BookService { - - @Autowired - BookRepository bookRepository; - - @Override - public List findAll() { - return bookRepository.findAll(); - } - - @Override - public Book insertByBook(Book book) { - return bookRepository.save(book); - } - - @CachePut(key = "#p0.id") - @Override - public Book update(Book book) { - System.out.println(" call update method "); - return bookRepository.save(book); - } - - @CacheEvict(key = "#p0") - @Override - public Book delete(Long id) { - System.out.println(" call delete method "); - Book book = bookRepository.findById(id).get(); - bookRepository.delete(book); - return book; - } - - @Cacheable(key = "#p0") - @Override - public Book findById(Long id) { - System.out.println(" call findById method "); - return bookRepository.findById(id).get(); - } -} diff --git a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/web/BookController.java b/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/web/BookController.java deleted file mode 100644 index 3c6ac114..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/java/demo/springboot/web/BookController.java +++ /dev/null @@ -1,89 +0,0 @@ -package demo.springboot.web; - -import demo.springboot.domain.Book; -import demo.springboot.service.BookService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.*; - -/** - * Book 控制层 - * - * Created by bysocket on 30/09/2017. - */ -@Controller -@RequestMapping(value = "/book") -public class BookController { - - private static final String BOOK_FORM_PATH_NAME = "bookForm"; - private static final String BOOK_LIST_PATH_NAME = "bookList"; - private static final String REDIRECT_TO_BOOK_URL = "redirect:/book"; - - @Autowired - BookService bookService; - - /** - * 获取 Book 列表 - * 处理 "/book" 的 GET 请求,用来获取 Book 列表 - */ - @RequestMapping(method = RequestMethod.GET) - public String getBookList(ModelMap map) { - map.addAttribute("bookList",bookService.findAll()); - return BOOK_LIST_PATH_NAME; - } - - /** - * 获取创建 Book 表单 - */ - @RequestMapping(value = "/create", method = RequestMethod.GET) - public String createBookForm(ModelMap map) { - map.addAttribute("book", new Book()); - map.addAttribute("action", "create"); - return BOOK_FORM_PATH_NAME; - } - - /** - * 创建 Book - * 处理 "/book/create" 的 POST 请求,用来新建 Book 信息 - * 通过 @ModelAttribute 绑定表单实体参数,也通过 @RequestParam 传递参数 - */ - @RequestMapping(value = "/create", method = RequestMethod.POST) - public String postBook(@ModelAttribute Book book) { - bookService.insertByBook(book); - return REDIRECT_TO_BOOK_URL; - } - - /** - * 获取更新 Book 表单 - * 处理 "/book/update/{id}" 的 GET 请求,通过 URL 中的 id 值获取 Book 信息 - * URL 中的 id ,通过 @PathVariable 绑定参数 - */ - @RequestMapping(value = "/update/{id}", method = RequestMethod.GET) - public String getUser(@PathVariable Long id, ModelMap map) { - map.addAttribute("book", bookService.findById(id)); - map.addAttribute("action", "update"); - return BOOK_FORM_PATH_NAME; - } - - /** - * 更新 Book - * 处理 "/update" 的 PUT 请求,用来更新 Book 信息 - */ - @RequestMapping(value = "/update", method = RequestMethod.POST) - public String putBook(@ModelAttribute Book book) { - bookService.update(book); - return REDIRECT_TO_BOOK_URL; - } - - /** - * 删除 Book - * 处理 "/book/{id}" 的 GET 请求,用来删除 Book 信息 - */ - @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) - public String deleteBook(@PathVariable Long id) { - bookService.delete(id); - return REDIRECT_TO_BOOK_URL; - } - -} diff --git a/chapter-6-spring-boot-cache-redis/src/main/resources/application.properties b/chapter-6-spring-boot-cache-redis/src/main/resources/application.properties deleted file mode 100644 index b0d364a8..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/resources/application.properties +++ /dev/null @@ -1,9 +0,0 @@ -## 是否启动日志 SQL 语句 -spring.jpa.show-sql=true - -spring.redis.host=localhost -spring.redis.port=6379 -spring.redis.jedis.pool.max-idle=8 -spring.redis.jedis.pool.min-idle=0 -spring.redis.jedis.pool.max-active=8 -spring.redis.jedis.pool.max-wait=-1 \ No newline at end of file diff --git a/chapter-6-spring-boot-cache-redis/src/main/resources/templates/bookForm.html b/chapter-6-spring-boot-cache-redis/src/main/resources/templates/bookForm.html deleted file mode 100644 index 43118b61..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/resources/templates/bookForm.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - 书籍管理 - - - -
- -
《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 5 章《数据存储》Demo
- - - 书籍管理 - - -
- - - -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
-
-    - -
-
-
-
- - \ No newline at end of file diff --git a/chapter-6-spring-boot-cache-redis/src/main/resources/templates/bookList.html b/chapter-6-spring-boot-cache-redis/src/main/resources/templates/bookList.html deleted file mode 100644 index 2ab11c67..00000000 --- a/chapter-6-spring-boot-cache-redis/src/main/resources/templates/bookList.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - 书籍列表 - - - - -
- -
《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 5 章《数据存储》Demo
- - - - 书籍列表 - - - - - - - - - - - - - - - - - - - -
书籍编号书名作者简介管理
删除
- - -
- - - \ No newline at end of file diff --git a/chapter-6-spring-boot-cache-redis/src/test/java/demo/springboot/WebApplicationTests.java b/chapter-6-spring-boot-cache-redis/src/test/java/demo/springboot/WebApplicationTests.java deleted file mode 100644 index ebd0f53f..00000000 --- a/chapter-6-spring-boot-cache-redis/src/test/java/demo/springboot/WebApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package demo.springboot; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class WebApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/pom.xml b/pom.xml index 01b6e17f..6a43a0b8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,85 +1,81 @@ 4.0.0 - springboot :: Examples + springboot-learning-example springboot - springboot + springboot-learning-example 1.0-SNAPSHOT pom - + + 2-x-spring-boot-webflux-handling-errors - - springboot-webflux-1-quickstart + + chapter-1-spring-boot-quickstart + + chapter-2-spring-boot-config + + chapter-3-spring-boot-web + + chapter-4-spring-boot-web-thymeleaf + + chapter-5-spring-boot-data-jpa + + chapter-4-spring-boot-validating-form-input + + chapter-5-spring-boot-paging-sorting - - springboot-webflux-2-restful + + spring-data-elasticsearch-crud + spring-data-elasticsearch-query - - - springboot-helloworld - springboot-properties - springboot-configuration - - - springboot-restful + + springboot-dubbo-server + springboot-dubbo-client + + + springboot-elasticsearch + springboot-freemarker - - springboot-validation-over-json - + + springboot-hbase + + + springboot-helloworld + + springboot-mybatis springboot-mybatis-annotation springboot-mybatis-mutil-datasource - - springboot-mybatis-redis springboot-mybatis-redis-annotation - - - - - - springboot-dubbo-server - springboot-dubbo-client - - springboot-elasticsearch + + springboot-restful - - spring-data-elasticsearch-crud - spring-data-elasticsearch-query + + springboot-properties - - chapter-1-spring-boot-quickstart - - chapter-2-spring-boot-config - - chapter-3-spring-boot-web - - chapter-4-spring-boot-web-thymeleaf - - chapter-5-spring-boot-data-jpa - - chapter-6-spring-boot-cache-redis - - - chapter-4-spring-boot-validating-form-input - - chapter-5-spring-boot-paging-sorting + + springboot-validation-over-json + + + springboot-webflux-1-quickstart + + springboot-webflux-2-restful diff --git a/spring-data-elasticsearch-crud/pom.xml b/spring-data-elasticsearch-crud/pom.xml index d0fa431f..821c3096 100755 --- a/spring-data-elasticsearch-crud/pom.xml +++ b/spring-data-elasticsearch-crud/pom.xml @@ -6,7 +6,7 @@ springboot spring-data-elasticsearch-crud 0.0.1-SNAPSHOT - spring-data-elasticsearch-crud :: spring-data-elasticsearch - 基本案例 + spring-data-elasticsearch-crud diff --git a/spring-data-elasticsearch-query/pom.xml b/spring-data-elasticsearch-query/pom.xml index 60235d90..0992e413 100755 --- a/spring-data-elasticsearch-query/pom.xml +++ b/spring-data-elasticsearch-query/pom.xml @@ -6,7 +6,7 @@ springboot spring-data-elasticsearch-query 0.0.1-SNAPSHOT - spring-data-elasticsearch-query :: spring-data-elasticsearch - 实战案例详解 + spring-data-elasticsearch-query diff --git a/springboot-configuration/pom.xml b/springboot-configuration/pom.xml index 8dd6a77d..fcb28fec 100755 --- a/springboot-configuration/pom.xml +++ b/springboot-configuration/pom.xml @@ -6,13 +6,13 @@ springboot springboot-configuration 0.0.1-SNAPSHOT - springboot-configuration :: 配置 Demo + springboot-configuration org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-dubbo-client/pom.xml b/springboot-dubbo-client/pom.xml index 0253e58a..f259ac70 100755 --- a/springboot-dubbo-client/pom.xml +++ b/springboot-dubbo-client/pom.xml @@ -6,13 +6,12 @@ springboot springboot-dubbo-client 0.0.1-SNAPSHOT - springboot-dubbo 客户端:: 整合 Dubbo/ZooKeeper 详解 SOA 案例 org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-dubbo-server/pom.xml b/springboot-dubbo-server/pom.xml index e156bc50..f6872272 100755 --- a/springboot-dubbo-server/pom.xml +++ b/springboot-dubbo-server/pom.xml @@ -6,13 +6,12 @@ springboot springboot-dubbo-server 0.0.1-SNAPSHOT - springboot-dubbo 服务端:: 整合 Dubbo/ZooKeeper 详解 SOA 案例 org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-elasticsearch/pom.xml b/springboot-elasticsearch/pom.xml index 20b46e8a..47187a9e 100755 --- a/springboot-elasticsearch/pom.xml +++ b/springboot-elasticsearch/pom.xml @@ -6,7 +6,7 @@ springboot springboot-elasticsearch 0.0.1-SNAPSHOT - springboot-elasticsearch :: 整合 Elasticsearch + springboot-elasticsearch diff --git a/springboot-freemarker/pom.xml b/springboot-freemarker/pom.xml index a756b199..b0358794 100755 --- a/springboot-freemarker/pom.xml +++ b/springboot-freemarker/pom.xml @@ -6,13 +6,13 @@ springboot springboot-freemarker 0.0.1-SNAPSHOT - springboot-freemarker :: 整合 FreeMarker 案例 + springboot-freemarker org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-freemarker/src/main/resources/application.properties b/springboot-freemarker/src/main/resources/application.properties index 981c14e5..ee82891d 100644 --- a/springboot-freemarker/src/main/resources/application.properties +++ b/springboot-freemarker/src/main/resources/application.properties @@ -1,7 +1,7 @@ ## 数据源配置 -spring.datasource.url=jdbc:mysql://139.224.14.39:3306/springbootdb?useUnicode=true&characterEncoding=utf8 +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springbootdb?useUnicode=true&characterEncoding=utf8 spring.datasource.username=root -spring.datasource.password=Hello123!@ +spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver ## Mybatis 配置 @@ -18,4 +18,4 @@ spring.freemarker.content-type=text/html spring.freemarker.expose-request-attributes=true spring.freemarker.expose-session-attributes=true spring.freemarker.request-context-attribute=request -spring.freemarker.suffix=.ftl \ No newline at end of file +spring.freemarker.suffix=.ftl diff --git a/springboot-freemarker/src/main/resources/mapper/CityMapper.xml b/springboot-freemarker/src/main/resources/mapper/CityMapper.xml index 1855f82c..f720f321 100644 --- a/springboot-freemarker/src/main/resources/mapper/CityMapper.xml +++ b/springboot-freemarker/src/main/resources/mapper/CityMapper.xml @@ -8,8 +8,6 @@ - - id, province_id, city_name, description @@ -27,14 +25,14 @@ from city - + insert into city(id,province_id,city_name,description) values (#{id},#{provinceId},#{cityName},#{description}) - + update city set diff --git a/springboot-hbase/pom.xml b/springboot-hbase/pom.xml new file mode 100755 index 00000000..2a594e83 --- /dev/null +++ b/springboot-hbase/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + springboot + springboot-hbase + 0.0.1-SNAPSHOT + springboot-hbase + + + + org.springframework.boot + spring-boot-starter-parent + 1.5.6.RELEASE + + + + 1.0.0.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + com.spring4all + spring-boot-starter-hbase + ${hbase-spring-boot} + + + + + junit + junit + 4.12 + + + diff --git a/springboot-hbase/src/main/java/org/spring/springboot/Application.java b/springboot-hbase/src/main/java/org/spring/springboot/Application.java new file mode 100644 index 00000000..5070937d --- /dev/null +++ b/springboot-hbase/src/main/java/org/spring/springboot/Application.java @@ -0,0 +1,20 @@ +package org.spring.springboot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Spring Boot 应用启动类 + * + * Created by bysocket on 16/4/26. + */ +// Spring Boot 应用的标识 +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + // 程序启动入口 + // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件 + SpringApplication.run(Application.class,args); + } +} diff --git a/springboot-hbase/src/main/java/org/spring/springboot/controller/CityRestController.java b/springboot-hbase/src/main/java/org/spring/springboot/controller/CityRestController.java new file mode 100644 index 00000000..06470b7d --- /dev/null +++ b/springboot-hbase/src/main/java/org/spring/springboot/controller/CityRestController.java @@ -0,0 +1,31 @@ +package org.spring.springboot.controller; + +import org.spring.springboot.domain.City; +import org.spring.springboot.service.CityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +/** + * Created by bysocket on 07/02/2017. + */ +@RestController +public class CityRestController { + + @Autowired + private CityService cityService; + + @RequestMapping(value = "/api/city/save", method = RequestMethod.GET) + public City save() { + cityService.saveOrUpdate(); + City city = new City(); + city.setAge(1); + return city; + } + + @RequestMapping(value = "/api/city/get", method = RequestMethod.GET) + public City getCity() { + return cityService.query("135xxxxxx"); + } +} diff --git a/springboot-hbase/src/main/java/org/spring/springboot/dao/CityRowMapper.java b/springboot-hbase/src/main/java/org/spring/springboot/dao/CityRowMapper.java new file mode 100644 index 00000000..9db7db92 --- /dev/null +++ b/springboot-hbase/src/main/java/org/spring/springboot/dao/CityRowMapper.java @@ -0,0 +1,24 @@ +package org.spring.springboot.dao; + +import com.spring4all.spring.boot.starter.hbase.api.RowMapper; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.util.Bytes; +import org.spring.springboot.domain.City; + +public class CityRowMapper implements RowMapper { + + private static byte[] COLUMN_FAMILY = "f".getBytes(); + private static byte[] NAME = "name".getBytes(); + private static byte[] AGE = "age".getBytes(); + + @Override + public City mapRow(Result result, int rowNum) throws Exception { + String name = Bytes.toString(result.getValue(COLUMN_FAMILY, NAME)); + int age = Bytes.toInt(result.getValue(COLUMN_FAMILY, AGE)); + + City dto = new City(); + dto.setCityName(name); + dto.setAge(age); + return dto; + } +} diff --git a/springboot-hbase/src/main/java/org/spring/springboot/domain/City.java b/springboot-hbase/src/main/java/org/spring/springboot/domain/City.java new file mode 100644 index 00000000..afe589e2 --- /dev/null +++ b/springboot-hbase/src/main/java/org/spring/springboot/domain/City.java @@ -0,0 +1,48 @@ +package org.spring.springboot.domain; + +/** + * 城市实体类 + * + * Created by bysocket on 07/02/2017. + */ +public class City { + + /** + * 城市编号 + */ + private Long id; + + /** + * 省份年龄 + */ + private Integer age; + + /** + * 城市名称 + */ + private String cityName; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public String getCityName() { + return cityName; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } +} diff --git a/springboot-hbase/src/main/java/org/spring/springboot/service/CityService.java b/springboot-hbase/src/main/java/org/spring/springboot/service/CityService.java new file mode 100644 index 00000000..cb183e56 --- /dev/null +++ b/springboot-hbase/src/main/java/org/spring/springboot/service/CityService.java @@ -0,0 +1,19 @@ +package org.spring.springboot.service; + +import org.spring.springboot.domain.City; + +import java.util.List; + +/** + * 城市业务逻辑接口类 + *

+ * Created by bysocket on 07/02/2017. + */ +public interface CityService { + + List query(String startRow, String stopRow); + + public City query(String row); + + void saveOrUpdate(); +} diff --git a/springboot-hbase/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java b/springboot-hbase/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java new file mode 100644 index 00000000..72b7bf75 --- /dev/null +++ b/springboot-hbase/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java @@ -0,0 +1,47 @@ +package org.spring.springboot.service.impl; + +import com.spring4all.spring.boot.starter.hbase.api.HbaseTemplate; +import org.apache.hadoop.hbase.client.Mutation; +import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.util.Bytes; +import org.spring.springboot.dao.CityRowMapper; +import org.spring.springboot.domain.City; +import org.spring.springboot.service.CityService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * 城市业务逻辑实现类 + *

+ * Created by bysocket on 07/02/2017. + */ +@Service +public class CityServiceImpl implements CityService { + + @Autowired private HbaseTemplate hbaseTemplate; + + public List query(String startRow, String stopRow) { + Scan scan = new Scan(Bytes.toBytes(startRow), Bytes.toBytes(stopRow)); + scan.setCaching(5000); + List dtos = this.hbaseTemplate.find("people_table", scan, new CityRowMapper()); + return dtos; + } + + public City query(String row) { + City dto = this.hbaseTemplate.get("people_table", row, new CityRowMapper()); + return dto; + } + + public void saveOrUpdate() { + List saveOrUpdates = new ArrayList(); + Put put = new Put(Bytes.toBytes("135xxxxxx")); + put.addColumn(Bytes.toBytes("people"), Bytes.toBytes("name"), Bytes.toBytes("test")); + saveOrUpdates.add(put); + + this.hbaseTemplate.saveOrUpdates("people_table", saveOrUpdates); + } +} diff --git a/springboot-hbase/src/main/resources/application.properties b/springboot-hbase/src/main/resources/application.properties new file mode 100644 index 00000000..03ccb627 --- /dev/null +++ b/springboot-hbase/src/main/resources/application.properties @@ -0,0 +1,4 @@ +## HBase 配置 +spring.data.hbase.quorum=xxx +spring.data.hbase.rootDir=xxx +spring.data.hbase.nodeParent=xxx diff --git a/springboot-helloworld/pom.xml b/springboot-helloworld/pom.xml index ca3bda25..20264a21 100755 --- a/springboot-helloworld/pom.xml +++ b/springboot-helloworld/pom.xml @@ -6,13 +6,13 @@ springboot springboot-helloworld 0.0.1-SNAPSHOT - springboot-helloworld :: HelloWorld Demo + springboot-helloworld org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-mybatis-annotation/pom.xml b/springboot-mybatis-annotation/pom.xml index 77ccd980..7f6b9c8e 100644 --- a/springboot-mybatis-annotation/pom.xml +++ b/springboot-mybatis-annotation/pom.xml @@ -9,13 +9,13 @@ jar springboot-mybatis-annotation - Springboot-mybatis :: 整合 Mybatis Annotation 案例 + Springboot-mybatis org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-mybatis-mutil-datasource/pom.xml b/springboot-mybatis-mutil-datasource/pom.xml index bc14a538..b86deaa1 100755 --- a/springboot-mybatis-mutil-datasource/pom.xml +++ b/springboot-mybatis-mutil-datasource/pom.xml @@ -6,13 +6,13 @@ springboot springboot-mybatis-mutil-datasource 0.0.1-SNAPSHOT - springboot-mybatis-mutil-datasource :: Spring Boot 实现 Mybatis 多数据源配置 + springboot-mybatis-mutil-datasource org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-mybatis-mutil-datasource/src/main/resources/mapper/cluster/CityMapper.xml b/springboot-mybatis-mutil-datasource/src/main/resources/mapper/cluster/CityMapper.xml index 6b35457e..13ce8f39 100644 --- a/springboot-mybatis-mutil-datasource/src/main/resources/mapper/cluster/CityMapper.xml +++ b/springboot-mybatis-mutil-datasource/src/main/resources/mapper/cluster/CityMapper.xml @@ -8,8 +8,6 @@ - - id, province_id, city_name, description diff --git a/springboot-mybatis-mutil-datasource/src/main/resources/mapper/master/UserMapper.xml b/springboot-mybatis-mutil-datasource/src/main/resources/mapper/master/UserMapper.xml index 9f21ced6..833ae1ac 100644 --- a/springboot-mybatis-mutil-datasource/src/main/resources/mapper/master/UserMapper.xml +++ b/springboot-mybatis-mutil-datasource/src/main/resources/mapper/master/UserMapper.xml @@ -7,8 +7,6 @@ - - id, user_name, description diff --git a/springboot-mybatis-redis-annotation/pom.xml b/springboot-mybatis-redis-annotation/pom.xml index 3199297f..ec20a361 100755 --- a/springboot-mybatis-redis-annotation/pom.xml +++ b/springboot-mybatis-redis-annotation/pom.xml @@ -6,13 +6,13 @@ springboot springboot-mybatis-redis-annotation 0.0.1-SNAPSHOT - springboot-mybatis-redis-annotation :: 注解实现整合 Redis 作为缓存 + springboot-mybatis-redis-annotation org.springframework.boot spring-boot-starter-parent - 1.5.3.RELEASE + 2.1.3.RELEASE diff --git a/springboot-mybatis-redis/pom.xml b/springboot-mybatis-redis/pom.xml index 21a30fcd..b61b9ac5 100755 --- a/springboot-mybatis-redis/pom.xml +++ b/springboot-mybatis-redis/pom.xml @@ -6,13 +6,13 @@ springboot springboot-mybatis-redis 0.0.1-SNAPSHOT - springboot-mybatis-redis :: 整合 Mybatis 并使用 Redis 作为缓存 + springboot-mybatis-redis org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-mybatis-redis/src/main/resources/mapper/CityMapper.xml b/springboot-mybatis-redis/src/main/resources/mapper/CityMapper.xml index 47528bfc..13bae454 100644 --- a/springboot-mybatis-redis/src/main/resources/mapper/CityMapper.xml +++ b/springboot-mybatis-redis/src/main/resources/mapper/CityMapper.xml @@ -8,8 +8,6 @@ - - id, province_id, city_name, description @@ -27,14 +25,14 @@ from city - + insert into city(id,province_id,city_name,description) values (#{id},#{provinceId},#{cityName},#{description}) - + update city set diff --git a/springboot-mybatis/pom.xml b/springboot-mybatis/pom.xml index f309b20f..465e6ad3 100755 --- a/springboot-mybatis/pom.xml +++ b/springboot-mybatis/pom.xml @@ -6,13 +6,13 @@ springboot springboot-mybatis 0.0.1-SNAPSHOT - springboot-mybatis :: 整合 Mybatis Demo + springboot-mybatis org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-mybatis/src/main/resources/mapper/CityMapper.xml b/springboot-mybatis/src/main/resources/mapper/CityMapper.xml index 82a07d13..8ebf7244 100644 --- a/springboot-mybatis/src/main/resources/mapper/CityMapper.xml +++ b/springboot-mybatis/src/main/resources/mapper/CityMapper.xml @@ -8,8 +8,6 @@ - - id, province_id, city_name, description diff --git a/springboot-properties/pom.xml b/springboot-properties/pom.xml index c8356620..5e49bf87 100755 --- a/springboot-properties/pom.xml +++ b/springboot-properties/pom.xml @@ -6,13 +6,13 @@ springboot springboot-properties 0.0.1-SNAPSHOT - springboot-properties :: Spring boot 配置文件 + springboot-properties org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE @@ -42,4 +42,24 @@ test + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.3.RELEASE + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.4 + + true + + + + + diff --git a/springboot-properties/springboot-properties.iml b/springboot-properties/springboot-properties.iml deleted file mode 100644 index 33f81965..00000000 --- a/springboot-properties/springboot-properties.iml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/springboot-restful/pom.xml b/springboot-restful/pom.xml index 5bfce9e5..dd11930e 100755 --- a/springboot-restful/pom.xml +++ b/springboot-restful/pom.xml @@ -6,13 +6,13 @@ springboot springboot-restful 0.0.1-SNAPSHOT - springboot-restful :: Spsringboot 实现 Restful 服务,基于 HTTP / JSON 传输 Demo + springboot-restful org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-restful/src/main/resources/mapper/CityMapper.xml b/springboot-restful/src/main/resources/mapper/CityMapper.xml index 1855f82c..f720f321 100644 --- a/springboot-restful/src/main/resources/mapper/CityMapper.xml +++ b/springboot-restful/src/main/resources/mapper/CityMapper.xml @@ -8,8 +8,6 @@ - - id, province_id, city_name, description @@ -27,14 +25,14 @@ from city - + insert into city(id,province_id,city_name,description) values (#{id},#{provinceId},#{cityName},#{description}) - + update city set diff --git a/springboot-validation-over-json/pom.xml b/springboot-validation-over-json/pom.xml index a39b50b6..9ae6de90 100755 --- a/springboot-validation-over-json/pom.xml +++ b/springboot-validation-over-json/pom.xml @@ -6,13 +6,13 @@ springboot springboot-validation-over-json 0.0.1-SNAPSHOT - springboot-validation-over-json :: Validation with http over json Demo + springboot-validation-over-json org.springframework.boot spring-boot-starter-parent - 1.5.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-1-quickstart/pom.xml b/springboot-webflux-1-quickstart/pom.xml index 6e824851..b1b5d163 100755 --- a/springboot-webflux-1-quickstart/pom.xml +++ b/springboot-webflux-1-quickstart/pom.xml @@ -6,12 +6,12 @@ springboot springboot-webflux-1-quickstart 0.0.1-SNAPSHOT - springboot-webflux-1-quickstart :: Spring Boot WebFlux 快速入门 + springboot-webflux-1-quickstart org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-10-book-manage-sys/pom.xml b/springboot-webflux-10-book-manage-sys/pom.xml index 9b98898b..4a99ddd5 100644 --- a/springboot-webflux-10-book-manage-sys/pom.xml +++ b/springboot-webflux-10-book-manage-sys/pom.xml @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-2-restful/pom.xml b/springboot-webflux-2-restful/pom.xml index aa189d4f..89478e1d 100755 --- a/springboot-webflux-2-restful/pom.xml +++ b/springboot-webflux-2-restful/pom.xml @@ -6,13 +6,13 @@ springboot springboot-webflux-2-restful 0.0.1-SNAPSHOT - springboot-webflux-2-restful :: Spring Boot WebFlux 实现 Restful 服务 + springboot-webflux-2-restful org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-3-mongodb/pom.xml b/springboot-webflux-3-mongodb/pom.xml index d5004d84..10cc5d9e 100755 --- a/springboot-webflux-3-mongodb/pom.xml +++ b/springboot-webflux-3-mongodb/pom.xml @@ -6,13 +6,13 @@ springboot springboot-webflux-3-mongodb 0.0.1-SNAPSHOT - springboot-webflux-3-mongodb :: Spring Boot WebFlux 整合 MongoDB + springboot-webflux-3-mongodb org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/handler/CityHandler.java b/springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/handler/CityHandler.java index 096ceb80..f52f7cfd 100644 --- a/springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/handler/CityHandler.java +++ b/springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/handler/CityHandler.java @@ -37,7 +37,6 @@ public Mono modifyCity(City city) { } public Mono deleteCity(Long id) { - cityRepository.deleteById(id); - return Mono.create(cityMonoSink -> cityMonoSink.success(id)); + return cityRepository.deleteById(id).flatMap(mono -> Mono.create(cityMonoSink -> cityMonoSink.success(id))); } } diff --git a/springboot-webflux-4-thymeleaf/pom.xml b/springboot-webflux-4-thymeleaf/pom.xml index 2c437ce4..b1ecafdf 100755 --- a/springboot-webflux-4-thymeleaf/pom.xml +++ b/springboot-webflux-4-thymeleaf/pom.xml @@ -6,13 +6,13 @@ springboot springboot-webflux-4-thymeleaf 0.0.1-SNAPSHOT - springboot-webflux-4-thymeleaf :: Spring Boot WebFlux 整合 Thymeleaf + springboot-webflux-4-thymeleaf org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-5-thymeleaf-mongodb/pom.xml b/springboot-webflux-5-thymeleaf-mongodb/pom.xml index 64c611d4..5d09644a 100755 --- a/springboot-webflux-5-thymeleaf-mongodb/pom.xml +++ b/springboot-webflux-5-thymeleaf-mongodb/pom.xml @@ -6,13 +6,13 @@ springboot springboot-webflux-5-thymeleaf-mongodb 0.0.1-SNAPSHOT - springboot-webflux-5-thymeleaf-mongodb :: Spring Boot WebFlux 中 Thymeleaf 和 Mongodb 实践 + springboot-webflux-5-thymeleaf-mongodb org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-6-redis/pom.xml b/springboot-webflux-6-redis/pom.xml index 8f68262a..91dd4f01 100755 --- a/springboot-webflux-6-redis/pom.xml +++ b/springboot-webflux-6-redis/pom.xml @@ -6,13 +6,13 @@ springboot springboot-webflux-6-redis 0.0.1-SNAPSHOT - springboot-webflux-6-redis :: Spring Boot WebFlux 整合 Redis + springboot-webflux-6-redis org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-7-redis-cache/pom.xml b/springboot-webflux-7-redis-cache/pom.xml index ddc1fdb9..3dd46cd7 100755 --- a/springboot-webflux-7-redis-cache/pom.xml +++ b/springboot-webflux-7-redis-cache/pom.xml @@ -6,13 +6,13 @@ springboot springboot-webflux-7-redis-cache 0.0.1-SNAPSHOT - springboot-webflux-7-redis-cache :: Spring Boot WebFlux 整合 Redis 实现缓存 + springboot-webflux-7-redis-cache org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-8-websocket/pom.xml b/springboot-webflux-8-websocket/pom.xml index c141f781..75a8467f 100755 --- a/springboot-webflux-8-websocket/pom.xml +++ b/springboot-webflux-8-websocket/pom.xml @@ -6,12 +6,12 @@ springboot springboot-webflux-8-websocket 0.0.1-SNAPSHOT - springboot-webflux-8-websocket :: Spring Boot WebFlux 中 WebSocket 实现通信 + springboot-webflux-8-websocket org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE diff --git a/springboot-webflux-9-test/pom.xml b/springboot-webflux-9-test/pom.xml index 24d9a2b0..87fa2b34 100755 --- a/springboot-webflux-9-test/pom.xml +++ b/springboot-webflux-9-test/pom.xml @@ -6,13 +6,13 @@ springboot springboot-webflux-9-test 0.0.1-SNAPSHOT - springboot-webflux-9-test :: Spring Boot WebFlux 集成测试及部署 + springboot-webflux-9-test org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.3.RELEASE