[
  {
    "path": ".gitignore",
    "content": "*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n\n\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n\n### STS ###\n.apt_generated\n.classpath\n.factorypath\n.project\n.settings\n.springBeans\n\n### IntelliJ IDEA ###\n.idea\n*.iws\n*.iml\n*.ipr\n\n### NetBeans ###\nnbproject/private/\nbuild/\nnbbuild/\ndist/\nnbdist/\n.nb-gradle/"
  },
  {
    "path": "2-x-spring-boot-groovy/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>2-x-spring-boot-groovy</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>2-x-spring-boot-groovy</name>\n\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.6.RELEASE</version>\n    <relativePath/> <!-- lookup parent from repository -->\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-web</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>org.codehaus.groovy</groupId>\n      <artifactId>groovy</artifactId>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "2-x-spring-boot-groovy/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n\n    }\n}\n"
  },
  {
    "path": "2-x-spring-boot-groovy/src/main/java/org/spring/springboot/filter/RouteRuleFilter.java",
    "content": "package org.spring.springboot.filter;\n\nimport groovy.lang.Binding;\nimport groovy.lang.GroovyShell;\nimport groovy.lang.Script;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Map;\n\n@Component\npublic class RouteRuleFilter {\n    \n    public Map<String,Object> filter(Map<String,Object> input) {\n    \n        Binding binding = new Binding();\n        binding.setVariable(\"input\", input);\n    \n        GroovyShell shell = new GroovyShell(binding);\n        \n        String filterScript = \"def field = input.get('field')\\n\"\n                                      + \"if (input.field == 'buyer') { return ['losDataBusinessName':'losESDataBusiness3', 'esIndex':'potential_goods_recommend1']}\\n\"\n                                      + \"if (input.field == 'seller') { return ['losDataBusinessName':'losESDataBusiness4', 'esIndex':'potential_goods_recommend2']}\\n\";\n        Script script = shell.parse(filterScript);\n        Object ret = script.run();\n        System.out.println(ret);\n        return (Map<String, Object>) ret;\n    }\n}\n"
  },
  {
    "path": "2-x-spring-boot-groovy/src/main/java/org/spring/springboot/web/GroovyScriptController.java",
    "content": "package org.spring.springboot.web;\n\nimport org.spring.springboot.filter.RouteRuleFilter;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n@RestController\n@RequestMapping(\"/groovy/script\")\npublic class GroovyScriptController {\n\n    @RequestMapping(value = \"/filter\", method = RequestMethod.GET)\n    public String filter() {\n        \n        RouteRuleFilter routeRuleFilter = new RouteRuleFilter();\n    \n        Map<String, Object> input = new HashMap<>();\n        input.put(\"field\", \"seller\");\n    \n        Map<String, Object> output = routeRuleFilter.filter(input);\n        return \"true\";\n        \n    }\n    \n    public static void main(String[] args) {\n        GroovyScriptController groovyScriptController = new GroovyScriptController();\n        groovyScriptController.filter();\n    }\n}\n"
  },
  {
    "path": "2-x-spring-boot-groovy/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "2-x-spring-boot-webflux-handling-errors/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>2-x-spring-boot-webflux-handling-errors</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>2-x-spring-boot-webflux-handling-errors</name>\n\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.3.RELEASE</version>\n    <relativePath/> <!-- lookup parent from repository -->\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>io.projectreactor</groupId>\n      <artifactId>reactor-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n\n</project>\n"
  },
  {
    "path": "2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n\n    }\n}\n"
  },
  {
    "path": "2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalErrorAttributes.java",
    "content": "package org.spring.springboot.error;\n\nimport org.springframework.boot.web.reactive.error.DefaultErrorAttributes;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.function.server.ServerRequest;\n\nimport java.util.Map;\n\n@Component\npublic class GlobalErrorAttributes extends DefaultErrorAttributes {\n    \n    @Override\n    public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {\n        Map<String, Object> map = super.getErrorAttributes(request, includeStackTrace);\n    \n        if (getError(request) instanceof GlobalException) {\n            GlobalException ex = (GlobalException) getError(request);\n            map.put(\"exception\", ex.getClass().getSimpleName());\n            map.put(\"message\", ex.getMessage());\n            map.put(\"status\", ex.getStatus().value());\n            map.put(\"error\", ex.getStatus().getReasonPhrase());\n            \n            return map;\n        }\n    \n        map.put(\"exception\", \"SystemException\");\n        map.put(\"message\", \"System Error , Check logs!\");\n        map.put(\"status\", \"500\");\n        map.put(\"error\", \" System Error \");\n        return map;\n    }\n}\n"
  },
  {
    "path": "2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalErrorWebExceptionHandler.java",
    "content": "package org.spring.springboot.error;\n\nimport org.springframework.boot.autoconfigure.web.ResourceProperties;\nimport org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;\nimport org.springframework.boot.web.reactive.error.ErrorAttributes;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.core.annotation.Order;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.codec.ServerCodecConfigurer;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.function.BodyInserters;\nimport org.springframework.web.reactive.function.server.RequestPredicates;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.RouterFunctions;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport reactor.core.publisher.Mono;\n\nimport java.util.Map;\n\n@Component\n@Order(-2)\npublic class GlobalErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {\n\n    public GlobalErrorWebExceptionHandler(GlobalErrorAttributes g, ApplicationContext applicationContext,\n            ServerCodecConfigurer serverCodecConfigurer) {\n        super(g, new ResourceProperties(), applicationContext);\n        super.setMessageWriters(serverCodecConfigurer.getWriters());\n        super.setMessageReaders(serverCodecConfigurer.getReaders());\n    }\n\n    @Override\n    protected RouterFunction<ServerResponse> getRoutingFunction(final ErrorAttributes errorAttributes) {\n        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);\n    }\n\n    private Mono<ServerResponse> renderErrorResponse(final ServerRequest request) {\n\n        final Map<String, Object> errorPropertiesMap = getErrorAttributes(request, false);\n\n        return ServerResponse.status(HttpStatus.BAD_REQUEST)\n            .contentType(MediaType.APPLICATION_JSON_UTF8)\n            .body(BodyInserters.fromObject(errorPropertiesMap));\n    }\n\n}\n"
  },
  {
    "path": "2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/error/GlobalException.java",
    "content": "package org.spring.springboot.error;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.server.ResponseStatusException;\n\npublic class GlobalException extends ResponseStatusException {\n    \n    public GlobalException(HttpStatus status, String message) {\n        super(status, message);\n    }\n    \n    public GlobalException(HttpStatus status, String message, Throwable e) {\n        super(status, message, e);\n    }\n}\n"
  },
  {
    "path": "2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/handler/CityHandler.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.spring.springboot.error.GlobalException;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport reactor.core.publisher.Mono;\n\nimport java.util.Optional;\n\n@Component\npublic class CityHandler {\n    \n    public Mono<ServerResponse> helloCity(ServerRequest request) {\n        return ServerResponse.ok().body(sayHelloCity(request), String.class);\n    }\n    \n    private Mono<String> sayHelloCity(ServerRequest request) {\n        Optional<String> cityParamOptional = request.queryParam(\"city\");\n        if (!cityParamOptional.isPresent()) {\n            throw new GlobalException(HttpStatus.INTERNAL_SERVER_ERROR, \"request param city is ERROR\");\n        }\n        \n        return Mono.just(\"Hello,\" + cityParamOptional.get());\n    }\n}\n"
  },
  {
    "path": "2-x-spring-boot-webflux-handling-errors/src/main/java/org/spring/springboot/router/CityRouter.java",
    "content": "package org.spring.springboot.router;\n\nimport org.spring.springboot.handler.CityHandler;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.reactive.function.server.RequestPredicates;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.RouterFunctions;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\n@Configuration\npublic class CityRouter {\n    \n    @Bean\n    public RouterFunction<ServerResponse> routeCity(CityHandler cityHandler) {\n        return RouterFunctions.route(RequestPredicates.GET(\"/hello\").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), cityHandler::helloCity);\n    }\n    \n}\n"
  },
  {
    "path": "2-x-spring-boot-webflux-handling-errors/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "[![Star History Chart](https://api.star-history.com/svg?repos=JeffLi1993/springboot-learning-example&type=Date)](https://star-history.com/#JeffLi1993/springboot-learning-example&Date)\n\n\n### 一、支持泥瓦匠\n\n关注泥瓦匠个人博客的更新：[我的博客](https://www.bysocket.com \"我的博客\") - 分享学习可落地的技术博文\n\n**Spring Boot 2.x 系列教程**，spring boot 实践学习案例，是初学者及核心技术巩固的最佳实践。\n\n1. 拿起微信，关注公众号：「程序员泥瓦匠 」\n2. 给教程的开源代码仓库点个 **Star** 吧\n\t- [GitHub（springboot-learning-example）](https://github.com/JeffLi1993/springboot-learning-example \"GitHub（springboot-learning-example）\")\n\t- [Gitee（springboot-learning-example）](https://gitee.com/jeff1993/springboot-learning-example \"Gitee（springboot-learning-example）\")\n3. 帮忙分享该系列文章链接给更多的朋友\n\n### 二、系列文章目录\n\n#### 『 Spring Boot 2 快速教程 』\n- [Spring Boot 2 快速教程：WebFlux 集成 Thymeleaf（五）](https://www.bysocket.com/springboot/2358.html)\n- [Spring Boot 2 快速教程：WebFlux 集成 Mongodb（四）](https://www.bysocket.com/springboot/2342.html)\n- [Spring Boot 2 快速教程：WebFlux Restful CRUD 实践（三）](https://www.bysocket.com/technique/2328.html)\n- [Spring Boot 2 快速教程：WebFlux 快速入门（二）](https://www.bysocket.com/technique/2306.html)\n- [Spring Boot 2 快速教程：WebFlux REST API 全局异常处理 Error Handling](https://www.bysocket.com/technique/2272.html)\n- [Spring Boot 2 快速教程：WebFlux 系列教程大纲（一）](https://www.bysocket.com/technique/2290.html)\n\n#### 『 基础 - 入门篇 』\n- [Spring Boot 2.0 配置图文教程](https://www.bysocket.com/technique/2135.html)\n- [Spring Boot 2.0 的快速入门（图文教程）](https://www.bysocket.com/technique/2119.html)\n- [Spring Boot 之 HelloWorld 详解](http://www.bysocket.com/?p=1124)\n-  [Spring Boot 之配置文件详解](http://www.bysocket.com/?p=1786)\n\n#### 『 基础 - Web 业务开发篇 』\n- [Spring Boot Web 开发注解篇](http://www.bysocket.com/?p=1929)\n- [Spring Boot 表单验证篇](http://www.bysocket.com/?p=1942)\n- [Spring Boot 2.x 小新功能 – Spring Data Web configuration](http://www.bysocket.com/?p=1950)\n- [Spring Boot 实现 Restful 服务，基于 HTTP / JSON 传输](http://www.bysocket.com/?p=1627)\n- [Spring Boot 之 RESRful API 权限控制](http://www.bysocket.com/?p=1080)\n- [Spring Boot 集成 FreeMarker](http://www.bysocket.com/?p=1666)\n- [Spring Boot HTTP over JSON 的错误码异常处理](http://www.bysocket.com/?p=1692)\n- Spring Boot 使用 Swagger2 构建 RESRful API 文档\n- Spring Boot 集成 JSP\n- Spring Boot 集成 Thymeleaf\n- Spring Boot 单元测试的使用\n- Spring Boot 热更新部署\n\n#### 『 基础 – 数据存储篇 』\n- [Spring Boot 整合 Mybatis 的完整 Web 案例](http://www.bysocket.com/?p=1610)\n- [Spring Boot 整合 Mybatis Annotation 注解案例](http://www.bysocket.com/?p=1811)\n- [Spring Boot 整合 Mybatis 实现 Druid 多数据源配置](http://www.bysocket.com/?p=1712)\n- Spring Boot 整合使用 JdbcTemplate\n- Spring Boot 整合 Spring-data-jpa\n- Spring Boot 声明式事务管理\n\n#### 『 基础 – 数据缓存篇 』\n- [Spring Boot 整合 Redis 实现缓存操作](http://www.bysocket.com/?p=1756)\n- Spring Boot 整合 Redis Annotation 实现缓存操作\n- Spring Boot 整合 MongoDB 实现缓存操作\n- Spring Boot 整合 EhCache 实现缓存操作\n\n#### 『 基础 – 日志管理篇 』\n- Spring Boot 默认日志 logback 配置解析\n- Spring Boot 使用 log4j 记录日志\n- Spring Boot 对 log4j 进行多环境不同日志级别的控制\n- Spring Boot 使用 log4j 记录日志到 MongoDB\n- Spring Boot 1.5.x 动态修改日志级别\n \n#### 『 基础 – 应用篇 』\n- Spring Boot Actuator 监控\n- Spring Boot Web 应用部署\n \n#### 『 提升 – 安全控制及权限篇 』\n- Spring Boot 整合 Spring Security\n- Spring Boot 整合 Shiro\n- Spring Boot 整合 Spring Session\n \n#### 『 提升 – 中间件篇 』\n- [Spring Boot 2.x ：通过 spring-boot-starter-hbase 集成 HBase](https://www.bysocket.com/technique/2162.html)\n- Spring Boot 整合 RabbitMQ\n- Spring Boot 整合 Quartz\n\n#### 『 提升 – 源码篇 』\n- Spring Boot 启动原理解析\n \n#### 『 Elasticsearch 篇 』\n- [Spring Boot 整合 Elasticsearch](http://www.bysocket.com/?p=1829)\n- [深入浅出 spring-data-elasticsearch 之 ElasticSearch 架构初探（一）](http://www.bysocket.com/?p=1889)\n- [深入浅出 spring-data-elasticsearch 系列 – 概述及入门（二）](http://www.bysocket.com/?p=1894)\n- [深入浅出 spring-data-elasticsearch – 基本案例详解（三）](http://www.bysocket.com/?p=1899)\n- [深入浅出 spring-data-elasticsearch – 实战案例详解（四）](http://www.bysocket.com/?p=1902)\n\n#### 『 Dubbo 篇 』\n-  [Spring Boot 整合 Dubbo/ZooKeeper 详解 SOA 案例](http://www.bysocket.com/?p=1681)\n-  [Spring Boot 中如何使用 Dubbo Activate 扩展点](http://www.bysocket.com/?p=1782)\n-  [Spring Boot Dubbo applications.properties 配置清单](http://www.bysocket.com/?p=1805)\n\n### 三、最后推荐\n\n- [我的博客](https://www.bysocket.com \"我的博客\")：分享学习可落地的技术博文\n- [我的GitHub](https://github.com/JeffLi1993 \"我的GitHub\")：Follow 下呗\n- [我的Gitee](https://gitee.com/jeff1993 \"我的Gitee\")：Follow 下呗\n- [Spring问答社区](http://www.spring4all.com/ \"Spring问答社区\")：如果您有什么问题，可以去这里发帖\n\n### 四、我的公号\n\n<img width=\"300\" src=\"https://www.bysocket.com/images/qrcode.jpeg\">\n"
  },
  {
    "path": "chapter-1-spring-boot-quickstart/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <name>chapter-1-spring-boot-quickstart</name>\n    <description>《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 1 章《Spring Boot 入门》Demo</description>\n\n    <groupId>demo.springboot</groupId>\n    <artifactId>chapter-1-spring-boot-quickstart</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n\n        <!-- Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- 测试依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <!-- Spring Boot Maven 插件 -->\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n\n    <repositories>\n        <repository>\n            <id>spring-snapshots</id>\n            <name>Spring Snapshots</name>\n            <url>https://repo.spring.io/libs-snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "chapter-1-spring-boot-quickstart/src/main/java/demo/springboot/QuickStartApplication.java",
    "content": "package demo.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 26/09/2017.\n */\n@SpringBootApplication\npublic class QuickStartApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(QuickStartApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "chapter-1-spring-boot-quickstart/src/main/java/demo/springboot/web/HelloBookController.java",
    "content": "package demo.springboot.web;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Spring Boot Hello案例\n *\n * Created by bysocket on 26/09/2017.\n */\n@RestController\npublic class HelloBookController {\n\n    @RequestMapping(value = \"/book/hello\",method = RequestMethod.GET)\n    public String sayHello() {\n        return \"Hello，《Spring Boot 2.x 核心技术实战 - 上 基础篇》！\";\n    }\n}\n"
  },
  {
    "path": "chapter-1-spring-boot-quickstart/src/main/java/demo/springboot/web/HelloController.java",
    "content": "package demo.springboot.web;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * Spring Boot Hello案例\n *\n * Created by bysocket on 26/09/2017.\n */\n@Controller\npublic class HelloController {\n\n    @RequestMapping(value = \"/hello\",method = RequestMethod.GET)\n    @ResponseBody\n    public String sayHello() {\n        return \"Hello，Spring Boot！\";\n    }\n}\n"
  },
  {
    "path": "chapter-1-spring-boot-quickstart/src/main/resources/application.properties",
    "content": "server.port=-1"
  },
  {
    "path": "chapter-1-spring-boot-quickstart/src/test/java/demo/springboot/QuickStartApplicationTests.java",
    "content": "package demo.springboot;\n\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.servlet.MockMvc;\n\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = QuickStartApplication.class)\n@AutoConfigureMockMvc\n@TestPropertySource(locations = \"classpath:application.properties\")\npublic class QuickStartApplicationTests {\n\n    @Autowired\n    private MockMvc mvc;\n\n\n    @Test\n    public void requestHello_thenStatus200_and_outputHello() throws Exception {\n        mvc.perform(get(\"/hello\")\n                .contentType(MediaType.APPLICATION_JSON))\n                .andExpect(status().isOk())\n                .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_PLAIN))\n                .andExpect(content().encoding(\"UTF-8\"))\n                .andExpect(content().string(\"Hello，Spring Boot！\"));\n    }\n\n}\n"
  },
  {
    "path": "chapter-1-spring-boot-quickstart/src/test/resources/application.properties",
    "content": "server.port=-1"
  },
  {
    "path": "chapter-2-spring-boot-config/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <name>chapter-2-spring-boot-config</name>\n    <description>《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 2 章《Spring Boot 配置》Demo</description>\n\n    <groupId>demo.springboot</groupId>\n    <artifactId>chapter-2-spring-boot-config</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n\n        <!-- Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- 自定义 swagger2 Starter 组件依赖 -->\n        <dependency>\n            <groupId>com.spring4all</groupId>\n            <artifactId>spring-boot-starter-swagger</artifactId>\n            <version>1.5.1.RELEASE</version>\n        </dependency>\n\n        <!-- 测试依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <!-- Spring Boot Maven 插件 -->\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>2.1.3.RELEASE</version>\n            </plugin>\n\n        </plugins>\n    </build>\n\n\n    <repositories>\n        <repository>\n            <id>spring-snapshots</id>\n            <name>Spring Snapshots</name>\n            <url>https://repo.spring.io/libs-snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "chapter-2-spring-boot-config/src/main/java/demo/springboot/ConfigApplication.java",
    "content": "package demo.springboot;\n\nimport com.spring4all.swagger.EnableSwagger2Doc;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 26/09/2017.\n */\n@EnableSwagger2Doc // 开启 Swagger\n@SpringBootApplication\npublic class ConfigApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(ConfigApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "chapter-2-spring-boot-config/src/main/java/demo/springboot/config/BookComponent.java",
    "content": "package demo.springboot.config;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\nimport org.springframework.validation.annotation.Validated;\n\nimport javax.validation.constraints.NotEmpty;\nimport javax.validation.constraints.NotNull;\n\n/**\n * 书属性\n *\n */\n@Component\n@ConfigurationProperties(prefix = \"demo.book\")\n@Validated\npublic class BookComponent {\n\n    /**\n     * 书名\n     */\n    @NotEmpty\n    private String name;\n\n    /**\n     * 作者\n     */\n    @NotNull\n    private String writer;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getWriter() {\n        return writer;\n    }\n\n    public void setWriter(String writer) {\n        this.writer = writer;\n    }\n}\n"
  },
  {
    "path": "chapter-2-spring-boot-config/src/main/java/demo/springboot/config/BookProperties.java",
    "content": "package demo.springboot.config;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n/**\n * 书属性\n *\n * Created by bysocket on 27/09/2017.\n */\n@Component\npublic class BookProperties {\n\n    /**\n     * 书名\n     */\n    @Value(\"${demo.book.name}\")\n    private String name;\n\n    /**\n     * 作者\n     */\n    @Value(\"${demo.book.writer}\")\n    private String writer;\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getWriter() {\n        return writer;\n    }\n\n    public void setWriter(String writer) {\n        this.writer = writer;\n    }\n}\n"
  },
  {
    "path": "chapter-2-spring-boot-config/src/main/java/demo/springboot/web/HelloBookController.java",
    "content": "package demo.springboot.web;\n\nimport demo.springboot.config.BookProperties;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Spring Boot Hello案例\n *\n * Created by bysocket on 26/09/2017.\n */\n@RestController\npublic class HelloBookController {\n\n    @Autowired\n    BookProperties bookProperties;\n\n    @GetMapping(\"/book/hello\")\n    public String sayHello() {\n        return \"Hello， \" + bookProperties.getWriter() + \" is writing \"\n                + bookProperties.getName() + \" ！\";\n    }\n}\n"
  },
  {
    "path": "chapter-2-spring-boot-config/src/main/resources/application-dev.properties",
    "content": "## \\u4E66\\u4FE1\\u606F\ndemo.book.name=[Spring Boot 2.x Core Action] From Dev\ndemo.book.writer=BYSocket\n"
  },
  {
    "path": "chapter-2-spring-boot-config/src/main/resources/application-prod.properties",
    "content": "## \\u4E66\\u4FE1\\u606F\ndemo.book.name=[Spring Boot 2.x Core Action] From Prod\ndemo.book.writer=BYSocket\n"
  },
  {
    "path": "chapter-2-spring-boot-config/src/main/resources/application.properties",
    "content": "## \\u4E66\\u4FE1\\u606F\ndemo.book.name=[Spring Boot 2.x Core Action]\ndemo.book.writer=BYSocket\ndemo.book.description=${demo.book.writer}'s${demo.book.name}\n\n"
  },
  {
    "path": "chapter-2-spring-boot-config/src/main/resources/application.yml",
    "content": "## 书信息\ndemo:\n    book:\n        name: 《Spring Boot 2.x 核心技术实战 - 上 基础篇》\n        writer: 泥瓦匠BYSocket"
  },
  {
    "path": "chapter-2-spring-boot-config/src/test/java/demo/springboot/ConfigApplicationTests.java",
    "content": "package demo.springboot;\n\nimport demo.springboot.config.BookComponent;\nimport demo.springboot.config.BookProperties;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ConfigApplicationTests {\n\n\t@Autowired\n\tBookProperties bookProperties;\n\n\t@Autowired\n\tBookComponent bookComponent;\n\n\t@Test\n\tpublic void testBookProperties() {\n\t\tAssert.assertEquals(bookProperties.getName(),\"[Spring Boot 2.x Core Action]\");\n\t\tAssert.assertEquals(bookProperties.getWriter(),\"BYSocket\");\n\t}\n\n\t@Test\n\tpublic void testBookComponent() {\n\t\tAssert.assertEquals(bookComponent.getName(),\"[Spring Boot 2.x Core Action]\");\n\t\tAssert.assertEquals(bookComponent.getWriter(),\"BYSocket\");\n\t}\n}\n"
  },
  {
    "path": "chapter-3-spring-boot-web/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <name>chapter-3-spring-boot-web</name>\n    <description>《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 3 章《Web 开发》Demo</description>\n\n    <groupId>demo.springboot</groupId>\n    <artifactId>chapter-3-spring-boot-web</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n\n        <!-- Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- 测试依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <!-- Spring Boot Maven 插件\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            -->\n        </plugins>\n    </build>\n\n\n    <repositories>\n        <repository>\n            <id>spring-snapshots</id>\n            <name>Spring Snapshots</name>\n            <url>https://repo.spring.io/libs-snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "chapter-3-spring-boot-web/src/main/java/demo/springboot/WebApplication.java",
    "content": "package demo.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 26/09/2017.\n */\n@SpringBootApplication\npublic class WebApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(WebApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "chapter-3-spring-boot-web/src/main/java/demo/springboot/domain/Book.java",
    "content": "package demo.springboot.domain;\n\nimport java.io.Serializable;\n\n/**\n * Book 实体类\n *\n * Created by bysocket on 27/09/2017.\n */\npublic class Book implements Serializable {\n\n    /**\n     * 编号\n     */\n    private Long id;\n\n    /**\n     * 书名\n     */\n    private String name;\n\n    /**\n     * 作者\n     */\n    private String writer;\n\n    /**\n     * 简介\n     */\n    private String introduction;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getWriter() {\n        return writer;\n    }\n\n    public void setWriter(String writer) {\n        this.writer = writer;\n    }\n\n    public String getIntroduction() {\n        return introduction;\n    }\n\n    public void setIntroduction(String introduction) {\n        this.introduction = introduction;\n    }\n\n    public Book(Long id, String name, String writer, String introduction) {\n        this.id = id;\n        this.name = name;\n        this.writer = writer;\n        this.introduction = introduction;\n    }\n\n    public Book(Long id, String name) {\n        this.id = id;\n        this.name = name;\n    }\n\n    public Book(String name) {\n        this.name = name;\n    }\n\n    public Book() {\n    }\n}\n"
  },
  {
    "path": "chapter-3-spring-boot-web/src/main/java/demo/springboot/service/BookService.java",
    "content": "package demo.springboot.service;\n\nimport demo.springboot.domain.Book;\n\nimport java.util.List;\n\n/**\n * Book 业务接口层\n *\n * Created by bysocket on 27/09/2017.\n */\npublic interface BookService {\n    /**\n     * 获取所有 Book\n     */\n    List<Book> findAll();\n\n    /**\n     * 新增 Book\n     *\n     * @param book {@link Book}\n     */\n    Book insertByBook(Book book);\n\n    /**\n     * 更新 Book\n     *\n     * @param book {@link Book}\n     */\n    Book update(Book book);\n\n    /**\n     * 删除 Book\n     *\n     * @param id 编号\n     */\n    Book delete(Long id);\n\n    /**\n     * 获取 Book\n     *\n     * @param id 编号\n     */\n    Book findById(Long id);\n\n    /**\n     * 查找书是否存在\n     * @param book\n     * @return\n     */\n    boolean exists(Book book);\n\n    /**\n     * 根据书名获取书籍\n     * @param name\n     * @return\n     */\n    Book findByName(String name);\n}\n"
  },
  {
    "path": "chapter-3-spring-boot-web/src/main/java/demo/springboot/service/impl/BookServiceImpl.java",
    "content": "package demo.springboot.service.impl;\n\nimport demo.springboot.domain.Book;\nimport demo.springboot.service.BookService;\nimport demo.springboot.web.BookController;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.ObjectUtils;\nimport org.springframework.util.StringUtils;\n\nimport javax.annotation.PostConstruct;\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Book 业务层实现\n * <p>\n * Created by bysocket on 27/09/2017.\n */\n@Service\npublic class BookServiceImpl implements BookService {\n\n    private static final AtomicLong counter = new AtomicLong();\n\n\n    /**\n     * 使用集合模拟数据库\n     */\n    private static List<Book> books = new ArrayList<>(\n            Arrays.asList(\n                    new Book(counter.incrementAndGet(), \"book\")));\n\n\n    // 模拟数据库，存储 Book 信息\n    // 第五章《﻿数据存储》会替换成 MySQL 存储\n    private static Map<String, Book> BOOK_DB = new HashMap<>();\n\n    @Override\n    public List<Book> findAll() {\n        return new ArrayList<>(BOOK_DB.values());\n    }\n\n    @Override\n    public Book insertByBook(Book book) {\n        book.setId(BOOK_DB.size() + 1L);\n        BOOK_DB.put(book.getId().toString(), book);\n        return book;\n    }\n\n    @Override\n    public Book update(Book book) {\n        BOOK_DB.put(book.getId().toString(), book);\n        return book;\n    }\n\n    @Override\n    public Book delete(Long id) {\n        return BOOK_DB.remove(id.toString());\n    }\n\n    @Override\n    public Book findById(Long id) {\n        return BOOK_DB.get(id.toString());\n    }\n\n    @Override\n    public boolean exists(Book book) {\n        return findByName(book.getName()) != null;\n    }\n\n    @Override\n    public Book findByName(String name) {\n\n        for (Book book : books) {\n            if (book.getName().equals(name)) {\n                return book;\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "chapter-3-spring-boot-web/src/main/java/demo/springboot/web/BookController.java",
    "content": "package demo.springboot.web;\n\nimport demo.springboot.domain.Book;\nimport demo.springboot.service.BookService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport java.util.List;\n\n/**\n * Book 控制层\n *\n * Created by bysocket on 27/09/2017.\n */\n@RestController\n@RequestMapping(value = \"/book\")\npublic class BookController {\n\n\n    private final Logger LOG = LoggerFactory.getLogger(BookController.class);\n\n\n    @Autowired\n    BookService bookService;\n\n    /**\n     * 获取 Book 列表\n     * 处理 \"/book\" 的 GET 请求，用来获取 Book 列表\n     */\n    @RequestMapping(method = RequestMethod.GET)\n    public List<Book> getBookList() {\n        return bookService.findAll();\n    }\n\n    /**\n     * 获取 Book\n     * 处理 \"/book/{id}\" 的 GET 请求，用来获取 Book 信息\n     */\n    @RequestMapping(value = \"/{id}\", method = RequestMethod.GET)\n    public Book getBook(@PathVariable Long id) {\n        return bookService.findById(id);\n    }\n\n    /**\n     * 创建 Book\n     * 处理 \"/book/create\" 的 POST 请求，用来新建 Book 信息\n     * 通过 @RequestBody 绑定实体参数，也通过 @RequestParam 传递参数\n     */\n    @RequestMapping(value = \"/create\", method = RequestMethod.POST)\n    public ResponseEntity<Void> postBook(@RequestBody Book book, UriComponentsBuilder ucBuilder) {\n\n        LOG.info(\"creating new book: {}\", book);\n\n        if (book.getName().equals(\"conflict\")){\n            LOG.info(\"a book with name \" + book.getName() + \" already exists\");\n            return new ResponseEntity<>(HttpStatus.CONFLICT);\n        }\n\n        bookService.insertByBook(book);\n\n        HttpHeaders headers = new HttpHeaders();\n        headers.setLocation(ucBuilder.path(\"/book/{id}\").buildAndExpand(book.getId()).toUri());\n        return new ResponseEntity<>(headers, HttpStatus.CREATED);\n    }\n\n    /**\n     * 更新 Book\n     * 处理 \"/update\" 的 PUT 请求，用来更新 Book 信息\n     */\n    @RequestMapping(value = \"/update\", method = RequestMethod.PUT)\n    public Book putBook(@RequestBody Book book) {\n        return bookService.update(book);\n    }\n\n    /**\n     * 删除 Book\n     * 处理 \"/book/{id}\" 的 GET 请求，用来删除 Book 信息\n     */\n    @RequestMapping(value = \"/delete/{id}\", method = RequestMethod.DELETE)\n    public Book deleteBook(@PathVariable Long id) {\n        return bookService.delete(id);\n    }\n\n}\n"
  },
  {
    "path": "chapter-3-spring-boot-web/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "chapter-3-spring-boot-web/src/test/java/demo/springboot/WebApplicationTests.java",
    "content": "package demo.springboot;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class WebApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "chapter-3-spring-boot-web/src/test/java/demo/springboot/web/BookControllerTest.java",
    "content": "package demo.springboot.web;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport demo.springboot.WebApplication;\nimport demo.springboot.domain.Book;\nimport demo.springboot.service.BookService;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.InjectMocks;\nimport org.mockito.Mock;\nimport org.mockito.MockitoAnnotations;\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.setup.MockMvcBuilders;\n\nimport static org.hamcrest.Matchers.*;\nimport static org.hamcrest.Matchers.is;\nimport static org.mockito.Mockito.*;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;\n\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebApplication.class)\n@AutoConfigureMockMvc\n@TestPropertySource(locations = \"classpath:application.properties\")\npublic class BookControllerTest {\n\n    private MockMvc mockMvc;\n\n    @Mock\n    private BookService bookService;\n\n    @InjectMocks\n    private BookController bookController;\n\n    @Before\n    public void init() {\n        MockitoAnnotations.initMocks(this);\n        mockMvc = MockMvcBuilders\n                .standaloneSetup(bookController)\n                //.addFilters(new CORSFilter())\n                .build();\n    }\n\n\n    @Test\n    public void getBookList() throws Exception {\n        mockMvc.perform(get(\"/book\")\n                .contentType(MediaType.APPLICATION_JSON))\n                .andExpect(status().isOk())\n                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON_UTF8))\n                .andExpect(jsonPath(\"$\", hasSize(0)));\n\n    }\n\n\n    @Test\n    public void test_create_book_success() throws Exception {\n\n        Book book = createOneBook();\n\n        when(bookService.insertByBook(book)).thenReturn(book);\n\n        mockMvc.perform(\n                post(\"/book/create\")\n                        .contentType(MediaType.APPLICATION_JSON)\n                        .content(asJsonString(book)))\n\n                .andExpect(status().isCreated())\n                .andExpect(header().string(\"location\", containsString(\"/book/1\")));\n    }\n\n\n    @Test\n    public void test_create_book_fail_404_not_found() throws Exception {\n\n        Book book = new Book(99L, \"conflict\");\n\n        when(bookService.exists(book)).thenReturn(true);\n\n        mockMvc.perform(\n                post(\"/book/create\")\n                        .contentType(MediaType.APPLICATION_JSON)\n                        .content(asJsonString(book)))\n                .andExpect(status().isConflict());\n    }\n\n    @Test\n    public void test_get_book_success() throws Exception {\n\n        Book book = new Book(1L, \"测试获取一本书\", \"strongant作者\", \"社区 www.spring4all.com 出版社出版\");\n\n        when(bookService.findById(1L)).thenReturn(book);\n\n        mockMvc.perform(get(\"/book/{id}\", 1L))\n                .andExpect(status().isOk())\n                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))\n                .andExpect(jsonPath(\"$.id\", is(1)))\n                .andExpect(jsonPath(\"$.name\", is(\"测试获取一本书\")));\n\n        verify(bookService, times(1)).findById(1L);\n        verifyNoMoreInteractions(bookService);\n    }\n\n    @Test\n    public void test_get_by_id_fail_null_not_found() throws Exception {\n        when(bookService.findById(1L)).thenReturn(null);\n\n        //TODO: 查找不到应该抛出 404 状态码， Demo 待优化\n        mockMvc.perform(get(\"/book/{id}\", 1L))\n                .andExpect(status().isOk())\n                .andExpect(content().string(\"\"));\n\n        verify(bookService, times(1)).findById(1L);\n        verifyNoMoreInteractions(bookService);\n    }\n\n    @Test\n    public void test_update_book_success() throws Exception {\n\n        Book book = createOneBook();\n\n        when(bookService.findById(book.getId())).thenReturn(book);\n        doReturn(book).when(bookService).update(book);\n\n        mockMvc.perform(\n                put(\"/book/update\", book)\n                        .contentType(MediaType.APPLICATION_JSON)\n                        .content(asJsonString(book)))\n                .andExpect(status().isOk());\n    }\n\n    @Test\n    public void test_update_book_fail_not_found() throws Exception {\n        Book book = new Book(999L, \"测试书名1\");\n\n        when(bookService.findById(book.getId())).thenReturn(null);\n\n        mockMvc.perform(\n                put(\"/book/update\", book)\n                        .contentType(MediaType.APPLICATION_JSON)\n                        .content(asJsonString(book)))\n                .andExpect(status().isOk())\n                .andExpect(content().string(\"\"));\n    }\n\n    // =========================================== Delete Book ============================================\n\n    @Test\n    public void test_delete_book_success() throws Exception {\n\n        Book book = new Book(1L, \"这本书会被删除啦\");\n\n        when(bookService.findById(book.getId())).thenReturn(book);\n        doReturn(book).when(bookService).delete(book.getId());\n\n        mockMvc.perform(\n                delete(\"/book/delete/{id}\", book.getId())\n        ).andExpect(status().isOk());\n    }\n\n    @Test\n    public void test_delete_book_fail_404_not_found() throws Exception {\n        Book book = new Book(1L, \"这本书会被删除啦\");\n\n        when(bookService.findById(book.getId())).thenReturn(null);\n\n        mockMvc.perform(\n                delete(\"/book/delete/{id}\", book.getId()))\n                .andExpect(status().isOk());\n    }\n\n\n    public static String asJsonString(final Object obj) {\n        try {\n            final ObjectMapper mapper = new ObjectMapper();\n            return mapper.writeValueAsString(obj);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private Book createOneBook() {\n        Book book = new Book();\n        book.setId(1L);\n        book.setName(\"测试书名1\");\n        book.setIntroduction(\"这是一本 www.spring4all.com 社区出版的很不错的一本书籍\");\n        book.setWriter(\"strongant\");\n        return book;\n    }\n}"
  },
  {
    "path": "chapter-3-spring-boot-web/src/test/resources/application.properties",
    "content": "server.port=9090"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>spring.boot.core</groupId>\n    <artifactId>chapter-4-spring-boot-validating-form-input</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>chapter-4-spring-boot-validating-form-input</name>\n    <description>第四章表单校验案例</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.0.M4</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-validation</artifactId>\n        </dependency>\n\n        <!-- Web 依赖 - 包含了 hibernate-validator 依赖-->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- 单元测试依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Spring Data JPA 依赖 :: 数据持久层框架 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n\n        <!-- h2 数据源连接驱动 -->\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n\n        <!-- 模板引擎 Thymeleaf 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <!-- Spring Boot Maven 插件 -->\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>2.1.3.RELEASE</version>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>spring-milestones</id>\n            <name>Spring Milestones</name>\n            <url>https://repo.spring.io/libs-milestone</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/ValidatingFormInputApplication.java",
    "content": "package spring.boot.core;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport spring.boot.core.domain.User;\nimport spring.boot.core.domain.UserRepository;\n\n@SpringBootApplication\npublic class ValidatingFormInputApplication implements CommandLineRunner {\n\n\n    private Logger LOG = LoggerFactory.getLogger(ValidatingFormInputApplication.class);\n\n    @Autowired\n    private UserRepository userRepository;\n\n    public static void main(String[] args) {\n        SpringApplication.run(ValidatingFormInputApplication.class, args);\n    }\n\n    @Override\n    public void run(String... args) throws Exception {\n        User user1 = new User(\"Sergey\", 24, \"1994-01-01\");\n        User user2 = new User(\"Ivan\", 26, \"1994-01-01\");\n        User user3 = new User(\"Adam\", 31, \"1994-01-01\");\n        LOG.info(\"Inserting data in DB.\");\n        userRepository.save(user1);\n        userRepository.save(user2);\n        userRepository.save(user3);\n        LOG.info(\"User count in DB: {}\", userRepository.count());\n        LOG.info(\"User with ID 1: {}\", userRepository.findById(1L));\n        LOG.info(\"Deleting user with ID 2L form DB.\");\n        userRepository.deleteById(2L);\n        LOG.info(\"User count in DB: {}\", userRepository.count());\n    }\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/domain/User.java",
    "content": "package spring.boot.core.domain;\n\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.validation.constraints.Max;\nimport javax.validation.constraints.Min;\nimport javax.validation.constraints.NotNull;\nimport javax.validation.constraints.Size;\nimport java.io.Serializable;\n\n/**\n * 用户实体类\n * <p>\n * Created by bysocket on 21/07/2017.\n */\n@Entity\npublic class User implements Serializable {\n\n    /**\n     * 编号\n     */\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    /**\n     * 名称\n     */\n    @NotEmpty(message = \"姓名不能为空\")\n    @Size(min = 2, max = 8, message = \"姓名长度必须大于 2 且小于 20 字\")\n    private String name;\n\n    /**\n     * 年龄\n     */\n    @NotNull(message = \"年龄不能为空\")\n    @Min(value = 0, message = \"年龄大于 0\")\n    @Max(value = 300, message = \"年龄不大于 300\")\n    private Integer age;\n\n    /**\n     * 出生时间\n     */\n    @NotEmpty(message = \"出生时间不能为空\")\n    private String birthday;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    public String getBirthday() {\n        return birthday;\n    }\n\n    public void setBirthday(String birthday) {\n        this.birthday = birthday;\n    }\n\n\n    public User(String name, Integer age, String birthday) {\n        this.name = name;\n        this.age = age;\n        this.birthday = birthday;\n    }\n\n    public User() {}\n\n    @Override\n    public String toString() {\n        return \"User{\" +\n                \"id=\" + id +\n                \", name='\" + name + '\\'' +\n                \", age=\" + age +\n                \", birthday=\" + birthday +\n                '}';\n    }\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/domain/UserRepository.java",
    "content": "package spring.boot.core.domain;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\n\n/**\n * 用户持久层操作接口\n *\n * Created by bysocket on 21/07/2017.\n */\npublic interface UserRepository extends JpaRepository<User, Long> {\n\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/service/UserService.java",
    "content": "package spring.boot.core.service;\n\n\nimport spring.boot.core.domain.User;\n\nimport java.util.List;\n\n/**\n * User 业务层接口\n *\n * Created by bysocket on 24/07/2017.\n */\npublic interface UserService {\n\n    List<User> findAll();\n\n    User insertByUser(User user);\n\n    User update(User user);\n\n    User delete(Long id);\n\n    User findById(Long id);\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/service/impl/UserServiceImpl.java",
    "content": "package spring.boot.core.service.impl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport spring.boot.core.domain.User;\nimport spring.boot.core.domain.UserRepository;\nimport spring.boot.core.service.UserService;\n\nimport java.util.List;\n\n/**\n * User 业务层实现\n *\n * Created by bysocket on 24/07/2017.\n */\n@Service\npublic class UserServiceImpl implements UserService {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);\n\n    @Autowired\n    UserRepository userRepository;\n\n    @Override\n    public List<User> findAll() {\n        return userRepository.findAll();\n    }\n\n    @Override\n    public User insertByUser(User user) {\n        LOGGER.info(\"新增用户：\" + user.toString());\n        return userRepository.save(user);\n    }\n\n    @Override\n    public User update(User user) {\n        LOGGER.info(\"更新用户：\" + user.toString());\n        return userRepository.save(user);\n    }\n\n    @Override\n    public User delete(Long id) {\n        User user = userRepository.findById(id).get();\n        userRepository.delete(user);\n\n        LOGGER.info(\"删除用户：\" + user.toString());\n        return user;\n    }\n\n    @Override\n    public User findById(Long id) {\n        LOGGER.info(\"获取用户 ID ：\" + id);\n        return userRepository.findById(id).get();\n    }\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/java/spring/boot/core/web/UserController.java",
    "content": "package spring.boot.core.web;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.ModelAttribute;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport spring.boot.core.domain.User;\nimport spring.boot.core.service.UserService;\n\nimport javax.validation.Valid;\n\n/**\n * 用户控制层\n *\n * Created by bysocket on 24/07/2017.\n */\n@Controller\n@RequestMapping(value = \"/users\")     // 通过这里配置使下面的映射都在 /users\npublic class UserController {\n\n    @Autowired\n    UserService userService;          // 用户服务层\n\n    /**\n     *  获取用户列表\n     *    处理 \"/users\" 的 GET 请求，用来获取用户列表\n     *    通过 @RequestParam 传递参数，进一步实现条件查询或者分页查询\n     */\n    @RequestMapping(method = RequestMethod.GET)\n    public String getUserList(ModelMap map) {\n        map.addAttribute(\"userList\", userService.findAll());\n        return \"userList\";\n    }\n\n    /**\n     * 显示创建用户表单\n     *\n     * @param map\n     * @return\n     */\n    @RequestMapping(value = \"/create\", method = RequestMethod.GET)\n    public String createUserForm(ModelMap map) {\n        map.addAttribute(\"user\", new User());\n        map.addAttribute(\"action\", \"create\");\n        return \"userForm\";\n    }\n\n    /**\n     *  创建用户\n     *    处理 \"/users\" 的 POST 请求，用来获取用户列表\n     *    通过 @ModelAttribute 绑定参数，也通过 @RequestParam 从页面中传递参数\n     */\n    @RequestMapping(value = \"/create\", method = RequestMethod.POST)\n    public String postUser(ModelMap map,\n                           @ModelAttribute @Valid User user,\n                           BindingResult bindingResult) {\n\n        if (bindingResult.hasErrors()) {\n            map.addAttribute(\"action\", \"create\");\n            return \"userForm\";\n        }\n\n        userService.insertByUser(user);\n\n        return \"redirect:/users/\";\n    }\n\n\n    /**\n     * 显示需要更新用户表单\n     *    处理 \"/users/{id}\" 的 GET 请求，通过 URL 中的 id 值获取 User 信息\n     *    URL 中的 id ，通过 @PathVariable 绑定参数\n     */\n    @RequestMapping(value = \"/update/{id}\", method = RequestMethod.GET)\n    public String getUser(@PathVariable Long id, ModelMap map) {\n        map.addAttribute(\"user\", userService.findById(id));\n        map.addAttribute(\"action\", \"update\");\n        return \"userForm\";\n    }\n\n    /**\n     * 处理 \"/users/{id}\" 的 PUT 请求，用来更新 User 信息\n     *\n     */\n    @RequestMapping(value = \"/update\", method = RequestMethod.POST)\n    public String putUser(ModelMap map,\n                          @ModelAttribute @Valid User user,\n                          BindingResult bindingResult) {\n\n        if (bindingResult.hasErrors()) {\n            map.addAttribute(\"action\", \"update\");\n            return \"userForm\";\n        }\n\n        userService.update(user);\n        return \"redirect:/users/\";\n    }\n\n    /**\n     * 处理 \"/users/{id}\" 的 GET 请求，用来删除 User 信息\n     */\n    @RequestMapping(value = \"/delete/{id}\", method = RequestMethod.DELETE)\n    public String deleteUser(@PathVariable Long id) {\n\n        userService.delete(id);\n        return \"redirect:/users/\";\n    }\n}"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/resources/application.properties",
    "content": "## 开启 H2 数据库\nspring.h2.console.enabled=true\n\n## 配置 H2 数据库连接信息\nspring.datasource.url=jdbc:h2:mem:testdb  \nspring.datasource.driverClassName=org.h2.Driver  \nspring.datasource.username=sa  \nspring.datasource.password=\n\n\n\n## 是否显示 SQL 语句\nspring.jpa.show-sql=true\nhibernate.dialect=org.hibernate.dialect.H2Dialect\nhibernate.hbm2ddl.auto=create\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/resources/static/css/default.css",
    "content": "/* contentDiv */\n.contentDiv {padding:20px 60px;}"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/resources/templates/userForm.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n    <head>\n        <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n        <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n        <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n        <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n        <meta charset=\"UTF-8\"/>\n        <title>用户管理</title>\n    </head>\n\n    <body>\n        <div class=\"contentDiv\">\n\n            <h5> 《 Spring Boot 2.x 核心技术实战》第二章快速入门案例</h5>\n\n            <legend>\n                <strong>用户管理</strong>\n            </legend>\n\n            <form th:action=\"@{/users/{action}(action=${action})}\" method=\"post\" class=\"form-horizontal\">\n\n                <input type=\"hidden\" name=\"id\" th:value=\"${user.id}\"/>\n\n                <div class=\"form-group\">\n                    <label for=\"user_name\" class=\"col-sm-2 control-label\">名称:</label>\n                    <div class=\"col-xs-4\">\n                        <input type=\"text\" class=\"form-control\" id=\"user_name\" name=\"name\" th:value=\"${user.name}\" th:field=\"*{user.name}\" />\n                    </div>\n                    <label class=\"col-sm-2 control-label text-danger\" th:if=\"${#fields.hasErrors('user.name')}\" th:errors=\"*{user.name}\">姓名有误!</label>\n                </div>\n\n                <div class=\"form-group\">\n                    <label for=\"user_age\" class=\"col-sm-2 control-label\">年龄:</label>\n                    <div class=\"col-xs-4\">\n                        <input type=\"text\" class=\"form-control\" id=\"user_age\" name=\"age\" th:value=\"${user.age}\" th:field=\"*{user.age}\" />\n                    </div>\n                    <label class=\"col-sm-2 control-label text-danger\" th:if=\"${#fields.hasErrors('user.age')}\" th:errors=\"*{user.age}\">年龄有误!</label>\n                </div>\n\n                <div class=\"form-group\">\n                    <label for=\"user_birthday\" class=\"col-sm-2 control-label\">出生日期:</label>\n                    <div class=\"col-xs-4\">\n                        <input type=\"date\" class=\"form-control\" id=\"user_birthday\" name=\"birthday\" th:value=\"${user.birthday}\" th:field=\"*{user.birthday}\"/>\n                    </div>\n                    <label class=\"col-sm-2 control-label text-danger\" th:if=\"${#fields.hasErrors('user.birthday')}\" th:errors=\"*{user.birthday}\">生日有误!</label>\n                </div>\n\n                <div class=\"form-group\">\n                    <div class=\"col-sm-offset-2 col-sm-10\">\n                        <input class=\"btn btn-primary\" type=\"submit\" value=\"提交\"/>&nbsp;&nbsp;\n                        <input class=\"btn\" type=\"button\" value=\"返回\" onclick=\"history.back()\"/>\n                    </div>\n                </div>\n            </form>\n        </div>\n    </body>\n</html>"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/main/resources/templates/userList.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n    <head>\n        <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n        <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n        <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n        <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n        <meta charset=\"UTF-8\"/>\n        <title>用户列表</title>\n    </head>\n\n    <body>\n\n        <div class=\"contentDiv\">\n\n            <h5> 《 Spring Boot 2.x 核心技术实战》第二章快速入门案例</h5>\n\n            <table class=\"table table-hover table-condensed\">\n                <legend>\n                    <strong>用户列表</strong>\n                </legend>\n                <thead>\n                    <tr>\n                        <th>用户编号</th>\n                        <th>名称</th>\n                        <th>年龄</th>\n                        <th>出生时间</th>\n                        <th>管理</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr th:each=\"user : ${userList}\">\n                        <th scope=\"row\" th:text=\"${user.id}\"></th>\n                        <td><a th:href=\"@{/users/update/{userId}(userId=${user.id})}\" th:text=\"${user.name}\"></a></td>\n                        <td th:text=\"${user.age}\"></td>\n                        <td th:text=\"${user.birthday}\"></td>\n                        <td><a class=\"btn btn-danger\" th:href=\"@{/users/delete/{userId}(userId=${user.id})}\">删除</a></td>\n                    </tr>\n                </tbody>\n            </table>\n\n            <div><a class=\"btn btn-primary\" href=\"/users/create\" role=\"button\">创建用户</a></div>\n        </div>\n\n    </body>\n</html>"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/test/java/spring/boot/core/ValidatingFormInputApplicationTests.java",
    "content": "package spring.boot.core;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ValidatingFormInputApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/test/java/spring/boot/core/web/UserControllerTest.java",
    "content": "package spring.boot.core.web;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.test.context.TestPropertySource;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.servlet.MockMvc;\nimport org.springframework.test.web.servlet.MvcResult;\nimport org.springframework.test.web.servlet.request.MockMvcRequestBuilders;\nimport org.springframework.test.web.servlet.result.MockMvcResultMatchers;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\nimport spring.boot.core.ValidatingFormInputApplication;\nimport spring.boot.core.domain.User;\nimport spring.boot.core.service.UserService;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.Map;\n\nimport static junit.framework.TestCase.assertNotNull;\nimport static junit.framework.TestCase.assertTrue;\nimport static org.assertj.core.api.Assertions.assertThat;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.beans.HasPropertyWithValue.hasProperty;\nimport static org.junit.Assert.assertEquals;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;\nimport static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ValidatingFormInputApplication.class)\n@AutoConfigureMockMvc\n@TestPropertySource(locations = \"classpath:application.properties\")\npublic class UserControllerTest {\n\n\n    @Autowired\n    private MockMvc mockMvc;\n\n    @Autowired\n    private UserService userService;\n\n    @Autowired\n    private ObjectMapper objectMapper;\n\n    @Test\n    public void getUserList() throws Exception {\n        mockMvc.perform(get(\"/users\"))\n                .andExpect(view().name(\"userList\"))\n                .andExpect(status().isOk())\n                .andDo(print());\n    }\n\n    private User createUser() {\n        User user = new User();\n        user.setName(\"测试用户\");\n        user.setAge(100);\n        user.setBirthday(\"1994-01-01\");\n        return userService.insertByUser(user);\n    }\n\n    @Test\n    public void createUserForm() throws Exception {\n\n        mockMvc.perform(get(\"/users/create\"))\n                .andDo(print())\n                .andExpect(view().name(\"userForm\"))\n                .andExpect(request().attribute(\"action\", \"create\"))\n                .andDo(print())\n                .andReturn();\n    }\n\n    @Test\n    public void postUser() throws Exception {\n        User user = createUser();\n        assertNotNull(user);\n\n        MultiValueMap parameters = new LinkedMultiValueMap<String, String>();\n        Map<String, String> maps = objectMapper.convertValue(user, new TypeReference<Map<String, String>>() {\n        });\n        parameters.setAll(maps);\n\n        mockMvc.perform(post(\"/users/create\").params(parameters))\n                .andDo(print())\n                .andExpect(status().is(HttpServletResponse.SC_FOUND))\n                .andDo(print())\n                .andExpect(view().name(\"redirect:/users/\"))\n                .andDo(print())\n                .andReturn();\n    }\n\n    @Test\n    public void getUser() throws Exception {\n\n        MvcResult result= mockMvc.perform(get(\"/users/update/{id}/\", 1))\n                .andExpect(status().isOk())\n                .andExpect(view().name(\"userForm\"))\n                .andExpect(MockMvcResultMatchers.model().attributeExists(\"action\"))\n                .andExpect(model().attribute(\"user\", hasProperty(\"id\", is(1L))))\n                .andExpect(model().attribute(\"user\", hasProperty(\"name\", is(\"Sergey\"))))\n                .andExpect(model().attribute(\"user\", hasProperty(\"age\", is(24))))\n                .andExpect(model().attribute(\"user\", hasProperty(\"birthday\", is(\"1994-01-01\"))))\n                .andReturn();\n\n\n        MockHttpServletResponse mockResponse=result.getResponse();\n        assertThat(mockResponse.getContentType()).isEqualTo(\"text/html;charset=UTF-8\");\n\n        Collection<String> responseHeaders = mockResponse.getHeaderNames();\n        assertNotNull(responseHeaders);\n        assertEquals(2, responseHeaders.size());\n        assertEquals(\"Check for Content-Type header\", \"Accept-Language\", responseHeaders.iterator().next());\n        String responseAsString=mockResponse.getContentAsString();\n        assertTrue(responseAsString.contains(\"用户管理\"));\n    }\n\n    @Test\n    public void putUser() throws Exception {\n        User user = createUser();\n        assertNotNull(user);\n\n        MultiValueMap parameters = new LinkedMultiValueMap<String, String>();\n        Map<String, String> maps = objectMapper.convertValue(user, new TypeReference<Map<String, String>>() {\n        });\n        parameters.setAll(maps);\n\n        mockMvc.perform(post(\"/users/update\").params(parameters))\n                .andDo(print())\n                .andExpect(status().is(HttpServletResponse.SC_FOUND))\n                .andDo(print())\n                .andExpect(view().name(\"redirect:/users/\"))\n                .andDo(print())\n                .andReturn();\n    }\n\n    @Test\n    public void deleteUser() throws Exception {\n        mockMvc.perform( MockMvcRequestBuilders.delete(\"/users/delete/{id}\", 1L) )\n                .andDo(print())\n                .andExpect(status().is(HttpServletResponse.SC_FOUND))\n                .andExpect(view().name(\"redirect:/users/\"));\n    }\n\n    public static byte[] convertObjectToJsonBytes(Object object) throws IOException {\n        ObjectMapper mapper = new ObjectMapper();\n        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);\n        return mapper.writeValueAsBytes(object);\n    }\n}"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/test/resources/application.properties",
    "content": "## 开启 H2 数据库\nspring.h2.console.enabled=true\n\n## 配置 H2 数据库连接信息\nspring.datasource.url=jdbc:h2:mem:testdb\nspring.datasource.driverClassName=org.h2.Driver\nspring.datasource.username=sa\nspring.datasource.password=\n\n\n## 是否显示 SQL 语句\nspring.jpa.show-sql=true\nhibernate.dialect=org.hibernate.dialect.H2Dialect\nhibernate.hbm2ddl.auto=create\n"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/test/resources/static/css/default.css",
    "content": "/* contentDiv */\n.contentDiv {padding:20px 60px;}"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/test/resources/templates/userForm.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n    <head>\n        <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n        <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n        <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n        <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n        <meta charset=\"UTF-8\"/>\n        <title>用户管理</title>\n    </head>\n\n    <body>\n        <div class=\"contentDiv\">\n\n            <h5> 《 Spring Boot 2.x 核心技术实战》第二章快速入门案例</h5>\n\n            <legend>\n                <strong>用户管理</strong>\n            </legend>\n\n            <form th:action=\"@{/users/{action}(action=${action})}\" method=\"post\" class=\"form-horizontal\">\n\n                <input type=\"hidden\" name=\"id\" th:value=\"${user.id}\"/>\n\n                <div class=\"form-group\">\n                    <label for=\"user_name\" class=\"col-sm-2 control-label\">名称:</label>\n                    <div class=\"col-xs-4\">\n                        <input type=\"text\" class=\"form-control\" id=\"user_name\" name=\"name\" th:value=\"${user.name}\" th:field=\"*{user.name}\" />\n                    </div>\n                    <label class=\"col-sm-2 control-label text-danger\" th:if=\"${#fields.hasErrors('user.name')}\" th:errors=\"*{user.name}\">姓名有误!</label>\n                </div>\n\n                <div class=\"form-group\">\n                    <label for=\"user_age\" class=\"col-sm-2 control-label\">年龄:</label>\n                    <div class=\"col-xs-4\">\n                        <input type=\"text\" class=\"form-control\" id=\"user_age\" name=\"age\" th:value=\"${user.age}\" th:field=\"*{user.age}\" />\n                    </div>\n                    <label class=\"col-sm-2 control-label text-danger\" th:if=\"${#fields.hasErrors('user.age')}\" th:errors=\"*{user.age}\">年龄有误!</label>\n                </div>\n\n                <div class=\"form-group\">\n                    <label for=\"user_birthday\" class=\"col-sm-2 control-label\">出生日期:</label>\n                    <div class=\"col-xs-4\">\n                        <input type=\"date\" class=\"form-control\" id=\"user_birthday\" name=\"birthday\" th:value=\"${user.birthday}\" th:field=\"*{user.birthday}\"/>\n                    </div>\n                    <label class=\"col-sm-2 control-label text-danger\" th:if=\"${#fields.hasErrors('user.birthday')}\" th:errors=\"*{user.birthday}\">生日有误!</label>\n                </div>\n\n                <div class=\"form-group\">\n                    <div class=\"col-sm-offset-2 col-sm-10\">\n                        <input class=\"btn btn-primary\" type=\"submit\" value=\"提交\"/>&nbsp;&nbsp;\n                        <input class=\"btn\" type=\"button\" value=\"返回\" onclick=\"history.back()\"/>\n                    </div>\n                </div>\n            </form>\n        </div>\n    </body>\n</html>"
  },
  {
    "path": "chapter-4-spring-boot-validating-form-input/src/test/resources/templates/userList.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n    <head>\n        <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n        <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n        <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n        <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n        <meta charset=\"UTF-8\"/>\n        <title>用户列表</title>\n    </head>\n\n    <body>\n\n        <div class=\"contentDiv\">\n\n            <h5> 《 Spring Boot 2.x 核心技术实战》第二章快速入门案例</h5>\n\n            <table class=\"table table-hover table-condensed\">\n                <legend>\n                    <strong>用户列表</strong>\n                </legend>\n                <thead>\n                    <tr>\n                        <th>用户编号</th>\n                        <th>名称</th>\n                        <th>年龄</th>\n                        <th>出生时间</th>\n                        <th>管理</th>\n                    </tr>\n                </thead>\n                <tbody>\n                    <tr th:each=\"user : ${userList}\">\n                        <th scope=\"row\" th:text=\"${user.id}\"></th>\n                        <td><a th:href=\"@{/users/update/{userId}(userId=${user.id})}\" th:text=\"${user.name}\"></a></td>\n                        <td th:text=\"${user.age}\"></td>\n                        <td th:text=\"${user.birthday}\"></td>\n                        <td><a class=\"btn btn-danger\" th:href=\"@{/users/delete/{userId}(userId=${user.id})}\">删除</a></td>\n                    </tr>\n                </tbody>\n            </table>\n\n            <div><a class=\"btn btn-primary\" href=\"/users/create\" role=\"button\">创建用户</a></div>\n        </div>\n\n    </body>\n</html>"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <name>chapter-4-spring-boot-web-thymeleaf</name>\n    <description>《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 4 章《模板引擎》Demo</description>\n\n    <groupId>demo.springboot</groupId>\n    <artifactId>chapter-4-spring-boot-web-thymeleaf</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n\n        <!-- Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- 模板引擎 Thymeleaf 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n        <!-- 测试依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <!-- Spring Boot Maven 插件\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            -->\n        </plugins>\n    </build>\n\n\n    <repositories>\n        <repository>\n            <id>spring-snapshots</id>\n            <name>Spring Snapshots</name>\n            <url>https://repo.spring.io/libs-snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/java/demo/springboot/WebApplication.java",
    "content": "package demo.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 30/09/2017.\n */\n@SpringBootApplication\npublic class WebApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(WebApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/java/demo/springboot/domain/Book.java",
    "content": "package demo.springboot.domain;\n\nimport java.io.Serializable;\n\n/**\n * Book 实体类\n *\n * Created by bysocket on 30/09/2017.\n */\npublic class Book implements Serializable {\n\n    /**\n     * 编号\n     */\n    private Long id;\n\n    /**\n     * 书名\n     */\n    private String name;\n\n    /**\n     * 作者\n     */\n    private String writer;\n\n    /**\n     * 简介\n     */\n    private String introduction;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getWriter() {\n        return writer;\n    }\n\n    public void setWriter(String writer) {\n        this.writer = writer;\n    }\n\n    public String getIntroduction() {\n        return introduction;\n    }\n\n    public void setIntroduction(String introduction) {\n        this.introduction = introduction;\n    }\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/java/demo/springboot/service/BookService.java",
    "content": "package demo.springboot.service;\n\nimport demo.springboot.domain.Book;\n\nimport java.util.List;\n\n/**\n * Book 业务接口层\n *\n * Created by bysocket on 30/09/2017.\n */\npublic interface BookService {\n    /**\n     * 获取所有 Book\n     */\n    List<Book> findAll();\n\n    /**\n     * 新增 Book\n     *\n     * @param book {@link Book}\n     */\n    Book insertByBook(Book book);\n\n    /**\n     * 更新 Book\n     *\n     * @param book {@link Book}\n     */\n    Book update(Book book);\n\n    /**\n     * 删除 Book\n     *\n     * @param id 编号\n     */\n    Book delete(Long id);\n\n    /**\n     * 获取 Book\n     *\n     * @param id 编号\n     */\n    Book findById(Long id);\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/java/demo/springboot/service/impl/BookServiceImpl.java",
    "content": "package demo.springboot.service.impl;\n\nimport demo.springboot.domain.Book;\nimport demo.springboot.service.BookService;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Book 业务层实现\n *\n * Created by bysocket on 30/09/2017.\n */\n@Service\npublic class BookServiceImpl implements BookService {\n\n    // 模拟数据库，存储 Book 信息\n    // 第五章《﻿数据存储》会替换成 H2 数据源存储\n    private static Map<Long, Book> BOOK_DB = new HashMap<>();\n\n    @Override\n    public List<Book> findAll() {\n        return new ArrayList<>(BOOK_DB.values());\n    }\n\n    @Override\n    public Book insertByBook(Book book) {\n        book.setId(BOOK_DB.size() + 1L);\n        BOOK_DB.put(book.getId(), book);\n        return book;\n    }\n\n    @Override\n    public Book update(Book book) {\n        BOOK_DB.put(book.getId(), book);\n        return book;\n    }\n\n    @Override\n    public Book delete(Long id) {\n        return BOOK_DB.remove(id);\n    }\n\n    @Override\n    public Book findById(Long id) {\n        return BOOK_DB.get(id);\n    }\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/java/demo/springboot/web/BookController.java",
    "content": "package demo.springboot.web;\n\nimport demo.springboot.domain.Book;\nimport demo.springboot.service.BookService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.web.bind.annotation.*;\n\n/**\n * Book 控制层\n *\n * Created by bysocket on 30/09/2017.\n */\n@Controller\n@RequestMapping(value = \"/book\")\npublic class BookController {\n\n    private static final String BOOK_FORM_PATH_NAME = \"bookForm\";\n    private static final String BOOK_LIST_PATH_NAME = \"bookList\";\n    private static final String REDIRECT_TO_BOOK_URL = \"redirect:/book\";\n\n    @Autowired\n    BookService bookService;\n\n    /**\n     * 获取 Book 列表\n     * 处理 \"/book\" 的 GET 请求，用来获取 Book 列表\n     */\n    @RequestMapping(method = RequestMethod.GET)\n    public String getBookList(ModelMap map) {\n        map.addAttribute(\"bookList\",bookService.findAll());\n        return BOOK_LIST_PATH_NAME;\n    }\n\n    /**\n     * 获取创建 Book 表单\n     */\n    @RequestMapping(value = \"/create\", method = RequestMethod.GET)\n    public String createBookForm(ModelMap map) {\n        map.addAttribute(\"book\", new Book());\n        map.addAttribute(\"action\", \"create\");\n        return BOOK_FORM_PATH_NAME;\n    }\n\n    /**\n     * 创建 Book\n     * 处理 \"/book/create\" 的 POST 请求，用来新建 Book 信息\n     * 通过 @ModelAttribute 绑定表单实体参数，也通过 @RequestParam 传递参数\n     */\n    @RequestMapping(value = \"/create\", method = RequestMethod.POST)\n    public String postBook(@ModelAttribute Book book) {\n        bookService.insertByBook(book);\n        return REDIRECT_TO_BOOK_URL;\n    }\n\n    /**\n     * 获取更新 Book 表单\n     *    处理 \"/book/update/{id}\" 的 GET 请求，通过 URL 中的 id 值获取 Book 信息\n     *    URL 中的 id ，通过 @PathVariable 绑定参数\n     */\n    @RequestMapping(value = \"/update/{id}\", method = RequestMethod.GET)\n    public String getUser(@PathVariable Long id, ModelMap map) {\n        map.addAttribute(\"book\", bookService.findById(id));\n        map.addAttribute(\"action\", \"update\");\n        return BOOK_FORM_PATH_NAME;\n    }\n\n    /**\n     * 更新 Book\n     * 处理 \"/update\" 的 PUT 请求，用来更新 Book 信息\n     */\n    @RequestMapping(value = \"/update\", method = RequestMethod.POST)\n    public String putBook(@ModelAttribute Book book) {\n        bookService.update(book);\n        return REDIRECT_TO_BOOK_URL;\n    }\n\n    /**\n     * 删除 Book\n     * 处理 \"/book/{id}\" 的 GET 请求，用来删除 Book 信息\n     */\n    @RequestMapping(value = \"/delete/{id}\", method = RequestMethod.GET)\n    public String deleteBook(@PathVariable Long id) {\n        bookService.delete(id);\n        return REDIRECT_TO_BOOK_URL;\n    }\n\n}\n"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/resources/static/css/default.css",
    "content": "/* contentDiv */\n.contentDiv {padding:20px 60px;}"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/resources/templates/bookForm.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n    <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n    <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n    <meta charset=\"UTF-8\"/>\n    <title>书籍管理</title>\n</head>\n\n<body>\n<div class=\"contentDiv\">\n\n    <h5>《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 4 章《模板引擎》Demo </h5>\n\n    <legend>\n        <strong>书籍管理</strong>\n    </legend>\n\n    <form th:action=\"@{/book/{action}(action=${action})}\" method=\"post\" class=\"form-horizontal\">\n\n        <input type=\"hidden\" name=\"id\" th:value=\"${book.id}\"/>\n\n        <div class=\"form-group\">\n            <label for=\"book_name\" class=\"col-sm-2 control-label\">书名:</label>\n            <div class=\"col-xs-4\">\n                <input type=\"text\" class=\"form-control\" id=\"book_name\" name=\"name\" th:value=\"${book.name}\"\n                       th:field=\"*{book.name}\"/>\n            </div>\n        </div>\n\n        <div class=\"form-group\">\n            <label for=\"book_writer\" class=\"col-sm-2 control-label\">作者:</label>\n            <div class=\"col-xs-4\">\n                <input type=\"text\" class=\"form-control\" id=\"book_writer\" name=\"writer\" th:value=\"${book.writer}\"\n                       th:field=\"*{book.writer}\"/>\n            </div>\n        </div>\n\n        <div class=\"form-group\">\n            <label for=\"book_introduction\" class=\"col-sm-2 control-label\">简介:</label>\n            <div class=\"col-xs-4\">\n                <textarea class=\"form-control\" id=\"book_introduction\" rows=\"3\" name=\"introduction\"\n                          th:value=\"${book.introduction}\" th:field=\"*{book.introduction}\"></textarea>\n            </div>\n        </div>\n\n        <div class=\"form-group\">\n            <div class=\"col-sm-offset-2 col-sm-10\">\n                <input class=\"btn btn-primary\" type=\"submit\" value=\"提交\"/>&nbsp;&nbsp;\n                <input class=\"btn\" type=\"button\" value=\"返回\" onclick=\"history.back()\"/>\n            </div>\n        </div>\n    </form>\n</div>\n</body>\n</html>"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/main/resources/templates/bookList.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n    <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n    <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n    <meta charset=\"UTF-8\"/>\n    <title>书籍列表</title>\n</head>\n\n<body>\n\n<div class=\"contentDiv\">\n\n    <h5> 《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 4 章《模板引擎》Demo </h5>\n\n    <table class=\"table table-hover table-condensed\">\n        <legend>\n            <strong>书籍列表</strong>\n        </legend>\n        <thead>\n        <tr>\n            <th>书籍编号</th>\n            <th>书名</th>\n            <th>作者</th>\n            <th>简介</th>\n            <th>管理</th>\n        </tr>\n        </thead>\n        <tbody>\n        <tr th:each=\"book : ${bookList}\">\n            <th scope=\"row\" th:text=\"${book.id}\"></th>\n            <td><a th:href=\"@{/book/update/{bookId}(bookId=${book.id})}\" th:text=\"${book.name}\"></a></td>\n            <td th:text=\"${book.writer}\"></td>\n            <td th:text=\"${book.introduction}\"></td>\n            <td><a class=\"btn btn-danger\" th:href=\"@{/book/delete/{bookId}(bookId=${book.id})}\">删除</a></td>\n        </tr>\n        </tbody>\n    </table>\n\n    <div><a class=\"btn btn-primary\" href=\"/book/create\" role=\"button\">新增书籍</a></div>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "chapter-4-spring-boot-web-thymeleaf/src/test/java/demo/springboot/WebApplicationTests.java",
    "content": "package demo.springboot;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class WebApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <name>chapter-5-spring-boot-data-jpa</name>\n    <description>《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 5 章《数据存储》Demo</description>\n\n    <groupId>demo.springboot</groupId>\n    <artifactId>chapter-5-spring-boot-data-jpa</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n\n        <!-- Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- 模板引擎 Thymeleaf 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-thymeleaf</artifactId>\n        </dependency>\n\n        <!-- Spring Data JPA 依赖 :: 数据持久层框架 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n\n        <!-- h2 数据源依赖 -->\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n        <!-- 测试依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <!-- Spring Boot Maven 插件\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n            </plugin>\n            -->\n        </plugins>\n    </build>\n\n\n    <repositories>\n        <repository>\n            <id>spring-snapshots</id>\n            <name>Spring Snapshots</name>\n            <url>https://repo.spring.io/libs-snapshot</url>\n            <snapshots>\n                <enabled>true</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/java/demo/springboot/WebApplication.java",
    "content": "package demo.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 30/09/2017.\n */\n@SpringBootApplication\npublic class WebApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(WebApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/java/demo/springboot/domain/Book.java",
    "content": "package demo.springboot.domain;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport java.io.Serializable;\n\n/**\n * Book 实体类\n *\n * Created by bysocket on 30/09/2017.\n */\n@Entity\npublic class Book implements Serializable {\n\n    /**\n     * 编号\n     */\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    /**\n     * 书名\n     */\n    private String name;\n\n    /**\n     * 作者\n     */\n    private String writer;\n\n    /**\n     * 简介\n     */\n    private String introduction;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getWriter() {\n        return writer;\n    }\n\n    public void setWriter(String writer) {\n        this.writer = writer;\n    }\n\n    public String getIntroduction() {\n        return introduction;\n    }\n\n    public void setIntroduction(String introduction) {\n        this.introduction = introduction;\n    }\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/java/demo/springboot/domain/BookRepository.java",
    "content": "package demo.springboot.domain;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\n\n/**\n * Book 数据持久层操作接口\n *\n * Created by bysocket on 09/10/2017.\n */\npublic interface BookRepository extends JpaRepository<Book, Long> {\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/java/demo/springboot/service/BookService.java",
    "content": "package demo.springboot.service;\n\nimport demo.springboot.domain.Book;\n\nimport java.util.List;\n\n/**\n * Book 业务接口层\n *\n * Created by bysocket on 30/09/2017.\n */\npublic interface BookService {\n    /**\n     * 获取所有 Book\n     */\n    List<Book> findAll();\n\n    /**\n     * 新增 Book\n     *\n     * @param book {@link Book}\n     */\n    Book insertByBook(Book book);\n\n    /**\n     * 更新 Book\n     *\n     * @param book {@link Book}\n     */\n    Book update(Book book);\n\n    /**\n     * 删除 Book\n     *\n     * @param id 编号\n     */\n    Book delete(Long id);\n\n    /**\n     * 获取 Book\n     *\n     * @param id 编号\n     */\n    Book findById(Long id);\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/java/demo/springboot/service/impl/BookServiceImpl.java",
    "content": "package demo.springboot.service.impl;\n\nimport demo.springboot.domain.Book;\nimport demo.springboot.domain.BookRepository;\nimport demo.springboot.service.BookService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * Book 业务层实现\n *\n * Created by bysocket on 30/09/2017.\n */\n@Service\npublic class BookServiceImpl implements BookService {\n\n    @Autowired\n    BookRepository bookRepository;\n\n    @Override\n    public List<Book> findAll() {\n        return bookRepository.findAll();\n    }\n\n    @Override\n    public Book insertByBook(Book book) {\n        return bookRepository.save(book);\n    }\n\n    @Override\n    public Book update(Book book) {\n        return bookRepository.save(book);\n    }\n\n    @Override\n    public Book delete(Long id) {\n        Book book = bookRepository.findById(id).get();\n        bookRepository.delete(book);\n        return book;\n    }\n\n    @Override\n    public Book findById(Long id) {\n        return bookRepository.findById(id).get();\n    }\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/java/demo/springboot/web/BookController.java",
    "content": "package demo.springboot.web;\n\nimport demo.springboot.domain.Book;\nimport demo.springboot.service.BookService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.ModelMap;\nimport org.springframework.web.bind.annotation.*;\n\n/**\n * Book 控制层\n *\n * Created by bysocket on 30/09/2017.\n */\n@Controller\n@RequestMapping(value = \"/book\")\npublic class BookController {\n\n    private static final String BOOK_FORM_PATH_NAME = \"bookForm\";\n    private static final String BOOK_LIST_PATH_NAME = \"bookList\";\n    private static final String REDIRECT_TO_BOOK_URL = \"redirect:/book\";\n\n    @Autowired\n    BookService bookService;\n\n    /**\n     * 获取 Book 列表\n     * 处理 \"/book\" 的 GET 请求，用来获取 Book 列表\n     */\n    @RequestMapping(method = RequestMethod.GET)\n    public String getBookList(ModelMap map) {\n        map.addAttribute(\"bookList\",bookService.findAll());\n        return BOOK_LIST_PATH_NAME;\n    }\n\n    /**\n     * 获取创建 Book 表单\n     */\n    @RequestMapping(value = \"/create\", method = RequestMethod.GET)\n    public String createBookForm(ModelMap map) {\n        map.addAttribute(\"book\", new Book());\n        map.addAttribute(\"action\", \"create\");\n        return BOOK_FORM_PATH_NAME;\n    }\n\n    /**\n     * 创建 Book\n     * 处理 \"/book/create\" 的 POST 请求，用来新建 Book 信息\n     * 通过 @ModelAttribute 绑定表单实体参数，也通过 @RequestParam 传递参数\n     */\n    @RequestMapping(value = \"/create\", method = RequestMethod.POST)\n    public String postBook(@ModelAttribute Book book) {\n        bookService.insertByBook(book);\n        return REDIRECT_TO_BOOK_URL;\n    }\n\n    /**\n     * 获取更新 Book 表单\n     *    处理 \"/book/update/{id}\" 的 GET 请求，通过 URL 中的 id 值获取 Book 信息\n     *    URL 中的 id ，通过 @PathVariable 绑定参数\n     */\n    @RequestMapping(value = \"/update/{id}\", method = RequestMethod.GET)\n    public String getUser(@PathVariable Long id, ModelMap map) {\n        map.addAttribute(\"book\", bookService.findById(id));\n        map.addAttribute(\"action\", \"update\");\n        return BOOK_FORM_PATH_NAME;\n    }\n\n    /**\n     * 更新 Book\n     * 处理 \"/update\" 的 PUT 请求，用来更新 Book 信息\n     */\n    @RequestMapping(value = \"/update\", method = RequestMethod.POST)\n    public String putBook(@ModelAttribute Book book) {\n        bookService.update(book);\n        return REDIRECT_TO_BOOK_URL;\n    }\n\n    /**\n     * 删除 Book\n     * 处理 \"/book/{id}\" 的 GET 请求，用来删除 Book 信息\n     */\n    @RequestMapping(value = \"/delete/{id}\", method = RequestMethod.GET)\n    public String deleteBook(@PathVariable Long id) {\n        bookService.delete(id);\n        return REDIRECT_TO_BOOK_URL;\n    }\n\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/resources/application.properties",
    "content": "## 是否启动日志 SQL 语句\nspring.jpa.show-sql=true"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/resources/static/css/default.css",
    "content": "/* contentDiv */\n.contentDiv {padding:20px 60px;}"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/resources/templates/bookForm.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n    <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n    <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n    <meta charset=\"UTF-8\"/>\n    <title>书籍管理</title>\n</head>\n\n<body>\n<div class=\"contentDiv\">\n\n    <h5>《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 5 章《数据存储》Demo </h5>\n\n    <legend>\n        <strong>书籍管理</strong>\n    </legend>\n\n    <form th:action=\"@{/book/{action}(action=${action})}\" method=\"post\" class=\"form-horizontal\">\n\n        <input type=\"hidden\" name=\"id\" th:value=\"${book.id}\"/>\n\n        <div class=\"form-group\">\n            <label for=\"book_name\" class=\"col-sm-2 control-label\">书名:</label>\n            <div class=\"col-xs-4\">\n                <input type=\"text\" class=\"form-control\" id=\"book_name\" name=\"name\" th:value=\"${book.name}\"\n                       th:field=\"*{book.name}\"/>\n            </div>\n        </div>\n\n        <div class=\"form-group\">\n            <label for=\"book_writer\" class=\"col-sm-2 control-label\">作者:</label>\n            <div class=\"col-xs-4\">\n                <input type=\"text\" class=\"form-control\" id=\"book_writer\" name=\"writer\" th:value=\"${book.writer}\"\n                       th:field=\"*{book.writer}\"/>\n            </div>\n        </div>\n\n        <div class=\"form-group\">\n            <label for=\"book_introduction\" class=\"col-sm-2 control-label\">简介:</label>\n            <div class=\"col-xs-4\">\n                <textarea class=\"form-control\" id=\"book_introduction\" rows=\"3\" name=\"introduction\"\n                          th:value=\"${book.introduction}\" th:field=\"*{book.introduction}\"></textarea>\n            </div>\n        </div>\n\n        <div class=\"form-group\">\n            <div class=\"col-sm-offset-2 col-sm-10\">\n                <input class=\"btn btn-primary\" type=\"submit\" value=\"提交\"/>&nbsp;&nbsp;\n                <input class=\"btn\" type=\"button\" value=\"返回\" onclick=\"history.back()\"/>\n            </div>\n        </div>\n    </form>\n</div>\n</body>\n</html>"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/main/resources/templates/bookList.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n    <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n    <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n    <meta charset=\"UTF-8\"/>\n    <title>书籍列表</title>\n</head>\n\n<body>\n\n<div class=\"contentDiv\">\n\n    <h5>《Spring Boot 2.x 核心技术实战 - 上 基础篇》第 5 章《数据存储》Demo </h5>\n\n    <table class=\"table table-hover table-condensed\">\n        <legend>\n            <strong>书籍列表</strong>\n        </legend>\n        <thead>\n        <tr>\n            <th>书籍编号</th>\n            <th>书名</th>\n            <th>作者</th>\n            <th>简介</th>\n            <th>管理</th>\n        </tr>\n        </thead>\n        <tbody>\n        <tr th:each=\"book : ${bookList}\">\n            <th scope=\"row\" th:text=\"${book.id}\"></th>\n            <td><a th:href=\"@{/book/update/{bookId}(bookId=${book.id})}\" th:text=\"${book.name}\"></a></td>\n            <td th:text=\"${book.writer}\"></td>\n            <td th:text=\"${book.introduction}\"></td>\n            <td><a class=\"btn btn-danger\" th:href=\"@{/book/delete/{bookId}(bookId=${book.id})}\">删除</a></td>\n        </tr>\n        </tbody>\n    </table>\n\n    <div><a class=\"btn btn-primary\" href=\"/book/create\" role=\"button\">新增书籍</a></div>\n</div>\n\n</body>\n</html>"
  },
  {
    "path": "chapter-5-spring-boot-data-jpa/src/test/java/demo/springboot/WebApplicationTests.java",
    "content": "package demo.springboot;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class WebApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>spring.boot.core</groupId>\n    <artifactId>chapter-5-spring-boot-paging-sorting</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>chapter-5-spring-boot-paging-sorting</name>\n    <description>第五章数据分页排序案例</description>\n\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.0.0.M4</version>\n        <relativePath/> <!-- lookup parent from repository -->\n    </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n    <dependencies>\n\n        <!-- Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- 单元测试依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Spring Data JPA 依赖 :: 数据持久层框架 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n\n        <!-- h2 数据源连接驱动 -->\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <scope>runtime</scope>\n        </dependency>\n\n    </dependencies>\n\n    <build>\n        <plugins>\n            <!-- Spring Boot Maven 插件 -->\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>2.1.3.RELEASE</version>\n            </plugin>\n        </plugins>\n    </build>\n\n    <repositories>\n        <repository>\n            <id>spring-milestones</id>\n            <name>Spring Milestones</name>\n            <url>https://repo.spring.io/libs-milestone</url>\n            <snapshots>\n                <enabled>false</enabled>\n            </snapshots>\n        </repository>\n    </repositories>\n\n</project>\n"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/src/main/java/spring/boot/core/PagingSortingApplication.java",
    "content": "package spring.boot.core;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * 应用启动程序\n *\n * Created by bysocket on 18/09/2017.\n */\n@SpringBootApplication\npublic class PagingSortingApplication {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(PagingSortingApplication.class, args);\n\t}\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/src/main/java/spring/boot/core/domain/User.java",
    "content": "package spring.boot.core.domain;\n\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport java.io.Serializable;\n\n/**\n * 用户实体类\n *\n * Created by bysocket on 18/09/2017.\n */\n@Entity\npublic class User implements Serializable {\n\n    /**\n     * 编号\n     */\n    @Id\n    @GeneratedValue\n    private Long id;\n\n    /**\n     * 名称\n     */\n    private String name;\n\n    /**\n     * 年龄\n     */\n    private Integer age;\n\n    /**\n     * 出生时间\n     */\n    private String birthday;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Integer getAge() {\n        return age;\n    }\n\n    public void setAge(Integer age) {\n        this.age = age;\n    }\n\n    public String getBirthday() {\n        return birthday;\n    }\n\n    public void setBirthday(String birthday) {\n        this.birthday = birthday;\n    }\n\n    @Override\n    public String toString() {\n        return \"User{\" +\n                \"id=\" + id +\n                \", name='\" + name + '\\'' +\n                \", age=\" + age +\n                \", birthday=\" + birthday +\n                '}';\n    }\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/src/main/java/spring/boot/core/domain/UserRepository.java",
    "content": "package spring.boot.core.domain;\n\nimport org.springframework.data.repository.PagingAndSortingRepository;\n\n/**\n * 用户持久层操作接口\n *\n * Created by bysocket on 18/09/2017.\n */\npublic interface UserRepository extends PagingAndSortingRepository<User, Long> {\n\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/src/main/java/spring/boot/core/service/UserService.java",
    "content": "package spring.boot.core.service;\n\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport spring.boot.core.domain.User;\n\n/**\n * User 业务层接口\n *\n * Created by bysocket on 18/09/2017.\n */\npublic interface UserService {\n\n    /**\n     * 获取用户分页列表\n     *\n     * @param pageable\n     * @return\n     */\n    Page<User> findByPage(Pageable pageable);\n\n    /**\n     * 新增用户\n     *\n     * @param user\n     * @return\n     */\n    User insertByUser(User user);\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/src/main/java/spring/boot/core/service/impl/UserServiceImpl.java",
    "content": "package spring.boot.core.service.impl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.stereotype.Service;\nimport spring.boot.core.domain.User;\nimport spring.boot.core.domain.UserRepository;\nimport spring.boot.core.service.UserService;\n\n/**\n * User 业务层实现\n *\n * Created by bysocket on 18/09/2017.\n */\n@Service\npublic class UserServiceImpl implements UserService {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);\n\n    @Autowired\n    UserRepository userRepository;\n\n    @Override\n    public Page<User> findByPage(Pageable pageable) {\n        LOGGER.info(\" \\n 分页查询用户：\"\n                + \" PageNumber = \" + pageable.getPageNumber()\n                + \" PageSize = \" + pageable.getPageSize());\n        return userRepository.findAll(pageable);\n    }\n\n    @Override\n    public User insertByUser(User user) {\n        LOGGER.info(\"新增用户：\" + user.toString());\n        return userRepository.save(user);\n    }\n}\n"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/src/main/java/spring/boot/core/web/UserController.java",
    "content": "package spring.boot.core.web;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.web.bind.annotation.*;\nimport spring.boot.core.domain.User;\nimport spring.boot.core.service.UserService;\n\n/**\n * 用户控制层\n *\n * Created by bysocket on 18/09/2017.\n */\n@RestController\n@RequestMapping(value = \"/users\")     // 通过这里配置使下面的映射都在 /users\npublic class UserController {\n\n    @Autowired\n    UserService userService;          // 用户服务层\n\n    /**\n     *  获取用户分页列表\n     *    处理 \"/users\" 的 GET 请求，用来获取用户分页列表\n     *    通过 @RequestParam 传递参数，进一步实现条件查询或者分页查询\n     *\n     *    Pageable 支持的分页参数如下\n     *    page - 当前页 从 0 开始\n     *    size - 每页大小 默认值在 application.properties 配置\n     */\n    @RequestMapping(method = RequestMethod.GET)\n    public Page<User> getUserPage(Pageable pageable) {\n        return userService.findByPage(pageable);\n    }\n\n    /**\n     *  创建用户\n     *    处理 \"/users\" 的 POST 请求，用来获取用户列表\n     *    通过 @RequestBody 绑定实体类参数\n     */\n    @RequestMapping(value = \"/create\", method = RequestMethod.POST)\n    public User postUser(@RequestBody User user) {\n        return userService.insertByUser(user);\n    }\n\n}"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/src/main/resources/application.properties",
    "content": "## 是否显示 SQL 语句\nspring.jpa.show-sql=true\n\n## DATA WEB 相关配置 {@link SpringDataWebProperties}\n## 分页大小 默认为 20\nspring.data.web.pageable.default-page-size=3\n## 当前页参数名 默认为 page\nspring.data.web.pageable.page-parameter=pageNumber\n## 当前页参数名 默认为 size\nspring.data.web.pageable.size-parameter=pageSize\n## 字段排序参数名 默认为 sort\nspring.data.web.sort.sort-parameter=orderBy"
  },
  {
    "path": "chapter-5-spring-boot-paging-sorting/src/test/java/spring/boot/core/PagingSortingApplicationTests.java",
    "content": "package spring.boot.core;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class PagingSortingApplicationTests {\n\n\t@Test\n\tpublic void contextLoads() {\n\t}\n\n}\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t\t xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<name>springboot-learning-example</name>\n\n\t<groupId>springboot</groupId>\n\t<artifactId>springboot-learning-example</artifactId>\n\t<version>1.0-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\n\t<modules>\n\t\t<!-- WebFlux 异常处理 -->\n\t\t<module>2-x-spring-boot-webflux-handling-errors</module>\n\t\t<!-- 动态运行 groovy 脚本 --> \n    \t<module>2-x-spring-boot-groovy</module>\n\n\t\t<!-- 第 1 章《Spring Boot 入门》 -->\n\t\t<module>chapter-1-spring-boot-quickstart</module>\n\t\t<!-- 第 2 章《配置》 -->\n\t\t<module>chapter-2-spring-boot-config</module>\n\t\t<!-- 第 3 章《Web 开发》 -->\n\t\t<module>chapter-3-spring-boot-web</module>\n\t\t<!-- 第 4 章《模板引擎》 -->\n\t\t<module>chapter-4-spring-boot-web-thymeleaf</module>\n\t\t<!-- 第 5 章《数据存储》 -->\n\t\t<module>chapter-5-spring-boot-data-jpa</module>\n\t\t<!-- 第 4 章表单校验案例 -->\n\t\t<module>chapter-4-spring-boot-validating-form-input</module>\n\t\t<!-- 第 4 章数据分页排序案例 -->\n\t\t<module>chapter-5-spring-boot-paging-sorting</module>\n\n\t\t<!-- Spring Data ES 篇 -->\n\t\t<module>spring-data-elasticsearch-crud</module>\n\t\t<module>spring-data-elasticsearch-query</module>\n\n\t\t<!-- Spring Boot 之配置文件详解 -->\n\t\t<module>springboot-configuration</module>\n\n\t\t<!-- Spring Boot 整合 Dubbo/ZooKeeper 详解 SOA 案例 -->\n\t\t<module>springboot-dubbo-server</module>\n\t\t<module>springboot-dubbo-client</module>\n\n\t\t<!-- Spring Boot 整合 Elasticsearch -->\n\t\t<module>springboot-elasticsearch</module>\n\n\t\t<!-- Spring Boot 集成 FreeMarker -->\n\t\t<module>springboot-freemarker</module>\n\n\t\t<!-- Spring Boot 整合 HBase -->\n\t\t<module>springboot-hbase</module>\n\n\t\t<!-- Spring Boot 之 HelloWorld 详解 -->\n\t\t<module>springboot-helloworld</module>\n\n\t\t<!-- 数据缓存篇 -->\n\t\t<!-- Spring Boot 整合 Mybatis 的完整 Web 案例 -->\n\t\t<module>springboot-mybatis</module>\n\t\t<!-- Spring Boot 整合 Mybatis Annotation 注解案例 -->\n\t\t<module>springboot-mybatis-annotation</module>\n\t\t<!-- Spring Boot 整合 Mybatis 实现 Druid 多数据源配置 -->\n\t\t<module>springboot-mybatis-mutil-datasource</module>\n\t\t<!-- Spring Boot 整合 Redis 实现缓存 -->\n\t\t<module>springboot-mybatis-redis</module>\n\t\t<!-- Spring Boot 注解实现整合 Redis 实现缓存 -->\n\t\t<module>springboot-mybatis-redis-annotation</module>\n\n\t\t<!-- Spring Boot 实现 Restful 服务，基于 HTTP / JSON 传输 -->\n\t\t<module>springboot-restful</module>\n\n\t\t<!-- Spring Boot 之配置文件详解 -->\n\t\t<module>springboot-properties</module>\n\n\t\t<!-- Spring Boot HTTP over JSON 的错误码异常处理 -->\n\t\t<module>springboot-validation-over-json</module>\n\n\t\t<!-- Spring Boot 2.0 WebFlux -->\n    <!-- Spring Boot WebFlux 快速入门 -->\n    <module>springboot-webflux-1-quickstart</module>\n    <!-- Spring Boot WebFlux 实现 Restful 服务，基于 HTTP / JSON 传输 -->\n    <module>springboot-webflux-2-restful</module>\n    <module>springboot-webflux-3-mongodb</module>\n    <module>springboot-webflux-4-thymeleaf</module>\n    <module>springboot-webflux-5-thymeleaf-mongodb</module>\n\t\t<module>springboot-webflux-6-redis</module>\n\t\t<module>springboot-webflux-7-redis-cache</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "spring-data-elasticsearch-crud/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>spring-data-elasticsearch-crud</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>spring-data-elasticsearch-crud</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.1.RELEASE</version>\n    </parent>\n\n    <dependencies>\n\n        <!-- Spring Boot Elasticsearch 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "spring-data-elasticsearch-crud/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n  public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-crud/src/main/java/org/spring/springboot/controller/CityRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n/**\n * 城市 Controller 实现 Restful HTTP 服务\n * <p>\n * Created by bysocket on 03/05/2017.\n */\n@RestController\npublic class CityRestController {\n\n    @Autowired\n    private CityService cityService;\n\n    /**\n     * 插入 ES 新城市\n     *\n     * @param city\n     * @return\n     */\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.POST)\n    public Long createCity(@RequestBody City city) {\n        return cityService.saveCity(city);\n    }\n\n    /**\n     * AND 语句查询\n     *\n     * @param description\n     * @param score\n     * @return\n     */\n    @RequestMapping(value = \"/api/city/and/find\", method = RequestMethod.GET)\n    public List<City> findByDescriptionAndScore(@RequestParam(value = \"description\") String description,\n                                                @RequestParam(value = \"score\") Integer score) {\n        return cityService.findByDescriptionAndScore(description, score);\n    }\n\n    /**\n     * OR 语句查询\n     *\n     * @param description\n     * @param score\n     * @return\n     */\n    @RequestMapping(value = \"/api/city/or/find\", method = RequestMethod.GET)\n    public List<City> findByDescriptionOrScore(@RequestParam(value = \"description\") String description,\n                                               @RequestParam(value = \"score\") Integer score) {\n        return cityService.findByDescriptionOrScore(description, score);\n    }\n\n    /**\n     * 查询城市描述\n     *\n     * @param description\n     * @return\n     */\n    @RequestMapping(value = \"/api/city/description/find\", method = RequestMethod.GET)\n    public List<City> findByDescription(@RequestParam(value = \"description\") String description) {\n        return cityService.findByDescription(description);\n    }\n\n    /**\n     * NOT 语句查询\n     *\n     * @param description\n     * @return\n     */\n    @RequestMapping(value = \"/api/city/description/not/find\", method = RequestMethod.GET)\n    public List<City> findByDescriptionNot(@RequestParam(value = \"description\") String description) {\n        return cityService.findByDescriptionNot(description);\n    }\n\n    /**\n     * LIKE 语句查询\n     *\n     * @param description\n     * @return\n     */\n    @RequestMapping(value = \"/api/city/like/find\", method = RequestMethod.GET)\n    public List<City> findByDescriptionLike(@RequestParam(value = \"description\") String description) {\n        return cityService.findByDescriptionLike(description);\n    }\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-crud/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport org.springframework.data.elasticsearch.annotations.Document;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n * <p>\n * Created by bysocket on 03/05/2017.\n */\n@Document(indexName = \"province\", type = \"city\")\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -1L;\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 城市名称\n     */\n    private String name;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    /**\n     * 城市评分\n     */\n    private Integer score;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    public Integer getScore() {\n        return score;\n    }\n\n    public void setScore(Integer score) {\n        this.score = score;\n    }\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-crud/src/main/java/org/spring/springboot/repository/CityRepository.java",
    "content": "package org.spring.springboot.repository;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.elasticsearch.annotations.Query;\nimport org.springframework.data.elasticsearch.repository.ElasticsearchRepository;\n\nimport java.util.List;\n\n/**\n * ES 操作类\n * <p>\n * Created by bysocket on 17/05/2017.\n */\npublic interface CityRepository extends ElasticsearchRepository<City, Long> {\n    /**\n     * AND 语句查询\n     *\n     * @param description\n     * @param score\n     * @return\n     */\n    List<City> findByDescriptionAndScore(String description, Integer score);\n\n    /**\n     * OR 语句查询\n     *\n     * @param description\n     * @param score\n     * @return\n     */\n    List<City> findByDescriptionOrScore(String description, Integer score);\n\n    /**\n     * 查询城市描述\n     *\n     * 等同于下面代码\n     * @Query(\"{\\\"bool\\\" : {\\\"must\\\" : {\\\"term\\\" : {\\\"description\\\" : \\\"?0\\\"}}}}\")\n     * Page<City> findByDescription(String description, Pageable pageable);\n     *\n     * @param description\n     * @param page\n     * @return\n     */\n    Page<City> findByDescription(String description, Pageable page);\n\n    /**\n     * NOT 语句查询\n     *\n     * @param description\n     * @param page\n     * @return\n     */\n    Page<City> findByDescriptionNot(String description, Pageable page);\n\n    /**\n     * LIKE 语句查询\n     *\n     * @param description\n     * @param page\n     * @return\n     */\n    Page<City> findByDescriptionLike(String description, Pageable page);\n\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-crud/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "\npackage org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市 ES 业务接口类\n *\n */\npublic interface CityService {\n\n    /**\n     * 新增 ES 城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long saveCity(City city);\n\n    /**\n     * AND 语句查询\n     *\n     * @param description\n     * @param score\n     * @return\n     */\n    List<City> findByDescriptionAndScore(String description, Integer score);\n\n    /**\n     * OR 语句查询\n     *\n     * @param description\n     * @param score\n     * @return\n     */\n    List<City> findByDescriptionOrScore(String description, Integer score);\n\n    /**\n     * 查询城市描述\n     *\n     * @param description\n     * @return\n     */\n    List<City> findByDescription(String description);\n\n    /**\n     * NOT 语句查询\n     *\n     * @param description\n     * @return\n     */\n    List<City> findByDescriptionNot(String description);\n\n    /**\n     * LIKE 语句查询\n     *\n     * @param description\n     * @return\n     */\n    List<City> findByDescriptionLike(String description);\n}"
  },
  {
    "path": "spring-data-elasticsearch-crud/src/main/java/org/spring/springboot/service/impl/CityESServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.repository.CityRepository;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * 城市 ES 业务逻辑实现类\n * <p>\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class CityESServiceImpl implements CityService {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(CityESServiceImpl.class);\n\n    // 分页参数 -> TODO 代码可迁移到具体项目的公共 common 模块\n    private static final Integer pageNumber = 0;\n    private static final Integer pageSize = 10;\n    Pageable pageable = new PageRequest(pageNumber, pageSize);\n\n    // ES 操作类\n    @Autowired\n    CityRepository cityRepository;\n\n    public Long saveCity(City city) {\n        City cityResult = cityRepository.save(city);\n        return cityResult.getId();\n    }\n\n    public List<City> findByDescriptionAndScore(String description, Integer score) {\n        return cityRepository.findByDescriptionAndScore(description, score);\n    }\n\n    public List<City> findByDescriptionOrScore(String description, Integer score) {\n        return cityRepository.findByDescriptionOrScore(description, score);\n    }\n\n    public List<City> findByDescription(String description) {\n        return cityRepository.findByDescription(description, pageable).getContent();\n    }\n\n    public List<City> findByDescriptionNot(String description) {\n        return cityRepository.findByDescriptionNot(description, pageable).getContent();\n    }\n\n    public List<City> findByDescriptionLike(String description) {\n        return cityRepository.findByDescriptionLike(description, pageable).getContent();\n    }\n\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-crud/src/main/resources/application.properties",
    "content": "# ES\nspring.data.elasticsearch.repositories.enabled = true\nspring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300"
  },
  {
    "path": "spring-data-elasticsearch-query/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>spring-data-elasticsearch-query</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>spring-data-elasticsearch-query</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.1.RELEASE</version>\n    </parent>\n\n    <dependencies>\n\n        <!-- Spring Boot Elasticsearch 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "spring-data-elasticsearch-query/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 20/06/2017.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-query/src/main/java/org/spring/springboot/controller/CityRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n/**\n * 城市 Controller 实现 Restful HTTP 服务\n * <p>\n * Created by bysocket on 20/06/2017.\n */\n@RestController\npublic class CityRestController {\n\n    @Autowired\n    private CityService cityService;\n\n    /**\n     * 插入 ES 新城市\n     *\n     * @param city\n     * @return\n     */\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.POST)\n    public Long createCity(@RequestBody City city) {\n        return cityService.saveCity(city);\n    }\n\n    /**\n     * 搜索返回分页结果\n     *\n     * @param pageNumber 当前页码\n     * @param pageSize 每页大小\n     * @param searchContent 搜索内容\n     * @return\n     */\n    @RequestMapping(value = \"/api/city/search\", method = RequestMethod.GET)\n    public List<City> searchCity(@RequestParam(value = \"pageNumber\") Integer pageNumber,\n                                                @RequestParam(value = \"pageSize\", required = false) Integer pageSize,\n                                                @RequestParam(value = \"searchContent\") String searchContent) {\n        return cityService.searchCity(pageNumber, pageSize,searchContent);\n    }\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-query/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport org.springframework.data.elasticsearch.annotations.Document;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n * <p>\n * Created by bysocket on 20/06/2017.\n */\n@Document(indexName = \"province\", type = \"city\")\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -1L;\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 城市名称\n     */\n    private String name;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    /**\n     * 城市评分\n     */\n    private Integer score;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    public Integer getScore() {\n        return score;\n    }\n\n    public void setScore(Integer score) {\n        this.score = score;\n    }\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-query/src/main/java/org/spring/springboot/repository/CityRepository.java",
    "content": "package org.spring.springboot.repository;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.elasticsearch.annotations.Query;\nimport org.springframework.data.elasticsearch.repository.ElasticsearchRepository;\n\nimport java.util.List;\n\n/**\n * ES 操作类\n * <p>\n * Created by bysocket on 20/06/2017.\n */\npublic interface CityRepository extends ElasticsearchRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-query/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "\npackage org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市 ES 业务接口类\n *\n */\npublic interface CityService {\n\n    /**\n     * 新增 ES 城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long saveCity(City city);\n\n    /**\n     * 搜索词搜索，分页返回城市信息\n     *\n     * @param pageNumber 当前页码\n     * @param pageSize 每页大小\n     * @param searchContent 搜索内容\n     * @return\n     */\n    List<City> searchCity(Integer pageNumber, Integer pageSize, String searchContent);\n}"
  },
  {
    "path": "spring-data-elasticsearch-query/src/main/java/org/spring/springboot/service/impl/CityESServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;\nimport org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.repository.CityRepository;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;\nimport org.springframework.data.elasticsearch.core.query.SearchQuery;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * 城市 ES 业务逻辑实现类\n * <p>\n * Created by bysocket on 20/06/2017.\n */\n@Service\npublic class CityESServiceImpl implements CityService {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(CityESServiceImpl.class);\n\n    /* 分页参数 */\n    Integer PAGE_SIZE = 12;          // 每页数量\n    Integer DEFAULT_PAGE_NUMBER = 0; // 默认当前页码\n\n    /* 搜索模式 */\n    String SCORE_MODE_SUM = \"sum\"; // 权重分求和模式\n    Float  MIN_SCORE = 10.0F;      // 由于无相关性的分值默认为 1 ，设置权重分最小值为 10\n\n    @Autowired\n    CityRepository cityRepository; // ES 操作类\n\n    public Long saveCity(City city) {\n        City cityResult = cityRepository.save(city);\n        return cityResult.getId();\n    }\n\n    @Override\n    public List<City> searchCity(Integer pageNumber, Integer pageSize, String searchContent) {\n\n        // 校验分页参数\n        if (pageSize == null || pageSize <= 0) {\n            pageSize = PAGE_SIZE;\n        }\n\n        if (pageNumber == null || pageNumber < DEFAULT_PAGE_NUMBER) {\n            pageNumber = DEFAULT_PAGE_NUMBER;\n        }\n\n        LOGGER.info(\"\\n searchCity: searchContent [\" + searchContent + \"] \\n \");\n\n        // 构建搜索查询\n        SearchQuery searchQuery = getCitySearchQuery(pageNumber,pageSize,searchContent);\n\n        LOGGER.info(\"\\n searchCity: searchContent [\" + searchContent + \"] \\n DSL  = \\n \" + searchQuery.getQuery().toString());\n\n        Page<City> cityPage = cityRepository.search(searchQuery);\n        return cityPage.getContent();\n    }\n\n    /**\n     * 根据搜索词构造搜索查询语句\n     *\n     * 代码流程：\n     *      - 权重分查询\n     *      - 短语匹配\n     *      - 设置权重分最小值\n     *      - 设置分页参数\n     *\n     * @param pageNumber 当前页码\n     * @param pageSize 每页大小\n     * @param searchContent 搜索内容\n     * @return\n     */\n    private SearchQuery getCitySearchQuery(Integer pageNumber, Integer pageSize,String searchContent) {\n        // 短语匹配到的搜索词，求和模式累加权重分\n        // 权重分查询 https://www.elastic.co/guide/cn/elasticsearch/guide/current/function-score-query.html\n        //   - 短语匹配 https://www.elastic.co/guide/cn/elasticsearch/guide/current/phrase-matching.html\n        //   - 字段对应权重分设置，可以优化成 enum\n        //   - 由于无相关性的分值默认为 1 ，设置权重分最小值为 10\n        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()\n                .add(QueryBuilders.matchPhraseQuery(\"name\", searchContent),\n                ScoreFunctionBuilders.weightFactorFunction(1000))\n                .add(QueryBuilders.matchPhraseQuery(\"description\", searchContent),\n                ScoreFunctionBuilders.weightFactorFunction(500))\n                .scoreMode(SCORE_MODE_SUM).setMinScore(MIN_SCORE);\n\n        // 分页参数\n        Pageable pageable = new PageRequest(pageNumber, pageSize);\n        return new NativeSearchQueryBuilder()\n                .withPageable(pageable)\n                .withQuery(functionScoreQueryBuilder).build();\n    }\n\n\n}\n"
  },
  {
    "path": "spring-data-elasticsearch-query/src/main/resources/application.properties",
    "content": "# ES\nspring.data.elasticsearch.repositories.enabled = true\nspring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300"
  },
  {
    "path": "springboot-configuration/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-configuration</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-configuration</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <dependencies>\n        <!-- Spring Boot web依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-configuration/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-configuration/src/main/java/org/spring/springboot/config/MessageConfiguration.java",
    "content": "package org.spring.springboot.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * Created by bysocket on 08/09/2017.\n */\n@Configuration\npublic class MessageConfiguration {\n\n    @Bean\n    public String message() {\n        return \"message configuration\";\n    }\n}\n"
  },
  {
    "path": "springboot-configuration/src/test/java/org/spring/springboot/config/MessageConfigurationTest.java",
    "content": "package org.spring.springboot.config;\n\nimport org.junit.Test;\nimport org.springframework.context.annotation.AnnotationConfigApplicationContext;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * Spring Boot MessageConfiguration 测试 - {@link MessageConfiguration}\n *\n */\npublic class MessageConfigurationTest {\n\n    @Test\n    public void testGetMessageBean() throws Exception {\n        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MessageConfiguration.class);\n        assertEquals(\"message configuration\", ctx.getBean(\"message\"));\n    }\n\n    @Test\n    public void testScanPackages() throws Exception {\n        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();\n        ctx.scan(\"org.spring.springboot\");\n        ctx.refresh();\n        assertEquals(\"message configuration\", ctx.getBean(\"message\"));\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo-client/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-dubbo-client</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <dubbo-spring-boot>1.0.0</dubbo-spring-boot>\n    </properties>\n\n    <dependencies>\n\n        <!-- Spring Boot Dubbo 依赖 -->\n        <dependency>\n            <groupId>io.dubbo.springboot</groupId>\n            <artifactId>spring-boot-starter-dubbo</artifactId>\n            <version>${dubbo-spring-boot}</version>\n        </dependency>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-dubbo-client/src/main/java/org/spring/springboot/ClientApplication.java",
    "content": "package org.spring.springboot;\n\nimport org.spring.springboot.dubbo.CityDubboConsumerService;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.context.ConfigurableApplicationContext;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class ClientApplication {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        ConfigurableApplicationContext run = SpringApplication.run(ClientApplication.class, args);\n        CityDubboConsumerService cityService = run.getBean(CityDubboConsumerService.class);\n        cityService.printCity();\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo-client/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -1L;\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    @Override\n    public String toString() {\n        return \"City{\" +\n                \"id=\" + id +\n                \", provinceId=\" + provinceId +\n                \", cityName='\" + cityName + '\\'' +\n                \", description='\" + description + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo-client/src/main/java/org/spring/springboot/dubbo/CityDubboConsumerService.java",
    "content": "package org.spring.springboot.dubbo;\n\nimport com.alibaba.dubbo.config.annotation.Reference;\nimport org.spring.springboot.domain.City;\nimport org.springframework.stereotype.Component;\n\n/**\n * 城市 Dubbo 服务消费者\n *\n * Created by bysocket on 28/02/2017.\n */\n@Component\npublic class CityDubboConsumerService {\n\n    @Reference(version = \"1.0.0\")\n    CityDubboService cityDubboService;\n\n    public void printCity() {\n        String cityName=\"温岭\";\n        City city = cityDubboService.findCityByName(cityName);\n        System.out.println(city.toString());\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo-client/src/main/java/org/spring/springboot/dubbo/CityDubboService.java",
    "content": "package org.spring.springboot.dubbo;\n\nimport org.spring.springboot.domain.City;\n\n/**\n * 城市业务 Dubbo 服务层\n *\n * Created by bysocket on 28/02/2017.\n */\npublic interface CityDubboService {\n\n    /**\n     * 根据城市名称，查询城市信息\n     * @param cityName\n     */\n    City findCityByName(String cityName);\n}\n"
  },
  {
    "path": "springboot-dubbo-client/src/main/resources/application.properties",
    "content": "## 避免和 server 工程端口冲突\nserver.port=8081\n\n## Dubbo 服务消费者配置\nspring.dubbo.application.name=consumer\nspring.dubbo.registry.address=zookeeper://127.0.0.1:2181\nspring.dubbo.scan=org.spring.springboot.dubbo"
  },
  {
    "path": "springboot-dubbo-server/DubboProperties.md",
    "content": "## Dubbo 配置\n# 扫描包路径\n<br>spring.dubbo.scan=org.<br>spring.<br>springboot.dubbo\n\n## Dubbo 应用配置\n// 应用名称\n<br>spring.dubbo.application.name=xxx\n\n// 模块版本\n<br>spring.dubbo.application.version=xxx\n\n// 应用负责人\n<br>spring.dubbo.application.owner=xxx\n\n// 组织名(BU或部门)\n<br>spring.dubbo.application.organization=xxx\n\n// 分层\n<br>spring.dubbo.application.architecture=xxx\n\n// 环境，如：dev/test/run\n<br>spring.dubbo.application.environment=xxx\n\n// Java代码编译器\n<br>spring.dubbo.application.compiler=xxx\n\n// 日志输出方式\n<br>spring.dubbo.application.logger=xxx\n\n// 注册中心 0\n<br>spring.dubbo.application.registries[0].address=zookeeper://127.0.0.1:2181=xxx\n// 注册中心 1\n<br>spring.dubbo.application.registries[1].address=zookeeper://127.0.0.1:2181=xxx\n\n// 服务监控\n<br>spring.dubbo.application.monitor.address=xxx\n\n## Dubbo 注册中心配置类\n// 注册中心地址\n<br>spring.dubbo.application.registries.address=xxx\n\n// 注册中心登录用户名\n<br>spring.dubbo.application.registries.username=xxx\n\n// 注册中心登录密码\n<br>spring.dubbo.application.registries.password=xxx\n\n// 注册中心缺省端口\n<br>spring.dubbo.application.registries.port=xxx\n\n// 注册中心协议\n<br>spring.dubbo.application.registries.protocol=xxx\n\n// 客户端实现\n<br>spring.dubbo.application.registries.transporter=xxx\n\n<br>spring.dubbo.application.registries.server=xxx\n\n<br>spring.dubbo.application.registries.client=xxx\n\n<br>spring.dubbo.application.registries.cluster=xxx\n\n<br>spring.dubbo.application.registries.group=xxx\n\n<br>spring.dubbo.application.registries.version=xxx\n\n// 注册中心请求超时时间(毫秒)\n<br>spring.dubbo.application.registries.timeout=xxx\n\n// 注册中心会话超时时间(毫秒)\n<br>spring.dubbo.application.registries.session=xxx\n\n// 动态注册中心列表存储文件\n<br>spring.dubbo.application.registries.file=xxx\n\n// 停止时等候完成通知时间\n<br>spring.dubbo.application.registries.wait=xxx\n\n// 启动时检查注册中心是否存在\n<br>spring.dubbo.application.registries.check=xxx\n\n// 在该注册中心上注册是动态的还是静态的服务\n<br>spring.dubbo.application.registries.dynamic=xxx\n\n// 在该注册中心上服务是否暴露\n<br>spring.dubbo.application.registries.register=xxx\n\n// 在该注册中心上服务是否引用\n<br>spring.dubbo.application.registries.subscribe=xxx\n\n\n## Dubbo 服务协议配置\n\n\n// 服务协议\n<br>spring.dubbo.application.protocol.name=xxx\n\n// 服务IP地址(多网卡时使用)\n<br>spring.dubbo.application.protocol.host=xxx\n\n// 服务端口\n<br>spring.dubbo.application.protocol.port=xxx\n\n// 上下文路径\n<br>spring.dubbo.application.protocol.contextpath=xxx\n\n// 线程池类型\n<br>spring.dubbo.application.protocol.threadpool=xxx\n\n// 线程池大小(固定大小)\n<br>spring.dubbo.application.protocol.threads=xxx\n\n// IO线程池大小(固定大小)\n<br>spring.dubbo.application.protocol.iothreads=xxx\n\n// 线程池队列大小\n<br>spring.dubbo.application.protocol.queues=xxx\n\n// 最大接收连接数\n<br>spring.dubbo.application.protocol.accepts=xxx\n\n// 协议编码\n<br>spring.dubbo.application.protocol.codec=xxx\n\n// 序列化方式\n<br>spring.dubbo.application.protocol.serialization=xxx\n\n// 字符集\n<br>spring.dubbo.application.protocol.charset=xxx\n\n// 最大请求数据长度\n<br>spring.dubbo.application.protocol.payload=xxx\n\n// 缓存区大小\n<br>spring.dubbo.application.protocol.buffer=xxx\n\n// 心跳间隔\n<br>spring.dubbo.application.protocol.heartbeat=xxx\n\n// 访问日志\n<br>spring.dubbo.application.protocol.accesslog=xxx\n\n// 网络传输方式\n<br>spring.dubbo.application.protocol.transporter=xxx\n\n// 信息交换方式\n<br>spring.dubbo.application.protocol.exchanger=xxx\n\n// 信息线程模型派发方式\n<br>spring.dubbo.application.protocol.dispatcher=xxx\n\n// 对称网络组网方式\n<br>spring.dubbo.application.protocol.networker=xxx\n\n// 服务器端实现\n<br>spring.dubbo.application.protocol.server=xxx\n\n// 客户端实现\n<br>spring.dubbo.application.protocol.client=xxx\n\n// 支持的telnet命令，多个命令用逗号分隔\n<br>spring.dubbo.application.protocol.telnet=xxx\n\n// 命令行提示符\n<br>spring.dubbo.application.protocol.prompt=xxx\n\n// status检查\n<br>spring.dubbo.application.protocol.status=xxx\n\n// 是否注册\n<br>spring.dubbo.application.protocol.status=xxx\n\n\n"
  },
  {
    "path": "springboot-dubbo-server/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-dubbo-server</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <dubbo-spring-boot>1.0.0</dubbo-spring-boot>\n    </properties>\n\n    <dependencies>\n\n        <!-- Spring Boot Dubbo 依赖 -->\n        <dependency>\n            <groupId>io.dubbo.springboot</groupId>\n            <artifactId>spring-boot-starter-dubbo</artifactId>\n            <version>${dubbo-spring-boot}</version>\n        </dependency>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-dubbo-server/src/main/java/org/spring/springboot/ServerApplication.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class ServerApplication {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(ServerApplication.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo-server/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -1L;\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public City() {\n    }\n\n    public City(Long id, Long provinceId, String cityName, String description) {\n        this.id = id;\n        this.provinceId = provinceId;\n        this.cityName = cityName;\n        this.description = description;\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo-server/src/main/java/org/spring/springboot/dubbo/CityDubboService.java",
    "content": "package org.spring.springboot.dubbo;\n\nimport org.spring.springboot.domain.City;\n\n/**\n * 城市业务 Dubbo 服务层\n *\n * Created by bysocket on 28/02/2017.\n */\npublic interface CityDubboService {\n\n    /**\n     * 根据城市名称，查询城市信息\n     * @param cityName\n     */\n    City findCityByName(String cityName);\n}\n"
  },
  {
    "path": "springboot-dubbo-server/src/main/java/org/spring/springboot/dubbo/impl/CityDubboServiceImpl.java",
    "content": "package org.spring.springboot.dubbo.impl;\n\nimport com.alibaba.dubbo.config.annotation.Service;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.dubbo.CityDubboService;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n/**\n * 城市业务 Dubbo 服务层实现层\n *\n * Created by bysocket on 28/02/2017.\n */\n// 注册为 Dubbo 服务\n@Service(version = \"1.0.0\")\npublic class CityDubboServiceImpl implements CityDubboService {\n\n    public City findCityByName(String cityName) {\n        return new City(1L,2L,\"温岭\",\"是我的故乡\");\n    }\n}\n"
  },
  {
    "path": "springboot-dubbo-server/src/main/resources/application.properties",
    "content": "## Dubbo 服务提供者配置\nspring.dubbo.application.name=provider\nspring.dubbo.registry.address=zookeeper://127.0.0.1:2181\nspring.dubbo.protocol.name=dubbo\nspring.dubbo.protocol.port=20880\nspring.dubbo.scan=org.spring.springboot.dubbo"
  },
  {
    "path": "springboot-elasticsearch/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-elasticsearch</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-elasticsearch</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.1.RELEASE</version>\n    </parent>\n\n    <dependencies>\n\n        <!-- Spring Boot Elasticsearch 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/org/spring/springboot/controller/CityRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n/**\n * 城市 Controller 实现 Restful HTTP 服务\n * <p>\n * Created by bysocket on 03/05/2017.\n */\n@RestController\npublic class CityRestController {\n\n    @Autowired\n    private CityService cityService;\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.POST)\n    public Long createCity(@RequestBody City city) {\n        return cityService.saveCity(city);\n    }\n\n    @RequestMapping(value = \"/api/city/search\", method = RequestMethod.GET)\n    public List<City> searchCity(@RequestParam(value = \"pageNumber\") Integer pageNumber,\n                                 @RequestParam(value = \"pageSize\", required = false) Integer pageSize,\n                                 @RequestParam(value = \"searchContent\") String searchContent) {\n        return cityService.searchCity(pageNumber,pageSize,searchContent);\n    }\n}\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport org.springframework.data.elasticsearch.annotations.Document;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 03/05/2017.\n */\n@Document(indexName = \"cityindex\", type = \"city\")\npublic class City implements Serializable{\n\n    private static final long serialVersionUID = -1L;\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceid;\n\n    /**\n     * 城市名称\n     */\n    private String cityname;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceid() {\n        return provinceid;\n    }\n\n    public void setProvinceid(Long provinceid) {\n        this.provinceid = provinceid;\n    }\n\n    public String getCityname() {\n        return cityname;\n    }\n\n    public void setCityname(String cityname) {\n        this.cityname = cityname;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/org/spring/springboot/repository/CityRepository.java",
    "content": "package org.spring.springboot.repository;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.data.elasticsearch.repository.ElasticsearchRepository;\nimport org.springframework.stereotype.Repository;\n\n/**\n * Created by bysocket on 17/05/2017.\n */\n@Repository\npublic interface CityRepository extends ElasticsearchRepository<City,Long> {\n\n\n}\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "\npackage org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\nimport java.util.List;\n\npublic interface CityService {\n\n    /**\n     * 新增城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long saveCity(City city);\n\n    /**\n     * 根据关键词，function score query 权重分分页查询\n     *\n     * @param pageNumber\n     * @param pageSize\n     * @param searchContent\n     * @return\n     */\n    List<City> searchCity(Integer pageNumber, Integer pageSize, String searchContent);\n}"
  },
  {
    "path": "springboot-elasticsearch/src/main/java/org/spring/springboot/service/impl/CityESServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.elasticsearch.index.query.QueryBuilders;\nimport org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;\nimport org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.repository.CityRepository;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;\nimport org.springframework.data.elasticsearch.core.query.SearchQuery;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * 城市 ES 业务逻辑实现类\n *\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class CityESServiceImpl implements CityService {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(CityESServiceImpl.class);\n\n    @Autowired\n    CityRepository cityRepository;\n\n    @Override\n    public Long saveCity(City city) {\n\n        City cityResult = cityRepository.save(city);\n        return cityResult.getId();\n    }\n\n    @Override\n    public List<City> searchCity(Integer pageNumber,\n                                 Integer pageSize,\n                                 String searchContent) {\n        // 分页参数\n        Pageable pageable = new PageRequest(pageNumber, pageSize);\n\n        // Function Score Query\n        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery()\n                .add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery(\"cityname\", searchContent)),\n                    ScoreFunctionBuilders.weightFactorFunction(1000))\n                .add(QueryBuilders.boolQuery().should(QueryBuilders.matchQuery(\"description\", searchContent)),\n                        ScoreFunctionBuilders.weightFactorFunction(100));\n\n        // 创建搜索 DSL 查询\n        SearchQuery searchQuery = new NativeSearchQueryBuilder()\n                .withPageable(pageable)\n                .withQuery(functionScoreQueryBuilder).build();\n\n        LOGGER.info(\"\\n searchCity(): searchContent [\" + searchContent + \"] \\n DSL  = \\n \" + searchQuery.getQuery().toString());\n\n        Page<City> searchPageResults = cityRepository.search(searchQuery);\n        return searchPageResults.getContent();\n    }\n\n}\n"
  },
  {
    "path": "springboot-elasticsearch/src/main/resources/application.properties",
    "content": "# ES\nspring.data.elasticsearch.repositories.enabled = true\nspring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300"
  },
  {
    "path": "springboot-freemarker/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-freemarker</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-freemarker</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <mybatis-spring-boot>1.2.0</mybatis-spring-boot>\n        <mysql-connector>5.1.39</mysql-connector>\n    </properties>\n\n    <dependencies>\n        <!-- Spring Boot Freemarker 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-freemarker</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Spring Boot Mybatis 依赖 -->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>${mybatis-spring-boot}</version>\n        </dependency>\n\n        <!-- MySQL 连接驱动依赖 -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector}</version>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-freemarker/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\n// mapper 接口类扫描包配置\n@MapperScan(\"org.spring.springboot.dao\")\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-freemarker/src/main/java/org/spring/springboot/controller/CityController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n/**\n * 城市 Controller 实现 Restful HTTP 服务\n * <p>\n * Created by bysocket on 07/02/2017.\n */\n@Controller\npublic class CityController {\n\n    @Autowired\n    private CityService cityService;\n\n    @RequestMapping(value = \"/api/city/{id}\", method = RequestMethod.GET)\n    public String findOneCity(Model model, @PathVariable(\"id\") Long id) {\n        model.addAttribute(\"city\", cityService.findCityById(id));\n        return \"city\";\n    }\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.GET)\n    public String findAllCity(Model model) {\n        List<City> cityList = cityService.findAllCity();\n        model.addAttribute(\"cityList\",cityList);\n        return \"cityList\";\n    }\n}\n"
  },
  {
    "path": "springboot-freemarker/src/main/java/org/spring/springboot/dao/CityDao.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市 DAO 接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityDao {\n\n    /**\n     * 获取城市信息列表\n     *\n     * @return\n     */\n    List<City> findAllCity();\n\n    /**\n     * 根据城市 ID，获取城市信息\n     *\n     * @param id\n     * @return\n     */\n    City findById(@Param(\"id\") Long id);\n\n    Long saveCity(City city);\n\n    Long updateCity(City city);\n\n    Long deleteCity(Long id);\n}\n"
  },
  {
    "path": "springboot-freemarker/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-freemarker/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "package org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市业务逻辑接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityService {\n\n    /**\n     * 获取城市信息列表\n     *\n     * @return\n     */\n    List<City> findAllCity();\n\n    /**\n     * 根据城市 ID,查询城市信息\n     *\n     * @param id\n     * @return\n     */\n    City findCityById(Long id);\n\n    /**\n     * 新增城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long saveCity(City city);\n\n    /**\n     * 更新城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long updateCity(City city);\n\n    /**\n     * 根据城市 ID,删除城市信息\n     *\n     * @param id\n     * @return\n     */\n    Long deleteCity(Long id);\n}\n"
  },
  {
    "path": "springboot-freemarker/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * 城市业务逻辑实现类\n *\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class CityServiceImpl implements CityService {\n\n    @Autowired\n    private CityDao cityDao;\n\n    public List<City> findAllCity(){\n        return cityDao.findAllCity();\n    }\n\n    public City findCityById(Long id) {\n        return cityDao.findById(id);\n    }\n\n    @Override\n    public Long saveCity(City city) {\n        return cityDao.saveCity(city);\n    }\n\n    @Override\n    public Long updateCity(City city) {\n        return cityDao.updateCity(city);\n    }\n\n    @Override\n    public Long deleteCity(Long id) {\n        return cityDao.deleteCity(id);\n    }\n\n}\n"
  },
  {
    "path": "springboot-freemarker/src/main/resources/application.properties",
    "content": "## 数据源配置\nspring.datasource.url=jdbc:mysql://127.0.0.1:3306/springbootdb?useUnicode=true&characterEncoding=utf8\nspring.datasource.username=root\nspring.datasource.password=123456\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\n\n## Mybatis 配置\nmybatis.typeAliasesPackage=org.spring.springboot.domain\nmybatis.mapperLocations=classpath:mapper/*.xml\n\n## Freemarker 配置\n## 文件配置路径\nspring.freemarker.template-loader-path=classpath:/web/\nspring.freemarker.cache=false\nspring.freemarker.charset=UTF-8\nspring.freemarker.check-template-location=true\nspring.freemarker.content-type=text/html\nspring.freemarker.expose-request-attributes=true\nspring.freemarker.expose-session-attributes=true\nspring.freemarker.request-context-attribute=request\nspring.freemarker.suffix=.ftl\n"
  },
  {
    "path": "springboot-freemarker/src/main/resources/mapper/CityMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n<mapper namespace=\"org.spring.springboot.dao.CityDao\">\n\t<resultMap id=\"BaseResultMap\" type=\"org.spring.springboot.domain.City\">\n\t\t<result column=\"id\" property=\"id\" />\n\t\t<result column=\"province_id\" property=\"provinceId\" />\n\t\t<result column=\"city_name\" property=\"cityName\" />\n\t\t<result column=\"description\" property=\"description\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tid, province_id, city_name, description\n\t</sql>\n\n\t<select id=\"findById\" resultMap=\"BaseResultMap\" parameterType=\"java.lang.Long\">\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom city\n\t\twhere id = #{id}\n\t</select>\n\n\t<select id=\"findAllCity\" resultMap=\"BaseResultMap\" >\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom city\n\t</select>\n\n\t<insert id=\"saveCity\" parameterType=\"City\" useGeneratedKeys=\"true\" keyProperty=\"id\">\n\t\tinsert into\n\t\t\tcity(id,province_id,city_name,description)\n\t\tvalues\n\t\t\t(#{id},#{provinceId},#{cityName},#{description})\n\t</insert>\n\n\t<update id=\"updateCity\" parameterType=\"City\">\n\t\tupdate\n\t\t\tcity\n\t\tset\n\t\t<if test=\"provinceId!=null\">\n\t\t\tprovince_id = #{provinceId},\n\t\t</if>\n\t\t<if test=\"cityName!=null\">\n\t\t\tcity_name = #{cityName},\n\t\t</if>\n\t\t<if test=\"description!=null\">\n\t\t\tdescription = #{description}\n\t\t</if>\n\t\twhere\n\t\t\tid = #{id}\n\t</update>\n\n\t<delete id=\"deleteCity\" parameterType=\"java.lang.Long\">\n\t\tdelete from\n\t\t\tcity\n\t\twhere\n\t\t\tid = #{id}\n\t</delete>\n</mapper>\n"
  },
  {
    "path": "springboot-freemarker/src/main/resources/web/city.ftl",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\nCity: ${city.cityName}! <br>\nQ:Why I like? <br>\nA:${city.description}!\n</body>\n\n</html>"
  },
  {
    "path": "springboot-freemarker/src/main/resources/web/cityList.ftl",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\">\n\n<body>\n<#list cityList as city>\n\nCity: ${city.cityName}! <br>\nQ:Why I like? <br>\nA:${city.description}!\n\n</#list>\n</body>\n\n</html>"
  },
  {
    "path": "springboot-hbase/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-hbase</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-hbase</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>1.5.6.RELEASE</version>\n    </parent>\n\n    <properties>\n        <hbase-spring-boot>1.0.0.RELEASE</hbase-spring-boot>\n    </properties>\n\n    <dependencies>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Spring Boot HBase 依赖 -->\n        <dependency>\n            <groupId>com.spring4all</groupId>\n            <artifactId>spring-boot-starter-hbase</artifactId>\n            <version>${hbase-spring-boot}</version>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-hbase/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-hbase/src/main/java/org/spring/springboot/controller/CityRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Created by bysocket on 07/02/2017.\n */\n@RestController\npublic class CityRestController {\n\n    @Autowired\n    private CityService cityService;\n\n    @RequestMapping(value = \"/api/city/save\", method = RequestMethod.GET)\n    public City save() {\n        cityService.saveOrUpdate();\n        City city = new City();\n        city.setAge(1);\n        return city;\n    }\n    \n    @RequestMapping(value = \"/api/city/get\", method = RequestMethod.GET)\n    public City getCity() {\n        return cityService.query(\"135xxxxxx\");\n    }\n}\n"
  },
  {
    "path": "springboot-hbase/src/main/java/org/spring/springboot/dao/CityRowMapper.java",
    "content": "package org.spring.springboot.dao;\n\nimport com.spring4all.spring.boot.starter.hbase.api.RowMapper;\nimport org.apache.hadoop.hbase.client.Result;\nimport org.apache.hadoop.hbase.util.Bytes;\nimport org.spring.springboot.domain.City;\n\npublic class CityRowMapper implements RowMapper<City> {\n\n    private static byte[] COLUMN_FAMILY = \"f\".getBytes();\n    private static byte[] NAME = \"name\".getBytes();\n    private static byte[] AGE = \"age\".getBytes();\n\n    @Override\n    public City mapRow(Result result, int rowNum) throws Exception {\n        String name = Bytes.toString(result.getValue(COLUMN_FAMILY, NAME));\n        int age = Bytes.toInt(result.getValue(COLUMN_FAMILY, AGE));\n    \n        City dto = new City();\n        dto.setCityName(name);\n        dto.setAge(age);\n        return dto;\n    }\n}\n"
  },
  {
    "path": "springboot-hbase/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份年龄\n     */\n    private Integer age;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n    \n    public Long getId() {\n        return id;\n    }\n    \n    public void setId(Long id) {\n        this.id = id;\n    }\n    \n    public Integer getAge() {\n        return age;\n    }\n    \n    public void setAge(Integer age) {\n        this.age = age;\n    }\n    \n    public String getCityName() {\n        return cityName;\n    }\n    \n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n}\n"
  },
  {
    "path": "springboot-hbase/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "package org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市业务逻辑接口类\n * <p>\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityService {\n    \n    List<City> query(String startRow, String stopRow);\n    \n    public City query(String row);\n    \n    void saveOrUpdate();\n}\n"
  },
  {
    "path": "springboot-hbase/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport com.spring4all.spring.boot.starter.hbase.api.HbaseTemplate;\nimport org.apache.hadoop.hbase.client.Mutation;\nimport org.apache.hadoop.hbase.client.Put;\nimport org.apache.hadoop.hbase.client.Scan;\nimport org.apache.hadoop.hbase.util.Bytes;\nimport org.spring.springboot.dao.CityRowMapper;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 城市业务逻辑实现类\n * <p>\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class CityServiceImpl implements CityService {\n    \n    @Autowired private HbaseTemplate hbaseTemplate;\n    \n    public List<City> query(String startRow, String stopRow) {\n        Scan scan = new Scan(Bytes.toBytes(startRow), Bytes.toBytes(stopRow));\n        scan.setCaching(5000);\n        List<City> dtos = this.hbaseTemplate.find(\"people_table\", scan, new CityRowMapper());\n        return dtos;\n    }\n    \n    public City query(String row) {\n        City dto = this.hbaseTemplate.get(\"people_table\", row, new CityRowMapper());\n        return dto;\n    }\n    \n    public void saveOrUpdate() {\n        List<Mutation> saveOrUpdates = new ArrayList<Mutation>();\n        Put            put           = new Put(Bytes.toBytes(\"135xxxxxx\"));\n        put.addColumn(Bytes.toBytes(\"people\"), Bytes.toBytes(\"name\"), Bytes.toBytes(\"test\"));\n        saveOrUpdates.add(put);\n        \n        this.hbaseTemplate.saveOrUpdates(\"people_table\", saveOrUpdates);\n    }\n}\n"
  },
  {
    "path": "springboot-hbase/src/main/resources/application.properties",
    "content": "## HBase 配置\nspring.data.hbase.quorum=xxx\nspring.data.hbase.rootDir=xxx\nspring.data.hbase.nodeParent=xxx\n"
  },
  {
    "path": "springboot-helloworld/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-helloworld</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-helloworld</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <dependencies>\n        <!-- Spring Boot web依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-helloworld/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-helloworld/src/main/java/org/spring/springboot/web/HelloWorldController.java",
    "content": "package org.spring.springboot.web;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Spring Boot HelloWorld 案例\n *\n * Created by bysocket on 16/4/26.\n */\n@RestController\npublic class HelloWorldController {\n\n    @RequestMapping(\"/\")\n    public String sayHello() {\n        return \"Hello,World!\";\n    }\n}\n"
  },
  {
    "path": "springboot-helloworld/src/test/java/org/spring/springboot/web/HelloWorldControllerTest.java",
    "content": "package org.spring.springboot.web;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * Spring Boot HelloWorldController 测试 - {@link HelloWorldController}\n *\n * Created by bysocket on 16/4/26.\n */\npublic class HelloWorldControllerTest {\n\n    @Test\n    public void testSayHello() {\n        assertEquals(\"Hello,World!\",new HelloWorldController().sayHello());\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-mybatis</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-mybatis</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <mybatis-spring-boot>1.2.0</mybatis-spring-boot>\n        <mysql-connector>5.1.39</mysql-connector>\n    </properties>\n\n    <dependencies>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Spring Boot Mybatis 依赖 -->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>${mybatis-spring-boot}</version>\n        </dependency>\n\n        <!-- MySQL 连接驱动依赖 -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector}</version>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\n// mapper 接口类扫描包配置\n@MapperScan(\"org.spring.springboot.dao\")\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/org/spring/springboot/controller/CityRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Created by bysocket on 07/02/2017.\n */\n@RestController\npublic class CityRestController {\n\n    @Autowired\n    private CityService cityService;\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.GET)\n    public City findOneCity(@RequestParam(value = \"cityName\", required = true) String cityName) {\n        return cityService.findCityByName(cityName);\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/org/spring/springboot/dao/CityDao.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.spring.springboot.domain.City;\n\n/**\n * 城市 DAO 接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityDao {\n\n    /**\n     * 根据城市名称，查询城市信息\n     *\n     * @param cityName 城市名\n     */\n    City findByName(@Param(\"cityName\") String cityName);\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "package org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\n/**\n * 城市业务逻辑接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityService {\n\n    /**\n     * 根据城市名称，查询城市信息\n     * @param cityName\n     */\n    City findCityByName(String cityName);\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n/**\n * 城市业务逻辑实现类\n *\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class CityServiceImpl implements CityService {\n\n    @Autowired\n    private CityDao cityDao;\n\n    public City findCityByName(String cityName) {\n        return cityDao.findByName(cityName);\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis/src/main/resources/application.properties",
    "content": "## 数据源配置\nspring.datasource.url=jdbc:mysql://localhost:3306/springbootdb?useUnicode=true&characterEncoding=utf8\nspring.datasource.username=root\nspring.datasource.password=123456\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\n\n## Mybatis 配置\nmybatis.typeAliasesPackage=org.spring.springboot.domain\nmybatis.mapperLocations=classpath:mapper/*.xml"
  },
  {
    "path": "springboot-mybatis/src/main/resources/mapper/CityMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n<mapper namespace=\"org.spring.springboot.dao.CityDao\">\n\t<resultMap id=\"BaseResultMap\" type=\"org.spring.springboot.domain.City\">\n\t\t<result column=\"id\" property=\"id\" />\n\t\t<result column=\"province_id\" property=\"provinceId\" />\n\t\t<result column=\"city_name\" property=\"cityName\" />\n\t\t<result column=\"description\" property=\"description\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tid, province_id, city_name, description\n\t</sql>\n\n\t<select id=\"findByName\" resultMap=\"BaseResultMap\" parameterType=\"java.lang.String\">\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom city\n\t\twhere city_name = #{cityName}\n\t</select>\n\n</mapper>\n"
  },
  {
    "path": "springboot-mybatis-annotation/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<groupId>springboot</groupId>\n\t<artifactId>springboot-mybatis-annotation</artifactId>\n\t<version>0.0.1-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>springboot-mybatis-annotation</name>\n\t<description>Springboot-mybatis</description>\n\n\t<!-- Spring Boot 启动父依赖 -->\n\t<parent>\n\t\t<groupId>org.springframework.boot</groupId>\n\t\t<artifactId>spring-boot-starter-parent</artifactId>\n\t\t<version>2.1.3.RELEASE</version>\n\t</parent>\n\n\t<properties>\n\t\t<mybatis-spring-boot>1.2.0</mybatis-spring-boot>\n\t\t<mysql-connector>5.1.39</mysql-connector>\n\t</properties>\n\n\t<dependencies>\n\t\t<!-- Spring Boot Web 依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-web</artifactId>\n\t\t</dependency>\n\n\t\t<!-- Spring Boot Test 依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>org.springframework.boot</groupId>\n\t\t\t<artifactId>spring-boot-starter-test</artifactId>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\n\t\t<!-- Spring Boot Mybatis 依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>org.mybatis.spring.boot</groupId>\n\t\t\t<artifactId>mybatis-spring-boot-starter</artifactId>\n\t\t\t<version>${mybatis-spring-boot}</version>\n\t\t</dependency>\n\n\t\t<!-- MySQL 连接驱动依赖 -->\n\t\t<dependency>\n\t\t\t<groupId>mysql</groupId>\n\t\t\t<artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>${mysql-connector}</version>\n\t\t</dependency>\n\n\t\t<!-- Junit -->\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t</dependency>\n\t</dependencies>\n\n\n</project>\n"
  },
  {
    "path": "springboot-mybatis-annotation/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n@SpringBootApplication\npublic class Application {\n\n\tpublic static void main(String[] args) {\n\t\tSpringApplication.run(Application.class, args);\n\t}\n}\n"
  },
  {
    "path": "springboot-mybatis-annotation/src/main/java/org/spring/springboot/controller/CityRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Created by xchunzhao on 02/05/2017.\n */\n@RestController\npublic class CityRestController {\n\n    @Autowired\n    private CityService cityService;\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.GET)\n    public City findOneCity(@RequestParam(value = \"cityName\", required = true) String cityName) {\n        return cityService.findCityByName(cityName);\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis-annotation/src/main/java/org/spring/springboot/dao/CityDao.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.apache.ibatis.annotations.*;\nimport org.spring.springboot.domain.City;\n\n/**\n * 城市 DAO 接口类\n *\n * Created by xchunzhao on 02/05/2017.\n */\n@Mapper // 标志为 Mybatis 的 Mapper\npublic interface CityDao {\n\n    /**\n     * 根据城市名称，查询城市信息\n     *\n     * @param cityName 城市名\n     */\n    @Select(\"SELECT * FROM city\")\n    // 返回 Map 结果集\n    @Results({\n            @Result(property = \"id\", column = \"id\"),\n            @Result(property = \"provinceId\", column = \"province_id\"),\n            @Result(property = \"cityName\", column = \"city_name\"),\n            @Result(property = \"description\", column = \"description\"),\n    })\n    City findByName(@Param(\"cityName\") String cityName);\n}\n"
  },
  {
    "path": "springboot-mybatis-annotation/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 城市实体类\n *\n * Created by xchunzhao on 02/05/2017.\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-annotation/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "package org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\n/**\n * 城市业务逻辑接口类\n *\n * Created by xchunzhao on 02/05/2017.\n */\npublic interface CityService {\n\n    /**\n     * 根据城市名称，查询城市信息\n     * @param cityName\n     */\n    City findCityByName(String cityName);\n}\n"
  },
  {
    "path": "springboot-mybatis-annotation/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n/**\n * 城市业务逻辑实现类\n *\n * Created by xchunzhao on 02/05/2017.\n */\n@Service\npublic class CityServiceImpl implements CityService {\n\n    @Autowired\n    private CityDao cityDao;\n\n    public City findCityByName(String cityName) {\n        return cityDao.findByName(cityName);\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis-annotation/src/main/resources/application.properties",
    "content": "## 数据源配置\nspring.datasource.url=jdbc:mysql://139.224.14.39:3306/springbootdb?useUnicode=true&characterEncoding=utf8\nspring.datasource.username=root\nspring.datasource.password=yt0923666\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-mybatis-mutil-datasource</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-mybatis-mutil-datasource</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <mybatis-spring-boot>1.2.0</mybatis-spring-boot>\n        <mysql-connector>5.1.39</mysql-connector>\n        <druid>1.0.18</druid>\n    </properties>\n\n    <dependencies>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Spring Boot Mybatis 依赖 -->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>${mybatis-spring-boot}</version>\n        </dependency>\n\n        <!-- MySQL 连接驱动依赖 -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector}</version>\n        </dependency>\n\n        <!-- Druid 数据连接池依赖 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>${druid}</version>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/config/ds/ClusterDataSourceConfig.java",
    "content": "package org.spring.springboot.config.ds;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\n\nimport javax.sql.DataSource;\n\n@Configuration\n// 扫描 Mapper 接口并容器管理\n@MapperScan(basePackages = ClusterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = \"clusterSqlSessionFactory\")\npublic class ClusterDataSourceConfig {\n\n    // 精确到 cluster 目录，以便跟其他数据源隔离\n    static final String PACKAGE = \"org.spring.springboot.dao.cluster\";\n    static final String MAPPER_LOCATION = \"classpath:mapper/cluster/*.xml\";\n\n    @Value(\"${cluster.datasource.url}\")\n    private String url;\n\n    @Value(\"${cluster.datasource.username}\")\n    private String user;\n\n    @Value(\"${cluster.datasource.password}\")\n    private String password;\n\n    @Value(\"${cluster.datasource.driverClassName}\")\n    private String driverClass;\n\n    @Bean(name = \"clusterDataSource\")\n    public DataSource clusterDataSource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(driverClass);\n        dataSource.setUrl(url);\n        dataSource.setUsername(user);\n        dataSource.setPassword(password);\n        return dataSource;\n    }\n\n    @Bean(name = \"clusterTransactionManager\")\n    public DataSourceTransactionManager clusterTransactionManager() {\n        return new DataSourceTransactionManager(clusterDataSource());\n    }\n\n    @Bean(name = \"clusterSqlSessionFactory\")\n    public SqlSessionFactory clusterSqlSessionFactory(@Qualifier(\"clusterDataSource\") DataSource clusterDataSource)\n            throws Exception {\n        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(clusterDataSource);\n        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()\n                .getResources(ClusterDataSourceConfig.MAPPER_LOCATION));\n        return sessionFactory.getObject();\n    }\n}"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/config/ds/MasterDataSourceConfig.java",
    "content": "package org.spring.springboot.config.ds;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport org.apache.ibatis.session.SqlSessionFactory;\nimport org.mybatis.spring.SqlSessionFactoryBean;\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Primary;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.jdbc.datasource.DataSourceTransactionManager;\n\nimport javax.sql.DataSource;\n\n@Configuration\n// 扫描 Mapper 接口并容器管理\n@MapperScan(basePackages = MasterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = \"masterSqlSessionFactory\")\npublic class MasterDataSourceConfig {\n\n    // 精确到 master 目录，以便跟其他数据源隔离\n    static final String PACKAGE = \"org.spring.springboot.dao.master\";\n    static final String MAPPER_LOCATION = \"classpath:mapper/master/*.xml\";\n\n    @Value(\"${master.datasource.url}\")\n    private String url;\n\n    @Value(\"${master.datasource.username}\")\n    private String user;\n\n    @Value(\"${master.datasource.password}\")\n    private String password;\n\n    @Value(\"${master.datasource.driverClassName}\")\n    private String driverClass;\n\n    @Bean(name = \"masterDataSource\")\n    @Primary\n    public DataSource masterDataSource() {\n        DruidDataSource dataSource = new DruidDataSource();\n        dataSource.setDriverClassName(driverClass);\n        dataSource.setUrl(url);\n        dataSource.setUsername(user);\n        dataSource.setPassword(password);\n        return dataSource;\n    }\n\n    @Bean(name = \"masterTransactionManager\")\n    @Primary\n    public DataSourceTransactionManager masterTransactionManager() {\n        return new DataSourceTransactionManager(masterDataSource());\n    }\n\n    @Bean(name = \"masterSqlSessionFactory\")\n    @Primary\n    public SqlSessionFactory masterSqlSessionFactory(@Qualifier(\"masterDataSource\") DataSource masterDataSource)\n            throws Exception {\n        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();\n        sessionFactory.setDataSource(masterDataSource);\n        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()\n                .getResources(MasterDataSourceConfig.MAPPER_LOCATION));\n        return sessionFactory.getObject();\n    }\n}"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/controller/UserRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.domain.User;\nimport org.spring.springboot.service.UserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * 用户控制层\n *\n * Created by bysocket on 07/02/2017.\n */\n@RestController\npublic class UserRestController {\n\n    @Autowired\n    private UserService userService;\n\n    /**\n     * 根据用户名获取用户信息，包括从库的地址信息\n     *\n     * @param userName\n     * @return\n     */\n    @RequestMapping(value = \"/api/user\", method = RequestMethod.GET)\n    public User findByName(@RequestParam(value = \"userName\", required = true) String userName) {\n        return userService.findByName(userName);\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/dao/cluster/CityDao.java",
    "content": "package org.spring.springboot.dao.cluster;\n\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.spring.springboot.domain.City;\n\n/**\n * 城市 DAO 接口类\n *\n * Created by bysocket on 07/02/2017.\n */\n@Mapper\npublic interface CityDao {\n\n    /**\n     * 根据城市名称，查询城市信息\n     *\n     * @param cityName 城市名\n     */\n    City findByName(@Param(\"cityName\") String cityName);\n}\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/dao/master/UserDao.java",
    "content": "package org.spring.springboot.dao.master;\n\nimport org.apache.ibatis.annotations.Mapper;\nimport org.apache.ibatis.annotations.Param;\nimport org.spring.springboot.domain.User;\n\n/**\n * 用户 DAO 接口类\n *\n * Created by bysocket on 07/02/2017.\n */\n@Mapper\npublic interface UserDao {\n\n    /**\n     * 根据用户名获取用户信息\n     *\n     * @param userName\n     * @return\n     */\n    User findByName(@Param(\"userName\") String userName);\n}\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/domain/User.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 用户实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class User {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 城市名称\n     */\n    private String userName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    private City city;\n\n    public City getCity() {\n        return city;\n    }\n\n    public void setCity(City city) {\n        this.city = city;\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getUserName() {\n        return userName;\n    }\n\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/service/UserService.java",
    "content": "package org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.domain.User;\n\n/**\n * 用户业务接口层\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface UserService {\n\n    /**\n     * 根据用户名获取用户信息，包括从库的地址信息\n     *\n     * @param userName\n     * @return\n     */\n    User findByName(String userName);\n}\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/service/impl/UserServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.spring.springboot.dao.cluster.CityDao;\nimport org.spring.springboot.dao.master.UserDao;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.domain.User;\nimport org.spring.springboot.service.UserService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n/**\n * 用户业务实现层\n *\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class UserServiceImpl implements UserService {\n\n    @Autowired\n    private UserDao userDao; // 主数据源\n\n    @Autowired\n    private CityDao cityDao; // 从数据源\n\n    @Override\n    public User findByName(String userName) {\n        User user = userDao.findByName(userName);\n        City city = cityDao.findByName(\"温岭市\");\n        user.setCity(city);\n        return user;\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/resources/application.properties",
    "content": "## master 数据源配置\nmaster.datasource.url=jdbc:mysql://localhost:3306/springbootdb?useUnicode=true&characterEncoding=utf8\nmaster.datasource.username=root\nmaster.datasource.password=123456\nmaster.datasource.driverClassName=com.mysql.jdbc.Driver\n\n## cluster 数据源配置\ncluster.datasource.url=jdbc:mysql://localhost:3306/springbootdb_cluster?useUnicode=true&characterEncoding=utf8\ncluster.datasource.username=root\ncluster.datasource.password=123456\ncluster.datasource.driverClassName=com.mysql.jdbc.Driver"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/resources/mapper/cluster/CityMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n<mapper namespace=\"org.spring.springboot.dao.cluster.CityDao\">\n\t<resultMap id=\"BaseResultMap\" type=\"org.spring.springboot.domain.City\">\n\t\t<result column=\"id\" property=\"id\" />\n\t\t<result column=\"province_id\" property=\"provinceId\" />\n\t\t<result column=\"city_name\" property=\"cityName\" />\n\t\t<result column=\"description\" property=\"description\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tid, province_id, city_name, description\n\t</sql>\n\n\t<select id=\"findByName\" resultMap=\"BaseResultMap\" parameterType=\"java.lang.String\">\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom city\n\t\twhere city_name = #{cityName}\n\t</select>\n\n</mapper>\n"
  },
  {
    "path": "springboot-mybatis-mutil-datasource/src/main/resources/mapper/master/UserMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n<mapper namespace=\"org.spring.springboot.dao.master.UserDao\">\n\t<resultMap id=\"BaseResultMap\" type=\"org.spring.springboot.domain.User\">\n\t\t<result column=\"id\" property=\"id\" />\n\t\t<result column=\"user_name\" property=\"userName\" />\n\t\t<result column=\"description\" property=\"description\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tid, user_name, description\n\t</sql>\n\n\t<select id=\"findByName\" resultMap=\"BaseResultMap\" parameterType=\"java.lang.String\">\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom user\n\t\twhere id = 1\n\t</select>\n\n</mapper>\n"
  },
  {
    "path": "springboot-mybatis-redis/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-mybatis-redis</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-mybatis-redis</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <mybatis-spring-boot>1.2.0</mybatis-spring-boot>\n        <mysql-connector>5.1.39</mysql-connector>\n        <spring-boot-starter-redis-version>1.3.2.RELEASE</spring-boot-starter-redis-version>\n    </properties>\n\n    <dependencies>\n\n        <!-- Spring Boot Redis 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-redis</artifactId>\n            <version>${spring-boot-starter-redis-version}</version>\n        </dependency>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Spring Boot Mybatis 依赖 -->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>${mybatis-spring-boot}</version>\n        </dependency>\n\n        <!-- MySQL 连接驱动依赖 -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector}</version>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-mybatis-redis/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\n// mapper 接口类扫描包配置\n@MapperScan(\"org.spring.springboot.dao\")\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-redis/src/main/java/org/spring/springboot/controller/CityRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n/**\n * Created by bysocket on 07/02/2017.\n */\n@RestController\npublic class CityRestController {\n\n    @Autowired\n    private CityService cityService;\n\n\n    @RequestMapping(value = \"/api/city/{id}\", method = RequestMethod.GET)\n    public City findOneCity(@PathVariable(\"id\") Long id) {\n        return cityService.findCityById(id);\n    }\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.POST)\n    public void createCity(@RequestBody City city) {\n        cityService.saveCity(city);\n    }\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.PUT)\n    public void modifyCity(@RequestBody City city) {\n        cityService.updateCity(city);\n    }\n\n    @RequestMapping(value = \"/api/city/{id}\", method = RequestMethod.DELETE)\n    public void modifyCity(@PathVariable(\"id\") Long id) {\n        cityService.deleteCity(id);\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-redis/src/main/java/org/spring/springboot/dao/CityDao.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市 DAO 接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityDao {\n\n    /**\n     * 获取城市信息列表\n     *\n     * @return\n     */\n    List<City> findAllCity();\n\n    /**\n     * 根据城市 ID，获取城市信息\n     *\n     * @param id\n     * @return\n     */\n    City findById(@Param(\"id\") Long id);\n\n    Long saveCity(City city);\n\n    Long updateCity(City city);\n\n    Long deleteCity(Long id);\n}\n"
  },
  {
    "path": "springboot-mybatis-redis/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -1L;\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    @Override\n    public String toString() {\n        return \"City{\" +\n                \"id=\" + id +\n                \", provinceId=\" + provinceId +\n                \", cityName='\" + cityName + '\\'' +\n                \", description='\" + description + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-redis/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "package org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市业务逻辑接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityService {\n    /**\n     * 根据城市 ID,查询城市信息\n     *\n     * @param id\n     * @return\n     */\n    City findCityById(Long id);\n\n    /**\n     * 新增城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long saveCity(City city);\n\n    /**\n     * 更新城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long updateCity(City city);\n\n    /**\n     * 根据城市 ID,删除城市信息\n     *\n     * @param id\n     * @return\n     */\n    Long deleteCity(Long id);\n}\n"
  },
  {
    "path": "springboot-mybatis-redis/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.StringRedisTemplate;\nimport org.springframework.data.redis.core.ValueOperations;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 城市业务逻辑实现类\n * <p>\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class CityServiceImpl implements CityService {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(CityServiceImpl.class);\n\n    @Autowired\n    private CityDao cityDao;\n\n    @Autowired\n    private RedisTemplate redisTemplate;\n\n    /**\n     * 获取城市逻辑：\n     * 如果缓存存在，从缓存中获取城市信息\n     * 如果缓存不存在，从 DB 中获取城市信息，然后插入缓存\n     */\n    public City findCityById(Long id) {\n        // 从缓存中获取城市信息\n        String key = \"city_\" + id;\n        ValueOperations<String, City> operations = redisTemplate.opsForValue();\n\n        // 缓存存在\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            City city = operations.get(key);\n\n            LOGGER.info(\"CityServiceImpl.findCityById() : 从缓存中获取了城市 >> \" + city.toString());\n            return city;\n        }\n\n        // 从 DB 中获取城市信息\n        City city = cityDao.findById(id);\n\n        // 插入缓存\n        operations.set(key, city, 10, TimeUnit.SECONDS);\n        LOGGER.info(\"CityServiceImpl.findCityById() : 城市插入缓存 >> \" + city.toString());\n\n        return city;\n    }\n\n    @Override\n    public Long saveCity(City city) {\n        return cityDao.saveCity(city);\n    }\n\n    /**\n     * 更新城市逻辑：\n     * 如果缓存存在，删除\n     * 如果缓存不存在，不操作\n     */\n    @Override\n    public Long updateCity(City city) {\n        Long ret = cityDao.updateCity(city);\n\n        // 缓存存在，删除缓存\n        String key = \"city_\" + city.getId();\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            redisTemplate.delete(key);\n\n            LOGGER.info(\"CityServiceImpl.updateCity() : 从缓存中删除城市 >> \" + city.toString());\n        }\n\n        return ret;\n    }\n\n    @Override\n    public Long deleteCity(Long id) {\n\n        Long ret = cityDao.deleteCity(id);\n\n        // 缓存存在，删除缓存\n        String key = \"city_\" + id;\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            redisTemplate.delete(key);\n\n            LOGGER.info(\"CityServiceImpl.deleteCity() : 从缓存中删除城市 ID >> \" + id);\n        }\n        return ret;\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis-redis/src/main/resources/application.properties",
    "content": "## 数据源配置\nspring.datasource.url=jdbc:mysql://localhost:3306/springbootdb?useUnicode=true&characterEncoding=utf8\nspring.datasource.username=root\nspring.datasource.password=123456\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\n\n## Mybatis 配置\nmybatis.typeAliasesPackage=org.spring.springboot.domain\nmybatis.mapperLocations=classpath:mapper/*.xml\n\n## Redis 配置\n## Redis数据库索引（默认为0）\nspring.redis.database=0\n## Redis服务器地址\nspring.redis.host=127.0.0.1\n## Redis服务器连接端口\nspring.redis.port=6379\n## Redis服务器连接密码（默认为空）\nspring.redis.password=\n## 连接池最大连接数（使用负值表示没有限制）\nspring.redis.pool.max-active=8\n## 连接池最大阻塞等待时间（使用负值表示没有限制）\nspring.redis.pool.max-wait=-1\n## 连接池中的最大空闲连接\nspring.redis.pool.max-idle=8\n## 连接池中的最小空闲连接\nspring.redis.pool.min-idle=0\n## 连接超时时间（毫秒）\nspring.redis.timeout=0"
  },
  {
    "path": "springboot-mybatis-redis/src/main/resources/mapper/CityMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n<mapper namespace=\"org.spring.springboot.dao.CityDao\">\n\t<resultMap id=\"BaseResultMap\" type=\"org.spring.springboot.domain.City\">\n\t\t<result column=\"id\" property=\"id\" />\n\t\t<result column=\"province_id\" property=\"provinceId\" />\n\t\t<result column=\"city_name\" property=\"cityName\" />\n\t\t<result column=\"description\" property=\"description\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tid, province_id, city_name, description\n\t</sql>\n\n\t<select id=\"findById\" resultMap=\"BaseResultMap\" parameterType=\"java.lang.Long\">\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom city\n\t\twhere id = #{id}\n\t</select>\n\n\t<select id=\"findAllCity\" resultMap=\"BaseResultMap\" >\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom city\n\t</select>\n\n\t<insert id=\"saveCity\" parameterType=\"City\" useGeneratedKeys=\"true\" keyProperty=\"id\">\n\t\tinsert into\n\t\tcity(id,province_id,city_name,description)\n\t\tvalues\n\t\t(#{id},#{provinceId},#{cityName},#{description})\n\t</insert>\n\n\t<update id=\"updateCity\" parameterType=\"City\">\n\t\tupdate\n\t\tcity\n\t\tset\n\t\t<if test=\"provinceId!=null\">\n\t\t\tprovince_id = #{provinceId},\n\t\t</if>\n\t\t<if test=\"cityName!=null\">\n\t\t\tcity_name = #{cityName},\n\t\t</if>\n\t\t<if test=\"description!=null\">\n\t\t\tdescription = #{description}\n\t\t</if>\n\t\twhere\n\t\tid = #{id}\n\t</update>\n\n\t<delete id=\"deleteCity\" parameterType=\"java.lang.Long\">\n\t\tdelete from\n\t\tcity\n\t\twhere\n\t\tid = #{id}\n\t</delete>\n\n</mapper>\n"
  },
  {
    "path": "springboot-mybatis-redis-annotation/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-mybatis-redis-annotation</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-mybatis-redis-annotation</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <mybatis-spring-boot>1.2.0</mybatis-spring-boot>\n        <mysql-connector>5.1.39</mysql-connector>\n        <fastjson-version>1.2.32</fastjson-version>\n    </properties>\n\n    <dependencies>\n\n        <!-- Spring Boot Data Cache 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-cache</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Data Redis 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-redis</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-mybatis-redis-annotation/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-redis-annotation/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -1L;\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public City(Long id, Long provinceId, String cityName, String description) {\n        this.id = id;\n        this.provinceId = provinceId;\n        this.cityName = cityName;\n        this.description = description;\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    @Override\n    public String toString() {\n        return \"City{\" +\n                \"id=\" + id +\n                \", provinceId=\" + provinceId +\n                \", cityName='\" + cityName + '\\'' +\n                \", description='\" + description + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "springboot-mybatis-redis-annotation/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "package org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市业务逻辑接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityService {\n\n    /**\n     * 获取城市\n     *\n     */\n    City getCityByName(String cityName);\n\n    /**\n     * 新增城市信息\n     *\n     */\n    void saveCity(City city);\n\n    /**\n     * 更新城市信息\n     *\n     */\n    void updateCityDescription(String cityName, String description);\n\n}\n"
  },
  {
    "path": "springboot-mybatis-redis-annotation/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.cache.annotation.CachePut;\nimport org.springframework.cache.annotation.Cacheable;\nimport org.springframework.stereotype.Service;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 城市业务逻辑实现类\n * <p>\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class CityServiceImpl implements CityService {\n\n\n    // 模拟数据库存储\n    private Map<String, City> cityMap = new HashMap<String, City>();\n\n    public void saveCity(City city){\n        // 模拟数据库插入操作\n        cityMap.put(city.getCityName(), city);\n    }\n\n    @Cacheable(value = \"baseCityInfo\")\n    public City getCityByName(String cityName){\n        // 模拟数据库查询并返回\n        return cityMap.get(cityName);\n    }\n\n    @CachePut(value = \"baseCityInfo\")\n    public void updateCityDescription(String cityName, String description){\n        City city = cityMap.get(cityName);\n        city.setDescription(description);\n        // 模拟更新数据库\n        cityMap.put(cityName, city);\n    }\n\n}\n"
  },
  {
    "path": "springboot-mybatis-redis-annotation/src/main/resources/application.properties",
    "content": "## Redis 配置\n## Redis数据库索引（默认为0）\nspring.redis.database=0\n## Redis服务器地址\nspring.redis.host=127.0.0.1\n## Redis服务器连接端口\nspring.redis.port=6379\n## Redis服务器连接密码（默认为空）\nspring.redis.password=\n## 连接池最大连接数（使用负值表示没有限制）\nspring.redis.pool.max-active=8\n## 连接池最大阻塞等待时间（使用负值表示没有限制）\nspring.redis.pool.max-wait=-1\n## 连接池中的最大空闲连接\nspring.redis.pool.max-idle=8\n## 连接池中的最小空闲连接\nspring.redis.pool.min-idle=0\n## 连接超时时间（毫秒）\nspring.redis.timeout=0"
  },
  {
    "path": "springboot-mybatis-redis-annotation/src/test/org/spring/springboot/ApplicationTests.java",
    "content": "package org.spring.springboot;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.spring.springboot.service.impl.CityServiceImpl;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * Created by bysocket on 05/06/2017.\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class ApplicationTests {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(CityServiceImpl.class);\n\n\n    @Autowired\n    private CityService cityService;\n\n    @Test\n    public void testRedis() {\n        City city = getShanghai();\n        // 向 redis 中存入数据\n        cityService.saveCity(city);\n\n        // 从 redis 中取数据\n        City cityInfo = cityService.getCityByName(\"上海\");\n\n        LOGGER.info(cityInfo.toString());\n\n    }\n\n    @Test\n    public void testRedisCache() {\n        City city = getBeijing();\n        // 向 redis 中存入数据\n        cityService.saveCity(city);\n\n        // 从 redis 中取数据, 第一次查询\n        City cityInfo = cityService.getCityByName(\"北京\");\n        LOGGER.info(\"第一次查询：\" + cityInfo.toString());\n\n        // 从 redis 中取数据, 第二次查询\n        cityInfo = cityService.getCityByName(\"北京\");\n        LOGGER.info(\"第二次查询：\" + cityInfo.toString());\n\n        // 更新 city 的描述信息后查询\n        cityService.updateCityDescription(\"北京\", \"想不想去北京玩玩呢？\");\n        cityInfo = cityService.getCityByName(\"北京\");\n        LOGGER.info(\"更新描述后查询：\" + cityInfo.toString());\n\n    }\n\n\n\n    private City getShanghai(){\n        return new City(1L, 10L, \"上海\", \"人称魔都的地方\");\n    }\n\n    private City getBeijing(){\n        return new City(2L, 20L, \"北京\", \"中国帝都\");\n    }\n}\n"
  },
  {
    "path": "springboot-properties/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-properties</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-properties</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <dependencies>\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-test</artifactId>\n            <version>1.4.2.RELEASE</version>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <!-- Spring Boot Maven 插件 -->\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <version>2.1.3.RELEASE</version>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>2.12.4</version>\n                <configuration>\n                    <skipTests>true</skipTests>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "springboot-properties/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.spring.springboot.property.HomeProperties;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n * <p>\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application implements CommandLineRunner {\n\n    @Autowired\n    private HomeProperties homeProperties;\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class, args);\n    }\n\n    @Override\n    public void run(String... args) throws Exception {\n        System.out.println(\"\\n\" + homeProperties.toString());\n        System.out.println();\n    }\n}\n"
  },
  {
    "path": "springboot-properties/src/main/java/org/spring/springboot/property/HomeProperties.java",
    "content": "package org.spring.springboot.property;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n/**\n * 家乡属性\n *\n * Created by bysocket on 17/04/2017.\n */\n@Component\n@ConfigurationProperties(prefix = \"home\")\npublic class HomeProperties {\n\n    /**\n     * 省份\n     */\n    private String province;\n\n    /**\n     * 城市\n     */\n    private String city;\n\n    /**\n     * 描述\n     */\n    private String desc;\n\n    public String getProvince() {\n        return province;\n    }\n\n    public void setProvince(String province) {\n        this.province = province;\n    }\n\n    public String getCity() {\n        return city;\n    }\n\n    public void setCity(String city) {\n        this.city = city;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    @Override\n    public String toString() {\n        return \"HomeProperties{\" +\n                \"province='\" + province + '\\'' +\n                \", city='\" + city + '\\'' +\n                \", desc='\" + desc + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "springboot-properties/src/main/java/org/spring/springboot/property/UserProperties.java",
    "content": "package org.spring.springboot.property;\n\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\n/**\n * Created by bysocket on 20/04/2017.\n */\n@Component\n@ConfigurationProperties(prefix = \"user\")\npublic class UserProperties {\n    /**\n     * 用户 ID\n     */\n    private Long id;\n\n    /**\n     * 年龄\n     */\n    private int age;\n\n    /**\n     * 用户名称\n     */\n    private String desc;\n\n    /**\n     * 用户 UUID\n     */\n    private String uuid;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public int getAge() {\n        return age;\n    }\n\n    public void setAge(int age) {\n        this.age = age;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getUuid() {\n        return uuid;\n    }\n\n    public void setUuid(String uuid) {\n        this.uuid = uuid;\n    }\n\n\n    @Override\n    public String toString() {\n        return \"UserProperties{\" +\n                \"id=\" + id +\n                \", age=\" + age +\n                \", desc='\" + desc + '\\'' +\n                \", uuid='\" + uuid + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "springboot-properties/src/main/java/org/spring/springboot/web/HelloWorldController.java",
    "content": "package org.spring.springboot.web;\n\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * Spring Boot HelloWorld 案例\n *\n * Created by bysocket on 16/4/26.\n */\n@RestController\npublic class HelloWorldController {\n\n    @RequestMapping(\"/\")\n    public String sayHello() {\n        return \"Hello,World!\";\n    }\n}\n"
  },
  {
    "path": "springboot-properties/src/main/resources/application-dev.properties",
    "content": "## 家乡属性 Dev\nhome.province=ZheJiang\nhome.city=WenLing\nhome.desc=dev: I'm living in ${home.province} ${home.city}."
  },
  {
    "path": "springboot-properties/src/main/resources/application-prod.properties",
    "content": "## 家乡属性 Prod\nhome.province=ZheJiang\nhome.city=WenLing\nhome.desc=prod: I'm living in ${home.province} ${home.city}."
  },
  {
    "path": "springboot-properties/src/main/resources/application.properties",
    "content": "# Spring Profiles Active\nspring.profiles.active=dev"
  },
  {
    "path": "springboot-properties/src/test/java/org/spring/springboot/property/HomeProperties1.java",
    "content": "package org.spring.springboot.property;\n\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.stereotype.Component;\n\n/**\n * 家乡属性\n *\n * Created by bysocket on 17/04/2017.\n */\n@Component\npublic class HomeProperties1 {\n\n    /**\n     * 省份\n     */\n    @Value(\"${home.province}\")\n    private String province;\n\n    /**\n     * 城市\n     */\n    @Value(\"${home.city}\")\n    private String city;\n\n    /**\n     * 描述\n     */\n    @Value(\"${home.desc}\")\n    private String desc;\n\n    public String getProvince() {\n        return province;\n    }\n\n    public void setProvince(String province) {\n        this.province = province;\n    }\n\n    public String getCity() {\n        return city;\n    }\n\n    public void setCity(String city) {\n        this.city = city;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    @Override\n    public String toString() {\n        return \"HomeProperties1{\" +\n                \"province='\" + province + '\\'' +\n                \", city='\" + city + '\\'' +\n                \", desc='\" + desc + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "springboot-properties/src/test/java/org/spring/springboot/property/PropertiesTest.java",
    "content": "package org.spring.springboot.property;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.junit4.SpringRunner;\n\n/**\n * 自定义配置文件测试类\n * <p>\n * Created by bysocket on 17/04/2017.\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest\npublic class PropertiesTest {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesTest.class);\n\n    @Autowired\n    private UserProperties userProperties;\n\n    @Autowired\n    private HomeProperties homeProperties;\n\n    @Test\n    public void getHomeProperties() {\n        LOGGER.info(\"\\n\\n\" + homeProperties.toString() + \"\\n\");\n    }\n\n    @Test\n    public void randomTestUser() {\n        LOGGER.info(\"\\n\\n\" + userProperties.toString() + \"\\n\");\n    }\n\n}\n"
  },
  {
    "path": "springboot-properties/src/test/java/org/spring/springboot/web/HelloWorldControllerTest.java",
    "content": "package org.spring.springboot.web;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.assertEquals;\n\n/**\n * Spring Boot HelloWorldController 测试 - {@link HelloWorldController}\n *\n * Created by bysocket on 16/4/26.\n */\npublic class HelloWorldControllerTest {\n\n    @Test\n    public void testSayHello() {\n        assertEquals(\"Hello,World!\",new HelloWorldController().sayHello());\n    }\n}\n"
  },
  {
    "path": "springboot-properties/src/test/resouorces/application.yml",
    "content": "## 家乡属性\nhome:\n  province: 浙江省\n  city: 温岭松门\n  desc: 我家住在${home.province}的${home.city}\n\n## 随机属性\nuser:\n  id: ${random.long}\n  age: ${random.int[1,200]}\n  desc: 泥瓦匠叫做${random.value}\n  uuid: ${random.uuid}\n"
  },
  {
    "path": "springboot-restful/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-restful</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-restful</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <properties>\n        <mybatis-spring-boot>1.2.0</mybatis-spring-boot>\n        <mysql-connector>5.1.39</mysql-connector>\n    </properties>\n\n    <dependencies>\n\n        <!-- Spring Boot Web 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Spring Boot Mybatis 依赖 -->\n        <dependency>\n            <groupId>org.mybatis.spring.boot</groupId>\n            <artifactId>mybatis-spring-boot-starter</artifactId>\n            <version>${mybatis-spring-boot}</version>\n        </dependency>\n\n        <!-- MySQL 连接驱动依赖 -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>${mysql-connector}</version>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-restful/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.mybatis.spring.annotation.MapperScan;\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\n// mapper 接口类扫描包配置\n@MapperScan(\"org.spring.springboot.dao\")\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-restful/src/main/java/org/spring/springboot/controller/CityRestController.java",
    "content": "package org.spring.springboot.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.List;\n\n/**\n * 城市 Controller 实现 Restful HTTP 服务\n *\n * Created by bysocket on 07/02/2017.\n */\n@RestController\npublic class CityRestController {\n\n    @Autowired\n    private CityService cityService;\n\n    @RequestMapping(value = \"/api/city/{id}\", method = RequestMethod.GET)\n    public City findOneCity(@PathVariable(\"id\") Long id) {\n        return cityService.findCityById(id);\n    }\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.GET)\n    public List<City> findAllCity() {\n        return cityService.findAllCity();\n    }\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.POST)\n    public void createCity(@RequestBody City city) {\n        cityService.saveCity(city);\n    }\n\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.PUT)\n    public void modifyCity(@RequestBody City city) {\n        cityService.updateCity(city);\n    }\n\n    @RequestMapping(value = \"/api/city/{id}\", method = RequestMethod.DELETE)\n    public void modifyCity(@PathVariable(\"id\") Long id) {\n        cityService.deleteCity(id);\n    }\n}\n"
  },
  {
    "path": "springboot-restful/src/main/java/org/spring/springboot/dao/CityDao.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.apache.ibatis.annotations.Param;\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市 DAO 接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityDao {\n\n    /**\n     * 获取城市信息列表\n     *\n     * @return\n     */\n    List<City> findAllCity();\n\n    /**\n     * 根据城市 ID，获取城市信息\n     *\n     * @param id\n     * @return\n     */\n    City findById(@Param(\"id\") Long id);\n\n    Long saveCity(City city);\n\n    Long updateCity(City city);\n\n    Long deleteCity(Long id);\n}\n"
  },
  {
    "path": "springboot-restful/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-restful/src/main/java/org/spring/springboot/service/CityService.java",
    "content": "package org.spring.springboot.service;\n\nimport org.spring.springboot.domain.City;\n\nimport java.util.List;\n\n/**\n * 城市业务逻辑接口类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic interface CityService {\n\n    /**\n     * 获取城市信息列表\n     *\n     * @return\n     */\n    List<City> findAllCity();\n\n    /**\n     * 根据城市 ID,查询城市信息\n     *\n     * @param id\n     * @return\n     */\n    City findCityById(Long id);\n\n    /**\n     * 新增城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long saveCity(City city);\n\n    /**\n     * 更新城市信息\n     *\n     * @param city\n     * @return\n     */\n    Long updateCity(City city);\n\n    /**\n     * 根据城市 ID,删除城市信息\n     *\n     * @param id\n     * @return\n     */\n    Long deleteCity(Long id);\n}\n"
  },
  {
    "path": "springboot-restful/src/main/java/org/spring/springboot/service/impl/CityServiceImpl.java",
    "content": "package org.spring.springboot.service.impl;\n\nimport org.spring.springboot.dao.CityDao;\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * 城市业务逻辑实现类\n *\n * Created by bysocket on 07/02/2017.\n */\n@Service\npublic class CityServiceImpl implements CityService {\n\n    @Autowired\n    private CityDao cityDao;\n\n    public List<City> findAllCity(){\n        return cityDao.findAllCity();\n    }\n\n    public City findCityById(Long id) {\n        return cityDao.findById(id);\n    }\n\n    @Override\n    public Long saveCity(City city) {\n        return cityDao.saveCity(city);\n    }\n\n    @Override\n    public Long updateCity(City city) {\n        return cityDao.updateCity(city);\n    }\n\n    @Override\n    public Long deleteCity(Long id) {\n        return cityDao.deleteCity(id);\n    }\n\n}\n"
  },
  {
    "path": "springboot-restful/src/main/resources/application.properties",
    "content": "## 数据源配置\nspring.datasource.url=jdbc:mysql://localhost:3306/springbootdb?useUnicode=true&characterEncoding=utf8\nspring.datasource.username=root\nspring.datasource.password=123456\nspring.datasource.driver-class-name=com.mysql.jdbc.Driver\n\n## Mybatis 配置\nmybatis.typeAliasesPackage=org.spring.springboot.domain\nmybatis.mapperLocations=classpath:mapper/*.xml\n\n"
  },
  {
    "path": "springboot-restful/src/main/resources/mapper/CityMapper.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\" >\n<mapper namespace=\"org.spring.springboot.dao.CityDao\">\n\t<resultMap id=\"BaseResultMap\" type=\"org.spring.springboot.domain.City\">\n\t\t<result column=\"id\" property=\"id\" />\n\t\t<result column=\"province_id\" property=\"provinceId\" />\n\t\t<result column=\"city_name\" property=\"cityName\" />\n\t\t<result column=\"description\" property=\"description\" />\n\t</resultMap>\n\n\t<sql id=\"Base_Column_List\">\n\t\tid, province_id, city_name, description\n\t</sql>\n\n\t<select id=\"findById\" resultMap=\"BaseResultMap\" parameterType=\"java.lang.Long\">\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom city\n\t\twhere id = #{id}\n\t</select>\n\n\t<select id=\"findAllCity\" resultMap=\"BaseResultMap\" >\n\t\tselect\n\t\t<include refid=\"Base_Column_List\" />\n\t\tfrom city\n\t</select>\n\n\t<insert id=\"saveCity\" parameterType=\"City\" useGeneratedKeys=\"true\" keyProperty=\"id\">\n\t\tinsert into\n\t\t\tcity(id,province_id,city_name,description)\n\t\tvalues\n\t\t\t(#{id},#{provinceId},#{cityName},#{description})\n\t</insert>\n\n\t<update id=\"updateCity\" parameterType=\"City\">\n\t\tupdate\n\t\t\tcity\n\t\tset\n\t\t<if test=\"provinceId!=null\">\n\t\t\tprovince_id = #{provinceId},\n\t\t</if>\n\t\t<if test=\"cityName!=null\">\n\t\t\tcity_name = #{cityName},\n\t\t</if>\n\t\t<if test=\"description!=null\">\n\t\t\tdescription = #{description}\n\t\t</if>\n\t\twhere\n\t\t\tid = #{id}\n\t</update>\n\n\t<delete id=\"deleteCity\" parameterType=\"java.lang.Long\">\n\t\tdelete from\n\t\t\tcity\n\t\twhere\n\t\t\tid = #{id}\n\t</delete>\n</mapper>\n"
  },
  {
    "path": "springboot-validation-over-json/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-validation-over-json</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-validation-over-json</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <dependencies>\n        <!-- Spring Boot web依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n</project>\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 16/4/26.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/constant/CityErrorInfoEnum.java",
    "content": "package org.spring.springboot.constant;\n\nimport org.spring.springboot.result.ErrorInfoInterface;\n\n/**\n * 业务错误码 案例\n *\n * Created by bysocket on 14/03/2017.\n */\npublic enum CityErrorInfoEnum implements ErrorInfoInterface {\n    PARAMS_NO_COMPLETE(\"000001\",\"params no complete\"),\n    CITY_EXIT(\"000002\",\"city exit\");\n\n    private String code;\n\n    private String message;\n\n    CityErrorInfoEnum(String code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public String getCode(){\n        return this.code;\n    }\n\n    public String getMessage(){\n        return this.message;\n    }\n}\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/result/ErrorInfoInterface.java",
    "content": "package org.spring.springboot.result;\n\n/**\n * 错误码接口\n *\n * Created by bysocket on 13/03/2017.\n */\npublic interface ErrorInfoInterface {\n    String getCode();\n    String getMessage();\n}\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/result/GlobalErrorInfoEnum.java",
    "content": "package org.spring.springboot.result;\n\n/**\n * 应用系统级别的错误码\n *\n * Created by bysocket on 14/03/2017.\n */\npublic enum GlobalErrorInfoEnum implements ErrorInfoInterface{\n    SUCCESS(\"0\", \"success\"),\n    NOT_FOUND(\"-1\", \"service not found\");\n\n    private String code;\n\n    private String message;\n\n    GlobalErrorInfoEnum(String code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public String getCode(){\n        return this.code;\n    }\n\n    public String getMessage(){\n        return this.message;\n    }\n}\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/result/GlobalErrorInfoException.java",
    "content": "package org.spring.springboot.result;\n\n/**\n * 统一错误码异常\n *\n * Created by bysocket on 14/03/2017.\n */\npublic class GlobalErrorInfoException extends Exception {\n\n    private ErrorInfoInterface errorInfo;\n\n    public GlobalErrorInfoException (ErrorInfoInterface errorInfo) {\n        this.errorInfo = errorInfo;\n    }\n\n    public ErrorInfoInterface getErrorInfo() {\n        return errorInfo;\n    }\n\n    public void setErrorInfo(ErrorInfoInterface errorInfo) {\n        this.errorInfo = errorInfo;\n    }\n}\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/result/GlobalErrorInfoHandler.java",
    "content": "package org.spring.springboot.result;\n\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.RestControllerAdvice;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * 统一错误码异常处理\n *\n * Created by bysocket on 14/03/2017.\n */\n@RestControllerAdvice\npublic class GlobalErrorInfoHandler {\n\n    @ExceptionHandler(value = GlobalErrorInfoException.class)\n    public ResultBody errorHandlerOverJson(HttpServletRequest request,\n                                           GlobalErrorInfoException exception) {\n        ErrorInfoInterface errorInfo = exception.getErrorInfo();\n        ResultBody result = new ResultBody(errorInfo);\n        return result;\n    }\n}\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/result/ResultBody.java",
    "content": "package org.spring.springboot.result;\n\n/**\n * 返回体\n *\n * Created by bysocket on 14/03/2017.\n */\npublic class ResultBody {\n    /**\n     * 响应代码\n     */\n    private String code;\n\n    /**\n     * 响应消息\n     */\n    private String message;\n\n    /**\n     * 响应结果\n     */\n    private Object result;\n\n    public ResultBody(ErrorInfoInterface errorInfo) {\n        this.code = errorInfo.getCode();\n        this.message = errorInfo.getMessage();\n    }\n\n    public ResultBody(Object result) {\n        this.code = GlobalErrorInfoEnum.SUCCESS.getCode();\n        this.message = GlobalErrorInfoEnum.SUCCESS.getMessage();\n        this.result = result;\n    }\n\n    public String getCode() {\n        return code;\n    }\n\n    public void setCode(String code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public Object getResult() {\n        return result;\n    }\n\n    public void setResult(Object result) {\n        this.result = result;\n    }\n}\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/web/City.java",
    "content": "package org.spring.springboot.web;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n * Created by bysocket on 07/02/2017.\n */\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -1L;\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public City() {\n    }\n\n    public City(Long id, Long provinceId, String cityName, String description) {\n        this.id = id;\n        this.provinceId = provinceId;\n        this.cityName = cityName;\n        this.description = description;\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-validation-over-json/src/main/java/org/spring/springboot/web/ErrorJsonController.java",
    "content": "package org.spring.springboot.web;\n\nimport org.spring.springboot.constant.CityErrorInfoEnum;\nimport org.spring.springboot.result.GlobalErrorInfoException;\nimport org.spring.springboot.result.ResultBody;\nimport org.springframework.util.StringUtils;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n/**\n * 错误码案例\n *\n * Created by bysocket on 16/4/26.\n */\n@RestController\npublic class ErrorJsonController {\n\n\n    /**\n     * 获取城市接口\n     *\n     * @param cityName\n     * @return\n     * @throws GlobalErrorInfoException\n     */\n    @RequestMapping(value = \"/api/city\", method = RequestMethod.GET)\n    public ResultBody findOneCity(@RequestParam(\"cityName\") String cityName) throws GlobalErrorInfoException {\n        // 入参为空\n        if (StringUtils.isEmpty(cityName)) {\n            throw new GlobalErrorInfoException(CityErrorInfoEnum.PARAMS_NO_COMPLETE);\n        }\n        return new ResultBody(new City(1L,2L,\"温岭\",\"是我的故乡\"));\n    }\n}"
  },
  {
    "path": "springboot-validation-over-json/src/test/java/org/spring/springboot/web/ErrorJsonControllerTest.java",
    "content": "package org.spring.springboot.web;\n\nimport org.junit.Test;\n\n/**\n * Spring Boot ErrorJsonController 测试 - {@link ErrorJsonController}\n *\n * Created by bysocket on 16/4/26.\n */\npublic class ErrorJsonControllerTest {\n\n    @Test\n    public void testSayHello() {\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-1-quickstart/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>springboot-webflux-1-quickstart</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>springboot-webflux-1-quickstart</name>\n\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.3.RELEASE</version>\n    <relativePath/> <!-- lookup parent from repository -->\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>io.projectreactor</groupId>\n      <artifactId>reactor-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "springboot-webflux-1-quickstart/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 09/29/2017.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-1-quickstart/src/main/java/org/spring/springboot/handler/CityHandler.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.function.BodyInserters;\nimport org.springframework.web.reactive.function.server.ServerRequest;\nimport org.springframework.web.reactive.function.server.ServerResponse;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class CityHandler {\n\n    public Mono<ServerResponse> helloCity(ServerRequest request) {\n        return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)\n                .body(BodyInserters.fromObject(\"Hello, City!\"));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-1-quickstart/src/main/java/org/spring/springboot/router/CityRouter.java",
    "content": "package org.spring.springboot.router;\n\nimport org.spring.springboot.handler.CityHandler;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\nimport org.springframework.web.reactive.function.server.RequestPredicates;\nimport org.springframework.web.reactive.function.server.RouterFunction;\nimport org.springframework.web.reactive.function.server.RouterFunctions;\nimport org.springframework.web.reactive.function.server.ServerResponse;\n\n@Configuration\npublic class CityRouter {\n\n\n    @Bean\n    public RouterFunction<ServerResponse> routeCity(CityHandler cityHandler) {\n        return RouterFunctions\n                .route(RequestPredicates.GET(\"/hello\")\n                                .and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),\n                        cityHandler::helloCity);\n    }\n\n}\n"
  },
  {
    "path": "springboot-webflux-1-quickstart/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <description>WebFlux 实战城市管理系统</description>\n\n    <groupId>demo.springboot</groupId>\n    <artifactId>springboot-webflux-10-book-manage-sys</artifactId>\n    <version>1.0</version>\n    <packaging>jar</packaging>\n\n  <!-- Spring Boot 启动父依赖 -->\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.3.RELEASE</version>\n  </parent>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <java.version>1.8</java.version>\n    </properties>\n\n  <dependencies>\n\n    <!-- Spring Boot Web Flux 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <!-- Spring Boot 响应式 MongoDB 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>\n    </dependency>\n\n    <!-- 模板引擎 Thymeleaf 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-thymeleaf</artifactId>\n    </dependency>\n\n    <!-- Spring Boot Test 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Junit -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/java/demo/springboot/WebApplication.java",
    "content": "package demo.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket\n */\n@SpringBootApplication\npublic class WebApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(WebApplication.class, args);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/java/demo/springboot/dao/CityRepository.java",
    "content": "package demo.springboot.dao;\n\nimport demo.springboot.domain.City;\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface CityRepository extends ReactiveMongoRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/java/demo/springboot/domain/City.java",
    "content": "package demo.springboot.domain;\n\n/**\n * 城市实体类\n *\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/java/demo/springboot/service/CityService.java",
    "content": "package demo.springboot.service;\n\nimport demo.springboot.domain.City;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\npublic interface CityService {\n\n    Flux<City> findAll();\n\n    Mono<City> insertByCity(City city);\n\n    Mono<City> update(City city);\n\n    Mono<Void> delete(Long id);\n\n    Mono<City> findById(Long id);\n}\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/java/demo/springboot/service/impl/CityServiceImpl.java",
    "content": "package demo.springboot.service.impl;\n\nimport demo.springboot.dao.CityRepository;\nimport demo.springboot.domain.City;\nimport demo.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class CityServiceImpl implements CityService {\n\n    private final CityRepository cityRepository;\n\n    @Autowired\n    public CityServiceImpl(CityRepository cityRepository) {\n        this.cityRepository = cityRepository;\n    }\n\n    @Override\n    public Flux<City> findAll() {\n        return cityRepository.findAll();\n    }\n\n    @Override\n    public Mono<City> insertByCity(City city) {\n        return cityRepository.save(city);\n    }\n\n    @Override\n    public Mono<City> update(City city) {\n        return cityRepository.save(city);\n    }\n\n    @Override\n    public Mono<Void> delete(Long id) {\n        return cityRepository.deleteById(id);\n    }\n\n    @Override\n    public Mono<City> findById(Long id) {\n        return cityRepository.findById(id);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/java/demo/springboot/web/CityController.java",
    "content": "package demo.springboot.web;\n\nimport demo.springboot.domain.City;\nimport demo.springboot.service.CityService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.ModelAttribute;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport reactor.core.publisher.Mono;\n\nimport java.awt.print.Book;\n\n/**\n * city 控制层\n * <p>\n * Created by bysocket\n */\n@Controller\n@RequestMapping(value = \"/city\")\npublic class CityController {\n\n    private static final String CITY_FORM_PATH_NAME = \"cityForm\";\n    private static final String CITY_LIST_PATH_NAME = \"cityList\";\n    private static final String REDIRECT_TO_CITY_URL = \"redirect:/city\";\n\n    @Autowired\n    CityService cityService;\n\n    @RequestMapping(method = RequestMethod.GET)\n    public String getCityList(final Model model) {\n        model.addAttribute(\"cityList\", cityService.findAll());\n        return CITY_LIST_PATH_NAME;\n    }\n\n    @RequestMapping(value = \"/create\", method = RequestMethod.GET)\n    public String createCityForm(final Model model) {\n        model.addAttribute(\"city\", new City());\n        model.addAttribute(\"action\", \"create\");\n        return CITY_FORM_PATH_NAME;\n    }\n\n    @RequestMapping(value = \"/create\", method = RequestMethod.POST)\n    public String postCity(@ModelAttribute City city) {\n        cityService.insertByCity(city);\n        return REDIRECT_TO_CITY_URL;\n    }\n\n    @RequestMapping(value = \"/update/{id}\", method = RequestMethod.GET)\n    public String getCity(@PathVariable Long id, final Model model) {\n        final Mono<City> city = cityService.findById(id);\n        model.addAttribute(\"city\", city);\n        model.addAttribute(\"action\", \"update\");\n        return CITY_FORM_PATH_NAME;\n    }\n\n    @RequestMapping(value = \"/update\", method = RequestMethod.POST)\n    public String putBook(@ModelAttribute City city) {\n        cityService.update(city);\n        return REDIRECT_TO_CITY_URL;\n    }\n\n    @RequestMapping(value = \"/delete/{id}\", method = RequestMethod.GET)\n    public String deleteCity(@PathVariable Long id) {\n        cityService.delete(id);\n        return CITY_LIST_PATH_NAME;\n    }\n\n}\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/resources/application.properties",
    "content": "spring.data.mongodb.host=localhost\nspring.data.mongodb.database=admin\nspring.data.mongodb.port=27017\nspring.data.mongodb.username=admin\nspring.data.mongodb.password=admin\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/resources/static/css/default.css",
    "content": "/* contentDiv */\n.contentDiv {padding:20px 60px;}"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/resources/templates/cityForm.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n  <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n  <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n  <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n  <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n  <meta charset=\"UTF-8\"/>\n  <title>城市管理</title>\n</head>\n\n<body>\n<div class=\"contentDiv\">\n\n  <legend>\n    <strong>城市管理</strong>\n  </legend>\n\n  <form th:action=\"@{/city/{action}(action=${action})}\" method=\"post\" class=\"form-horizontal\">\n\n    <div class=\"form-group\">\n      <label for=\"city_id\" class=\"col-sm-2 control-label\">城市编号:</label>\n      <div class=\"col-xs-4\">\n        <input type=\"text\" class=\"form-control\" id=\"city_id\" name=\"id\" th:value=\"${city.id}\"/>\n      </div>\n    </div>\n\n    <div class=\"form-group\">\n      <label for=\"city_name\" class=\"col-sm-2 control-label\">城市名称:</label>\n      <div class=\"col-xs-4\">\n        <input type=\"text\" class=\"form-control\" id=\"city_name\" name=\"cityName\" th:value=\"${city.cityName}\"/>\n      </div>\n    </div>\n\n    <div class=\"form-group\">\n      <label for=\"city_description\" class=\"col-sm-2 control-label\">城市描述:</label>\n      <div class=\"col-xs-4\">\n        <input class=\"form-control\" id=\"city_description\" rows=\"3\" name=\"description\"\n                  th:value=\"${city.description}\" />\n\n      </div>\n    </div>\n\n    <div class=\"form-group\">\n      <label for=\"city_provinceId\" class=\"col-sm-2 control-label\">省份编号:</label>\n      <div class=\"col-xs-4\">\n        <input type=\"text\" class=\"form-control\" id=\"city_provinceId\" name=\"provinceId\" th:value=\"${city.provinceId}\"\n               />\n      </div>\n    </div>\n\n    <div class=\"form-group\">\n      <div class=\"col-sm-offset-2 col-sm-10\">\n        <input class=\"btn btn-primary\" type=\"submit\" value=\"提交\"/>&nbsp;&nbsp;\n        <input class=\"btn\" type=\"button\" value=\"返回\" onclick=\"history.back()\"/>\n      </div>\n    </div>\n  </form>\n</div>\n</body>\n</html>\n"
  },
  {
    "path": "springboot-webflux-10-book-manage-sys/src/main/resources/templates/cityList.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <script type=\"text/javascript\" th:src=\"@{https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js}\"></script>\n    <link th:href=\"@{https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css}\" rel=\"stylesheet\"/>\n    <link th:href=\"@{/css/default.css}\" rel=\"stylesheet\"/>\n    <link rel=\"icon\" th:href=\"@{/images/favicon.ico}\" type=\"image/x-icon\"/>\n    <meta charset=\"UTF-8\"/>\n    <title>城市列表</title>\n</head>\n\n<body>\n\n<div class=\"contentDiv\">\n\n    <table class=\"table table-hover table-condensed\">\n        <legend>\n            <strong>城市列表</strong>\n        </legend>\n        <thead>\n        <tr>\n            <th>城市编号</th>\n            <th>城市名称</th>\n            <th>描述</th>\n            <th>省份编号</th>\n            <th>管理</th>\n        </tr>\n        </thead>\n        <tbody>\n        <tr th:each=\"city : ${cityList}\">\n            <th scope=\"row\" th:text=\"${city.id}\"></th>\n            <td><a th:href=\"@{/city/update/{cityId}(cityId=${city.id})}\" th:text=\"${city.cityName}\"></a></td>\n            <td th:text=\"${city.description}\"></td>\n            <td th:text=\"${city.provinceId}\"></td>\n            <td><a class=\"btn btn-danger\" th:href=\"@{/city/delete/{cityId}(cityId=${city.id})}\">删除</a></td>\n        </tr>\n\n        </tbody>\n    </table>\n\n    <div><a class=\"btn btn-primary\" href=\"/city/create\" role=\"button\">新增城市</a></div>\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "springboot-webflux-2-restful/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>springboot</groupId>\n    <artifactId>springboot-webflux-2-restful</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <name>springboot-webflux-2-restful</name>\n\n    <!-- Spring Boot 启动父依赖 -->\n    <parent>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-starter-parent</artifactId>\n        <version>2.1.3.RELEASE</version>\n    </parent>\n\n    <dependencies>\n\n        <!-- Spring Boot Web Flux 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-webflux</artifactId>\n        </dependency>\n\n        <!-- Spring Boot Test 依赖 -->\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n\n        <!-- Junit -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.12</version>\n        </dependency>\n    </dependencies>\n\n</project>\n"
  },
  {
    "path": "springboot-webflux-2-restful/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 09/29/2017.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-2-restful/src/main/java/org/spring/springboot/dao/CityRepository.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.Collection;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\n@Repository\npublic class CityRepository {\n\n    private ConcurrentMap<Long, City> repository = new ConcurrentHashMap<>();\n\n    private static final AtomicLong idGenerator = new AtomicLong(0);\n\n    public Long save(City city) {\n        Long id = idGenerator.incrementAndGet();\n        city.setId(id);\n        repository.put(id, city);\n        return id;\n    }\n\n    public Collection<City> findAll() {\n        return repository.values();\n    }\n\n\n    public City findCityById(Long id) {\n        return repository.get(id);\n    }\n\n    public Long updateCity(City city) {\n        repository.put(city.getId(), city);\n        return city.getId();\n    }\n\n    public Long deleteCity(Long id) {\n        repository.remove(id);\n        return id;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-2-restful/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 城市实体类\n *\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-2-restful/src/main/java/org/spring/springboot/handler/CityHandler.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.spring.springboot.dao.CityRepository;\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class CityHandler {\n\n    private final CityRepository cityRepository;\n\n    @Autowired\n    public CityHandler(CityRepository cityRepository) {\n        this.cityRepository = cityRepository;\n    }\n\n    public Mono<Long> save(City city) {\n        return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.save(city)));\n    }\n\n    public Mono<City> findCityById(Long id) {\n        return Mono.justOrEmpty(cityRepository.findCityById(id));\n    }\n\n    public Flux<City> findAllCity() {\n        return Flux.fromIterable(cityRepository.findAll());\n    }\n\n    public Mono<Long> modifyCity(City city) {\n        return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.updateCity(city)));\n    }\n\n    public Mono<Long> deleteCity(Long id) {\n        return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.deleteCity(id)));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-2-restful/src/main/java/org/spring/springboot/webflux/controller/CityWebFluxController.java",
    "content": "package org.spring.springboot.webflux.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.handler.CityHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@RestController\n@RequestMapping(value = \"/city\")\npublic class CityWebFluxController {\n\n    @Autowired\n    private CityHandler cityHandler;\n\n    @GetMapping(value = \"/{id}\")\n    public Mono<City> findCityById(@PathVariable(\"id\") Long id) {\n        return cityHandler.findCityById(id);\n    }\n\n    @GetMapping()\n    public Flux<City> findAllCity() {\n        return cityHandler.findAllCity();\n    }\n\n    @PostMapping()\n    public Mono<Long> saveCity(@RequestBody City city) {\n        return cityHandler.save(city);\n    }\n\n    @PutMapping()\n    public Mono<Long> modifyCity(@RequestBody City city) {\n        return cityHandler.modifyCity(city);\n    }\n\n    @DeleteMapping(value = \"/{id}\")\n    public Mono<Long> deleteCity(@PathVariable(\"id\") Long id) {\n        return cityHandler.deleteCity(id);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-2-restful/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "springboot-webflux-3-mongodb/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>springboot-webflux-3-mongodb</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>springboot-webflux-3-mongodb</name>\n\n  <!-- Spring Boot 启动父依赖 -->\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.3.RELEASE</version>\n  </parent>\n\n  <dependencies>\n\n    <!-- Spring Boot Web Flux 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <!-- ❤️Spring Boot 响应式 MongoDB 支持 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>\n    </dependency>\n\n    <!-- Spring Boot Test 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Junit -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 09/29/2017.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/dao/CityRepository.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface CityRepository extends ReactiveMongoRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport org.springframework.data.annotation.Id;\n\n/**\n * 城市实体类\n *\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/handler/CityHandler.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.spring.springboot.dao.CityRepository;\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class CityHandler {\n\n    private final CityRepository cityRepository;\n\n    @Autowired\n    public CityHandler(CityRepository cityRepository) {\n        this.cityRepository = cityRepository;\n    }\n\n    public Mono<City> save(City city) {\n        return cityRepository.save(city);\n    }\n\n    public Mono<City> findCityById(Long id) {\n\n        return cityRepository.findById(id);\n    }\n\n    public Flux<City> findAllCity() {\n\n        return cityRepository.findAll();\n    }\n\n    public Mono<City> modifyCity(City city) {\n\n        return cityRepository.save(city);\n    }\n\n    public Mono<Long> deleteCity(Long id) {\n        return cityRepository.deleteById(id).flatMap(mono -> Mono.create(cityMonoSink -> cityMonoSink.success(id)));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-3-mongodb/src/main/java/org/spring/springboot/webflux/controller/CityWebFluxController.java",
    "content": "package org.spring.springboot.webflux.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.handler.CityHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@RestController\n@RequestMapping(value = \"/city\")\npublic class CityWebFluxController {\n\n    @Autowired\n    private CityHandler cityHandler;\n\n    @GetMapping(value = \"/{id}\")\n    public Mono<City> findCityById(@PathVariable(\"id\") Long id) {\n        return cityHandler.findCityById(id);\n    }\n\n    @GetMapping()\n    public Flux<City> findAllCity() {\n        return cityHandler.findAllCity();\n    }\n\n    @PostMapping()\n    public Mono<City> saveCity(@RequestBody City city) {\n        return cityHandler.save(city);\n    }\n\n    @PutMapping()\n    public Mono<City> modifyCity(@RequestBody City city) {\n        return cityHandler.modifyCity(city);\n    }\n\n    @DeleteMapping(value = \"/{id}\")\n    public Mono<Long> deleteCity(@PathVariable(\"id\") Long id) {\n        return cityHandler.deleteCity(id);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-3-mongodb/src/main/resources/application.properties",
    "content": "spring.data.mongodb.host=localhost\nspring.data.mongodb.database=admin\nspring.data.mongodb.port=27017\nspring.data.mongodb.username=admin\nspring.data.mongodb.password=admin\n"
  },
  {
    "path": "springboot-webflux-4-thymeleaf/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>springboot-webflux-4-thymeleaf</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>springboot-webflux-4-thymeleaf</name>\n\n  <!-- Spring Boot 启动父依赖 -->\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.5.RELEASE</version>\n  </parent>\n\n  <dependencies>\n\n    <!-- Spring Boot Web Flux 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <!-- 模板引擎 Thymeleaf 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-thymeleaf</artifactId>\n    </dependency>\n\n\n    <!-- Spring Boot Test 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Junit -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "springboot-webflux-4-thymeleaf/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-4-thymeleaf/src/main/java/org/spring/springboot/dao/CityRepository.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.stereotype.Repository;\n\nimport java.util.Collection;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\n@Repository\npublic class CityRepository {\n\n    private ConcurrentMap<Long, City> repository = new ConcurrentHashMap<>();\n\n    private static final AtomicLong idGenerator = new AtomicLong(0);\n\n    public Long save(City city) {\n        Long id = idGenerator.incrementAndGet();\n        city.setId(id);\n        repository.put(id, city);\n        return id;\n    }\n\n    public Collection<City> findAll() {\n        return repository.values();\n    }\n\n\n    public City findCityById(Long id) {\n        return repository.get(id);\n    }\n\n    public Long updateCity(City city) {\n        repository.put(city.getId(), city);\n        return city.getId();\n    }\n\n    public Long deleteCity(Long id) {\n        repository.remove(id);\n        return id;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-4-thymeleaf/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 城市实体类\n *\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-4-thymeleaf/src/main/java/org/spring/springboot/handler/CityHandler.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.spring.springboot.dao.CityRepository;\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class CityHandler {\n\n    private final CityRepository cityRepository;\n\n    @Autowired\n    public CityHandler(CityRepository cityRepository) {\n        this.cityRepository = cityRepository;\n    }\n\n    public Mono<Long> save(City city) {\n        return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.save(city)));\n    }\n\n    public Mono<City> findCityById(Long id) {\n        return Mono.justOrEmpty(cityRepository.findCityById(id));\n    }\n\n    public Flux<City> findAllCity() {\n        return Flux.fromIterable(cityRepository.findAll());\n    }\n\n    public Mono<Long> modifyCity(City city) {\n        return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.updateCity(city)));\n    }\n\n    public Mono<Long> deleteCity(Long id) {\n        return Mono.create(cityMonoSink -> cityMonoSink.success(cityRepository.deleteCity(id)));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-4-thymeleaf/src/main/java/org/spring/springboot/webflux/controller/CityWebFluxController.java",
    "content": "package org.spring.springboot.webflux.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.handler.CityHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Controller\n@RequestMapping(value = \"/city\")\npublic class CityWebFluxController {\n\n    @Autowired\n    private CityHandler cityHandler;\n\n    @GetMapping(value = \"/{id}\")\n    @ResponseBody\n    public Mono<City> findCityById(@PathVariable(\"id\") Long id) {\n        return cityHandler.findCityById(id);\n    }\n\n    @GetMapping()\n    @ResponseBody\n    public Flux<City> findAllCity() {\n        return cityHandler.findAllCity();\n    }\n\n    @PostMapping()\n    @ResponseBody\n    public Mono<Long> saveCity(@RequestBody City city) {\n        return cityHandler.save(city);\n    }\n\n    @PutMapping()\n    @ResponseBody\n    public Mono<Long> modifyCity(@RequestBody City city) {\n        return cityHandler.modifyCity(city);\n    }\n\n    @DeleteMapping(value = \"/{id}\")\n    @ResponseBody\n    public Mono<Long> deleteCity(@PathVariable(\"id\") Long id) {\n        return cityHandler.deleteCity(id);\n    }\n\n    @GetMapping(\"/hello\")\n    public Mono<String> hello(final Model model) {\n        model.addAttribute(\"name\", \"泥瓦匠\");\n        model.addAttribute(\"city\", \"浙江温岭\");\n\n        String path = \"hello\";\n        return Mono.create(monoSink -> monoSink.success(path));\n    }\n\n    private static final String CITY_LIST_PATH_NAME = \"cityList\";\n\n    @GetMapping(\"/page/list\")\n    public String listPage(final Model model) {\n        final Flux<City> cityFluxList = cityHandler.findAllCity();\n        model.addAttribute(\"cityList\", cityFluxList);\n        return CITY_LIST_PATH_NAME;\n    }\n\n}\n"
  },
  {
    "path": "springboot-webflux-4-thymeleaf/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "springboot-webflux-4-thymeleaf/src/main/resources/templates/cityList.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>城市列表</title>\n</head>\n\n<body>\n\n<div>\n\n\n    <table>\n        <legend>\n            <strong>城市列表</strong>\n        </legend>\n        <thead>\n        <tr>\n            <th>城市编号</th>\n            <th>省份编号</th>\n            <th>名称</th>\n            <th>描述</th>\n        </tr>\n        </thead>\n        <tbody>\n        <tr th:each=\"city : ${cityList}\">\n            <td th:text=\"${city.id}\"></td>\n            <td th:text=\"${city.provinceId}\"></td>\n            <td th:text=\"${city.cityName}\"></td>\n            <td th:text=\"${city.description}\"></td>\n        </tr>\n        </tbody>\n    </table>\n\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "springboot-webflux-4-thymeleaf/src/main/resources/templates/hello.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>欢迎页面</title>\n</head>\n\n<body>\n\n<h1 >你好，欢迎来自<p th:text=\"${city}\"></p>的<p th:text=\"${name}\"></p></h1>\n\n</body>\n</html>\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>springboot-webflux-5-thymeleaf-mongodb</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>springboot-webflux-5-thymeleaf-mongodb</name>\n\n  <!-- Spring Boot 启动父依赖 -->\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.5.RELEASE</version>\n  </parent>\n\n  <dependencies>\n\n    <!-- Spring Boot Web Flux 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <!-- Spring Boot 响应式 MongoDB 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>\n    </dependency>\n\n    <!-- 模板引擎 Thymeleaf 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-thymeleaf</artifactId>\n    </dependency>\n\n    <!-- Spring Boot Test 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Junit -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/src/main/java/org/spring/springboot/dao/CityRepository.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\nimport org.springframework.stereotype.Repository;\nimport reactor.core.publisher.Mono;\n\n@Repository\npublic interface CityRepository extends ReactiveMongoRepository<City, Long> {\n\n    Mono<City> findByCityName(String cityName);\n\n}\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\n/**\n * 城市实体类\n *\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/src/main/java/org/spring/springboot/handler/CityHandler.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.spring.springboot.dao.CityRepository;\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class CityHandler {\n\n    private final CityRepository cityRepository;\n\n    @Autowired\n    public CityHandler(CityRepository cityRepository) {\n        this.cityRepository = cityRepository;\n    }\n\n    public Mono<City> save(City city) {\n        return cityRepository.save(city);\n    }\n\n    public Mono<City> findCityById(Long id) {\n\n        return cityRepository.findById(id);\n    }\n\n    public Flux<City> findAllCity() {\n\n        return cityRepository.findAll();\n    }\n\n    public Mono<City> modifyCity(City city) {\n\n        return cityRepository.save(city);\n    }\n\n    public Mono<Long> deleteCity(Long id) {\n        cityRepository.deleteById(id);\n        return Mono.create(cityMonoSink -> cityMonoSink.success(id));\n    }\n\n    public Mono<City> getByCityName(String cityName) {\n        return cityRepository.findByCityName(cityName);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/src/main/java/org/spring/springboot/webflux/controller/CityWebFluxController.java",
    "content": "package org.spring.springboot.webflux.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.handler.CityHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Controller\n@RequestMapping(value = \"/city\")\npublic class CityWebFluxController {\n\n    @Autowired\n    private CityHandler cityHandler;\n\n    @GetMapping(value = \"/{id}\")\n    @ResponseBody\n    public Mono<City> findCityById(@PathVariable(\"id\") Long id) {\n        return cityHandler.findCityById(id);\n    }\n\n    @GetMapping()\n    @ResponseBody\n    public Flux<City> findAllCity() {\n        return cityHandler.findAllCity();\n    }\n\n    @PostMapping()\n    @ResponseBody\n    public Mono<City> saveCity(@RequestBody City city) {\n        return cityHandler.save(city);\n    }\n\n    @PutMapping()\n    @ResponseBody\n    public Mono<City> modifyCity(@RequestBody City city) {\n        return cityHandler.modifyCity(city);\n    }\n\n    @DeleteMapping(value = \"/{id}\")\n    @ResponseBody\n    public Mono<Long> deleteCity(@PathVariable(\"id\") Long id) {\n        return cityHandler.deleteCity(id);\n    }\n\n    private static final String CITY_LIST_PATH_NAME = \"cityList\";\n    private static final String CITY_PATH_NAME = \"city\";\n\n    @GetMapping(\"/page/list\")\n    public String listPage(final Model model) {\n        final Flux<City> cityFluxList = cityHandler.findAllCity();\n        model.addAttribute(\"cityList\", cityFluxList);\n        return CITY_LIST_PATH_NAME;\n    }\n\n    @GetMapping(\"/getByName\")\n    public String getByCityName(final Model model,\n                                @RequestParam(\"cityName\") String cityName) {\n        final Mono<City> city = cityHandler.getByCityName(cityName);\n        model.addAttribute(\"city\", city);\n        return CITY_PATH_NAME;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/src/main/resources/application.properties",
    "content": "spring.data.mongodb.host=localhost\nspring.data.mongodb.database=admin\nspring.data.mongodb.port=27017\nspring.data.mongodb.username=admin\nspring.data.mongodb.password=admin\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/src/main/resources/templates/city.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>城市</title>\n</head>\n\n<body>\n\n<div>\n\n\n    <table>\n        <legend>\n            <strong>城市单个查询</strong>\n        </legend>\n        <tbody>\n            <td th:text=\"${city.id}\"></td>\n            <td th:text=\"${city.provinceId}\"></td>\n            <td th:text=\"${city.cityName}\"></td>\n            <td th:text=\"${city.description}\"></td>\n        </tbody>\n    </table>\n\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "springboot-webflux-5-thymeleaf-mongodb/src/main/resources/templates/cityList.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n    <meta charset=\"UTF-8\"/>\n    <title>城市列表</title>\n</head>\n\n<body>\n\n<div>\n\n\n    <table>\n        <legend>\n            <strong>城市列表</strong>\n        </legend>\n        <thead>\n        <tr>\n            <th>城市编号</th>\n            <th>省份编号</th>\n            <th>名称</th>\n            <th>描述</th>\n        </tr>\n        </thead>\n        <tbody>\n        <tr th:each=\"city : ${cityList}\">\n            <td th:text=\"${city.id}\"></td>\n            <td th:text=\"${city.provinceId}\"></td>\n            <td th:text=\"${city.cityName}\"></td>\n            <td th:text=\"${city.description}\"></td>\n        </tr>\n        </tbody>\n    </table>\n\n</div>\n\n</body>\n</html>\n"
  },
  {
    "path": "springboot-webflux-6-redis/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>springboot-webflux-6-redis</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>springboot-webflux-6-redis</name>\n\n  <!-- Spring Boot 启动父依赖 -->\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.5.RELEASE</version>\n  </parent>\n\n  <dependencies>\n\n    <!-- Spring Boot Web Flux 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <!-- Spring Boot 响应式 Redis 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>\n    </dependency>\n\n    <!-- Spring Boot Test 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Junit -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "springboot-webflux-6-redis/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-6-redis/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport org.springframework.data.annotation.Id;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n */\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -2081742442561524068L;\n\n    /**\n     * 城市编号\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-6-redis/src/main/java/org/spring/springboot/webflux/controller/CityWebFluxController.java",
    "content": "package org.spring.springboot.webflux.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.ValueOperations;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Mono;\n\nimport java.util.concurrent.TimeUnit;\n\n@RestController\n@RequestMapping(value = \"/city\")\npublic class CityWebFluxController {\n\n    @Autowired\n    private RedisTemplate redisTemplate;\n\n    @GetMapping(value = \"/{id}\")\n    public Mono<City> findCityById(@PathVariable(\"id\") Long id) {\n        String key = \"city_\" + id;\n        ValueOperations<String, City> operations = redisTemplate.opsForValue();\n        boolean hasKey = redisTemplate.hasKey(key);\n        City city = operations.get(key);\n\n        if (!hasKey) {\n            return Mono.create(monoSink -> monoSink.success(null));\n        }\n        return Mono.create(monoSink -> monoSink.success(city));\n    }\n\n    @PostMapping()\n    public Mono<City> saveCity(@RequestBody City city) {\n        String key = \"city_\" + city.getId();\n        ValueOperations<String, City> operations = redisTemplate.opsForValue();\n        operations.set(key, city, 60, TimeUnit.SECONDS);\n\n        return Mono.create(monoSink -> monoSink.success(city));\n    }\n\n    @DeleteMapping(value = \"/{id}\")\n    public Mono<Long> deleteCity(@PathVariable(\"id\") Long id) {\n        String key = \"city_\" + id;\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            redisTemplate.delete(key);\n        }\n        return Mono.create(monoSink -> monoSink.success(id));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-6-redis/src/main/java/org/spring/springboot/webflux/controller/CityWebFluxReactiveController.java",
    "content": "package org.spring.springboot.webflux.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.ReactiveRedisTemplate;\nimport org.springframework.data.redis.core.ReactiveValueOperations;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Mono;\n\n@RestController\n@RequestMapping(value = \"/city2\")\npublic class CityWebFluxReactiveController {\n\n    @Autowired\n    private ReactiveRedisTemplate reactiveRedisTemplate;\n\n    @GetMapping(value = \"/{id}\")\n    public Mono<City> findCityById(@PathVariable(\"id\") Long id) {\n        String key = \"city_\" + id;\n        ReactiveValueOperations<String, City> operations = reactiveRedisTemplate.opsForValue();\n        Mono<City> city = operations.get(key);\n        return city;\n    }\n\n    @PostMapping\n    public Mono<City> saveCity(@RequestBody City city) {\n        String key = \"city_\" + city.getId();\n        ReactiveValueOperations<String, City> operations = reactiveRedisTemplate.opsForValue();\n        return operations.getAndSet(key, city);\n    }\n\n    @DeleteMapping(value = \"/{id}\")\n    public Mono<Long> deleteCity(@PathVariable(\"id\") Long id) {\n        String key = \"city_\" + id;\n        return reactiveRedisTemplate.delete(key);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-6-redis/src/main/resources/application.properties",
    "content": "## Redis 配置\n## Redis服务器地址\nspring.redis.host=127.0.0.1\n## Redis服务器连接端口\nspring.redis.port=6379\n## Redis服务器连接密码（默认为空）\nspring.redis.password=\n# 连接超时时间（毫秒）\nspring.redis.timeout=5000\n"
  },
  {
    "path": "springboot-webflux-7-redis-cache/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>springboot-webflux-7-redis-cache</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>springboot-webflux-7-redis-cache</name>\n\n  <!-- Spring Boot 启动父依赖 -->\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.5.RELEASE</version>\n  </parent>\n\n  <dependencies>\n\n    <!-- Spring Boot Web Flux 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <!-- Spring Boot 响应式 MongoDB 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>\n    </dependency>\n\n    <!-- Spring Boot 响应式 Redis 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>\n    </dependency>\n\n    <!-- Spring Boot Test 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Junit -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "springboot-webflux-7-redis-cache/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        SpringApplication.run(Application.class, args);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-7-redis-cache/src/main/java/org/spring/springboot/dao/CityRepository.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface CityRepository extends ReactiveMongoRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "springboot-webflux-7-redis-cache/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport org.springframework.data.annotation.Id;\n\nimport java.io.Serializable;\n\n/**\n * 城市实体类\n *\n */\npublic class City implements Serializable {\n\n    private static final long serialVersionUID = -2081742442561524068L;\n\n    /**\n     * 城市编号\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n\n    @Override\n    public String toString() {\n        return \"City{\" +\n                \"id=\" + id +\n                \", provinceId=\" + provinceId +\n                \", cityName='\" + cityName + '\\'' +\n                \", description='\" + description + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-7-redis-cache/src/main/java/org/spring/springboot/handler/CityHandler.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.spring.springboot.dao.CityRepository;\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.redis.core.RedisTemplate;\nimport org.springframework.data.redis.core.ValueOperations;\nimport org.springframework.stereotype.Component;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class CityHandler {\n\n    private static final Logger LOGGER = LoggerFactory.getLogger(CityHandler.class);\n\n    @Autowired\n    private RedisTemplate redisTemplate;\n\n    private final CityRepository cityRepository;\n\n    @Autowired\n    public CityHandler(CityRepository cityRepository) {\n        this.cityRepository = cityRepository;\n    }\n\n    public Mono<City> save(City city) {\n        return cityRepository.save(city);\n    }\n\n\n    public Mono<City> findCityById(Long id) {\n\n        // 从缓存中获取城市信息\n        String key = \"city_\" + id;\n        ValueOperations<String, City> operations = redisTemplate.opsForValue();\n\n        // 缓存存在\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            City city = operations.get(key);\n\n            LOGGER.info(\"CityHandler.findCityById() : 从缓存中获取了城市 >> \" + city.toString());\n            return Mono.create(cityMonoSink -> cityMonoSink.success(city));\n        }\n\n        // 从 MongoDB 中获取城市信息\n        Mono<City> cityMono = cityRepository.findById(id);\n\n        if (cityMono == null)\n            return cityMono;\n\n        // 插入缓存\n        cityMono.subscribe(cityObj -> {\n            operations.set(key, cityObj);\n            LOGGER.info(\"CityHandler.findCityById() : 城市插入缓存 >> \" + cityObj.toString());\n        });\n\n        return cityMono;\n    }\n\n    public Flux<City> findAllCity() {\n        return cityRepository.findAll().cache();\n    }\n\n    public Mono<City> modifyCity(City city) {\n\n        // 缓存存在，删除缓存\n        String key = \"city_\" + city.getId();\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            redisTemplate.delete(key);\n\n            LOGGER.info(\"CityHandler.modifyCity() : 从缓存中删除城市 ID >> \" + city.getId());\n        }\n\n        return cityRepository.save(city).cache();\n    }\n\n    public Mono<Long> deleteCity(Long id) {\n\n        // 缓存存在，删除缓存\n        String key = \"city_\" + id;\n        boolean hasKey = redisTemplate.hasKey(key);\n        if (hasKey) {\n            redisTemplate.delete(key);\n\n            LOGGER.info(\"CityHandler.deleteCity() : 从缓存中删除城市 ID >> \" + id);\n        }\n\n        cityRepository.deleteById(id);\n        return Mono.create(cityMonoSink -> cityMonoSink.success(id));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-7-redis-cache/src/main/java/org/spring/springboot/webflux/controller/CityWebFluxController.java",
    "content": "package org.spring.springboot.webflux.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.handler.CityHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@RestController\n@RequestMapping(value = \"/city\")\npublic class CityWebFluxController {\n\n    @Autowired\n    private CityHandler cityHandler;\n\n    @GetMapping(value = \"/{id}\")\n    public Mono<City> findCityById(@PathVariable(\"id\") Long id) {\n        return cityHandler.findCityById(id);\n    }\n\n    @GetMapping()\n    public Flux<City> findAllCity() {\n        return cityHandler.findAllCity();\n    }\n\n    @PostMapping()\n    public Mono<City> saveCity(@RequestBody City city) {\n        return cityHandler.save(city);\n    }\n\n    @PutMapping()\n    public Mono<City> modifyCity(@RequestBody City city) {\n        return cityHandler.modifyCity(city);\n    }\n\n    @DeleteMapping(value = \"/{id}\")\n    public Mono<Long> deleteCity(@PathVariable(\"id\") Long id) {\n        return cityHandler.deleteCity(id);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-7-redis-cache/src/main/resources/application.properties",
    "content": "## Redis 配置\n## Redis服务器地址\nspring.redis.host=127.0.0.1\n## Redis服务器连接端口\nspring.redis.port=6379\n## Redis服务器连接密码（默认为空）\nspring.redis.password=\n# 连接超时时间（毫秒）\nspring.redis.timeout=5000\n\n## MongoDB\nspring.data.mongodb.host=localhost\nspring.data.mongodb.database=admin\nspring.data.mongodb.port=27017\nspring.data.mongodb.username=admin\nspring.data.mongodb.password=admin\n"
  },
  {
    "path": "springboot-webflux-8-websocket/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>springboot-webflux-8-websocket</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>springboot-webflux-8-websocket</name>\n\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.3.RELEASE</version>\n    <relativePath/> <!-- lookup parent from repository -->\n  </parent>\n\n  <properties>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n    <java.version>1.8</java.version>\n  </properties>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.springframework.boot</groupId>\n        <artifactId>spring-boot-maven-plugin</artifactId>\n      </plugin>\n    </plugins>\n  </build>\n</project>\n"
  },
  {
    "path": "springboot-webflux-8-websocket/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 09/29/2017.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-8-websocket/src/main/java/org/spring/springboot/config/WebSocketConfiguration.java",
    "content": "package org.spring.springboot.config;\n\nimport org.spring.springboot.handler.EchoHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.Ordered;\nimport org.springframework.web.reactive.HandlerMapping;\nimport org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;\nimport org.springframework.web.reactive.socket.WebSocketHandler;\nimport org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n@Configuration\npublic class WebSocketConfiguration {\n\n    @Autowired\n    @Bean\n    public HandlerMapping webSocketMapping(final EchoHandler echoHandler) {\n        final Map<String, WebSocketHandler> map = new HashMap<>();\n        map.put(\"/echo\", echoHandler);\n\n        final SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();\n        mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);\n        mapping.setUrlMap(map);\n        return mapping;\n    }\n\n    @Bean\n    public WebSocketHandlerAdapter handlerAdapter() {\n        return new WebSocketHandlerAdapter();\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-8-websocket/src/main/java/org/spring/springboot/handler/EchoHandler.java",
    "content": "\npackage org.spring.springboot.handler;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.reactive.socket.WebSocketHandler;\nimport org.springframework.web.reactive.socket.WebSocketSession;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class EchoHandler implements WebSocketHandler {\n    @Override\n    public Mono<Void> handle(final WebSocketSession session) {\n        return session.send(\n                session.receive()\n                        .map(msg -> session.textMessage(\n                                \"服务端返回：小明， \" + msg.getPayloadAsText())));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-8-websocket/src/main/resources/application.properties",
    "content": ""
  },
  {
    "path": "springboot-webflux-8-websocket/src/main/resources/websocket-client.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Client WebSocket</title>\n</head>\n<body>\n\n<div class=\"chat\"></div>\n\n<script>\n  var clientWebSocket = new WebSocket(\"ws://localhost:8080/echo\");\n\n  clientWebSocket.onopen = function () {\n    console.log(\"clientWebSocket.onopen\", clientWebSocket);\n    console.log(\"clientWebSocket.readyState\", \"websocketstatus\");\n    clientWebSocket.send(\"你好！\");\n  }\n\n  clientWebSocket.onclose = function (error) {\n    console.log(\"clientWebSocket.onclose\", clientWebSocket, error);\n    events(\"聊天会话关闭！\");\n  }\n\n  function events(responseEvent) {\n    document.querySelector(\".chat\").innerHTML += responseEvent + \"<br>\";\n  }\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "springboot-webflux-8-websocket/src/test/java/WSClient.java",
    "content": "import org.springframework.web.reactive.socket.WebSocketMessage;\nimport org.springframework.web.reactive.socket.client.ReactorNettyWebSocketClient;\nimport org.springframework.web.reactive.socket.client.WebSocketClient;\nimport reactor.core.publisher.Flux;\n\nimport java.net.URI;\nimport java.time.Duration;\n\npublic class WSClient {\n\n\n    public static void main(final String[] args) {\n        final WebSocketClient client = new ReactorNettyWebSocketClient();\n        client.execute(URI.create(\"ws://localhost:8080/echo\"), session ->\n                session.send(Flux.just(session.textMessage(\"你好\")))\n                        .thenMany(session.receive().take(1).map(WebSocketMessage::getPayloadAsText))\n                        .doOnNext(System.out::println)\n                        .then())\n                .block(Duration.ofMillis(5000));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-9-test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <groupId>springboot</groupId>\n  <artifactId>springboot-webflux-9-test</artifactId>\n  <version>0.0.1-SNAPSHOT</version>\n  <name>springboot-webflux-9-test</name>\n\n  <!-- Spring Boot 启动父依赖 -->\n  <parent>\n    <groupId>org.springframework.boot</groupId>\n    <artifactId>spring-boot-starter-parent</artifactId>\n    <version>2.1.3.RELEASE</version>\n  </parent>\n\n  <dependencies>\n\n    <!-- Spring Boot Web Flux 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-webflux</artifactId>\n    </dependency>\n\n    <!-- ❤️Spring Boot 响应式 MongoDB 支持 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>\n    </dependency>\n\n    <!-- Spring Boot Test 依赖 -->\n    <dependency>\n      <groupId>org.springframework.boot</groupId>\n      <artifactId>spring-boot-starter-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <dependency>\n      <groupId>io.projectreactor</groupId>\n      <artifactId>reactor-test</artifactId>\n      <scope>test</scope>\n    </dependency>\n\n    <!-- Junit -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <version>4.12</version>\n    </dependency>\n  </dependencies>\n\n</project>\n"
  },
  {
    "path": "springboot-webflux-9-test/src/main/java/org/spring/springboot/Application.java",
    "content": "package org.spring.springboot;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\n\n/**\n * Spring Boot 应用启动类\n *\n * Created by bysocket on 09/29/2017.\n */\n// Spring Boot 应用的标识\n@SpringBootApplication\npublic class Application {\n\n    public static void main(String[] args) {\n        // 程序启动入口\n        // 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件\n        SpringApplication.run(Application.class,args);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-9-test/src/main/java/org/spring/springboot/dao/CityRepository.java",
    "content": "package org.spring.springboot.dao;\n\nimport org.spring.springboot.domain.City;\nimport org.springframework.data.mongodb.repository.ReactiveMongoRepository;\nimport org.springframework.stereotype.Repository;\n\n@Repository\npublic interface CityRepository extends ReactiveMongoRepository<City, Long> {\n\n}\n"
  },
  {
    "path": "springboot-webflux-9-test/src/main/java/org/spring/springboot/domain/City.java",
    "content": "package org.spring.springboot.domain;\n\nimport org.springframework.data.annotation.Id;\n\n/**\n * 城市实体类\n *\n */\npublic class City {\n\n    /**\n     * 城市编号\n     */\n    @Id\n    private Long id;\n\n    /**\n     * 省份编号\n     */\n    private Long provinceId;\n\n    /**\n     * 城市名称\n     */\n    private String cityName;\n\n    /**\n     * 描述\n     */\n    private String description;\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getProvinceId() {\n        return provinceId;\n    }\n\n    public void setProvinceId(Long provinceId) {\n        this.provinceId = provinceId;\n    }\n\n    public String getCityName() {\n        return cityName;\n    }\n\n    public void setCityName(String cityName) {\n        this.cityName = cityName;\n    }\n\n    public String getDescription() {\n        return description;\n    }\n\n    public void setDescription(String description) {\n        this.description = description;\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-9-test/src/main/java/org/spring/springboot/handler/CityHandler.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.spring.springboot.dao.CityRepository;\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@Component\npublic class CityHandler {\n\n    private final CityRepository cityRepository;\n\n    @Autowired\n    public CityHandler(CityRepository cityRepository) {\n        this.cityRepository = cityRepository;\n    }\n\n    public Mono<City> save(City city) {\n        return cityRepository.save(city);\n    }\n\n    public Mono<City> findCityById(Long id) {\n\n        return cityRepository.findById(id);\n    }\n\n    public Flux<City> findAllCity() {\n\n        return cityRepository.findAll();\n    }\n\n    public Mono<City> modifyCity(City city) {\n\n        return cityRepository.save(city);\n    }\n\n    public Mono<Long> deleteCity(Long id) {\n        cityRepository.deleteById(id);\n        return Mono.create(cityMonoSink -> cityMonoSink.success(id));\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-9-test/src/main/java/org/spring/springboot/webflux/controller/CityWebFluxController.java",
    "content": "package org.spring.springboot.webflux.controller;\n\nimport org.spring.springboot.domain.City;\nimport org.spring.springboot.handler.CityHandler;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.web.bind.annotation.*;\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\n@RestController\n@RequestMapping(value = \"/city\")\npublic class CityWebFluxController {\n\n    @Autowired\n    private CityHandler cityHandler;\n\n    @GetMapping(value = \"/{id}\")\n    public Mono<City> findCityById(@PathVariable(\"id\") Long id) {\n        return cityHandler.findCityById(id);\n    }\n\n    @GetMapping()\n    public Flux<City> findAllCity() {\n        return cityHandler.findAllCity();\n    }\n\n    @PostMapping()\n    public Mono<City> saveCity(@RequestBody City city) {\n        return cityHandler.save(city);\n    }\n\n    @PutMapping()\n    public Mono<City> modifyCity(@RequestBody City city) {\n        return cityHandler.modifyCity(city);\n    }\n\n    @DeleteMapping(value = \"/{id}\")\n    public Mono<Long> deleteCity(@PathVariable(\"id\") Long id) {\n        return cityHandler.deleteCity(id);\n    }\n}\n"
  },
  {
    "path": "springboot-webflux-9-test/src/main/resources/application.properties",
    "content": "spring.data.mongodb.host=localhost\nspring.data.mongodb.database=admin\nspring.data.mongodb.port=27017\nspring.data.mongodb.username=admin\nspring.data.mongodb.password=admin\n"
  },
  {
    "path": "springboot-webflux-9-test/src/test/java/org/spring/springboot/handler/CityHandlerTest.java",
    "content": "package org.spring.springboot.handler;\n\nimport org.junit.Assert;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.spring.springboot.domain.City;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.http.MediaType;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.web.reactive.server.WebTestClient;\nimport org.springframework.web.reactive.function.BodyInserters;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\npublic class CityHandlerTest {\n\n    @Autowired\n    private WebTestClient webClient;\n\n    private static Map<String, City> cityMap = new HashMap<>();\n\n    @BeforeClass\n    public static void setup() throws Exception {\n        City wl = new City();\n        wl.setId(1L);\n        wl.setProvinceId(2L);\n        wl.setCityName(\"WL\");\n        wl.setDescription(\"WL IS GOOD\");\n        cityMap.put(\"WL\", wl);\n    }\n\n    @Test\n    public void testSave() throws Exception {\n\n        City expectCity = webClient.post().uri(\"/city\")\n                .contentType(MediaType.APPLICATION_JSON)\n                .body(BodyInserters.fromObject(cityMap.get(\"WL\")))\n                .exchange()\n                .expectStatus().isOk()\n                .expectBody(City.class).returnResult().getResponseBody();\n\n        Assert.assertNotNull(expectCity);\n        Assert.assertEquals(expectCity.getId(), cityMap.get(\"WL\").getId());\n        Assert.assertEquals(expectCity.getCityName(), cityMap.get(\"WL\").getCityName());\n    }\n\n}\n"
  }
]