├── .gitignore ├── LICENSE ├── README.md ├── converting-jar-to-war └── README.md ├── deploying-cloud-foundry-from-sts └── README.md ├── deploying-spring-boot-app-to-azure └── README.md ├── draft-gs-multi-module └── README.md ├── gs-accessing-data-gemfire └── README.md ├── gs-accessing-data-jpa └── README.md ├── gs-accessing-data-mongodb └── README.md ├── gs-accessing-data-mysql └── README.md ├── gs-accessing-data-neo4j └── README.md ├── gs-accessing-data-rest └── README.md ├── gs-accessing-gemfire-data-rest └── README.md ├── gs-accessing-mongodb-data-rest └── README.md ├── gs-accessing-neo4j-data-rest └── README.md ├── gs-accessing-vault └── README.md ├── gs-actuator-service └── README.md ├── gs-async-method └── README.md ├── gs-authenticationg-ldap └── README.md ├── gs-batch-processing └── README.md ├── gs-caching-gemfire └── README.md ├── gs-caching └── README.md ├── gs-centralized-configuration └── README.md ├── gs-circuit-breaker └── README.md ├── gs-client-side-load-balancing └── README.md ├── gs-consuming-rest ├── README.adoc └── gs-consuming-rest │ ├── pom.xml │ └── src │ └── main │ └── java │ └── hello │ ├── Application.java │ ├── Quote.java │ └── Value.java ├── gs-consuming-web-service └── README.md ├── gs-contract-rest └── README.md ├── gs-crud-with-vaadin └── README.md ├── gs-gateway └── README.md ├── gs-handling-form-submission └── README.md ├── gs-integration └── README.md ├── gs-managing-transactions └── README.md ├── gs-maven └── README.md ├── gs-messaging-gcp-pubsub └── README.md ├── gs-messaging-jms └── README.md ├── gs-messaging-rabbitmq └── README.md ├── gs-messaging-redis └── README.md ├── gs-messaging-stomp-websocket └── README.md ├── gs-reactive-rest-service └── README.md ├── gs-relational-data-access ├── README.adoc └── gs-relational-data-access │ ├── build.gradle │ ├── pom.xml │ └── src │ └── main │ └── java │ └── hello │ ├── Application.java │ └── Customer.java ├── gs-rest-hateoas └── README.md ├── gs-rest-service-cors └── README.md ├── gs-rest-service ├── README.adoc └── gs-rest-service │ ├── pom.xml │ └── src │ └── main │ └── java │ └── hello │ ├── Application.java │ ├── Greeting.java │ └── GreetingController.java ├── gs-routing-and-filtering └── README.md ├── gs-scheduling-tasks ├── README.adoc └── gs-scheduling-tasks │ ├── pom.xml │ └── src │ └── main │ └── java │ └── hello │ ├── Application.java │ └── ScheduledTasks.java ├── gs-securing-web └── README.md ├── gs-service-registration-and-discovery └── README.md ├── gs-serving-web-content └── README.md ├── gs-soap-service └── README.md ├── gs-spring-boot-docker └── README.md ├── gs-spring-boot └── README.md ├── gs-spring-data-reactive-redis └── README.md ├── gs-testing-restdocs └── README.md ├── gs-testing-web └── README.md ├── gs-uploading-files ├── README.adoc └── gs-uploading-files │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── hello │ │ │ ├── Application.java │ │ │ ├── FileUploadController.java │ │ │ └── storage │ │ │ ├── FileSystemStorageService.java │ │ │ ├── StorageException.java │ │ │ ├── StorageFileNotFoundException.java │ │ │ ├── StorageProperties.java │ │ │ └── StorageService.java │ └── resources │ │ ├── application.properties │ │ └── templates │ │ └── uploadForm.html │ └── test │ └── java │ └── hello │ └── FileUploadTests.java ├── gs-validating-form-input └── README.md ├── gs-vault-config └── README.md ├── restful-service-with-angularjs └── README.md ├── restful-service-with-jquery └── README.md ├── restful-service-with-restjs └── README.md ├── spring-boot-docker └── README.md ├── spring-security-architecture └── README.md ├── start-guid-with-intellij └── README.md └── working-with-sts └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/macos,intellij+all 3 | 4 | ### Intellij+all ### 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff 9 | .idea/**/workspace.xml 10 | .idea/**/tasks.xml 11 | .idea/**/usage.statistics.xml 12 | .idea/**/dictionaries 13 | .idea/**/shelf 14 | 15 | # Generated files 16 | .idea/**/contentModel.xml 17 | 18 | # Sensitive or high-churn files 19 | .idea/**/dataSources/ 20 | .idea/**/dataSources.ids 21 | .idea/**/dataSources.local.xml 22 | .idea/**/sqlDataSources.xml 23 | .idea/**/dynamic.xml 24 | .idea/**/uiDesigner.xml 25 | .idea/**/dbnavigator.xml 26 | 27 | # Gradle 28 | .idea/**/gradle.xml 29 | .idea/**/libraries 30 | 31 | # Gradle and Maven with auto-import 32 | # When using Gradle or Maven with auto-import, you should exclude module files, 33 | # since they will be recreated, and may cause churn. Uncomment if using 34 | # auto-import. 35 | # .idea/modules.xml 36 | # .idea/*.iml 37 | # .idea/modules 38 | 39 | # CMake 40 | cmake-build-*/ 41 | 42 | # Mongo Explorer plugin 43 | .idea/**/mongoSettings.xml 44 | 45 | # File-based project format 46 | *.iws 47 | 48 | # IntelliJ 49 | out/ 50 | 51 | # mpeltonen/sbt-idea plugin 52 | .idea_modules/ 53 | 54 | # JIRA plugin 55 | atlassian-ide-plugin.xml 56 | 57 | # Cursive Clojure plugin 58 | .idea/replstate.xml 59 | 60 | # Crashlytics plugin (for Android Studio and IntelliJ) 61 | com_crashlytics_export_strings.xml 62 | crashlytics.properties 63 | crashlytics-build.properties 64 | fabric.properties 65 | 66 | # Editor-based Rest Client 67 | .idea/httpRequests 68 | 69 | # Android studio 3.1+ serialized cache file 70 | .idea/caches/build_file_checksums.ser 71 | 72 | ### Intellij+all Patch ### 73 | # Ignores the whole .idea folder and all .iml files 74 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 75 | 76 | .idea/ 77 | 78 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 79 | 80 | *.iml 81 | modules.xml 82 | .idea/misc.xml 83 | *.ipr 84 | 85 | ### macOS ### 86 | # General 87 | .DS_Store 88 | .AppleDouble 89 | .LSOverride 90 | 91 | # Icon must end with two \r 92 | Icon 93 | 94 | # Thumbnails 95 | ._* 96 | 97 | # Files that might appear in the root of a volume 98 | .DocumentRevisions-V100 99 | .fseventsd 100 | .Spotlight-V100 101 | .TemporaryItems 102 | .Trashes 103 | .VolumeIcon.icns 104 | .com.apple.timemachine.donotpresent 105 | 106 | # Directories potentially created on remote AFP share 107 | .AppleDB 108 | .AppleDesktop 109 | Network Trash Folder 110 | Temporary Items 111 | .apdisk 112 | *.bak 113 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 프로젝트 소개 2 | `spring-guides` 프로젝트는 영어가 어려워 spring에서 제공하는 공식 레퍼런스를 읽기 힘드신 분들을 위해 한글화 작업을 진행하는 프로젝트입니다. 번역이 일회성으로 끝나는 것이 아닌 많은 분들과 함께 진행하여 가이드 또는 레퍼런스가 업데이트됐을 때 최신 번역 자료를 많은 분들께 제공하고자 합니다. 3 | 4 | 이미 훌륭한 분들께서 레퍼런스를 작업을 하셨지만, 개인 블로그나 저장소에 흩어져 있으며, 특정 버전의 번역 작업만 이루어져 있고 (특정 버전 1회성 번역으로 끝남) 최신 버전의 내용은 번역이 안되고 있는 것 같습니다. `spring-guides` 번역 프로젝트를 통해 한국 spring 개발자 분들을 위해 최신의 가이드와 레퍼런스 자료를 제공하는 것이 목표입니다. 5 | 6 | 우선은 [spring-guides](https://spring.io/guides/)를 먼저 번역을 시작하고자 합니다. 이 작업이 끝나면 `spring reference` 번역 작업을 진행하고자 합니다. 7 | 8 | 많은 분들과 함께 번역 작업을 진행하여 최신 자료들을 빠르게 반영하고, 번역 작업을 진행하면서 발생하는 오타 및 오역을 바로잡고 우수한 자료를 만들고자 오픈소스 프로젝트를 진행하기로 하였습니다. 9 | 10 | 번역 작업이 까다롭고 시간도 오래 걸리겠지만, 영어가 어려운 국내 개발자분들을 위해 도움을 주실 수 있으면 좋겠습니다. 11 | 12 | 여러분들의 `contribution`은 언제나 환영입니다. 13 | 14 | # 컨트리뷰션 하는 방법 15 | [issue](https://github.com/Hanope/spring-guides/issues) 페이지에 [spring.io](https://spring.io)에 등록된 가이드들이 있습니다. 번역에 관심 있는 `issue`에 `comment` 혹은 `관심`을 표해주시고 번역 작업을 진행해 주시면 됩니다. 16 | 17 | [issue](https://github.com/Hanope/spring-guides/issues)에 등록된 가이드들의 영문 자료는 각 폴더에 README.md 파일로 등록이 되어있습니다. 해당 파일을 번역하여 Pull Request 주시면 됩니다. -------------------------------------------------------------------------------- /converting-jar-to-war/README.md: -------------------------------------------------------------------------------- 1 | ## 스프링 부트 어플리케이션 JAR를 WAR로 변환하기 2 | 스프링 부트는 두 개의 강력한 플러그인이 있습니다: 3 | 4 | * `spring-boot-gradle-plugin` 5 | * `spring-boot-maven-plugin` 6 | 7 | 두 개의 플러그인은 본질적으로 스프링 부트 어플리케이션을 커맨드 라인 창에서 실행 가능한 JAR로 묶어주는 기능을 제공합니다. 이러한 기능은 대부분 가이드의 마지막에 언급됩니다. 8 | 9 | 많은 사람들은 웹 컨테이너 안에 배포할 WAR 파일을 만들기를 원합니다. 물론 위의 플러그인도 WAR 파일을 만드는 기능을 지원합니다. 그래서 기본적으로 여러분의 프로젝트 안에서 JAR에 포함된 컨테이너 종속성을 "제공된"것으로 선언해주는 WAR 파일로 재구성해야 합니다. 그러면 WAR 파일 안에는 JAR에 포함된 컨테이너 종속성이 포함되지 않게 됩니다. 10 | 11 | 여러분의 웹 컨테이너를 위해 어플리케이션을 WAR 파일로 만드는 자세한 방법은 다음을 참조하세요: 12 | 13 | * [Packaging executable jar and war files with Maven](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#build-tool-plugins-maven-packaging) 14 | * [Spring Boot Gradle Plugin](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#build-tool-plugins-gradle-plugin) or 15 | * [Gradle Plugin Reference: Packaging executable wars](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html/#packaging-executable-wars) 16 | 17 | > 스프링 부트는 Servlet 3.0 스펙의 컨테이너에서 동작합니다. 18 | 19 | ## 추가로 볼만한 것 20 | 이 가이드들을 따라 하면 도움이 될 것입니다: 21 | 22 | * [Building an Application with Spring Boot](https://spring.io/guides/gs/spring-boot/) -------------------------------------------------------------------------------- /deploying-cloud-foundry-from-sts/README.md: -------------------------------------------------------------------------------- 1 | ## Deploying to Cloud Foundry from STS 2 | This guide walks you through the process of deploying a "hello world" Spring application to Cloud Foundry from Spring Tool Suite (STS). 3 | 4 | ## What You’ll Deploy to Cloud Foundry 5 | You’ll deploy a Spring Boot application to Cloud Foundry that will accept HTTP GET requests at: 6 | 7 | ``` 8 | http://gs-sts-cloud-foundry-deployment-myname.cfapps.io/greeting 9 | ``` 10 | 11 | The application URL will vary depending on the host portion that you have to change later on in this guide. 12 | 13 | The application will then respond with a web page displaying a greeting: 14 | 15 | ``` 16 | "Hello, World!" 17 | ``` 18 | 19 | You can customize the greeting with an optional `name` parameter in the query string: 20 | 21 | ``` 22 | http://gs-sts-cloud-foundry-deployment-myname.cfapps.io/greeting?name=User 23 | ``` 24 | 25 | The `name` parameter value overrides the default value of "World" and is reflected in the response: 26 | 27 | ``` 28 | "Hello, User!" 29 | ``` 30 | 31 | > The `myname` portion of the URL is what you will change when you deploy your application to Cloud Foundry through STS, to avoid host-taken errors during deployment. 32 | 33 | This application is based on a Spring service that serves web content. Further information on how to create the service from scratch can be found at [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/), or it can be imported into STS through the [Import Spring Getting Started Content wizard](https://spring.io/guides/gs/sts/). 34 | 35 | ## What You’ll Need 36 | * About 15 minutes 37 | * [Spring Tool Suite (STS)](https://spring.io/tools/sts/all) 38 | * [JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) or later 39 | * [Pivotal Web Services (PWS) account](http://try.run.pivotal.io/sts-guide) 40 | * [Spring Boot Dashboard](https://docs.spring.io/sts/nan/v373/NewAndNoteworthy.html#bootdash) 41 | 42 | ## Installing STS 43 | If you don’t have STS installed yet, visit the link up above. From there, you can download a copy for your platform. To install it simply unpack the downloaded archive. 44 | 45 | When you’re done, go ahead and launch STS. 46 | 47 | ## Spring Boot Dashboard 48 | The Spring Boot Dashboard is what you will use to deploy your application to Cloud Foundry, and is included in STS version 3.7.1 or higher. It is required for this guide. 49 | 50 | ## Creating a Cloud Foundry Target 51 | You first need to create a target to a Cloud Foundry organization and space where you would like to deploy your application. 52 | 53 | To create a Cloud Foundry target, first open the Boot Dashboard view. 54 | 55 | You can click on the Boot Dashboard button in the main STS toolbar: 56 | 57 | ![](http://spring.io/guides/gs/sts-cloud-foundry-deployment/images/boot_dashboard_view_main_toolbar.png) 58 | Or you can open it through the Eclipse Show View menu: 59 | 60 | Window → Show View → Other → Spring → Boot Dashboard 61 | 62 | Once visible, click on the '+' button on the top right of the Boot Dashboard toolbar to open the Cloud Foundry Target wizard. 63 | 64 | ![](http://spring.io/guides/gs/sts-cloud-foundry-deployment/images/boot_dashboard_view_basic.png) 65 | In the wizard, enter your PWS credentials, and click "Select Space" to select a Cloud Foundry organization and space to connect to. Once a space is selected, click "Finish" to create the target. 66 | 67 | ![](http://spring.io/guides/gs/sts-cloud-foundry-deployment/images/add_cf_target.png) 68 | The target will now appear in the Boot Dashboard. 69 | 70 | ## Import the Sample Spring Application 71 | Now you can import a Spring Boot application that serves web content. You will be deploying this to Cloud Foundry. 72 | 73 | In STS, open the "Import Spring Getting Started Content" wizard: 74 | 75 | ![](http://spring.io/guides/gs/sts-cloud-foundry-deployment/images/import_gsg.png) 76 | In the search field, enter "sts cloud foundry" and the sts-cloud-foundry-deployment guide should appear. 77 | 78 | ![](http://spring.io/guides/gs/sts-cloud-foundry-deployment/images/import_gsg_wizard.png) 79 | * Select the build type. 80 | * Select the "default" code set. 81 | * Click "Finish". 82 | 83 | The import wizard will create a new project in your workspace called "gs-sts-cloud-foundry-deployment". 84 | 85 | ## Deploying to Cloud Foundry 86 | Now simply drag and drop the project to your Cloud Foundry target in the Boot Dashboard. 87 | 88 | ![](http://spring.io/guides/gs/sts-cloud-foundry-deployment/images/drag_drop.png) 89 | This will open the deployment manifest dialogue. Boot Dashboard uses Cloud Foundry manifest.yml to specify deployment details for your application, including the application name, host, memory, and services to bind. 90 | 91 | You can either use an existing manifest.yml file that you have added to your Spring Boot project, or you can select "manual" to use default values generated by the dialogue. 92 | 93 | In manual mode, no manifest.yml file is created in your project. 94 | 95 | > To ensure that the URL for the application has not yet been taken by another application, and avoid host-taken errors during deployment, specify a different host in the manifest.yml editor inside the dialogue. 96 | 97 | ![](http://spring.io/guides/gs/sts-cloud-foundry-deployment/images/deployment_manifest.png) 98 | Once you have finished configuring your application, click "OK" to complete the deployment. 99 | 100 | The deployment may take some time, but as the application is being deployed and started, the application’s console will automatically open and indicate progress. Both the console and the Boot Dashboard view will show when the application has successfully started and is running. The Boot Dashboard icon for the application will turn into a green "up" arrow. 101 | 102 | ![](http://spring.io/guides/gs/sts-cloud-foundry-deployment/images/console_application_running.png) 103 | 104 | ## Test the Application 105 | Now that your application is running on Cloud Foundry, you can open the application’s web site within STS by double-clicking on the application in the Boot Dashboard. This will open a default web browser. 106 | 107 | In the browser, append: 108 | 109 | /greeting 110 | 111 | to the application URL, and you will see the application page show: 112 | 113 | ``` 114 | "Hello, World!" 115 | ``` 116 | 117 | Provide a `name` query string parameter and append it to the URL in the browser: 118 | 119 | ``` 120 | /greeting?name=User. 121 | ``` 122 | 123 | Notice how the message changes from "Hello, World!" to "Hello, User!": 124 | 125 | ``` 126 | "Hello, User!" 127 | ``` 128 | 129 | ## Summary 130 | Congratulations! You have just deployed your Spring Boot application to Cloud Foundry. -------------------------------------------------------------------------------- /deploying-spring-boot-app-to-azure/README.md: -------------------------------------------------------------------------------- 1 | ## Spring Boot 앱을 Azure에 배포 해 보기 2 | 이 글은 어플리케이션을 Azure에 배포하는 방법을 보여줍니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | GitHub에서 하나의 샘플 Spring Boot 어플리케이션을 복제한 후, Maven을 이용해서 Azure로 배포하게 됩니다. 6 | 7 | ## 무엇이 필요한가? 8 | 이 글의 단계들을 따라하기 위해선 다음의 전제조건들이 요구됩니다: 9 | 10 | * Azure 서비스 가입. 아직 Azure 서비스에 가입하지 않았다면, [무료 Azure 계정](https://azure.microsoft.com/pricing/free-trial/) 에서 가입을 하거나 [MSDN 서비스 가입자 혜택](https://azure.microsoft.com/pricing/member-offers/msdn-benefits-details/) 를 통한 활성화. 11 | * [Azure 터미널 명령 인터페이스(CLI)](http://docs.microsoft.com/cli/azure/overview). 12 | * 최신의 [Java Development Kit(JDK)](http://www.oracle.com/technetwork/java/javase/downloads/), 버전은 1.8 또는 그 이상. 13 | * [Git](https://github.com/) 클라이언트. 14 | 15 | ## 샘플 Spring Boot 웹앱 만드는 과정 16 | 본 섹션에서는 이미 작성된 Spring Boot 어플리케이션을 복제한 후, 로컬 환경에서 테스트 하게 됩니다: 17 | 18 | 1. 터미널 창을 엽니다. 19 | 20 | 2. `mkdir SpringBoot` 명령으로 Spring Boot 어플리케이션이 저장될 로컬 디렉토리를 생성합니다. 21 | 22 | 3. `cd SpringBoot` 명령으로 해당 디렉토리로 이동합니다. 23 | 24 | 4. `git clone https://github.com/microsoft/gs-spring-boot` 명령으로 [Spring Boot Getting Started](https://github.com/microsoft/gs-spring-boot)라는 샘플 프로젝트를, 방금 생성한 디렉토리에 복제하여 넣습니다. 25 | 26 | 5. `cd gs-spring-boot/complete` 명령으로 완료된 프로젝트가 존재하는 디렉토리로 이동합니다. 27 | 28 | 6. `./mvnw clean package` 명령으로 Maven을 사용하여 JAR 파일을 빌드 합니다. 29 | 30 | 7. 웹앱이 생성되면, `./mvnw spring-boot:run` 명령으로 해당 웹앱을 실행합니다. 31 | 32 | 8. http://localhost:8080 을 방문하거나, 또 다른 터미널 창에서 `curl http://localhost:8080` 명령을 수행하여 로컬환경에서 테스트 합니다. 33 | 34 | 9. 그러면 다음과 같은 메세지가 출력됨이 확인 되어야만 합니다: **Greetings from Spring Boot!** 35 | 36 | ## Azure service principal를 생성하는 단계 37 | 본 섹션에서는 웹앱을 Azure로 배포시 Maven 플러그인이 사용하는 [Azure service principal](https://cmatskas.com/service-principals-in-microsoft-azure/)를 생성하게 됩니다. 38 | 39 | 1. 터미널 창을 엽니다. 40 | 41 | 2. `az login` 라는 Azure CLI 명령으로 Azure 계정에 로그인 합니다. 42 | 43 | 3. `az ad sp create-for-rbac --name "uuuuuuuu" --password "pppppppp" `(`uuuuuuuu`와 `pppppppp`는 service principal에 대한 사용자이름과 비밀번호 입니다) 명령으로 Azure service principal을 생성합니다. 44 | 45 | 그러면, Azure는 아래와 닮은 JSON 응답을 출력 해야만 합니다: 46 | 47 | ```json 48 | { 49 | "appId": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", 50 | "displayName": "uuuuuuuu", 51 | "name": "http://uuuuuuuu", 52 | "password": "pppppppp", 53 | "tenant": "tttttttt-tttt-tttt-tttt-tttttttttttt" 54 | } 55 | ``` 56 | 57 | > 값들은 아래쪽에서 계속해서 사용됨을 알아두세요. 58 | 59 | ## Azure service principal을 사용하기 위한 Maven을 설정하는 단계 60 | 본 섹션에서는 웹앱 배포를 위한 Azure service principal 사용을 인증하는데 있어서, Maven을 설정하게 됩니다. 61 | 62 | 1. Maven의 `settings.xml` 파일을 텍스트 편집기로 엽니다 (보통 `/etc/maven/settings.xml` 또는 `$HOME/.m2/settings.xml`에 위치해 있습니다). 63 | 64 | 2. 아래 처럼, 본 튜토리얼의 직전 세션내용에 기반하여 Azure service principal 에 대한 설정을 **settings.xml** 파일 내용 중 `` 컬렉션에 추가하여 줍니다: 65 | 66 | ```xml 67 | 68 | 69 | azure-auth 70 | 71 | aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa 72 | tttttttt-tttt-tttt-tttt-tttttttttttt 73 | pppppppp 74 | AZURE 75 | 76 | 77 | 78 | ``` 79 | 80 | 3. 저장하고, **settings.xml** 파일을 닫습니다. 81 | 82 | > [Azure 웹앱을 위한 Maven 플러그인](https://github.com/Microsoft/azure-maven-plugins/tree/master/azure-webapp-maven-plugin) 도큐먼트를 확인해 보세요. 83 | 84 | ## 웹앱을 빌드하고 Azure로 배포하는 단계 85 | 앞 섹션들의 모든 설정을 완료 했다면, 웹앱을 Azure로 배포할 준비가 되었습니다. 86 | 87 | 터미널 창에서, `./mvnw azure-webapp:deploy` 명령으로 웹앱을 Maven을 이용하여 Azure로 배포합니다. (Maven이 복제한 샘플 프로젝트의 빌드 파일에 이미 포함되어 있는, 플러그인을 사용하여 웹앱을 Azure로 배포하게 됩니다. 만약 웹앱이 존재하지 않는다면, 해당 명령이 이를 생성하게 됩니다.) 88 | 89 | 웹앱이 배포되면, 이를 관리하기 위해서 [Azure 포탈](https://portal.azure.com/)에 접속합니다. 다음과 같이 **App Services** 에 리스트업 될 것입니다: 90 | 91 | ![](http://spring.io/guides/gs/spring-boot-for-azure/AP01.png) 92 | 해당 어플리케이션을 클릭합니다. 그러면, 웹앱을 퍼블릭에서 접근 가능한 URL이 **Overview** 섹션에 리스트업 될 것입니다. 93 | 94 | ![](http://spring.io/guides/gs/spring-boot-for-azure/AP02.png) 95 | 해당 링크를 클릭하면, Spring Boot 어플리케이션을 방문하고 상호작용 할 수 있습니다. 96 | 97 | ## 요약 98 | 축하드립니다! Spring Boot 앱을 빌드하고 Azure로 배포 하였습니다. 99 | 100 | ## 추가로 볼만한 것 101 | Azure와 Spring사용법에 대한 추가적인 정보는 아래에서 찾아볼 수 있습니다: 102 | 103 | * [Azure에서의 Spring](https://docs.microsoft.com/java/azure/spring-framework/) 104 | * [Azure 웹 앱을 위하여 Maven 플러그인을 사용한 Spring Boot 앱의 클라우드 배포 방법](https://docs.microsoft.com/java/azure/spring-framework/deploy-spring-boot-java-app-with-maven-plugin) 105 | -------------------------------------------------------------------------------- /gs-accessing-data-jpa/README.md: -------------------------------------------------------------------------------- 1 | ## JPA로 데이터 접근하기 2 | 이 가이드는 스프링 데이터 JPA를 통해 관계형 데이터베이스(RDB)에서 데이터를 주고 받는 어플리케이션을 만드는 과정으로 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 여러분은 메모리 기반 데이터베이스에서 `Customer` [POJOs](http://spring.io/understanding/POJO)를 활용하여 저장하는 어플리케이션을 만들 것입니다. 6 | 7 | ## 무엇이 필요한가? 8 | * 약 15분의 시간 9 | * 좋아하는 텍스트 에디터나 IDE 10 | * [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 또는 그 이상 11 | * [Gradle 4+](http://www.gradle.org/downloads) 또는 [Maven 3.2+](https://maven.apache.org/download.cgi) 12 | * 또한 아래의 IDE를 이용해 코드를 바로 불러올 수 있습니다: 13 | - [Spring Tool Suite (STS)](http://spring.io/guides/gs/sts) 14 | - [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea/) 15 | 16 | ## 이 가이드를 완료하는 방법 17 | 대부분의 [스프링 시작 가이드](http://spring.io/guides)처럼 처음부터 하나씩 완성해 가거나 익숙한 시작 부분은 건너뛰어도 됩니다. 어느 방법을 선택하시더라도 작업을 진행할 수 있는 코드가 완성됩니다. 18 | 19 | **처음부터 작업하실 분**은 [Gradle을 사용한 빌드](#Gradle을-사용한-빌드)로 가세요. 20 | 21 | **시작부분을 건너뛰실 분**은 아래방법을 따라하세요. 22 | 23 | * [다운로드](https://github.com/spring-guides/gs-accessing-data-jpa/archive/master.zip) 하시고 압축파일을 풀어주시거나 [GIT](http://spring.io/understanding/Git)을 사용해 복제해주세요: `git clone https://github.com/spring-guides/gs-accessing-data-jpa.git` 24 | * 소스의 압축을 해제한 폴더에서 `gs-validating-form-input/initial`로 이동합니다. 25 | * [간단한 엔티티 정의하기](#간단한-엔티티-정의하기)로 이동합니다. 26 | 27 | **끝나고 나면**, `gs-accessing-data-jpa/complete`의 코드와 비교해서 맞는지 확인해보세요. 28 | 29 | ## Gradle을 사용한 빌드 30 | 첫 번째로 여러분은 빌드 스크립트를 만들어야 합니다. 여러분은 스프링 어플리케이션을 빌드 할 때 원하는 시스템을 사용할 수 있습니다만, 코드가 작동하기 위해서는 [Gradle](http://gradle.org/)이나 [Maven](https://maven.apache.org/)이 포함되어 있어야 합니다. Gradle이나 Maven에 익숙하지 않은 경우, [Building Java Projects with Gradle](http://spring.io/guides/gs/gradle) 또는 [Building Java Projects with Maven](http://spring.io/guides/gs/maven)을 참조하세요. 31 | 32 | ### 폴더 구조 만들기 33 | 프로젝트 폴더를 선택하시고 안에 다음과 같이 하위 폴더를 만들어주세요 예를 들면, *nix(linux, unix)에서는 `mkdir -p src/main/java/hello`를 입력하면 됩니다: 34 | 35 | ``` 36 | └── src 37 | └── main 38 | └── java 39 | └── hello 40 | ``` 41 | 42 | ### Gradle 빌드 파일 만들기 43 | [초기 Gradle build file](https://github.com/spring-guides/gs-validating-form-input/blob/master/initial/build.gradle)은 아래와 같습니다. 44 | 45 | `build.gradle` 46 | 47 | ```gradle 48 | buildscript { 49 | repositories { 50 | mavenCentral() 51 | } 52 | dependencies { 53 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 54 | } 55 | } 56 | 57 | apply plugin: 'java' 58 | apply plugin: 'eclipse' 59 | apply plugin: 'idea' 60 | apply plugin: 'org.springframework.boot' 61 | apply plugin: 'io.spring.dependency-management' 62 | 63 | bootJar { 64 | baseName = 'gs-accessing-data-jpa' 65 | version = '0.1.0' 66 | } 67 | 68 | repositories { 69 | mavenCentral() 70 | maven { url "https://repository.jboss.org/nexus/content/repositories/releases" } 71 | } 72 | 73 | sourceCompatibility = 1.8 74 | targetCompatibility = 1.8 75 | 76 | dependencies { 77 | compile("org.springframework.boot:spring-boot-starter-data-jpa") 78 | compile("com.h2database:h2") 79 | testCompile("junit:junit") 80 | } 81 | ``` 82 | 83 | [Spring Boot gradle plugin](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html)은 많고 편리한 기능을 제공합니다: 84 | 85 | * 이 플러그인은 클래스패스 위의 jar를 하나의 실행 가능한 jar로 모아서 여러분의 서비스를 실행하고 전송하는데 편리하게 만들어줍니다. 86 | * 이 플러그인은 `public static void main()`메소드를 찾아 실행 가능한 클래스로 표시를 해줍니다. 87 | * 이 플러그인은 [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)에 맞는 내장된 의존성 해석자를 제공합니다. 여러분이 원하는 버전을 사용할 수도 있습니다만 기본적으로 Spring Boot에서 선택한 버전이 기본 제공됩니다. 88 | 89 | ## Maven을 사용한 빌드 90 | 첫번째로 여러분은 빌드 스크립트를 만들어야 합니다. 여러분은 스프링 어플리케이션을 빌드할때 원하는 시스템을 사용할 수 있습니다만, 코드가 작동하기 위해서는 [Maven](https://maven.apache.org/)이 포함되어 있어야 합니다. Maven에 익숙하지 않은 경우, [Building Java Projects with Maven](http://spring.io/guides/gs/maven)을 참조하세요. 91 | 92 | ### 폴더 구조 만들기 93 | 프로젝트 폴더를 선택하시고 안에 다음과 같이 하위 폴더를 만들어주세요. 예를 들면, *nix(linux, unix)에서는 `mkdir -p src/main/java/hello`를 입력하면 됩니다: 94 | 95 | ``` 96 | └── src 97 | └── main 98 | └── java 99 | └── hello 100 | ``` 101 | 102 | `pom.xml` 103 | 104 | ```xml 105 | 106 | 109 | 4.0.0 110 | 111 | org.springframework 112 | gs-accessing-data-jpa 113 | 0.1.0 114 | 115 | 116 | org.springframework.boot 117 | spring-boot-starter-parent 118 | 2.0.5.RELEASE 119 | 120 | 121 | 122 | 1.8 123 | 124 | 125 | 126 | 127 | org.springframework.boot 128 | spring-boot-starter-data-jpa 129 | 130 | 131 | com.h2database 132 | h2 133 | 134 | 135 | org.springframework.boot 136 | spring-boot-starter-test 137 | test 138 | 139 | 140 | 141 | 142 | 143 | 144 | org.springframework.boot 145 | spring-boot-maven-plugin 146 | 147 | 148 | 149 | 150 | 151 | 152 | spring-releases 153 | Spring Releases 154 | https://repo.spring.io/libs-release 155 | 156 | 157 | org.jboss.repository.releases 158 | JBoss Maven Release Repository 159 | https://repository.jboss.org/nexus/content/repositories/releases 160 | 161 | 162 | 163 | 164 | 165 | spring-releases 166 | Spring Releases 167 | https://repo.spring.io/libs-release 168 | 169 | 170 | 171 | 172 | ``` 173 | 174 | 이 [Spring Boot Maven plugin](https://docs.spring.io/spring-boot/docs/current/maven-plugin)은 많고 편리한 기능을 제공합니다.: 175 | 176 | * 이 플러그인은 클래스패스 위의 jar를 하나의 실행가능한 jar로 모아서 여러분의 서비스를 실행하고 전송하는데 편리하게 만들어줍니다. 177 | * 이 플러그인은 `public static void main()`메소드를 찾아 실행 가능한 클래스로 표시를 해줍니다. 178 | * 이 플러그인은 [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)에 맞는 내장된 의존성 해석자를 제공합니다. 179 | 180 | ## 여러분의 IDE를 사용한 빌드 하기 181 | * 이 가이드를 STS에 직접 삽입하는 방법을 알고싶으면 [Spring Tool Suite](http://spring.io/guides/gs/sts/)을 읽어주세요. 182 | * 이 가이드를 Intellij IDEA에서 작동시키는 법을 알고 싶으면 [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea)을 읽어주세요. 183 | 184 | ## 간단한 엔티티 정의하기 185 | 이 예제에서는 JPA의 entity 어노테이션이 지정된 Customer 오브젝트를 만들어서 저장합니다. 186 | 187 | `src/main/java/hello/Customer.java` 188 | 189 | ```java 190 | package hello; 191 | 192 | import javax.persistence.Entity; 193 | import javax.persistence.GeneratedValue; 194 | import javax.persistence.GenerationType; 195 | import javax.persistence.Id; 196 | 197 | @Entity 198 | public class Customer { 199 | 200 | @Id 201 | @GeneratedValue(strategy=GenerationType.AUTO) 202 | private Long id; 203 | private String firstName; 204 | private String lastName; 205 | 206 | protected Customer() {} 207 | 208 | public Customer(String firstName, String lastName) { 209 | this.firstName = firstName; 210 | this.lastName = lastName; 211 | } 212 | 213 | @Override 214 | public String toString() { 215 | return String.format( 216 | "Customer[id=%d, firstName='%s', lastName='%s']", 217 | id, firstName, lastName); 218 | } 219 | 220 | } 221 | ``` 222 | 223 | 여기의 `Customer` 클래스는 `id`, `firstName`, lastName의 세 개의 속성을 가지고 있습니다. 또한 이 클래스는 두 개의 생성자를 가지고 있습니다. 클래스의 기본 생성자는 JPA를 위해서만 존재합니다 그리고 여러분이 생성자를 직접 사용하지 않을것이므로 `protected`로 만들었습니다. 다른 생성자는 여러분이 `Customer` 인스턴스를 생성해서 데이터베이스에 저장하는데 사용될 것입니다. 224 | 225 | > 이 가이드에서 간결함을 위해 Getter와 Setter는 넣지 않았습니다. 226 | 227 | `@Entity` 어노테이션으로 표시된 `Customer` 클래스는 JPA 엔티티 임을 나타냅니다. `@Table` 어노테이션으로 따로 표시되지 않으므로, `Customer`의 이름을 가진 테이블에 자동으로 매핑됩니다. 228 | 229 | `Customer`의 `id` 속성은 `@Id` 어노테이션이 붙어 있어 JPA가 객체의 ID로 이 속성을 사용할 것임을 알 수 있습니다. 그리고 `id` 속성에 붙어 있는 `@GeneratedValue` 어노테이션은 ID가 자동적으로 생성되는 것임을 나타냅니다. 230 | 231 | 나머지 두개의 `firstName`과 `lastName`는 어노테이션이 없습니다. 이것은 그 속성들이 각각 같은 이름을 가진 컬럼과 매핑되는 것을 의미합니다. 232 | 233 | 편리한 `toString()` 메소드는 customer 속성들을 출력할 것입니다. 234 | 235 | ## 간단한 쿼리들 만들기 236 | Spring Data JPA는 JPA를 사용하여 관계형 데이터베이스에 저장하는데 초점이 맞춰져 있습니다. 그리고 이것의 가장 강력한 기능은 시작할 때 저장소(리포지토리) 인터페이스가 자동으로 구현이 되는 것입니다. 237 | 238 | `Customer` 엔티티에서 리포지토리 인터페이스을 생성하면서 어떻게 JPA가 작동하는지 보겠습니다. 239 | 240 | `src/main/java/hello/CustomerRepository.java` 241 | 242 | ```java 243 | package hello; 244 | 245 | import java.util.List; 246 | 247 | import org.springframework.data.repository.CrudRepository; 248 | 249 | public interface CustomerRepository extends CrudRepository { 250 | 251 | List findByLastName(String lastName); 252 | } 253 | ``` 254 | 255 | `CustomerRepository`는 `CrudRepository` 인터페이스를 상속받습니다. `CrudRepository`의 일반적인 파리미터는 엔티티와 ID의 타입을 받으며 엔티티에는 `Customer`를 ID의 타입인 `Long`을 넣어서 작업하였습니다. `CrudRepository`를 상속받은 `CustomerRepository`는 `Customer` 엔티티를 가지고 저장, 삭제, 찾기 등의 다양한 메소드를 가지고 있습니다. 256 | 257 | 또한 Spring Data JPA는 여러분이 JPA의 간단한 메소드 시그니처(메소드를 생성하기 위한 규칙 중 메소드명과 파라미터)를 활용하여 간단하게 다른 쿼리 메소드를 정의할수도 있습니다. `CustomerRepository`에서는 `findByLastName()` 메소드에서 시그니처를 활용해 정의한 것을 볼 수 있습니다. 258 | 259 | 전통적인 자바 어플리케이션에서는 `CustomerRepository`를 구현하는 클래스를 생성해야 합니다. 그러나 여러분은 리포지토리 인터페이스를 구현하는 클래스를 작성할 필요가 없습니다. 이것이 Spring Data JPA가 강력하다고 불리는 이유입니다. Spring Data JPA는 여러분이 어플리케이션을 실행할 때 즉석에서 인터페이스 구현을 생성합니다. 260 | 261 | 생성한 것을 연결하고 어떻게 작동되는지 확인해 봅시다. 262 | 263 | ## 어플리케이션 클래스 만들기 264 | 모든 구성요소가 있는 어플리케이션 클래스를 만들어 보겠습니다. 265 | 266 | `src/main/java/hello/Application.java` 267 | 268 | ```java 269 | package hello; 270 | 271 | import org.slf4j.Logger; 272 | import org.slf4j.LoggerFactory; 273 | 274 | import org.springframework.boot.CommandLineRunner; 275 | import org.springframework.boot.SpringApplication; 276 | import org.springframework.boot.autoconfigure.SpringBootApplication; 277 | import org.springframework.context.annotation.Bean; 278 | 279 | @SpringBootApplication 280 | public class Application { 281 | 282 | private static final Logger log = LoggerFactory.getLogger(Application.class); 283 | 284 | public static void main(String[] args) { 285 | SpringApplication.run(Application.class); 286 | } 287 | 288 | @Bean 289 | public CommandLineRunner demo(CustomerRepository repository) { 290 | return (args) -> { 291 | // save a couple of customers 292 | repository.save(new Customer("Jack", "Bauer")); 293 | repository.save(new Customer("Chloe", "O'Brian")); 294 | repository.save(new Customer("Kim", "Bauer")); 295 | repository.save(new Customer("David", "Palmer")); 296 | repository.save(new Customer("Michelle", "Dessler")); 297 | 298 | // fetch all customers 299 | log.info("Customers found with findAll():"); 300 | log.info("-------------------------------"); 301 | for (Customer customer : repository.findAll()) { 302 | log.info(customer.toString()); 303 | } 304 | log.info(""); 305 | 306 | // fetch an individual customer by ID 307 | repository.findById(1L) 308 | .ifPresent(customer -> { 309 | log.info("Customer found with findById(1L):"); 310 | log.info("--------------------------------"); 311 | log.info(customer.toString()); 312 | log.info(""); 313 | }); 314 | 315 | // fetch customers by last name 316 | log.info("Customer found with findByLastName('Bauer'):"); 317 | log.info("--------------------------------------------"); 318 | repository.findByLastName("Bauer").forEach(bauer -> { 319 | log.info(bauer.toString()); 320 | }); 321 | // for (Customer bauer : repository.findByLastName("Bauer")) { 322 | // log.info(bauer.toString()); 323 | // } 324 | log.info(""); 325 | }; 326 | } 327 | 328 | } 329 | ``` 330 | 331 | `@SpringBootApplication`은 아래의 모든것을 더해주는 편리한 어노테이션입니다. 332 | 333 | * `@Configuration` 태그는 어플리케이션 컨텍스트에서 이 클래스를 빈으로 정의합니다. 334 | * `@EnableAutoConfiguration`는 스프링 부트에서 클래스패스 세팅과 다른 빈과 다양한 설정을 해줍니다. 335 | * 보통 Spring MVC app에서는 `@EnableWebMvc`를 붙이지만, 스프링 부트에서는 클래스 패스 위에 자동으로 **spring-webmvc**가 붙습니다. 이 플래그는 이 어플리케이션이 웹 어플리케이션이라는 것을 표시하고 `DispatcherServlet` 설정 등 핵심 행동을 하도록 합니다. 336 | * `@ComponentScan`는 `hello` 패키지 내의 컨트롤러, 서비스, 컴포넌트(구성요소), 설정등을 찾도록 합니다. 337 | 338 | 어플리케이션 실행을 위한 `main()` 메소드에서는 스프링 부트에서 실행에 사용하는 `SpringApplication.run()` 메소드를 사용합니다. 여러분은 **web.xml**을 포함해서 한줄의 XML도 없다는 것을 알고 있으신가요? 이 웹 어플리케이션은 100% 순수한 자바로 되어있으며 여러분은 내부구조 설정을 위해 전혀 신경 쓸 필요가 없습니다. 339 | 340 | `Application`은 `CustomerRepository`를 통한 몇가지 테스트가 들어있는 `main()` 메소드를 포함하고 있습니다. 첫째로, 스프링의 어플리케이션 컨텍스트에서 `CustomerRepository`를 가져옵니다. 그리고 `save()` 메소드를 시연을 위해 데이터를 세팅해서 소수의 `Customer` 오브젝트를 저장합니다. 다음에, `findAll()` 메소드를 불러 모든 `Customer` 오브젝트를 데이터베이스로 부터 가져옵니다. 그리고 `findOne()` 메소드를 사용하여 ID로 하나의 `Customer` 오브젝트를 가져옵니다. 마지막으로 모든 고객 오브젝트 중 `findByLastName()` 메소드를 활용하여 이름이 "Bauer"인 고객을 가져옵니다. 341 | 342 | > 기본적으로, 스프링 부트는 `@SpringBootApplication`이 위치한 패키지와 하위 서브패키지에서만 JPA 리포지토리를 지원합니다. 패키지내부에서 접근불가능한 곳에 정의된 JPA 리포지토리를 사용하려면, `@EnableJpaRepositories`과 파라미터 `basePackageClasses=MyRepository.class`를 사용해 안전하게 쓸 수 있습니다. 343 | 344 | ## 실행가능한 JAR로 빌드하기 345 | 여러분은 Gradle이나 Maven을 이용한 커맨드 라인으로 이 어플리케이션을 실행할 수 있습니다. 또는 모든 필요한 의존성, 클래스, 자원 등을 포함한 하나의 실행 가능한 JAR로 빌드 할 수도 있습니다. 그래서 다양한 환경에서 개발 주기 전반에 걸쳐 버전을 올리고 서비스를 배포하는 것이 쉬워집니다. 346 | 347 | Gradle을 사용할 경우 `./gradlew bootRun` 명령어로 실행할 수 있습니다. 또는 `./gradlew build` 명령어로 JAR 파일을 만들고 다음과 같이 JAR 파일을 실행할 수 있습니다. 348 | 349 | ``` 350 | java -jar build/libs/gs-accessing-data-jpa-0.1.0.jar 351 | ``` 352 | 353 | Maven을 사용할 경우 `./mvnw spring-boot:run` 명령어로 실행할 수 있습니다. 또는 `./mvnw clean package` 명령어로 JAR 파일을 만들고 다음과 같이 JAR 파일을 실행할 수 있습니다. 354 | 355 | ``` 356 | java -jar target/gs-accessing-data-jpa-0.1.0.jar 357 | ``` 358 | 359 | > 이 행동은 실행 가능한 JAR 파일을 만드는 방법입니다. 물론 [WAR파일로 만드는 방법](http://spring.io/guides/gs/convert-jar-to-war/)도 대신 선택할 수 있습니다. 360 | 361 | 실행하면 여러분은 이것을 볼 수 있을겁니다: 362 | 363 | ``` 364 | == Customers found with findAll(): 365 | Customer[id=1, firstName='Jack', lastName='Bauer'] 366 | Customer[id=2, firstName='Chloe', lastName='O'Brian'] 367 | Customer[id=3, firstName='Kim', lastName='Bauer'] 368 | Customer[id=4, firstName='David', lastName='Palmer'] 369 | Customer[id=5, firstName='Michelle', lastName='Dessler'] 370 | 371 | == Customer found with findOne(1L): 372 | Customer[id=1, firstName='Jack', lastName='Bauer'] 373 | 374 | == Customer found with findByLastName('Bauer'): 375 | Customer[id=1, firstName='Jack', lastName='Bauer'] 376 | Customer[id=3, firstName='Kim', lastName='Bauer'] 377 | ``` 378 | 379 | ## 요약 380 | 축하합니다! 여러분은 Spring Data JPA를 사용하여 리포지토리를 구체적으로 구현하지 않은 상태로 데이터베이스에 저장하고 가져오는 간단한 어플리케이션을 만들었습니다. 381 | 382 | > 여러분이 조금의 노력을 추가해서 JPA 리포지토리를 활용하는 하이퍼미디어 기반의 RESTful한 프론트 엔드에 관심이 있다면, [Accessing JPA Data with REST](http://spring.io/guides/gs/accessing-data-rest)을 읽어보시는 것이 좋습니다. 383 | 384 | ## 추가로 볼만한 것 385 | 다음 가이드 또한 도움이 될 수 있습니다: 386 | 387 | * [Accessing Data with Gemfire](https://spring.io/guides/gs/accessing-data-gemfire/) 388 | * [Accessing Data with MongoDB](https://spring.io/guides/gs/accessing-data-mongodb/) 389 | * [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/) 390 | * [Accessing Data with Neo4j](https://spring.io/guides/gs/accessing-data-neo4j/) 391 | -------------------------------------------------------------------------------- /gs-accessing-data-mysql/README.md: -------------------------------------------------------------------------------- 1 | ## MySQL 데이터 접근하기 2 | 이 가이드는 다른 모든 가이드와 많은 샘플 애플리케이션이 사용하는 메모리 내장형 데이터베이스와 달리 MySQL 데이터베이스와 연결된 스프링 애플리케이션을 만드는 과정을 안내합니다. 이 가이드는 Spring Data JPA를 사용하여 데이터베이스에 접근하지만, Spring Data JPA는 많은 가능한 선택 사항 중 하나 일뿐입니다 (예 : 일반 Spring JDBC를 사용할 수 있음). 3 | 4 | ## 목표 5 | 먼저 MySQL 데이터 베이스, 스프링 애플리케이션를 만들고 새로 생성된 데이터베이스와 연결을 목표로 합니다. 6 | 7 | > MySQL은 GPL로 라이선스가 부여되어 있으므로 이를 사용하여 배포하는 모든 프로그램 바이너리도 GPL을 사용해야합니다. 자세한 내용은 [GNU General Public Licence](https://www.gnu.org/licenses/gpl.html)을 참고하세요. 8 | 9 | ## 요구사항 10 | * [MySQL](https://dev.mysql.com/downloads/) 버전 5.6 또는 최신버전. 도커가 설치되어있는 경우 데이터베이스를 [컨테이너](https://hub.docker.com/_/mysql/)로 실행하는 것이 유용 할 수 있습니다. 11 | * 약 15분 12 | * 좋아하는 텍스트 에디터 또는 자신있는 개발환경 13 | * [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 또는 최신버전의 JDK 14 | * [Gradle 4+](http://www.gradle.org/downloads) 또는 [Maven 3.2+](https://maven.apache.org/download.cgi) 15 | * 다운로드 가능한 IDE: 16 | - [Spring Tool Suite (STS)](http://spring.io/guides/gs/sts) 17 | - [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea/) 18 | 19 | ## 이 가이드를 완성하는 방법 20 | 대부분의 Spring Getting Started 가이드와 마찬가지로, 처음부터 시작하여 각 단계를 완료하거나 이미 익숙한 기본 설정 단계를 건너 뛸 수 있습니다. 21 | 22 | **처음부터 시작하려면**, [Gradle_빌드하기](#Gradle_빌드하기). 23 | 24 | **기초 건너뛰기** : 25 | 26 | * [다운로드](https://github.com/spring-guides/gs-accessing-data-mysql/archive/master.zip)하여 압축을 풀거나 레파지토리를 클론하여 사용하세요 [Git](http://spring.io/understanding/Git): `git clone https://github.com/spring-guides/gs-accessing-data-mysql.git` 27 | * cd 로 폴더 이동 `gs-accessing-data-mysql/initial` 28 | * 이동하기 [데이터베이스_생성하기](#create-the-database). 29 | 30 | **완성 했을 경우**, `gs-accessing-data-mysql/complete`의 코드와 비교하여 결과를 확인할 수 있습니다. 31 | 32 | ## Gradle_빌드하기 33 | 먼저 기본 빌드 스크립트를 설정합니다. Spring을 사용하여 응용 프로그램을 빌드 할 때 원하는 빌드 시스템을 사용할 수 있지만 [Gradle](http://gradle.org/)을 사용하여 작업해야하는 코드와 [Maven](https://maven.apache.org/)을 사용하여 작업해야하는 방법이 포함되어 있습니다. 익숙하지 않은 경우 [Gradle을 사용하여 Java 프로젝트 빌드하기](http://spring.io/guides/gs/gradle) 또는 [Maven을 사용하여 Java 프로젝트 빌드하기](http://spring.io/guides/gs/maven) 를 참조하십시오. 34 | 35 | ### 디렉토리 구조 만들기 36 | 선택한 프로젝트 디렉토리에서 다음과 같은 하위 디렉토리 구조를 만듭니다. *nix 시스템에서는 `mkdir -p src/main/java/hello` 를 사용합니다 : 37 | 38 | ``` 39 | └── src 40 | └── main 41 | └── java 42 | └── hello 43 | ``` 44 | 45 | ### Gradle 빌드 파일 만들기 46 | 아래는 [초기 Gradle 빌드 파일](https://github.com/spring-guides/gs-accessing-data-mysql/blob/master/initial/build.gradle)입니다. 47 | 48 | `build.gradle` 49 | 50 | ```gradle 51 | buildscript { 52 | repositories { 53 | mavenCentral() 54 | } 55 | dependencies { 56 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 57 | } 58 | } 59 | 60 | apply plugin: 'java' 61 | apply plugin: 'eclipse' 62 | apply plugin: 'idea' 63 | apply plugin: 'org.springframework.boot' 64 | apply plugin: 'io.spring.dependency-management' 65 | 66 | bootJar { 67 | baseName = 'gs-accessing-data-mysql' 68 | version = '0.1.0' 69 | } 70 | 71 | repositories { 72 | mavenCentral() 73 | } 74 | 75 | sourceCompatibility = 1.8 76 | targetCompatibility = 1.8 77 | 78 | dependencies { 79 | compile("org.springframework.boot:spring-boot-starter-web") 80 | 81 | // JPA Data (We are going to use Repositories, Entities, Hibernate, etc...) 82 | compile 'org.springframework.boot:spring-boot-starter-data-jpa' 83 | 84 | // Use MySQL Connector-J 85 | compile 'mysql:mysql-connector-java' 86 | 87 | testCompile('org.springframework.boot:spring-boot-starter-test') 88 | } 89 | ``` 90 | 91 | [Spring Boot gradle plugin](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html)은 많은 편리한 기능을 제공합니다 : 92 | 93 | * 클래스패스와 빌드파일을 모으고 실행할 수있는 "über-jar"를 하나 만들고 실행하여 서비스를 실행하고 전송하는 것이 더 편리합니다. 94 | * 이것은 `public static void main()`메소드를 검색하여 실행 가능한 클래스로 변환한다. 95 | * [스프링 부트 의존성](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)에 맞게 버전 번호를 설정하는 빌트인 의존성 분석기를 제공합니다. 원하는 모든 버전을 무시할 수 있지만 기본적으로 Boot에서 선택한 버전 세트가 사용됩니다. 96 | 97 | ## Maven으로 빌드 98 | 먼저 기본 빌드 스크립트를 설정합니다. Spring을 사용하여 응용 프로그램을 빌드 할 때 원하는 빌드 시스템을 사용할 수 있지만 [Maven](https://maven.apache.org/)을 사용하여 작업해야하는 코드가 여기에 포함됩니다. Maven에 익숙하지 않은 경우 [Maven으로 Java 프로젝트 빌드하기](http://spring.io/guides/gs/maven)를 참조하십시오. 99 | 100 | ### 디렉토리 구조 만들기 101 | 선택한 프로젝트 디렉토리에서 다음과 같은 하위 디렉토리 구조를 만듭니다. *nix 시스템에서는 `mkdir -p src/ main/java/hello` 를 사용합니다 : 102 | 103 | ``` 104 | └── src 105 | └── main 106 | └── java 107 | └── hello 108 | ``` 109 | 110 | `pom.xml` 111 | 112 | ```xml 113 | 114 | 116 | 4.0.0 117 | 118 | org.springframework 119 | gs-mysql-data 120 | 0.1.0 121 | 122 | 123 | org.springframework.boot 124 | spring-boot-starter-parent 125 | 2.0.5.RELEASE 126 | 127 | 128 | 129 | 130 | org.springframework.boot 131 | spring-boot-starter-web 132 | 133 | 134 | 135 | 136 | 137 | org.springframework.boot 138 | spring-boot-starter-data-jpa 139 | 140 | 141 | 142 | 143 | 144 | mysql 145 | mysql-connector-java 146 | 147 | 148 | 149 | org.springframework.boot 150 | spring-boot-starter-test 151 | test 152 | 153 | 154 | 155 | 156 | 1.8 157 | 158 | 159 | 160 | 161 | 162 | org.springframework.boot 163 | spring-boot-maven-plugin 164 | 165 | 166 | 167 | 168 | 169 | ``` 170 | 171 | [Spring Boot Maven plugin](https://docs.spring.io/spring-boot/docs/current/maven-plugin) 플러그인은 많은 편리한 기능을 제공합니다 : 172 | 173 | * 클래스패스와 빌드파일을 모으고 실행할 수있는 "über-jar"를 하나 만들고 실행하여 서비스를 실행하고 전송하는 것이 더 편리합니다. 174 | * 이것은 `public static void main()`메소드를 검색하여 실행 가능한 클래스로 변환한다. 175 | * [스프링 부트 의존성](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)에 맞게 버전 번호를 설정하는 빌트인 의존성 분석기를 제공합니다. 원하는 모든 버전을 무시할 수 있지만 기본적으로 Boot에서 선택한 버전 세트가 사용됩니다. 176 | 177 | ## IDE로 빌드하기 178 | * [Spring Tool Suite로 직접 빌드하는 방법](http://spring.io/guides/gs/sts/)을 읽어보십시오. 179 | * [IntelliJ IDEA로 직접 빌드하는 방법](http://spring.io/guides/gs/intellij-idea)을 읽어보십시오. 180 | 181 | ## 데이터베이스 생성하기 182 | 터미널로 이동하십시오. (Microsoft Windows의 프롬프트 `cmd`) 이후 새로운 사용자를 생성 할 수 있는 사용자로 MySQL 클라이언트를 엽니다. 183 | 184 | 예시 : Linux에서는 다음 명령을 사용하십시오. 185 | 186 | ```bash 187 | $ sudo mysql --password 188 | ``` 189 | 190 | > 191 | MySQL을 루트로 연결합니다. **이것은 프로덕션 서버에 권장되는 방법은 아닙니다.** 192 | 193 | 194 | 새 데이터베이스 생성하기 195 | 196 | ```bash 197 | mysql> create database db_example; -- 새 데이터베이스 만들기 198 | mysql> create user 'springuser'@'localhost' identified by 'ThePassword'; -- 사용자 생성하기 199 | mysql> grant all on db_example.* to 'springuser'@'localhost'; -- 생성된 사용자에게 모든 권한을 부여하기 200 | ``` 201 | 202 | ## `application.properties` 파일을 만들기 203 | Spring Boot는 모든 것에 기본값을 주며, 데이터베이스의 기본값은 `H2` 이므로이 값을 변경하고 다른 데이터베이스를 사용하려면 `application.properties` 파일에 연결 속성을 정의해야합니다. 204 | 205 | sources 폴더에서, `src/main/resources/application.properties` 리소스 파일을 생성합니다. 206 | 207 | ```properties 208 | spring.jpa.hibernate.ddl-auto=create 209 | spring.datasource.url=jdbc:mysql://localhost:3306/db_example 210 | spring.datasource.username=springuser 211 | spring.datasource.password=ThePassword 212 | ``` 213 | 214 | 여기서 `spring.jpa.hibernate.ddl-auto` 는 `none` , `update` , `create` , `create-drop` 일 수 있습니다. 자세한 내용은 Hibernate 문서를 참조하십시오. 215 | 216 | * `none` 이것이 MySQL의 기본값이며, 데이터베이스 구조는 변경되지 않습니다. 217 | * `update` Hibernate는 주어진 Entity 구조에 따라 데이터베이스를 변경합니다. 218 | * `create` 매번 데이터베이스를 생성하지만 닫을 때 데이터베이스를 삭제하지 않습니다. 219 | * `create-drop` 데이터베이스를 생성 한 후 `SessionFactory`가 닫힐 때 데이터베이스를 삭제합니다. 220 | 221 | 우리는 아직 데이터베이스 구조가 없기 때문에 `create`로 구조를 생성합니다. 첫 번째 실행 후 프로그램 요구 사항에 따라 `update` 또는 `none`으로 전환 할 수 있습니다. 데이터베이스 구조를 약간 변경하려면 `update`를 사용하십시오. 222 | 223 | `H2`와 다른 내장 데이터베이스의 기본값은 `create-drop`이지만, `MySQL`과 같은 것들은 `none`입니다. 224 | 225 | 데이터베이스를 프로덕션 상태로 만든 후에는이 옵션을 `none` 으로 만들고 Spring 응용 프로그램에 연결된 MySQL 사용자의 모든 권한을 취소 한 다음 SELECT, UPDATE, INSERT, DELETE 만 제공하는 것이 좋습니다. 226 | 227 | 자세한 내용은 이 가이드의 끝 부분에 나와 있습니다. 228 | 229 | ## `@Entity` 모델 만들기 230 | 231 | `src/main/java/hello/User.java` 232 | 233 | ```java 234 | package hello; 235 | 236 | import javax.persistence.Entity; 237 | import javax.persistence.GeneratedValue; 238 | import javax.persistence.GenerationType; 239 | import javax.persistence.Id; 240 | 241 | @Entity // Entity 어노테이션은 Hibernate에게 이 클래스에서 테이블을 만들도록 지시한다. 242 | public class User { 243 | @Id 244 | @GeneratedValue(strategy=GenerationType.AUTO) 245 | private Integer id; 246 | 247 | private String name; 248 | 249 | private String email; 250 | 251 | public Integer getId() { 252 | return id; 253 | } 254 | 255 | public void setId(Integer id) { 256 | this.id = id; 257 | } 258 | 259 | public String getName() { 260 | return name; 261 | } 262 | 263 | public void setName(String name) { 264 | this.name = name; 265 | } 266 | 267 | public String getEmail() { 268 | return email; 269 | } 270 | 271 | public void setEmail(String email) { 272 | this.email = email; 273 | } 274 | 275 | 276 | } 277 | ``` 278 | 279 | 위 모델은 Hibernate가 자동으로 테이블로 변환하는 엔티티 클래스입니다. 280 | 281 | ## repository만들기 282 | 283 | `src/main/java/hello/UserRepository.java` 284 | 285 | ```java 286 | package hello; 287 | 288 | import org.springframework.data.repository.CrudRepository; 289 | 290 | import hello.User; 291 | 292 | // 이것은 AUTO에 의해 자동으로 Spring에 의해 userRepository라는 Bean에 구현 될 것입니다. 293 | // CRUD는 생성, 읽기, 업데이트, 삭제를 나타냅니다. 294 | 295 | public interface UserRepository extends CrudRepository { 296 | 297 | } 298 | ``` 299 | 300 | 위 코드는 리포지터리 (repository) 인터페이스입니다. 대문자를 변경해, 같은 이름의 bean로 Spring에 의해 자동적으로 구현됩니다. bean명은 `userRepository`입니다. 301 | 302 | ## Spring 애플리케이션을위한 새로운 컨트롤러 생성하기 303 | 304 | `src/main/java/hello/MainController.java` 305 | 306 | ```java 307 | package hello; 308 | 309 | import org.springframework.beans.factory.annotation.Autowired; 310 | import org.springframework.stereotype.Controller; 311 | import org.springframework.web.bind.annotation.RequestMapping; 312 | import org.springframework.web.bind.annotation.GetMapping; 313 | import org.springframework.web.bind.annotation.RequestParam; 314 | import org.springframework.web.bind.annotation.ResponseBody; 315 | 316 | import hello.User; 317 | import hello.UserRepository; 318 | 319 | @Controller // Controller 어노테이션은 클래스가 컨트롤러라는 것을 의미합니다. 320 | @RequestMapping(path="/demo") // URL이 demo로 시작한다는 것을 의미합니다 (응용 프로그램 경로 이후). 321 | public class MainController { 322 | @Autowired // userRepository라는 빈을 얻는다는 것을 의미합니다. 323 | // Spring에 의해 자동으로 생성 된 데이터를 처리하기 위해 사용합니다. 324 | private UserRepository userRepository; 325 | 326 | @GetMapping(path="/add") // GET 방식으로 요청하기 327 | public @ResponseBody String addNewUser (@RequestParam String name 328 | , @RequestParam String email) { 329 | // @ResponseBody는 반환 된 문자열이 뷰 이름이 아니라 요청값임을 의미합니다. 330 | // @RequestParam은 GET 또는 POST 요청의 매개 변수임을 의미합니다. 331 | 332 | User n = new User(); 333 | n.setName(name); 334 | n.setEmail(email); 335 | userRepository.save(n); 336 | return "Saved"; 337 | } 338 | 339 | @GetMapping(path="/all") 340 | public @ResponseBody Iterable getAllUsers() { 341 | // 이렇게하면 사용자에게 JSON 또는 XML이 반환됩니다. 342 | return userRepository.findAll(); 343 | } 344 | } 345 | ``` 346 | 347 | > 위의 예제는 `@GetMapping`이 `@RequestMapping(method = GET)`의 바로 가기이므로 `GET`과 `PUT`, `POST` 등을 명시 적으로 지정하지 않았습니다. `@RequestMapping`은 기본적으로 모든 HTTP 연산을 매핑합니다. 이 매핑을 줄이려면`@RequestMapping(method = GET)`또는 다른 어노테이션을 사용하십시오. 348 | 349 | ## 애플리케이션을 실행 가능하게 만들기 350 | 이 서비스를 외부 응용 프로그램 서버에 배포하기위한 기존 [WAR](http://spring.io/understanding/WAR) 파일로 패키지화 할 수 있지만 아래에 설명 된 간단한 방법은 독립 실행 형 응용 프로그램을 만듭니다. 자바 `main()`메소드로 구동되는, 실행 가능한 단일 JAR 파일로 모든 것을 패키지화합니다. 도중에, 외부 인스턴스로 전개하는 대신 [Tomcat](http://spring.io/understanding/Tomcat) 서블릿 컨테이너를 HTTP 런타임으로 임베딩하기위한 Spring의 지원을 사용한다. 351 | 352 | `src/main/java/hello/Application.java` 353 | 354 | ```java 355 | package hello; 356 | 357 | import org.springframework.boot.SpringApplication; 358 | import org.springframework.boot.autoconfigure.SpringBootApplication; 359 | 360 | @SpringBootApplication 361 | public class Application { 362 | 363 | public static void main(String[] args) { 364 | SpringApplication.run(Application.class, args); 365 | } 366 | } 367 | ``` 368 | 369 | ## 실행 가능한 JAR로 빌드하기 370 | Gradle 또는 Maven을 사용하여 명령 줄에서 응용 프로그램을 실행할 수 있습니다. 또는 모든 필요한 종속성, 클래스 및 자원을 포함하는 단일 실행 가능 JAR 파일을 빌드하고 실행할 수 있습니다. 따라서 개발 수명주기, 다양한 환경에 걸쳐 응용 프로그램으로 서비스를 쉽게 배포, 버전 및 배포 할 수 있습니다. 371 | 372 | Gradle을 사용하는 경우, `./gradlew bootRun`을 사용하여 응용 프로그램을 실행할 수 있습니다. 또는 `./gradlew build`를 사용하여 JAR 파일을 빌드 할 수 있습니다. 그런 다음 JAR 파일을 실행할 수 있습니다 : 373 | 374 | ``` 375 | java -jar build/libs/gs-accessing-data-mysql-0.1.0.jar 376 | ``` 377 | 378 | Maven을 사용한다면 `./mvnw spring-boot:run`을 사용하여 응용 프로그램을 실행할 수 있습니다. 또는 `./mvnw clean package`로 JAR 파일을 빌드 할 수 있습니다. 그런 다음 JAR 파일을 실행할 수 있습니다 : 379 | 380 | ``` 381 | java -jar target/gs-accessing-data-mysql-0.1.0.jar 382 | ``` 383 | 384 | > 385 | 위의 절차는 실행 가능한 JAR을 생성합니다. 대신 [고전적인 WAR 파일을 빌드](http://spring.io/guides/gs/convert-jar-to-war/)하도록 선택할 수도 있습니다 386 | 387 | 로깅 출력이 표시됩니다. 몇 초 내에 서비스가 실행됩니다. 388 | 389 | ## 응용 프로그램 테스트 390 | 이제 응용 프로그램이 실행 중이므로 이를 테스트 할 수 있습니다. 391 | 392 | 393 | 예를 들어, `curl`을 사용하십시오. 이제 테스트 할 수 있는 2 개의 REST 웹 서비스가 있습니다. 394 | 395 | `localhost:8080/demo/all` 모든 데이터를 얻어오기 또는 `localhost:8080/demo/add` 하나의 사용자를 데이터에 추가하기 396 | 397 | ```bash 398 | $ curl 'localhost:8080/demo/add?name=First&email=someemail@someemailprovider.com' 399 | ``` 400 | 401 | 리턴값 402 | 403 | ```bash 404 | Saved 405 | ``` 406 | 407 | ```bash 408 | $ curl 'localhost:8080/demo/all' 409 | ``` 410 | 411 | 리턴값 412 | 413 | ```json 414 | [{"id":1,"name":"First","email":"someemail@someemailprovider.com"}] 415 | ``` 416 | 417 | ## 보안 변경하기 418 | 이제 프로덕션 환경에서 SQL 삽입 공격에 노출 될 수 있습니다. 해커는 `DROP TABLE`또는 다른 파괴적인 SQL 명령을 삽입 할 수 있습니다. 따라서 보안 사례로서 응용 프로그램을 사용자에게 노출하기 전에 데이터베이스에 변경 사항을 적용하십시오. 419 | 420 | ```bash 421 | mysql> revoke all on db_example.* from 'springuser'@'localhost'; 422 | ``` 423 | 424 | 이것은 Spring 애플리케이션과 관련된 사용자로부터 모든 권한을 취소합니다. 이제 Spring 애플리케이션은 **데이터베이스에서** 아무 것도 할 수 없습니다. 425 | 426 | ```bash 427 | mysql> grant select, insert, delete, update on db_example.* to 'springuser'@'localhost'; 428 | ``` 429 | 430 | 이렇게하면 Spring 애플리케이션에 구조 (스키마)가 아닌 데이터베이스의 **데이터만** 변경하는 데 필요한 권한 만 부여됩니다. 431 | 432 | 이제 당신의 `src/main/resources/application.properties`에서 변경하십시오. 433 | 434 | ```properties 435 | spring.jpa.hibernate.ddl-auto=none 436 | ``` 437 | 438 | 위 코드는 Hibernate가 엔티티들로부터 테이블을 생성하기위한 첫 번째 실행에 있던 `create` 대신에 사용됩니다. 439 | 440 | 데이터베이스를 변경하려면 권한을 변경하고 `spring.jpa.hibernate.ddl-auto` 파일을 `update` 파일로 변경 한 다음 응용 프로그램을 다시 실행하고 반복하십시오. 또는 Flyway 또는 Liquibase와 같은 전용 마이그레이션 도구를 사용하십시오. 441 | 442 | ## 요약 443 | 축하합니다! 당신은 방금 MySQL 데이터베이스에 바인딩 된 Spring 애플리케이션을 개발했습니다. 444 | 445 | ## 참고 사항 446 | 447 | 다음 가이드도 도움이 될 수 있습니다 : 448 | 449 | * [JPA로 데이터 액세스](https://spring.io/guides/gs/accessing-data-jpa/) 450 | * [MongoDB로 데이터 액세스](https://spring.io/guides/gs/accessing-data-mongodb/) 451 | * [Gemfire로 데이터 액세스](https://spring.io/guides/gs/accessing-data-gemfire/) -------------------------------------------------------------------------------- /gs-accessing-vault/README.md: -------------------------------------------------------------------------------- 1 | ## Vault 사용해보기 2 | 이 가이드는 비밀 관리 툴인 [HashiCorp Vault](https://www.vaultproject.io/)에서 데이터를 불러오는 [Spring Vault](https://projects.spring.io/spring-vault/)를 사용하여 어플리케이션을 만드는 과정으로 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 여러분은 transit encryption backend를 사용하여 Valut에 저장된 비밀정보를 불러올 것입니다. 6 | 7 | ## 무엇이 필요한가? 8 | * 약 15분의 시간 9 | * 좋아하는 텍스트 에디터나 IDE 10 | * [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 이상 11 | * [Gradle 4+](http://www.gradle.org/downloads) 또는 [Maven 3.2+](https://maven.apache.org/download.cgi) 12 | * 여러분이 코드를 IDE에 직접 가져오려면 다음을 참고하세요: 13 | - [Spring Tool Suite (STS)](http://spring.io/guides/gs/sts) 14 | - [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea/) 15 | 16 | ## 이 가이드를 완료하는 방법 17 | 대부분의 [스프링 시작 가이드](http://spring.io/guides)처럼 처음부터 하나씩 완성해 가거나 익숙한 시작 부분은 건너뛰어도 됩니다. 어느 방법을 선택하시더라도 작동되는 코드를 완성시킬 수 있습니다. 18 | 19 | **처음부터 작업하실 분**은 [Gradle을 사용한 빌드](#Gradle을-사용한-빌드)로 가세요. 20 | 21 | **시작부분을 건너뛰실 분**은 아래방법을 따라하세요: 22 | 23 | * [다운로드](https://github.com/spring-guides/gs-accessing-vault/archive/master.zip) 하시고 압축파일을 풀어주시거나 [GIT](http://spring.io/understanding/Git)을 사용해 복제해주세요 (명령어): `git clone https://github.com/spring-guides/gs-accessing-vault.git` 24 | * 소스의 압축을 해제한 폴더에서 `gs-accessing-vault/initial`로 이동합니다.(cd) 25 | * [HashiCorp Vault를 설치하고 실행하기](#HashiCorp-Vault를-설치하고-실행하기)로 이동합니다. 26 | 27 | **다 끝나고나서**, `gs-accessing-vault/complete`의 코드와 비교해서 맞는지 확인해보세요. 28 | 29 | ## Gradle을 사용한 빌드 30 | 첫 번째로 여러분은 빌드 스크립트를 만들어야 합니다. 여러분은 스프링 어플리케이션을 빌드 할 때 원하는 시스템을 사용할 수 있습니다만, 코드가 작동하기 위해서는 [Gradle](http://gradle.org/)이나 [Maven](https://maven.apache.org/)이 포함되어 있어야 합니다. Gradle이나 Maven에 익숙하지 않은 경우, [Building Java Projects with Gradle](http://spring.io/guides/gs/gradle) 또는 [Building Java Projects with Maven (http://spring.io/guides/gs/maven) 을 참조하세요. 31 | 32 | ### 폴더 구조 만들기 33 | 프로젝트 폴더를 선택하시고 안에 다음과 같이 하위 폴더를 만들어주세요 예를 들면, *nix(linux, unix)에서는 `mkdir -p src/main/java/hello`를 입력하면 됩니다: 34 | 35 | ``` 36 | └── src 37 | └── main 38 | └── java 39 | └── hello 40 | ``` 41 | 42 | ### Gradle 빌드 파일 만들기 43 | [초기 Gradle build file](https://github.com/spring-guides/gs-accessing-vault/blob/master/initial/build.gradle)은 아래와 같습니다. 44 | 45 | `build.gradle` 46 | 47 | ```gradle 48 | buildscript { 49 | repositories { 50 | mavenCentral() 51 | } 52 | dependencies { 53 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 54 | } 55 | } 56 | 57 | apply plugin: 'java' 58 | apply plugin: 'eclipse' 59 | apply plugin: 'idea' 60 | apply plugin: 'org.springframework.boot' 61 | apply plugin: 'io.spring.dependency-management' 62 | 63 | bootJar { 64 | baseName = 'gs-accessing-vault' 65 | version = '0.1.0' 66 | } 67 | 68 | repositories { 69 | mavenCentral() 70 | } 71 | 72 | ext { 73 | springCloudVersion = 'Finchley.SR1' 74 | } 75 | 76 | sourceCompatibility = 1.8 77 | targetCompatibility = 1.8 78 | 79 | dependencies { 80 | compile('org.springframework.cloud:spring-cloud-starter-vault-config') 81 | testCompile("org.springframework.boot:spring-boot-starter-test") 82 | } 83 | 84 | dependencyManagement { 85 | imports { 86 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 87 | } 88 | } 89 | 90 | repositories { 91 | maven { 92 | url 'https://repo.spring.io/libs-milestone' 93 | } 94 | } 95 | ``` 96 | 97 | [Spring Boot gradle plugin](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html)은 많고 편리한 기능을 제공합니다: 98 | 99 | * 이 플러그인은 클래스패스 위의 jar를 하나의 실행 가능한 jar로 모아서 여러분의 서비스를 실행하고 전송하는데 편리하게 만들어줍니다. 100 | * 이 플러그인은 `public static void main()`메소드를 찾아 실행 가능한 클래스로 표시를 해줍니다. 101 | * 이 플러그인은 [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)에 맞는 내장된 의존성 해석자를 제공합니다. 여러분이 원하는 버전을 사용할 수도 있습니다만 기본적으로 Spring Boot에서 선택한 버전이 기본 제공됩니다. 102 | 103 | ## Maven을 사용한 빌드 104 | 첫번째로 여러분은 빌드 스크립트를 만들어야 합니다. 여러분은 스프링 어플리케이션을 빌드할때 원하는 시스템을 사용할 수 있습니다만, 코드가 작동하기 위해서는 [Maven](https://maven.apache.org/)이 포함되어 있어야 합니다. Maven에 익숙하지 않은 경우, [Building Java Projects with Maven](http://spring.io/guides/gs/maven)을 참조하세요. 105 | 106 | ### 폴더 구조 만들기 107 | 프로젝트 폴더를 선택하시고 안에 다음과 같이 하위 폴더를 만들어주세요. 예를 들면, *nix(linux, unix)에서는 `mkdir -p src/main/java/hello`를 입력하면 됩니다: 108 | 109 | ``` 110 | └── src 111 | └── main 112 | └── java 113 | └── hello 114 | ``` 115 | 116 | `pom.xml` 117 | 118 | ```xml 119 | 120 | 122 | 4.0.0 123 | 124 | org.springframework 125 | gs-accessing-vault 126 | 0.1.0 127 | 128 | 129 | org.springframework.boot 130 | spring-boot-starter-parent 131 | 2.0.5.RELEASE 132 | 133 | 134 | 135 | 1.8 136 | Finchley.SR1 137 | 138 | 139 | 140 | 141 | 142 | 143 | org.springframework.cloud 144 | spring-cloud-starter-vault-config 145 | 146 | 147 | 148 | org.springframework.boot 149 | spring-boot-starter-test 150 | test 151 | 152 | 153 | 154 | 155 | 156 | 157 | org.springframework.cloud 158 | spring-cloud-dependencies 159 | ${spring-cloud.version} 160 | pom 161 | import 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | org.springframework.boot 170 | spring-boot-maven-plugin 171 | 172 | 173 | 174 | 175 | 176 | 177 | spring-milestones 178 | Spring Milestones 179 | https://repo.spring.io/libs-milestone 180 | 181 | false 182 | 183 | 184 | 185 | 186 | 187 | 188 | ``` 189 | 190 | 이 [Spring Boot Maven plugin](https://docs.spring.io/spring-boot/docs/current/maven-plugin)은 많고 편리한 기능을 제공합니다.: 191 | 192 | * 이 플러그인은 클래스패스 위의 jar를 하나의 실행가능한 jar로 모아서 여러분의 서비스를 실행하고 전송하는데 편리하게 만들어줍니다. 193 | * 이 플러그인은 `public static void main()`메소드를 찾아 실행 가능한 클래스로 표시를 해줍니다. 194 | * 이 플러그인은 [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)에 맞는 내장된 의존성 해석자를 제공합니다. 195 | 196 | ## 여러분의 IDE를 사용한 빌드 하기 197 | * 이 가이드를 STS에 직접 포함하는 방법을 알고싶으면 [Spring Tool Suite](http://spring.io/guides/gs/sts/)을 읽어주세요. 198 | * 이 가이드를 Intellij IDEA에서 작동시키는 법을 알고 싶으면 [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea)을 읽어주세요. 199 | 200 | ## HashiCorp Vault를 설치하고 실행하기 201 | 프로젝트 설정과 함께 여러분은 HashiCorp Vault를 설치하고 실행할 수 있습니다. 202 | 203 | homebrew가 설치된 맥을 쓰신다면 간단하게 진행할 수 있습니다: 204 | 205 | ```bash 206 | $ brew install vault 207 | ``` 208 | 209 | 또는, 여러분의 시스템에 맞게 https://www.vaultproject.io/downloads.html에서 Vault를 다운로드할 수 있습니다: 210 | 211 | ```bash 212 | $ https://releases.hashicorp.com/vault/0.8.3/vault_0.8.3_darwin_amd64.zip 213 | $ unzip vault_0.8.3_darwin_amd64.zip 214 | ``` 215 | 216 | 레드햇, 우분투, 데비안, CENT OS, 윈도우등의 패키지 매니저로 설치하시려면 https://www.vaultproject.io/docs/install/index.html를 보고 설치해 주세요. 217 | 218 | Vault를 설치하신 후, 콘솔 창에서 실행할 수 있습니다. 그리고 아래의 커맨드를 입력하셔서 서버를 시작해 주세요. 219 | 220 | ``` 221 | $ vault server --dev --dev-root-token-id="00000000-0000-0000-0000-000000000000" 222 | ``` 223 | 224 | 여러분은 마지막 한 줄을 다음과 같이 볼 수 있을 겁니다. 225 | 226 | ``` 227 | [INFO ] core: post-unseal setup complete 228 | ``` 229 | 230 | > 이 커맨드는 Vault를 개발 모드로 시작하며 암호화하지 않고 저장소를 메모리 안에 만들어서 사용합니다. 또한 이 커맨드로 Vault를 내부에서 사용하는 것으로는 괜찮습니다. 실제 운영 용도로는 신뢰할 수 있는 저장소와 적절한 SSL 인증서를 사용해야 합니다. Vault’s [Production Hardening guide](https://www.vaultproject.io/guides/production.html)에서 정보를 더 얻을 수 있습니다. 231 | 232 | ## Vault안에 비밀정보 저장하기 233 | Vault는 숨겨진 상태로 암호화된 중요한 데이터를 저장할 수 있는 비밀 관리 시스템입니다. 암호, 암호화 키, API 키와 같은 중요한 구성 정보를 저장하는 것이 이상적입니다. 234 | 235 | 다른 콘솔 창을 켜서 커맨드 라인으로 Vault 안에 어플리케이션 구성 정보를 저장해 보겠습니다. 236 | 237 | 첫 번째로, 여러분은 Vault CLI에서 인증된 토큰을 제공하기 위한 두 개의 환경 변수를 설정해야 합니다. 238 | 239 | ```bash 240 | $ export export VAULT_TOKEN="00000000-0000-0000-0000-000000000000" 241 | $ export VAULT_ADDR="http://127.0.0.1:8200" 242 | ``` 243 | 244 | 이제 키-값으로 구성된 정보를 Vault 안으로 저장해 보겠습니다: 245 | 246 | ```bash 247 | $ vault write secret/github github.oauth2.key=foobar 248 | ``` 249 | 250 | ### 여러분의 어플리케이션을 환경설정 하기 251 | 252 | 여러분은 여기 `bootstrap.properties`에서 환경설정을 할 수 있습니다. Spring Cloud Vault는 부트스트랩 컨텍스트에서 환경설정이 됩니다. 253 | 254 | `src/main/resources/bootstrap.properties` 255 | 256 | ```properties 257 | spring.cloud.vault.token=00000000-0000-0000-0000-000000000000 258 | spring.cloud.vault.scheme=http 259 | ``` 260 | 261 | ## 어플리케이션 클래스 만들기 262 | 모든 구성요소를 담은 Application 클래스를 만듭니다. 263 | 264 | `src/main/java/hello/Application.java` 265 | 266 | ```java 267 | package hello; 268 | 269 | import org.springframework.beans.factory.annotation.Autowired; 270 | import org.springframework.beans.factory.annotation.Value; 271 | import org.springframework.boot.CommandLineRunner; 272 | import org.springframework.boot.SpringApplication; 273 | import org.springframework.boot.autoconfigure.SpringBootApplication; 274 | import org.springframework.vault.core.VaultSysOperations; 275 | import org.springframework.vault.core.VaultTemplate; 276 | import org.springframework.vault.core.VaultTransitOperations; 277 | import org.springframework.vault.support.VaultMount; 278 | import org.springframework.vault.support.VaultResponse; 279 | 280 | @SpringBootApplication 281 | public class Application implements CommandLineRunner { 282 | 283 | @Autowired 284 | private VaultTemplate vaultTemplate; 285 | 286 | public static void main(String[] args) { 287 | SpringApplication.run(Application.class, args); 288 | } 289 | 290 | @Override 291 | public void run(String... strings) throws Exception { 292 | 293 | // You usually would not print a secret to stdout 294 | VaultResponse response = vaultTemplate.read("secret/github"); 295 | System.out.println("Value of github.oauth2.key"); 296 | System.out.println("-------------------------------"); 297 | System.out.println(response.getData().get("github.oauth2.key")); 298 | System.out.println("-------------------------------"); 299 | System.out.println(); 300 | 301 | // Let's encrypt some data using the Transit backend. 302 | VaultTransitOperations transitOperations = vaultTemplate.opsForTransit(); 303 | 304 | // We need to setup transit first (assuming you didn't set up it yet). 305 | VaultSysOperations sysOperations = vaultTemplate.opsForSys(); 306 | 307 | if (!sysOperations.getMounts().containsKey("transit/")) { 308 | 309 | sysOperations.mount("transit", VaultMount.create("transit")); 310 | 311 | transitOperations.createKey("foo-key"); 312 | } 313 | 314 | // Encrypt a plain-text value 315 | String ciphertext = transitOperations.encrypt("foo-key", "Secure message"); 316 | 317 | System.out.println("Encrypted value"); 318 | System.out.println("-------------------------------"); 319 | System.out.println(ciphertext); 320 | System.out.println("-------------------------------"); 321 | System.out.println(); 322 | 323 | // Decrypt 324 | 325 | String plaintext = transitOperations.decrypt("foo-key", ciphertext); 326 | 327 | System.out.println("Decrypted value"); 328 | System.out.println("-------------------------------"); 329 | System.out.println(plaintext); 330 | System.out.println("-------------------------------"); 331 | System.out.println(); 332 | } 333 | } 334 | ``` 335 | 336 | Spring Cloud Vault는 `VaultOperations`를 통해 Vault와 상호작용합니다. Vault의 속성은 형식에 안전한(type-safe) 액세스를 위해 `MyConfiguration`에 매핑됩니다. `@EnableConfigurationProperties(MyConfiguration.class)`는 `MyConfiguration`빈을 등록하고 속성들을 매핑할 수 있게 해줍니다. 337 | 338 | `Application`은 `MyConfiguration`인스턴스를 자동으로 생성할 수 있는(autowire) `main()` 메소드를 포함하고 있습니다. 339 | 340 | ## 실행가능한 JAR로 빌드하기 341 | 여러분은 Gradle이나 Maven을 이용한 커맨드 라인으로 이 어플리케이션을 실행할 수 있습니다. 또는 모든 필요한 의존성, 클래스, 자원 등을 포함한 하나의 실행 가능한 JAR로 빌드 할 수도 있습니다. 그래서 다양한 환경에서 개발 주기 전반에 걸쳐 버전을 올리고 서비스를 배포하는 것이 쉬워집니다. 342 | 343 | Gradle을 사용할 경우 `./gradlew bootRun` 명령어로 실행할 수 있습니다. 또는 `./gradlew build` 명령어로 JAR 파일을 만들고 다음과 같이 JAR 파일을 실행할 수 있습니다. 344 | 345 | ``` 346 | java -jar build/libs/gs-accessing-vault-0.1.0.jar 347 | ``` 348 | 349 | Maven을 사용할 경우 `./mvnw spring-boot:run` 명령어로 실행할 수 있습니다. 또는 `./mvnw clean package` 명령어로 JAR 파일을 만들고 다음과 같이 JAR 파일을 실행할 수 있습니다. 350 | 351 | ``` 352 | java -jar target/gs-accessing-vault-0.1.0.jar 353 | ``` 354 | 355 | > 이 과정은 실행가능한 JAR를 만듭니다. 물론 [build a classic WAR file](http://spring.io/guides/gs/convert-jar-to-war/)도 옵션으로 선택하실 수 있습니다. 356 | 357 | 우리가 만든 `Application`은 `CommandLineRunner`를 구현합니다, 그래서 `run` 메소드가 시작 시 자동으로 호출됩니다. 여러분은 다음과 같은 화면을 볼 수 있습니다: 358 | 359 | ``` 360 | Value of github.oauth2.key 361 | ------------------------------- 362 | foobar 363 | ------------------------------- 364 | 365 | Encrypted value 366 | ------------------------------- 367 | vault:v1:2wgVE2PXiR9o55xbyur5KHJl8IwyGDkDU4l1SZScUq6BuqZYgTopwvc4 368 | ------------------------------- 369 | 370 | Decrypted value 371 | ------------------------------- 372 | Secure message 373 | ------------------------------- 374 | ``` 375 | 376 | > Vault의 secret backend는 고유 문서를 URI를 사용해서 비교합니다. 문서는 Vault 데이터로 편하게 변환할 수 있도록 JSON 기반으로 이루어져 있습니다. 377 | 378 | ## 요약 379 | 축하합니다! 여러분은 Vault 서버를 설치하고 강력하게 암호화된 데이터를 스프링 Vault를 사용하여 읽는 간단한 어플리케이션을 만들어 보았습니다. -------------------------------------------------------------------------------- /gs-consuming-rest/README.adoc: -------------------------------------------------------------------------------- 1 | == RESTful 웹 서비스 사용하기 2 | 이 가이드는 RESTful 웹 서비스를 사용하는 어플리케이션을 만드는 과정을 안내한다. 3 | 4 | == 무엇을 만들게 되는가 5 | http://gturnquist-quoters.cfapps.io/api/random에서 Spring의 `RestTemplate` 를 사용하여 랜덤의 Spring Boot 인용문을 검색하는 어플리케이션을 만들 것이다. 6 | 7 | == 무엇이 필요한가 8 | * 약 15분 9 | * 선호하는 텍스트 에디터 혹은 IDE 10 | * http://www.oracle.com/technetwork/java/javase/downloads/index.html[JDK 1.8] 혹은 그 이상 11 | * http://www.gradle.org/downloads[Gradle 4+] 혹은 https://maven.apache.org/download.cgi[Maven 3.2+] 12 | * 코드를 IDE로 직접 가져올 수도 있다. 13 | ** http://spring.io/guides/gs/sts[Spring Tool Suite (STS)] 14 | ** http://spring.io/guides/gs/intellij-idea/[IntelliJ IDEA] 15 | 16 | == 이 가이드를 완료하는 방법 17 | 대부분의 http://spring.io/guides[Spring Getting Started] 가이드와 마찬가지로, 처음부터 시작하여 각 단계를 완료하거나 이미 익숙한 기본 설정 단계를 건너뛸 수 있다. 어느 쪽이든 코드가 작동한다. 18 | 19 | 처음부터 시작하려면 <>로 이동하시오. 20 | 21 | 기본 사항을 건너뛰려면 다음을 수행하라: 22 | 23 | * 이 가이드의 소스 저장소를 https://github.com/spring-guides/gs-consuming-rest/archive/master.zip[다운로드]하여 압축을 풀거나 http://spring.io/understanding/Git[Git]: `git clone https://github.com/spring-guides/gs-consuming-rest.git` 을 사용하여 clone 하시오. 24 | * cd into `gs-consuming-rest/initial` 25 | * <>로 넘어가시오. 26 | 27 | **끝나면** `gs-consuming-rest/complete` 코드와 결과를 비교할 수 있다. 28 | 29 | [[build-with-gradle]] 30 | == Gradle로 빌드하기 31 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 http://gradle.org/[Gradle] 및 https://maven.apache.org/[Maven]으로 작업하는 데 필요한 코드가 여기에 있다. 둘다 익숙하지 않은 경우 http://spring.io/guides/gs/gradle[Gradle로 Java 프로젝트 만들기] 또는 http://spring.io/guides/gs/maven[Maven으로 Java 프로젝트 만들기]를 참조하시오. 32 | 33 | === 디렉토리 구조 만들기 34 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 mkdir -p src/main/java/hello를 사용하여 다음 하위 디렉토리 구조를 작성한다: 35 | 36 | [source,indent=0] 37 | ---- 38 | └── src 39 | └── main 40 | └── java 41 | └── hello 42 | ---- 43 | 44 | === Gradle 빌드 파일 만들기 45 | 아래는 https://github.com/spring-guides/gs-consuming-rest/blob/master/initial/build.gradle[초기 Gradle 빌드 파일]이다. 46 | 47 | `build.gradle` 48 | 49 | [source,gradle,indent=0] 50 | ---- 51 | buildscript { 52 | repositories { 53 | mavenCentral() 54 | } 55 | dependencies { 56 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 57 | } 58 | } 59 | 60 | apply plugin: 'java' 61 | apply plugin: 'eclipse' 62 | apply plugin: 'idea' 63 | apply plugin: 'org.springframework.boot' 64 | apply plugin: 'io.spring.dependency-management' 65 | 66 | bootJar { 67 | baseName = 'gs-consuming-rest' 68 | version = '0.1.0' 69 | } 70 | 71 | repositories { 72 | mavenCentral() 73 | } 74 | 75 | sourceCompatibility = 1.8 76 | targetCompatibility = 1.8 77 | 78 | dependencies { 79 | compile("org.springframework.boot:spring-boot-starter") 80 | compile("org.springframework:spring-web") 81 | compile("com.fasterxml.jackson.core:jackson-databind") 82 | testCompile("junit:junit") 83 | } 84 | ---- 85 | 86 | https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html[Spring Boot Gralde 플러그인]은 다음과 같은 여러 편리한 기능을 제공한다: 87 | 88 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 89 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 90 | * https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml[Spring Boot 의존성]과 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 91 | 92 | == Maven으로 빌드하기 93 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 https://maven.apache.org/[Maven]으로 작업하는 데 필요한 코드가 여기에 있다. Maven이 익숙하지 않은 경우 http://spring.io/guides/gs/maven[Maven으로 Java 프로젝트 만들기]를 참조하시오. 94 | 95 | === 디렉토리 구조 만들기 96 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 mkdir -p src/main/java/hello를 사용하여 다음 하위 디렉토리 구조를 작성한다: 97 | 98 | [source,indent=0] 99 | ---- 100 | └── src 101 | └── main 102 | └── java 103 | └── hello 104 | ---- 105 | 106 | `pom.xml` 107 | 108 | [source,xml,indent=0] 109 | ---- 110 | 111 | 113 | 4.0.0 114 | 115 | org.springframework 116 | gs-consuming-rest 117 | 0.1.0 118 | 119 | 120 | org.springframework.boot 121 | spring-boot-starter-parent 122 | 2.0.5.RELEASE 123 | 124 | 125 | 126 | 1.8 127 | 128 | 129 | 130 | 131 | org.springframework.boot 132 | spring-boot-starter 133 | 134 | 135 | org.springframework 136 | spring-web 137 | 138 | 139 | com.fasterxml.jackson.core 140 | jackson-databind 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | org.springframework.boot 149 | spring-boot-maven-plugin 150 | 151 | 152 | 153 | 154 | 155 | ---- 156 | 157 | https://docs.spring.io/spring-boot/docs/current/maven-plugin[Spring Boot Maven 플러그인]은 다음과 같은 여러 편리한 기능을 제공한다: 158 | 159 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 160 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 161 | * https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml[Spring Boot 의존성]과 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 162 | 163 | == IDE로 빌드하기 164 | * http://spring.io/guides/gs/sts/[Spring Tool Suite]에서 import 하는 가이드를 읽으시오. 165 | * http://spring.io/guides/gs/intellij-idea[IntelliJ IDEA]에서 가이드를 읽으시오. 166 | 167 | [[fetch-a-rest-resource]] 168 | == REST 리소스 가져오기 169 | 프로젝트 설정이 완료되면 RESTful 서비스를 사용하는 간단한 어플리케이션을 만들 수 있다. 170 | 171 | RESTful 서비스가 http://gturnquist-quoters.cfapps.io/api/random에서 동작되고 있다. Spring Boot에 대한 인용문을 랜덤으로 가져와서 JSON 문서로 반환한다. 172 | 173 | 웹 브라우저나 curl을 통해 URL을 요청하면 다음과 같은 JSON 문서를 받게될 것이다. 174 | 175 | [source,json,indent=0] 176 | ---- 177 | { 178 | type: "success", 179 | value: { 180 | id: 10, 181 | quote: "Really loving Spring Boot, makes stand alone Spring apps easy." 182 | } 183 | } 184 | ---- 185 | 186 | 많이 간단하지만, 브라우저나 curl을 통해 가져올 때 유용하지는 않다. 187 | 188 | 더 유용하게 사용하는 방법은 REST 웹 서비스를 프로그래밍 방식으로 사용하는 것이다. 이 작업을 돕기 위해 Spring은 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html[`RestTemplate`] 이라는 편리한 템플릿 클래스를 제공한다. `RestTemplate` 은 대부분의 RESTful 서비스와 상호작용을 한줄로 표현한다. 그리고 데이터를 커스텀 도메인 타입에 바인딩할 수도 있다. 189 | 190 | 먼저 필요한 데이터를 포함할 도메인 클래스를 만든다. 191 | 192 | `src/main/java/hello/Quote.java` 193 | 194 | [source,java,indent=0] 195 | ---- 196 | package hello; 197 | 198 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 199 | 200 | @JsonIgnoreProperties(ignoreUnknown = true) 201 | public class Quote { 202 | 203 | private String type; 204 | private Value value; 205 | 206 | public Quote() { 207 | } 208 | 209 | public String getType() { 210 | return type; 211 | } 212 | 213 | public void setType(String type) { 214 | this.type = type; 215 | } 216 | 217 | public Value getValue() { 218 | return value; 219 | } 220 | 221 | public void setValue(Value value) { 222 | this.value = value; 223 | } 224 | 225 | @Override 226 | public String toString() { 227 | return "Quote{" + 228 | "type='" + type + '\'' + 229 | ", value=" + value + 230 | '}'; 231 | } 232 | } 233 | ---- 234 | 235 | 보다시피, 이 클래스는 몇 가지 속성과 getter 메소드가 있는 간단한 Java 클래스이다. Jackson JSON 처리 라이브러리의 `@JsonIgnoreProperties` 어노테이션이 달려 있어 이 유형에 바인딩되지 않은 모든 속성을 무시하는 것을 나타낸다. 236 | 237 | 위에서 작성한 커스텀 타입에 데이터를 직접 바인딩하려면 API에서 반환 된 JSON 문서의 key와 완전히 동일한 변수 이름을 지정해야 한다. JSON 문서의 변수 이름과 key가 일치하지 않는 경우 `@JsonProperty` 어노테이션을 사용하여 JSON 문서의 정확한 key를 지정해야 한다. 238 | 239 | 내부 인용문 자체를 포함하려면 추가 클래스가 필요하다. 240 | 241 | `src/main/java/hello/Value.java` 242 | 243 | [source,java,indent=0] 244 | ---- 245 | package hello; 246 | 247 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 248 | 249 | @JsonIgnoreProperties(ignoreUnknown = true) 250 | public class Value { 251 | 252 | private Long id; 253 | private String quote; 254 | 255 | public Value() { 256 | } 257 | 258 | public Long getId() { 259 | return this.id; 260 | } 261 | 262 | public String getQuote() { 263 | return this.quote; 264 | } 265 | 266 | public void setId(Long id) { 267 | this.id = id; 268 | } 269 | 270 | public void setQuote(String quote) { 271 | this.quote = quote; 272 | } 273 | 274 | @Override 275 | public String toString() { 276 | return "Value{" + 277 | "id=" + id + 278 | ", quote='" + quote + '\'' + 279 | '}'; 280 | } 281 | } 282 | ---- 283 | 284 | 이는 동일한 어노테이션을 사용하지만 다른 데이터 필드에 매핑된다. 285 | 286 | == 실행 가능한 어플리케이션 만들기 287 | 이 서비스를 외부 어플리케이션 서버에 배포하기 위해 기존의 http://spring.io/understanding/WAR[WAR] 파일로 패키징할 수 있지만, 아래에서 설명하는 더 간단한 접근 방식으로 독립 실행형 어플리케이션을 생성할 수 있다. Java `main()` 메소드로 구동되는 실행 가능한 단일 JAR 파일로 모든 것을 패키징한다. 이 과정에서 외부 인스턴스에 배포하는 대신 HTTP 런타임으로 Spring에서 지원하는 내장형 http://spring.io/understanding/Tomcat[Tomcat] 서블릿 컨테이너를 사용한다. 288 | 289 | 이제 `RestTemplate` 을 사용하는 `Application` 클래스를 작성하여 Spring Boot 인용문 서비스에서 데이터를 가져올 수 있다. 290 | 291 | `src/main/java/hello/Application.java` 292 | 293 | [source,java,indent=0] 294 | ---- 295 | package hello; 296 | 297 | import org.slf4j.Logger; 298 | import org.slf4j.LoggerFactory; 299 | import org.springframework.boot.SpringApplication; 300 | import org.springframework.boot.autoconfigure.SpringBootApplication; 301 | import org.springframework.web.client.RestTemplate; 302 | 303 | public class Application { 304 | 305 | private static final Logger log = LoggerFactory.getLogger(Application.class); 306 | 307 | public static void main(String args[]) { 308 | RestTemplate restTemplate = new RestTemplate(); 309 | Quote quote = restTemplate.getForObject("http://gturnquist-quoters.cfapps.io/api/random", Quote.class); 310 | log.info(quote.toString()); 311 | } 312 | 313 | } 314 | ---- 315 | 316 | Jackson JSON 처리 라이브러리가 클래스 경로에 있기 때문에 `RestTemplate` 은 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/converter/HttpMessageConverter.html[메시지 컨버터]를 통해 수신한 JSON 데이터를 `Quote` 객체로 변환한다. 여기에서 `Quote` 객체의 내용이 콘솔에 기록된다. 317 | 318 | 여기서는 `RestTemplate` 을 사용하여 HTTP `GET` 요청만 했다. 그러나 RestTemplate은 `POST`, `PUT` 및 `DELETE` 와 같은 다른 HTTP도 지원한다. 319 | 320 | == Spring Boot로 어플리케이션 Lifecycle 관리하기 321 | 지금까지 어플리케이션에서 Spring Boot를 사용하지 않았다. 하지만 Spring Boot를 이용하면 몇 가지 장점이 있고, 사용하는 것도 어렵지 않다. 장점 중 하나는 Spring Boot가 `RestTemplate` 에서 메시지 컨버터를 관리하도록 하여 사용자 정의를 선언적으로 쉽게 추가할 수 있도록 한다. 이를 위해 main 클래스에 `@SpringBootApplication` 을 사용하고 Spring Boot 어플리케이션과 마찬가지로 main 메소드를 시작하도록 변환한다. 마지막으로 `RestTemplate` 을 `CommandLineRunner` 콜백으로 이동한다. 그러면 시작시 Spring Boot에 의해 실행된다: 322 | 323 | `src/main/java/hello/Application.java` 324 | 325 | [source,java,indent=0] 326 | ---- 327 | package hello; 328 | 329 | import org.slf4j.Logger; 330 | import org.slf4j.LoggerFactory; 331 | import org.springframework.boot.CommandLineRunner; 332 | import org.springframework.boot.SpringApplication; 333 | import org.springframework.boot.autoconfigure.SpringBootApplication; 334 | import org.springframework.boot.web.client.RestTemplateBuilder; 335 | import org.springframework.context.annotation.Bean; 336 | import org.springframework.web.client.RestTemplate; 337 | 338 | @SpringBootApplication 339 | public class Application { 340 | 341 | private static final Logger log = LoggerFactory.getLogger(Application.class); 342 | 343 | public static void main(String args[]) { 344 | SpringApplication.run(Application.class); 345 | } 346 | 347 | @Bean 348 | public RestTemplate restTemplate(RestTemplateBuilder builder) { 349 | return builder.build(); 350 | } 351 | 352 | @Bean 353 | public CommandLineRunner run(RestTemplate restTemplate) throws Exception { 354 | return args -> { 355 | Quote quote = restTemplate.getForObject( 356 | "http://gturnquist-quoters.cfapps.io/api/random", Quote.class); 357 | log.info(quote.toString()); 358 | }; 359 | } 360 | } 361 | ---- 362 | 363 | `RestTemplateBuilder` 는 Spring에 의해 주입되며, `RestTemplate` 을 생성하기 위해 이 템플릿을 사용하면 Spring Boot에서 메시지 컨버터와 request factories로 발생하는 모든 자동 구성을 활용할 수 있다. 또한 `RestTemplate` 을 `@Bean` 으로 추출하여 쉽게 테스트할 수 있다. 364 | 365 | === 실행 가능한 JAR 만들기 366 | Gradle 또는 Maven을 사용하여 커맨드 라인에서 어플리케이션을 실행할 수 있다. 또는 모든 필요한 의존성, 클래스 및 리소스 포함하는 단일 실행 가능한 JAR 파일을 빌드하고 실행할 수 있다. 따라서 개발 생명주기(life cycle), 다양한 환경에 걸쳐 어플리케이션으로 서비스를 쉽게 제공 및 배포할 수 있다. 367 | 368 | Gradle을 사용하는 경우 `./gradlew bootRun` 을 사용하여 어플리케이션을 실행할 수 있다. 또는 `./gradlew build` 를 사용하여 JAR 파일을 작성할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 369 | 370 | [source,bash,indent=0] 371 | ---- 372 | java -jar build/libs/gs-consuming-rest-0.1.0.jar 373 | ---- 374 | 375 | Maven을 사용하는 경우 ./mvnw spring-boot:run을 사용하여 어플리케이션을 실행할 수 있다. 또는 ./mvnw clean package로 JAR 파일을 빌드할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 376 | 377 | [source,bash,indent=0] 378 | ---- 379 | java -jar target/gs-consuming-rest-0.1.0.jar 380 | ---- 381 | 382 | ==== 383 | 위 절차는 실행 가능한 JAR를 생성한다. 고전의 http://spring.io/guides/gs/convert-jar-to-war/[WAR 파일을 빌드]하도록 선택할 수도 있다. 384 | ==== 385 | 386 | 다음과 같이 랜덤의 인용문이 출력되는 것을 볼 수 있다: 387 | 388 | [source,indent=0] 389 | ---- 390 | 2015-09-23 14:22:26.415 INFO 23613 --- [main] hello.Application : Quote{type='success', value=Value{id=12, quote='@springboot with @springframework is pure productivity! Who said in #java one has to write double the code than in other langs? #newFavLib'}} 391 | ---- 392 | 393 | ==== 394 | 만약 `Could not extract response: no suitable HttpMessageConverter found for response type [class hello.Quote]` 오류가 발생하면 백엔드 서비스에 연결할 수 없는 환경일 가능성이 있다 (만약 연결된 경우 JSON을 보낸다). proxy를 사용중이면 표준 시스템 프로퍼티 http.proxyHost 및 http.proxyPort를 환경에 적절한 값으로 설정하시오. 395 | ==== 396 | 397 | == 요약 398 | 축하합니다! Spring을 사용하여 간다한 REST 클라이언트를 개발했다. 399 | 400 | == 다른 예제들 401 | 다음 가이드들도 도움이 될 것이다: 402 | 403 | * https://spring.io/guides/gs/rest-service/[Building a RESTful Web Service] 404 | * https://spring.io/guides/gs/consuming-rest-angularjs/[Consuming a RESTful Web Service with AngularJS] 405 | * https://spring.io/guides/gs/consuming-rest-jquery/[Consuming a RESTful Web Service with jQuery] 406 | * https://spring.io/guides/gs/consuming-rest-restjs/[Consuming a RESTful Web Service with rest.js] 407 | * https://spring.io/guides/gs/accessing-gemfire-data-rest/[Accessing GemFire Data with REST] 408 | * https://spring.io/guides/gs/accessing-mongodb-data-rest/[Accessing MongoDB Data with REST] 409 | * https://spring.io/guides/gs/accessing-data-mysql/[Accessing data with MySQL] 410 | * https://spring.io/guides/gs/accessing-data-rest/[Accessing JPA Data with REST] 411 | * https://spring.io/guides/gs/accessing-neo4j-data-rest/[Accessing Neo4j Data with REST] 412 | * https://spring.io/guides/gs/securing-web/[Securing a Web Application] 413 | * https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot] 414 | * https://spring.io/guides/gs/testing-restdocs/[Creating API Documentation with Restdocs] 415 | * https://spring.io/guides/gs/rest-service-cors/[Enabling Cross Origin Requests for a RESTful Web Service] 416 | * https://spring.io/guides/gs/rest-hateoas/[Building a Hypermedia-Driven RESTful Web Service] -------------------------------------------------------------------------------- /gs-consuming-rest/gs-consuming-rest/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework 7 | gs-consuming-rest 8 | 0.1.0 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.0.5.RELEASE 14 | 15 | 16 | 17 | 1.8 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter 24 | 25 | 26 | org.springframework 27 | spring-web 28 | 29 | 30 | com.fasterxml.jackson.core 31 | jackson-databind 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-maven-plugin 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /gs-consuming-rest/gs-consuming-rest/src/main/java/hello/Application.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.CommandLineRunner; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.boot.web.client.RestTemplateBuilder; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.web.client.RestTemplate; 11 | 12 | @SpringBootApplication 13 | public class Application { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Application.class); 16 | 17 | public static void main(String args[]) { 18 | SpringApplication.run(Application.class); 19 | } 20 | 21 | @Bean 22 | public RestTemplate restTemplate(RestTemplateBuilder builder) { 23 | return builder.build(); 24 | } 25 | 26 | @Bean 27 | public CommandLineRunner run(RestTemplate restTemplate) throws Exception { 28 | return args -> { 29 | Quote quote = restTemplate.getForObject( 30 | "http://gturnquist-quoters.cfapps.io/api/random", Quote.class); 31 | log.info(quote.toString()); 32 | }; 33 | } 34 | } -------------------------------------------------------------------------------- /gs-consuming-rest/gs-consuming-rest/src/main/java/hello/Quote.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | public class Quote { 7 | 8 | private String type; 9 | private Value value; 10 | 11 | public Quote() { 12 | } 13 | 14 | public String getType() { 15 | return type; 16 | } 17 | 18 | public void setType(String type) { 19 | this.type = type; 20 | } 21 | 22 | public Value getValue() { 23 | return value; 24 | } 25 | 26 | public void setValue(Value value) { 27 | this.value = value; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "Quote{" + 33 | "type='" + type + '\'' + 34 | ", value=" + value + 35 | '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /gs-consuming-rest/gs-consuming-rest/src/main/java/hello/Value.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | @JsonIgnoreProperties(ignoreUnknown = true) 6 | public class Value { 7 | 8 | private Long id; 9 | private String quote; 10 | 11 | public Value() { 12 | } 13 | 14 | public Long getId() { 15 | return this.id; 16 | } 17 | 18 | public String getQuote() { 19 | return this.quote; 20 | } 21 | 22 | public void setId(Long id) { 23 | this.id = id; 24 | } 25 | 26 | public void setQuote(String quote) { 27 | this.quote = quote; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "Value{" + 33 | "id=" + id + 34 | ", quote='" + quote + '\'' + 35 | '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /gs-maven/README.md: -------------------------------------------------------------------------------- 1 | ## Maven으로 Java Projects 빌드하기 2 | 이 가이드는 Maven을 사용하여 간단한 Java 프로젝트를 작성하는 과정을 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 현재의 시간을 제공하고 Maven으로 빌드하는 어플리케이션을 만들것입니다. 6 | 7 | ## 무엇이 필요한가? 8 | * 약 15분 9 | * 좋아하는 텍스트 편집기 또는 IDE 10 | * [JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 또는 그 이상 11 | 12 | ## 이 가이드를 완료하는 방법 13 | 대부분의 Spring[시작가이드](http://spring.io/guides)처럼 처음부터 시작해서 완료하거나 이미 익숙한 기본 설정단계를 건너뛸 수 있습니다. 어느쪽이든 작업코드로 끝납니다. 14 | 15 | **처음부터 시작** 하려면 [프로젝트 설정](#set-up-the-project)으로 이동하십시오. 16 | 17 | **기초를 생략** 하려면 다음을 수행하십시오: 18 | 19 | * [다운로드](https://github.com/spring-guides/gs-maven/archive/master.zip) 및 이 가이드의 소스 repository를 압축 해제하거나, [Git](http://spring.io/understanding/Git): `git clone https://github.com/spring-guides/gs-maven.git`을 사용하여 복제하십시오. 20 | * cd 명령어로 `gs-maven/initial` 으로 이동하십시오. 21 | * [initial](#initial)로 바로 이동. 22 | 23 | **작업이 끝나면** `gs-maven/complete`에 있는 코드와 결과를 비교할 수 있습니다. 24 | 25 | ## 프로젝트 설정 26 | 먼저 빌드할 Maven용 Java 프로젝트를 설정해야 합니다. Maven에 초점을 맞추려면 가능한 한 프로젝트를 단순하게 만드십시오. 선택한 프로젝트 폴더에 프로젝트를 생성합니다. 27 | 28 | ## 디렉토리 구조 만들기 29 | 선택한 프로젝트 디렉토리에서 다음과 같은 하위 디렉토리 구조를 만듭니다. *nix 시스템에서는 `mkdir -p src/main/java/hello`를 사용합니다: 30 | 31 | ``` 32 | └── src 33 | └── main 34 | └── java 35 | └── hello 36 | ``` 37 | 38 | `src/main/java/hello` 디렉토리 안에 원하는 Java 클래스를 생성할 수 있습니다. 이 가이드의 일관성을 유지하지하려면 다음과 같은 두 클래스를 생성하십시오: `HelloWorld.java` 와 `Greeter.java`. 39 | 40 | `src/main/java/hello/HelloWorld.java` 41 | 42 | ```java 43 | package hello; 44 | 45 | public class HelloWorld { 46 | public static void main(String[] args) { 47 | Greeter greeter = new Greeter(); 48 | System.out.println(greeter.sayHello()); 49 | } 50 | } 51 | ``` 52 | 53 | `src/main/java/hello/Greeter.java` 54 | 55 | ```java 56 | package hello; 57 | 58 | public class Greeter { 59 | public String sayHello() { 60 | return "Hello world!"; 61 | } 62 | } 63 | ``` 64 | 65 | ## 초기 설정 66 | 이제 Maven으로 빌드할 준비과 된 프로젝트가 생겼으니, 다음 단계는 Maven을 설치하는 것입니다. 67 | 68 | Maven은 http://maven.apache.org/download.cgi 에서 zip 파일로 다운로드할 수 있습니다. 바이너리만 필요하므로 apache-maven-{version}-bin.zip 또는 apache-maven-{*version*}-bin.tar.gz에 대한 링크를 찾으십시오. 69 | 70 | zip 파일을 다운로드한 다음 컴퓨터에 압축을 풉니다. 그 다음 경로에 bin 폴더를 추가하십시오. 71 | 72 | Maven 설치를 테스트하려면 command-line에서 `mvn`을 실행하십시오. 73 | 74 | ``` 75 | mvn -v 76 | ``` 77 | 78 | 모든 것이 잘 진행된다면 Maven 설치에 대한 정보를 얻을 수 있습니다. 다음과 같이(아마 약간 다르게라도) 나타날 것입니다. 79 | 80 | ``` 81 | Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-10T16:41:47+00:00) 82 | Maven home: /home/dsyer/Programs/apache-maven 83 | Java version: 1.8.0_152, vendor: Azul Systems, Inc. 84 | Java home: /home/dsyer/.sdkman/candidates/java/8u152-zulu/jre 85 | Default locale: en_GB, platform encoding: UTF-8 86 | OS name: "linux", version: "4.15.0-36-generic", arch: "amd64", family: "unix" 87 | ``` 88 | 89 | 축하합니다! 이제 Maven이 설치되었습니다. 90 | 91 | 정보 : [Maven wrapper](https://github.com/takari/maven-wrapper)를 사용하여 개발자가 Maven의 올바른 버전을 보유하지 못하도록 차단하거나 전체를 설치해야 하는 경우를 고려하십시오. [Spring Initializr](https://start.spring.io/)에서 다운로드한 프로젝트에는 wrapper가 포함되어 있습니다. `mvn` 대신 실행한 프로젝트 최상위 단계에서 `mvnw` 스크립트로 나타납니다. 92 | 93 | ## 간단한 Maven 빌드 정의 94 | 이제 Maven이 설치되었으므로 Maven 프로젝트 정의를 만들어야 합니다. Maven 프로젝트는 *pom.xml* 이라는 XML 파일로 정의됩니다. 이 파일은 외부 라이브러리에 있는 프로젝트의 이름, 버전 및 종속성을 제공합니다. 95 | 96 | 프로젝트의 root에 pom.xml이라는 파일을 생성하고(즉, `src` 폴더 옆에 배치) 다음 내용을 지정합니다: 97 | `pom.xml` 98 | 99 | ```xml 100 | 101 | 103 | 4.0.0 104 | 105 | org.springframework 106 | gs-maven 107 | jar 108 | 0.1.0 109 | 110 | 111 | 1.8 112 | 1.8 113 | 114 | 115 | 116 | 117 | 118 | org.apache.maven.plugins 119 | maven-shade-plugin 120 | 2.1 121 | 122 | 123 | package 124 | 125 | shade 126 | 127 | 128 | 129 | 131 | hello.HelloWorld 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | ``` 142 | 143 | 선택적인 `` 요소를 제외하고, 이것은 Java 프로젝트를 만드는데 필요한 가장 간단한 *pom.xml* 파일입니다. 여기에는 프로젝트 구성에 대한 다음 세부사항이 포함됩니다: 144 | 145 | * ``. POM 모델 버전 (항상 4.0.0). 146 | * ``. 프로젝트가 속한 그룹 또는 조직. 종종 반전된 도메인명으로 표현됩니다. 147 | * ``. 프로젝트의 라이브러리 아티팩트에 부여할 이름 (예, JAR 또는 WAR 파일명) 148 | * ``. 빌드중인 프로젝트의 버전 149 | * `` - 프로젝트 패키징 방법. JAR 파일 패키징인경우 기본값은 "jar"입니다. WAR 패키지파일에는 "war"를 사용하십시오. 150 | 151 | > 버전 관리체계를 선택할 때, Spring은 [semantic versioning](http://semver.org/) 접근방식을 권장합니다. 152 | 153 | 이 시점에서 최소의, 그러나 유능한 Maven 프로젝트를 정의했습니다. 154 | 155 | ## Java 코드 빌드 156 | Maven은 이제 프로젝트를 빌드할 준비가 되었습니다. 프로젝트 코드를 컴파일하고, 라이브러리 패키지(예 : JAR파일)를 생성하고, 로컬 Maven 종속 저장소에 라이브러리를 설치하는 것과 같은 목표를 포함하여 Maven에서 여러 빌드 수명주기 명령을 실행할 수 있습니다. 157 | 158 | 빌드를 시도하려면 command line에서 다음을 실행하십시오: 159 | 160 | ``` 161 | mvn compile 162 | ``` 163 | 164 | 이것은 Maven이 실행되어 컴파일 명령을 실행하게됩니다. 작업이 끝나면 컴파일된 *.class* 파일을 *target/classes* 디렉토리에서 찾을 수 있습니다. 165 | 166 | *.class* 파일을 직접 배포하거나 작업하는 경우가 드물기 때문에 *package* 명령을 실행하는 것이 좋습니다: 167 | 168 | ``` 169 | mvn package 170 | ``` 171 | 172 | *package* 명령은 Java코드를 컴파일하고 테스트를 실행하며, *target* 디렉토리에 내의 JAR파일에 코드를 패키징해서 마무리합니다. JAR파일명은 프로젝트의 ``와 ``을 기반으로 합니다. 이전 예제의 *pom.xml* 파일인 경우 JAR파일명은 *gs-maven-0.1.0.jar* 입니다. 173 | 174 | > ``값을 "jar"에서 "war"로 변경할 경우 결과는 JAR 파일 대신 *target* 디렉터리 내의 WAR 파일이 됩니다. 175 | 176 | 또한 Maven은 프로젝트의 종속성에 빠르게 액세스 할 수 있도록 로컬 장비(일반적으로 홈디렉토리의 *.m2/repository* 디렉토리)에 종속성 저장소를 유지 관리합니다. 프로젝트의 JAR파일을 해당 로컬 저장소에 설치하려면 `install`명령을 호출해야 합니다: 177 | ``` 178 | mvn install 179 | ``` 180 | 181 | *install* 명령은 컴파일, 테스트 및 프로젝트 코드를 패키징한 후 로컬 종속 저장소에 복사하여 다른 프로젝트에서 이를 종속적으로 참조할 수 있도록 합니다. 182 | 183 | 의존성에 대해 말하자면, 이제 Maven 빌드에 의존성을 선언할 때입니다. 184 | 185 | ## 종속성 선언 186 | 간단한 Hello World 예제는 완전히 자체적으로 포함되며 다른 추가라이브러리에 의존하지 않습니다. 그러나 대부분의 애플리케이션은 공통 및 복잡한 기능을 수행하기 위해 외부라이브러리에 의존합니다. 187 | 188 | 예를들어, "Hello World!"라고 말하는 것 이외에도, 애플리케이션이 현재 날짜와 시간을 출력하기를 원한다고 가정해보십시오. 기본 Java 라이브러리의 날짜 및 시간 기능을 사용할 수 있지만 Joda Time 라이브러리를 사용하면 더 재미있는 것을 만들 수 있습니다. 189 | 190 | 먼저, HelloWorld.java를 다음과 같이 변경합니다: 191 | `src/main/java/hello/HelloWorld.java` 192 | 193 | ```java 194 | package hello; 195 | 196 | import org.joda.time.LocalTime; 197 | 198 | public class HelloWorld { 199 | public static void main(String[] args) { 200 | LocalTime currentTime = new LocalTime(); 201 | System.out.println("The current local time is: " + currentTime); 202 | Greeter greeter = new Greeter(); 203 | System.out.println(greeter.sayHello()); 204 | } 205 | } 206 | ``` 207 | 208 | 여기서 `HelloWorld`는 Joda Time의 `LocalTime`클래스를 사용하여 현재시간을 가져와 출력합니다. 209 | 210 | 만약 지금 `mvn compile`을 실행하여 프로젝트를 빌드한다면 Joda Time을 컴파일 의존성으로 선언하지 않았으므로 빌드가 실패할 것입니다. *pom.xml*(`` 요소 내)에 다음 줄을 추가하여 수정할 수 있습니다. 211 | ```xml 212 | 213 | 214 | joda-time 215 | joda-time 216 | 2.9.2 217 | 218 | 219 | ``` 220 | 221 | 이 XML 블록은 프로젝트에 대한 종속성 목록을 선언합니다. 특히 Joda Time 라이브러리에 대한 단일 종속성을 선언합니다. ``요소 내에서 종속성은 세가지 하위요소에 의해 정의됩니다. 222 | 223 | * `` - 종속성이 속한 그룹 또는 조직입니다. 224 | * `` - 필요한 라이브러리입니다. 225 | * `` - 필요한 라이브러리의 특정 버전입니다. 226 | 227 | 기본적으로, 모든 종속성은 `compile`종속성으로 범위가 지정됩니다. 즉 컴파일시 사용이 가능해야 합니다(WAR 파일을 빌드하는 경우 WAR의 */WEB-INF/libs* 폴더 포함). 추가적으로 다음 스코프 중 하나를 지정하는 ``요소를 지정할 수 있습니다. 228 | 229 | * `provided` - 프로젝트 코드를 컴파일 하는데 필요하지만, 코드를 실행하는 컨테이너(예: Java Servlet API)에 의해 런타임에 제공되는 종속성입니다. 230 | 231 | * `test` - 테스트를 컴파일하고 실행하는데 사용되지만, 프로젝트의 런타임 코드를 작성하거나 실행할 때는 필요하지 않은 종속성입니다. 232 | 233 | 이제 `mvn complire` 또는 `mvn package`를 실행하면 Maven은 Maven 중앙 저장소로부터 Joda Time 종속성을 가져와 해결할 것이며 빌드는 성공할 것입니다. 234 | 235 | ## 테스트 작성하기 236 | 처음 JUnit 종속성을 test scope로 pom.xml에 추가합니다: 237 | 238 | ```xml 239 | 240 | junit 241 | junit 242 | 4.12 243 | test 244 | 245 | ``` 246 | 247 | 그리고 다음과 같이 테스트케이스를 만듭니다: 248 | `src/test/java/hello/GreeterTest.java` 249 | 250 | ```java 251 | package hello; 252 | 253 | import static org.hamcrest.CoreMatchers.containsString; 254 | import static org.junit.Assert.*; 255 | 256 | import org.junit.Test; 257 | 258 | public class GreeterTest { 259 | 260 | private Greeter greeter = new Greeter(); 261 | 262 | @Test 263 | public void greeterSaysHello() { 264 | assertThat(greeter.sayHello(), containsString("Hello")); 265 | } 266 | 267 | } 268 | ``` 269 | 270 | Maven은 "surefire"라는 플러그인을 단위테스트에 사용합니다. 이 플러그인의 기본 구성은 컴파일 및 `src/test/java`의 모든 클래스를 `*Test*`와 일치하는 이름으로 실행합니다. 명령줄에서 다음과 같이 실행할 수 있습니다. 271 | ``` 272 | mvn test 273 | ``` 274 | 275 | 또는 앞서 설명한 대로 `mvn install`단계를 사용하십시오(여기서 "test"는 "install"의 단계로 포함됩니다). 276 | 277 | 완료된 `pom.xml`파일은 다음과 같습니다: 278 | 279 | `pom.xml` 280 | 281 | ```xml 282 | 283 | 285 | 4.0.0 286 | 287 | org.springframework 288 | gs-maven 289 | jar 290 | 0.1.0 291 | 292 | 293 | 1.8 294 | 1.8 295 | 296 | 297 | 298 | 299 | 300 | joda-time 301 | joda-time 302 | 2.9.2 303 | 304 | 305 | 306 | 307 | junit 308 | junit 309 | 4.12 310 | test 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | org.apache.maven.plugins 319 | maven-shade-plugin 320 | 2.1 321 | 322 | 323 | package 324 | 325 | shade 326 | 327 | 328 | 329 | 330 | hello.HelloWorld 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | ``` 342 | 343 | > 완료된 **pom.xml**파일은 간편한 JAR 파일 실행을 위해 [Maven Shade Plugin](https://maven.apache.org/plugins/maven-shade-plugin/)을 사용합니다. 이 가이드는 특정 플러그인을 사용하지 않고 Maven을 사용하는 것에 초점을 두었습니다. 344 | 345 | ## 요약 346 | 축하합니다! Java 프로젝트 빌드시 간단하면서도 효과적인 Maven 프로젝트 정의를 작성했습니다. 347 | 348 | ## 추가로 볼만한 것 349 | 다음 가이드 또한 도움이 될 수 있습니다. 350 | * [Gradle로 Java프로젝트 빌드하기](https://spring.io/guides/gs/gradle/) 351 | -------------------------------------------------------------------------------- /gs-messaging-rabbitmq/README.md: -------------------------------------------------------------------------------- 1 | ## Messaging with RabbitMQ 2 | 이 가이드는 메시지를 게시하고 구독하는 RabbitMQ AMQP 서버를 설정하는 과정을 안내한다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | Spring AMQP의 `RabbitTemplate`을 사용하여 메시지를 게시하고 `MessageListenerAdapter`를 사용하여 [POJO](http://spring.io/understanding/POJO)를 구독하는 어플리케이션을 만들 것이다. 6 | 7 | ## 무엇이 필요한가? 8 | * 약 15분 9 | * 선호하는 텍스트 에디터 또는 IDE 10 | * [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 혹은 그 이상 11 | * [Gradle 4+](http://www.gradle.org/downloads) 혹은 [Maven 3.2+](https://maven.apache.org/download.cgi) 12 | * 코드를 IDE로 직접 가져올 수도 있다: 13 | - [Spring Tool Suite (STS)](http://spring.io/guides/gs/sts) 14 | - [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea/) 15 | - RabbitMQ server (아래 설치 지침) 16 | 17 | ## 이 가이드를 완료하는 방법 18 | 대부분의 [Spring Getting Started](http://spring.io/guides) 가이드와 마찬가지로, 처음부터 시작하여 각 단계를 완료하거나 이미 익숙한 기본 설정 단계를 건너뛸 수 있다. 어느 쪽이든 코드가 작동한다. 19 | 20 | **처음부터 시작하려면** [Gradle로 빌드하기](#Gradle로-빌드하기)로 이동하시오. 21 | 22 | **기본 사항을 건너뛰려면** 다음을 수행하시오: 23 | 24 | * 이 가이드의 소스 저장소를 [다운로드](https://github.com/spring-guides/gs-messaging-rabbitmq/archive/master.zip)하여 압축을 풀거나 [Git](http://spring.io/understanding/Git): `git clone https://github.com/spring-guides/gs-messaging-rabbitmq.git` 을 사용하여 clone 하시오. 25 | * cd into `gs-messaging-rabbitmq/initial` 26 | * [RabbitMQ message receiver 만들기](#RabbitMQ-message-receiver-만들기)로 넘어가시오. 27 | 28 | **끝나면**, `gs-messaging-rabbitmq/complete` 코드와 결과를 비교할 수 있다. 29 | 30 | ## Gradle로 빌드하기 31 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 [Gradle](http://gradle.org/) 및 [Maven](https://maven.apache.org/)으로 작업하는 데 필요한 코드가 여기에 있다. 둘다 익숙하지 않은 경우 [Gradle로 Java 프로젝트 만들기](http://spring.io/guides/gs/gradle) 또는 [Maven으로 Java 프로젝트 만들기](http://spring.io/guides/gs/maven)를 참조하시오. 32 | 33 | ### 디렉토리 구조 만들기 34 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 `mkdir -p src/main/java/hello` 를 사용하여 다음 하위 디렉토리 구조를 작성한다: 35 | 36 | ``` 37 | └── src 38 | └── main 39 | └── java 40 | └── hello 41 | ``` 42 | 43 | ### Gradle 빌드 파일 만들기 44 | 아래는 [초기 Gradle 빌드 파일](https://github.com/spring-guides/gs-messaging-rabbitmq/blob/master/initial/build.gradle)이다. 45 | 46 | `build.gradle` 47 | 48 | ```gradle 49 | buildscript { 50 | repositories { 51 | mavenCentral() 52 | } 53 | dependencies { 54 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 55 | } 56 | } 57 | 58 | apply plugin: 'java' 59 | apply plugin: 'eclipse' 60 | apply plugin: 'idea' 61 | apply plugin: 'org.springframework.boot' 62 | apply plugin: 'io.spring.dependency-management' 63 | 64 | bootJar { 65 | baseName = 'gs-messaging-rabbitmq' 66 | version = '0.1.0' 67 | } 68 | 69 | repositories { 70 | mavenCentral() 71 | } 72 | 73 | sourceCompatibility = 1.8 74 | targetCompatibility = 1.8 75 | 76 | dependencies { 77 | compile("org.springframework.boot:spring-boot-starter-amqp") 78 | testCompile("junit:junit") 79 | } 80 | ``` 81 | 82 | [Spring Boot gradle plugin](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html)은 다음과 같은 여러 편리한 기능을 제공한다: 83 | 84 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 85 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 86 | * [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)와 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 87 | 88 | ## Maven으로 빌드하기 89 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 [Maven](https://maven.apache.org/)으로 작업하는 데 필요한 코드가 여기에 있다. Maven이 익숙하지 않은 경우 [Maven으로 Java 프로젝트 만들기](http://spring.io/guides/gs/maven)를 참조하시오. 90 | 91 | ### 디렉토리 구조 만들기 92 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 `mkdir -p src/main/java/hello`를 사용하여 다음 하위 디렉토리 구조를 작성한다: 93 | 94 | ``` 95 | └── src 96 | └── main 97 | └── java 98 | └── hello 99 | ``` 100 | 101 | `pom.xml` 102 | 103 | ```xml 104 | 105 | 107 | 4.0.0 108 | 109 | org.springframework 110 | gs-messaging-rabbitmq 111 | 0.1.0 112 | 113 | 114 | org.springframework.boot 115 | spring-boot-starter-parent 116 | 2.0.5.RELEASE 117 | 118 | 119 | 120 | 1.8 121 | 122 | 123 | 124 | 125 | org.springframework.boot 126 | spring-boot-starter-amqp 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | org.springframework.boot 135 | spring-boot-maven-plugin 136 | 137 | 138 | 139 | 140 | 141 | ``` 142 | 143 | [Spring Boot Maven plugin](https://docs.spring.io/spring-boot/docs/current/maven-plugin)은 다음과 같은 여러 편리한 기능을 제공한다: 144 | 145 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 146 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 147 | * [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)와 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 148 | 149 | ## IDE로 빌드하기 150 | * [Spring Tool Suite](http://spring.io/guides/gs/sts/)에서 import 하는 가이드를 읽으시오. 151 | * [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea)에서 가이드를 읽으시오. 152 | 153 | ## RabbitMQ broker 설정 154 | 메시징 어플리케이션을 빌드하기 전에 메시지 수신 및 전송을 처리할 서버를 설정해야 한다. 155 | 156 | RabbitMQ는 AMQP 서버이다. 서버는 http://www.rabbitmq.com/download.html 에서 무료로 사용할 수 있다. 수동으로 다운로드하거나 homebrew가 설치된 Mac을 사용하는 경우 다음을 입력하여 사용할 수 있다: 157 | 158 | ``` 159 | brew install rabbitmq 160 | ``` 161 | 서버 압축을 풀면 기본 설정으로 시작할 수 있다. 162 | 163 | ``` 164 | rabbitmq-server 165 | ``` 166 | 167 | 다음과 같은 메시지가 나타난다. 168 | 169 | ``` 170 | RabbitMQ 3.1.3. Copyright (C) 2007-2013 VMware, Inc. 171 | ## ## Licensed under the MPL. See http://www.rabbitmq.com/ 172 | ## ## 173 | ########## Logs: /usr/local/var/log/rabbitmq/rabbit@localhost.log 174 | ###### ## /usr/local/var/log/rabbitmq/rabbit@localhost-sasl.log 175 | ########## 176 | Starting broker... completed with 6 plugins. 177 | ``` 178 | 179 | 또한 로컬에서 도커가 실행되는 경우 [Docker Compose](https://docs.docker.com/compose/)를 사용하여 RabbitMQ 서버를 빠르게 시작할 수 있다. Github의 "complete" 프로젝트의 root에 `docker-compose.yml`가 있다. `docker-compose.yml`는 매우 간단하다: 180 | 181 | `docker-compose.yml` 182 | 183 | ```yml 184 | rabbitmq: 185 | image: rabbitmq:management 186 | ports: 187 | - "5672:5672" 188 | - "15672:15672" 189 | ``` 190 | 191 | 현재 디렉토리에 있는 이 파일을 사용하여 `docker-compose`를 실행하면 컨테이너에서 RabbitMQ를 실행할 수 있다. 192 | 193 | ## RabbitMQ message receiver 만들기 194 | 메시징 기반 어플리케이션에서는 게시된 메시지에 응답할 수 있는 수신자(receiver)를 만들어야 한다. 195 | 196 | `src/main/java/hello/Receiver.java` 197 | 198 | ```java 199 | package hello; 200 | 201 | import java.util.concurrent.CountDownLatch; 202 | import org.springframework.stereotype.Component; 203 | 204 | @Component 205 | public class Receiver { 206 | 207 | private CountDownLatch latch = new CountDownLatch(1); 208 | 209 | public void receiveMessage(String message) { 210 | System.out.println("Received <" + message + ">"); 211 | latch.countDown(); 212 | } 213 | 214 | public CountDownLatch getLatch() { 215 | return latch; 216 | } 217 | 218 | } 219 | ``` 220 | 221 | `Receiver`는 메시지를 수신하는 메소드를 정의하는 간단한 POJO이다. 메시지를 수신하기 위해 등록할 때 원하는 이름을 지정할 수 있다. 222 | 223 | > 편의상 이 POJO에는 `CountDownLatch`가 있다. 이것은 메시지가 수신되었음을 알릴 수 있다. 이는 프로덕션 어플리케이션에서 구현할 필요가 없다는 것이다.. 224 | 225 | ## listener 등록 및 메시지 보내기 226 | Spring AMQP의 `RabbitTemplate`은 RabbitMQ로 메시지를 주고받는데 필요한 모든 것을 제공한다. 특히 다음을 구성해야 한다: 227 | 228 | * message listener container 229 | * 큐, 교환 및 이들 사이의 바인딩 선언 230 | * listener를 테스트하기 위해 일부 메시지를 보내는 component 231 | 232 | > Spring Boot는 자동으로 connection factory와 RabbitTemplate을 생성하여 작성해야 하는 코드의 양을 줄여준다. 233 | 234 | `RabbitTemplate`을 사용하여 메시지를 보내면 메시지 수신을 위해 Receiver를 message listener conatiner에 등록한다. connection factory는 둘 다 구동하여 RabbitMQ 서버에 연결할 수 있게 한다. 235 | 236 | `src/main/java/hello/Application.java` 237 | 238 | ```java 239 | package hello; 240 | 241 | import org.springframework.amqp.core.Binding; 242 | import org.springframework.amqp.core.BindingBuilder; 243 | import org.springframework.amqp.core.Queue; 244 | import org.springframework.amqp.core.TopicExchange; 245 | import org.springframework.amqp.rabbit.connection.ConnectionFactory; 246 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; 247 | import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; 248 | import org.springframework.boot.SpringApplication; 249 | import org.springframework.boot.autoconfigure.SpringBootApplication; 250 | import org.springframework.context.annotation.Bean; 251 | 252 | @SpringBootApplication 253 | public class Application { 254 | 255 | static final String topicExchangeName = "spring-boot-exchange"; 256 | 257 | static final String queueName = "spring-boot"; 258 | 259 | @Bean 260 | Queue queue() { 261 | return new Queue(queueName, false); 262 | } 263 | 264 | @Bean 265 | TopicExchange exchange() { 266 | return new TopicExchange(topicExchangeName); 267 | } 268 | 269 | @Bean 270 | Binding binding(Queue queue, TopicExchange exchange) { 271 | return BindingBuilder.bind(queue).to(exchange).with("foo.bar.#"); 272 | } 273 | 274 | @Bean 275 | SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, 276 | MessageListenerAdapter listenerAdapter) { 277 | SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(); 278 | container.setConnectionFactory(connectionFactory); 279 | container.setQueueNames(queueName); 280 | container.setMessageListener(listenerAdapter); 281 | return container; 282 | } 283 | 284 | @Bean 285 | MessageListenerAdapter listenerAdapter(Receiver receiver) { 286 | return new MessageListenerAdapter(receiver, "receiveMessage"); 287 | } 288 | 289 | public static void main(String[] args) throws InterruptedException { 290 | SpringApplication.run(Application.class, args).close(); 291 | } 292 | 293 | } 294 | ``` 295 | 296 | `@SpringBootApplication` 은 다음을 모두 추가하는 편리한 주석이다: 297 | 298 | * `@Configuration` 은 클래스를 어플리케이션 context의 bean 정의 소스로 태그 지정한다. 299 | * `@EnableAutoConfiguration` 은 Spring Boot에게 클래스 경로 설정, 다른 bean 및 다양한 프로퍼티 설정을 기반으로 bean 추가를 시작하도록 한다. 300 | * 일반적으로 `@EnableWebMvc` 를 Spring MVC app에 추가할 것이지만, Spring Boot는 클래스 경로에서 **spring-webmvc**를 발견할 때 그것을 자동으로 추가한다. 이것은 어플리케이션에 웹 어플리케이션으로 플래그를 지정하고 `DispatcherServlet` 설정과 같은 주요 동작을 활성화 한다. 301 | * `@ComponentScan` 은 `hello` 패키지에서 다른 컴포넌트, 구성 및 서비스를 찾아서 컨트롤러를 찾을 수 있도록 Spring에 지시한다. 302 | 303 | `main()` 메소드는 `Spring Boot의 SpringApplicaiton.run()` 메소드를 사용하여 어플리케이션을 시작한다. 한줄의 XML이 없다는 것을 알고 있었는가? **web.xml** 파일도 없다. 이 웹 어플리케이션은 100% 순수 자바이며 인프라 구성에 대해 다룰 필요가 없다. 304 | 305 | `listenerAdapter()` 메소드에 정의된 bean은 `container()`에 정의 된 컨테이너에 메시지 리스너로 등록된다. 그것은 "spring-boot" 큐에 있는 메시지를 수신한다. `Receiver` 클래스는 POJO이기 때문에 `MessageListenerAdapter`에 감싸야 한다. 여기서 `receiveMessage`를 호출한다. 306 | 307 | > JMS 큐와 AMQP 큐는 다른 의미를 가진다. 예를들어 JMS는 대기중인 메시지를 하나의 consumer에게만 보낸다. 반면 AMQP 큐는 동일한 작업을 수행하지만 AMQP producer는 큐에 직접적으로 메시지를 보내지 않는다. 그 대신 메시지가 교환기로 보내지며, 단일 큐로 이동하거나 여러 큐로 팬아웃되어 JMS topic들의 concept를 에뮬레이팅한다. 자세한 것은 [Understanding AMQP](http://spring.io/understanding/AMQP)를 참조하시오. 308 | 309 | message listener container 및 receiver bean은 메시지를 수신하는 데 필요한 모든 것이다. 메시지를 보내려면 Rabbit template이 필요하다. 310 | 311 | `queue()` 메소드는 AMQP 큐를 생성한다. `exchange()` 메소드는 topic 교환을 생성한다. `binding()` 메소드는 RabbitTemplate이 교환기에 발행(publish)할 때 발생하는 동작을 정의하여 둘을 서로 바인딩한다. 312 | 313 | > Spring AMQP는 `Queue`, `TopicExchange` 그리고 `Binding`이 제대로 설정되기 위해 최상위 Spring bean으로 선언할 것을 요구한다. 314 | 315 | 이 경우, topic 교환을 사용하고 큐는 `foo.bar`로 시작하는 라우팅 키로 보내진 모든 메시지를 의미하는 `foo.bar.#`로 묶여있다. 이는 큐로 라우팅 된다. 316 | 317 | ## 테스트 메시지 보내기 318 | 테스트 메시지는 `CommandLineRunner`에 의해 보내진다. `CommandLineRunner`는 receiver의 latch를 대기하고 어플리케이션 컨텍스트를 닫는다: 319 | 320 | `src/main/java/hello/Runner.java` 321 | 322 | ```java 323 | package hello; 324 | 325 | import java.util.concurrent.TimeUnit; 326 | 327 | import org.springframework.amqp.rabbit.core.RabbitTemplate; 328 | import org.springframework.boot.CommandLineRunner; 329 | import org.springframework.stereotype.Component; 330 | 331 | @Component 332 | public class Runner implements CommandLineRunner { 333 | 334 | private final RabbitTemplate rabbitTemplate; 335 | private final Receiver receiver; 336 | 337 | public Runner(Receiver receiver, RabbitTemplate rabbitTemplate) { 338 | this.receiver = receiver; 339 | this.rabbitTemplate = rabbitTemplate; 340 | } 341 | 342 | @Override 343 | public void run(String... args) throws Exception { 344 | System.out.println("Sending message..."); 345 | rabbitTemplate.convertAndSend(Application.topicExchangeName, "foo.bar.baz", "Hello from RabbitMQ!"); 346 | receiver.getLatch().await(10000, TimeUnit.MILLISECONDS); 347 | } 348 | 349 | } 350 | ``` 351 | 352 | 템플릿은 바인딩과 일치하는 라우팅 키 `foo.bar.baz`를 사용하여 메시지를 교환기로 라우팅한다. 353 | 354 | runner는 테스트에서 mock으로 될 수 있으며, receiver를 따로따로 테스트할 수 있다. 355 | 356 | ## 어플리케이션 실행하기 357 | `main()` 메소드는 Spring 어플리케이션 컨택스트를 생성하여 프로세스를 시작한다. 그러면 message listener container가 시작되어 메시지 수신을 시작한다. `Runner` bean이 자동으로 시작된다: 어플리케이션 컨텍스트에서 `RabbitTemplate`을 검색하고 "spring-boot" 큐에 "Hello from RabbitMQ!" 메시지를 보낸다. 마지막으로 Spring 어플리케이션 컨텍스트를 닫고 어플리케이션이 종료된다. 358 | 359 | ## 실행 가능한 JAR 만들기 360 | Gradle 또는 Maven을 사용하여 커맨드 라인에서 어플리케이션을 실행할 수 있다. 또는 모든 필요한 의존성, 클래스 및 리소스 포함하는 단일 실행 가능한 JAR 파일을 빌드하고 실행할 수 있다. 따라서 개발 생명주기(life cycle), 다양한 환경에 걸쳐 어플리케이션으로 서비스를 쉽게 제공 및 배포할 수 있다. 361 | 362 | Gradle을 사용하는 경우 `./gradlew bootRun`을 사용하여 어플리케이션을 실행할 수 있다. 또는 `./gradlew build`를 사용하여 JAR 파일을 작성할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 363 | 364 | ``` 365 | java -jar build/libs/gs-messaging-rabbitmq-0.1.0.jar 366 | ``` 367 | 368 | Maven을 사용하는 경우, `./mvnw spring-boot:run`을 사용하여 어플리케이션을 실행할 수 있다. 또는 `./mvnw clean package`로 JAR 파일을 빌드할 수 있다. 그런다음 JAR 파일을 실행할 수 있다: 369 | 370 | ``` 371 | java -jar target/gs-messaging-rabbitmq-0.1.0.jar 372 | ``` 373 | 374 | > 위 절차는 실행 가능한 JAR를 생성한다. 고전의 [WAR 파일을 빌드](http://spring.io/guides/gs/convert-jar-to-war/)하도록 선택할 수도 있다. 375 | 376 | 다음 출력을 볼 수 있다: 377 | 378 | ``` 379 | Sending message... 380 | Received 381 | ``` 382 | 383 | ## 요약 384 | 축하합니다! Spring과 RabbitMQ로 간단한 게시(publish)와 구독(subscribe) 어플리케이션을 개발했다. [이곳](https://docs.spring.io/spring-amqp/reference/html/_introduction.html#quick-tour)에서 Spring과 RabbitMQ를 이용하여 여기보다 더 많은 것을 할 수 있다. 385 | 386 | ## 추가로 볼만한 것 387 | 다음 가이드 또한 도움이 될 수 있습니다: 388 | 389 | * [Messaging with Redis](https://spring.io/guides/gs/messaging-redis/) 390 | * [Messaging with JMS](https://spring.io/guides/gs/messaging-jms/) 391 | * [Building an Application with Spring Boot](https://spring.io/guides/gs/spring-boot/) -------------------------------------------------------------------------------- /gs-relational-data-access/README.adoc: -------------------------------------------------------------------------------- 1 | == Spring에서 JDBC를 사용하여 관계형 데이터 액세스하기 2 | 이 가이드는 Spring에서 관계형 데이터를 액세스하는 과정을 안내한다. 3 | 4 | == 무엇을 만들게 되는가 5 | Spring의 `JdbcTemplate` 을 사용하여 관계형 데이터베이스에 저장된 데이터에 액세스하는 어플리케이션을 만들 것이다. 6 | 7 | == 무엇이 필요한가 8 | * 약 15분 9 | * 선호하는 텍스트 에디터 혹은 IDE 10 | * http://www.oracle.com/technetwork/java/javase/downloads/index.html[JDK 1.8] 혹은 그 이상 11 | * http://www.gradle.org/downloads[Gradle 4+] 혹은 https://maven.apache.org/download.cgi[Maven 3.2+] 12 | * 코드를 IDE로 직접 가져올 수도 있다. 13 | ** http://spring.io/guides/gs/sts[Spring Tool Suite (STS)] 14 | ** http://spring.io/guides/gs/intellij-idea/[IntelliJ IDEA] 15 | 16 | == 이 가이드를 완료하는 방법 17 | 대부분의 http://spring.io/guides[Spring Getting Started] 가이드와 마찬가지로, 처음부터 시작하여 각 단계를 완료하거나 이미 익숙한 기본 설정 단계를 건너뛸 수 있다. 어느 쪽이든 코드가 작동한다. 18 | 19 | 처음부터 시작하려면 <>로 이동하시오. 20 | 21 | 기본 사항을 건너뛰려면 다음을 수행하라: 22 | 23 | * 이 가이드의 소스 저장소를 https://github.com/spring-guides/gs-relational-data-access/archive/master.zip[다운로드]하여 압축을 풀거나 http://spring.io/understanding/Git[Git]: `git clone https://github.com/spring-guides/gs-relational-data-access.git` 을 사용하여 clone 하시오. 24 | * cd into `gs-relational-data-access/initial` 25 | * <>로 넘어가시오. 26 | 27 | **끝나면** `gs-relational-data-access/complete` 코드와 결과를 비교할 수 있다. 28 | 29 | [[build-with-gradle]] 30 | == Gradle로 빌드하기 31 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 http://gradle.org/[Gradle] 및 https://maven.apache.org/[Maven]으로 작업하는 데 필요한 코드가 여기에 있다. 둘다 익숙하지 않은 경우 http://spring.io/guides/gs/gradle[Gradle로 Java 프로젝트 만들기] 또는 http://spring.io/guides/gs/maven[Maven으로 Java 프로젝트 만들기]를 참조하시오. 32 | 33 | === 디렉토리 구조 만들기 34 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 mkdir -p src/main/java/hello를 사용하여 다음 하위 디렉토리 구조를 작성한다: 35 | 36 | [source,indent=0] 37 | ---- 38 | └── src 39 | └── main 40 | └── java 41 | └── hello 42 | ---- 43 | 44 | === Gradle 빌드 파일 만들기 45 | 아래는 https://github.com/spring-guides/gs-relational-data-access/blob/master/initial/build.gradle[초기 Gradle 빌드 파일]이다. 46 | 47 | `build.gradle` 48 | 49 | [source,gradle,indent=0] 50 | ---- 51 | buildscript { 52 | repositories { 53 | mavenCentral() 54 | } 55 | dependencies { 56 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 57 | } 58 | } 59 | 60 | apply plugin: 'java' 61 | apply plugin: 'eclipse' 62 | apply plugin: 'idea' 63 | apply plugin: 'org.springframework.boot' 64 | apply plugin: 'io.spring.dependency-management' 65 | 66 | bootJar { 67 | baseName = 'gs-relational-data-access' 68 | version = '0.1.0' 69 | } 70 | 71 | repositories { 72 | mavenCentral() 73 | } 74 | 75 | sourceCompatibility = 1.8 76 | targetCompatibility = 1.8 77 | 78 | dependencies { 79 | compile("org.springframework.boot:spring-boot-starter") 80 | compile("org.springframework:spring-jdbc") 81 | compile("com.h2database:h2") 82 | testCompile("junit:junit") 83 | } 84 | ---- 85 | 86 | https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html[Spring Boot Gralde 플러그인]은 다음과 같은 여러 편리한 기능을 제공한다: 87 | 88 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 89 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 90 | * https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml[Spring Boot 의존성]과 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 91 | 92 | == Maven으로 빌드하기 93 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 https://maven.apache.org/[Maven]으로 작업하는 데 필요한 코드가 여기에 있다. Maven이 익숙하지 않은 경우 http://spring.io/guides/gs/maven[Maven으로 Java 프로젝트 만들기]를 참조하시오. 94 | 95 | === 디렉토리 구조 만들기 96 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 mkdir -p src/main/java/hello를 사용하여 다음 하위 디렉토리 구조를 작성한다: 97 | 98 | [source,indent=0] 99 | ---- 100 | └── src 101 | └── main 102 | └── java 103 | └── hello 104 | ---- 105 | 106 | `pom.xml` 107 | 108 | [source,xml,indent=0] 109 | ---- 110 | 111 | 113 | 4.0.0 114 | 115 | org.springframework 116 | gs-relational-data-access 117 | 0.1.0 118 | 119 | 120 | org.springframework.boot 121 | spring-boot-starter-parent 122 | 2.0.5.RELEASE 123 | 124 | 125 | 126 | 1.8 127 | 128 | 129 | 130 | 131 | org.springframework.boot 132 | spring-boot-starter-jdbc 133 | 134 | 135 | com.h2database 136 | h2 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | org.springframework.boot 145 | spring-boot-maven-plugin 146 | 147 | 148 | 149 | 150 | 151 | ---- 152 | 153 | https://docs.spring.io/spring-boot/docs/current/maven-plugin[Spring Boot Maven 플러그인]은 다음과 같은 여러 편리한 기능을 제공한다: 154 | 155 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 156 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 157 | * https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml[Spring Boot 의존성]과 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 158 | 159 | == IDE로 빌드하기 160 | * http://spring.io/guides/gs/sts/[Spring Tool Suite]에서 import 하는 가이드를 읽으시오. 161 | * http://spring.io/guides/gs/intellij-idea[IntelliJ IDEA]에서 가이드를 읽으시오. 162 | 163 | [[create-a-customer-object]] 164 | == Customer 객체 만들기 165 | 아래에서 작업할 간단한 데이터 액세스 로직은 고객의 이름과 성을 관리한다. 이 데이터를 어플리케이션 수준에서 표시하려면 고객 클래스를 생성하시오. 166 | 167 | `src/main/java/hello/Customer.java` 168 | 169 | [source,java,indent=0] 170 | ---- 171 | package hello; 172 | 173 | public class Customer { 174 | private long id; 175 | private String firstName, lastName; 176 | 177 | public Customer(long id, String firstName, String lastName) { 178 | this.id = id; 179 | this.firstName = firstName; 180 | this.lastName = lastName; 181 | } 182 | 183 | @Override 184 | public String toString() { 185 | return String.format( 186 | "Customer[id=%d, firstName='%s', lastName='%s']", 187 | id, firstName, lastName); 188 | } 189 | 190 | // getters & setters omitted for brevity 191 | } 192 | ---- 193 | 194 | == 데이터 저장 및 검색 195 | Spring은 SQL 관계형 데이터베이스 및 JDBC에서 쉽게 작업할 수 있도록 `JdbcTemplate` 이라는 템플릿 클래스를 제공한다. 대부분의 JDBC 코드는 리소스 확보, 연결 관리, 예외 처리 및 코드 오류와는 전혀 관련이 없는 일반적인 오류 검사에 빠져있다. `JdbcTemplate` 은 이 모든 것을 처리한다. 당신이 할 일은 당면한 일에 집중하는 것 뿐이다. 196 | 197 | `src/main/java/hello/Application.java` 198 | 199 | [source,java,indent=0] 200 | ---- 201 | package hello; 202 | 203 | import org.slf4j.Logger; 204 | import org.slf4j.LoggerFactory; 205 | import org.springframework.beans.factory.annotation.Autowired; 206 | import org.springframework.boot.CommandLineRunner; 207 | import org.springframework.boot.SpringApplication; 208 | import org.springframework.boot.autoconfigure.SpringBootApplication; 209 | import org.springframework.jdbc.core.JdbcTemplate; 210 | 211 | import java.util.Arrays; 212 | import java.util.List; 213 | import java.util.stream.Collectors; 214 | 215 | @SpringBootApplication 216 | public class Application implements CommandLineRunner { 217 | 218 | private static final Logger log = LoggerFactory.getLogger(Application.class); 219 | 220 | public static void main(String args[]) { 221 | SpringApplication.run(Application.class, args); 222 | } 223 | 224 | @Autowired 225 | JdbcTemplate jdbcTemplate; 226 | 227 | @Override 228 | public void run(String... strings) throws Exception { 229 | 230 | log.info("Creating tables"); 231 | 232 | jdbcTemplate.execute("DROP TABLE customers IF EXISTS"); 233 | jdbcTemplate.execute("CREATE TABLE customers(" + 234 | "id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))"); 235 | 236 | // Split up the array of whole names into an array of first/last names 237 | List splitUpNames = Arrays.asList("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long").stream() 238 | .map(name -> name.split(" ")) 239 | .collect(Collectors.toList()); 240 | 241 | // Use a Java 8 stream to print out each tuple of the list 242 | splitUpNames.forEach(name -> log.info(String.format("Inserting customer record for %s %s", name[0], name[1]))); 243 | 244 | // Uses JdbcTemplate's batchUpdate operation to bulk load data 245 | jdbcTemplate.batchUpdate("INSERT INTO customers(first_name, last_name) VALUES (?,?)", splitUpNames); 246 | 247 | log.info("Querying for customer records where first_name = 'Josh':"); 248 | jdbcTemplate.query( 249 | "SELECT id, first_name, last_name FROM customers WHERE first_name = ?", new Object[] { "Josh" }, 250 | (rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name")) 251 | ).forEach(customer -> log.info(customer.toString())); 252 | } 253 | } 254 | ---- 255 | 256 | `@SpringBootApplication` 은 다음을 모두 추가하는 편리한 주석이다: 257 | 258 | * `@Configuration` 은 클래스를 어플리케이션 context의 bean 정의 소스로 태그 지정한다. 259 | * `@EnableAutoConfiguration` 은 Spring Boot에게 클래스 경로 설정, 다른 bean 및 다양한 프로퍼티 설정을 기반으로 bean 추가를 시작하도록 한다. 260 | * `@ComponentScan` 은 `hello` 패키지에서 다른 컴포넌트, 구성 및 서비스를 찾아서 컨트롤러를 찾을 수 있도록 Spring에 지시한다. 이 경우에는, 아무것도 없다. 261 | 262 | `main()` 메소드는 `Spring Boot의 SpringApplicaiton.run()` 메소드를 사용하여 어플리케이션을 시작한다. 한줄의 XML이 없다는 것을 알고 있었는가? **web.xml** 파일도 없다. 이 웹 어플리케이션은 100% 순수 자바이며 인프라 구성에 대해 다룰 필요가 없다. 263 | 264 | Spring Boot는 in-memory 관계형 데이터베이스 엔진인 **H2**를 지원하고 자동으로 연결을 생성한다. **spring-jdbc**를 사용하기 때문에 Spring Boot는 자동으로 `JdbcTemplate` 을 생성한다. `@Autowired JdbcTemplate` 필드는 자동으로 이 필드를 로드하여 사용할 수 있게 한다. 265 | 266 | 이 `Application` 클래스는 Spring Boot의 `CommandLineRunner` 를 구현한다. 즉, 어플리케이션 컨텍스트가 로드된 후 `run()` 메소드를 실행한다. 267 | 268 | 먼저, `JdbcTemplate의 `execute` 메소드를 사용하여 DDL을 실행한다. 269 | 270 | 둘째, 문자열 리스트를 가져와 Java 8 스트림을 사용하여 Java 배열의 firstname/lastname 쌍으로 분리한다. 271 | 272 | 그런 다음 `JdbcTemplate의 `batchUpdate` 메소드를 사용하여 새로 생생된 테이블에 레코드를 추가한다. 메소드 호출의 첫 번째 인수는 쿼리 문자열이며, 마지막 인수(`Object` 배열)는 "?" 문자가 있는 쿼리에 대체할 변수이다. 273 | 274 | ==== 275 | 단일 insert의 경우, `JdbcTemplate의 `insert` 메소드가 좋다. 그러나 여러개의 insert일 경우 `batchUpdate` 를 사용하는 것이 좋다. 276 | ==== 277 | 278 | ==== 279 | 변수에 바인드하도록 JDBC에 지시하여 https://en.wikipedia.org/wiki/SQL_injection[SQL injection 공격]을 피하기 위해 인수에 `?` 를 사용하시오. 280 | ==== 281 | 282 | 마지막으로 `query` 메소드를 사용하여 테이블에서 조건과 일치하는 레코드를 검색한다. 다시 "?" 인수를 사용하여 쿼리 매개 변수를 만들고 호출할 때 실제 값을 전달한다. 마지막 인수는 각 결과 행을 새 `Customer` 객체로 변환하는 데 사용되는 Java 8 람다이다. 283 | 284 | ==== 285 | Java 8 람다는 Spring의 `RowMapper` 와 같은 단일 메소드 인터페이스에 잘 매핑된다. Java 7 이전 버전을 사용하는 경우 익명 인터페이스 구현을 쉽게 플러그인할 수 있으며, 람다 expresion의 본문과 동일한 메소드 본문을 가질 수 있으며 Spring의 방해 없이 작동한다. 286 | ==== 287 | 288 | === 실행 가능한 JAR 만들기 289 | Gradle 또는 Maven을 사용하여 커맨드 라인에서 어플리케이션을 실행할 수 있다. 또는 모든 필요한 의존성, 클래스 및 리소스 포함하는 단일 실행 가능한 JAR 파일을 빌드하고 실행할 수 있다. 따라서 개발 생명주기(life cycle), 다양한 환경에 걸쳐 어플리케이션으로 서비스를 쉽게 제공 및 배포할 수 있다. 290 | 291 | Gradle을 사용하는 경우 `./gradlew bootRun` 을 사용하여 어플리케이션을 실행할 수 있다. 또는 `./gradlew build` 를 사용하여 JAR 파일을 작성할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 292 | 293 | [source,bash,indent=0] 294 | ---- 295 | java -jar build/libs/gs-relational-data-access-0.1.0.jar 296 | ---- 297 | 298 | Maven을 사용하는 경우 ./mvnw spring-boot:run을 사용하여 어플리케이션을 실행할 수 있다. 또는 ./mvnw clean package로 JAR 파일을 빌드할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 299 | 300 | [source,bash,indent=0] 301 | ---- 302 | java -jar target/gs-relational-data-access-0.1.0.jar 303 | ---- 304 | 305 | ==== 306 | 위 절차는 실행 가능한 JAR를 생성한다. 고전의 http://spring.io/guides/gs/convert-jar-to-war/[WAR 파일을 빌드]하도록 선택할 수도 있다. 307 | ==== 308 | 309 | 다음 출력을 볼 수 있다: 310 | 311 | [source,indent=0] 312 | ---- 313 | 2015-06-19 10:58:31.152 INFO 67731 --- [ main] hello.Application : Creating tables 314 | 2015-06-19 10:58:31.219 INFO 67731 --- [ main] hello.Application : Inserting customer record for John Woo 315 | 2015-06-19 10:58:31.220 INFO 67731 --- [ main] hello.Application : Inserting customer record for Jeff Dean 316 | 2015-06-19 10:58:31.220 INFO 67731 --- [ main] hello.Application : Inserting customer record for Josh Bloch 317 | 2015-06-19 10:58:31.220 INFO 67731 --- [ main] hello.Application : Inserting customer record for Josh Long 318 | 2015-06-19 10:58:31.230 INFO 67731 --- [ main] hello.Application : Querying for customer records where first_name = 'Josh': 319 | 2015-06-19 10:58:31.242 INFO 67731 --- [ main] hello.Application : Customer[id=3, firstName='Josh', lastName='Bloch'] 320 | 2015-06-19 10:58:31.242 INFO 67731 --- [ main] hello.Application : Customer[id=4, firstName='Josh', lastName='Long'] 321 | 2015-06-19 10:58:31.244 INFO 67731 --- [ main] hello.Application : Started Application in 1.693 seconds (JVM running for 2.054) 322 | ---- 323 | 324 | == 요약 325 | 축하합니다! 방금 Spring을 사용하여 간단한 JDBC 클라이언트를 개발했다. 326 | 327 | ==== 328 | Spring Boot에는 connection pool을 구성하고 커스터마이징을 위한 많은 기능이 있다 (예: in-memory 대신 외부 데이터베이스에 연결). 자세한 내용은 https://docs.spring.io/spring-boot/docs/2.0.5.RELEASE/reference/htmlsingle/#boot-features-configure-datasource[사용자 가이드]를 참조하시오. 329 | ==== 330 | 331 | == 다른 예제들 332 | 다음 가이드들도 도움이 될 것이다: 333 | 334 | * https://spring.io/guides/gs/accessing-data-jpa/[Accessing Data with JPA] 335 | * https://spring.io/guides/gs/accessing-data-mongodb/[Accessing Data with MongoDB] 336 | * https://spring.io/guides/gs/accessing-data-gemfire/[Accessing Data with GemFire] 337 | * https://spring.io/guides/gs/accessing-data-neo4j/[Accessing Data with Neo4j] 338 | * https://spring.io/guides/gs/accessing-data-mysql/[Accessing data with MySQL] 339 | * https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot] -------------------------------------------------------------------------------- /gs-relational-data-access/gs-relational-data-access/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | } 5 | dependencies { 6 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 7 | } 8 | } 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'eclipse' 12 | apply plugin: 'idea' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'io.spring.dependency-management' 15 | 16 | bootJar { 17 | baseName = 'gs-relational-data-access' 18 | version = '0.1.0' 19 | } 20 | 21 | repositories { 22 | mavenCentral() 23 | } 24 | 25 | sourceCompatibility = 1.8 26 | targetCompatibility = 1.8 27 | 28 | dependencies { 29 | compile("org.springframework.boot:spring-boot-starter") 30 | compile("org.springframework:spring-jdbc") 31 | compile("com.h2database:h2") 32 | testCompile("junit:junit") 33 | } 34 | 35 | -------------------------------------------------------------------------------- /gs-relational-data-access/gs-relational-data-access/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework 7 | gs-relational-data-access 8 | 0.1.0 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.0.5.RELEASE 14 | 15 | 16 | 17 | 1.8 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-jdbc 24 | 25 | 26 | com.h2database 27 | h2 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-maven-plugin 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /gs-relational-data-access/gs-relational-data-access/src/main/java/hello/Application.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.CommandLineRunner; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.jdbc.core.JdbcTemplate; 10 | 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | @SpringBootApplication 16 | public class Application implements CommandLineRunner { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(Application.class); 19 | 20 | public static void main(String args[]) { 21 | SpringApplication.run(Application.class, args); 22 | } 23 | 24 | @Autowired 25 | JdbcTemplate jdbcTemplate; 26 | 27 | @Override 28 | public void run(String... strings) throws Exception { 29 | 30 | log.info("Creating tables"); 31 | 32 | jdbcTemplate.execute("DROP TABLE customers IF EXISTS"); 33 | jdbcTemplate.execute("CREATE TABLE customers(" + 34 | "id SERIAL, first_name VARCHAR(255), last_name VARCHAR(255))"); 35 | 36 | // Split up the array of whole names into an array of first/last names 37 | List splitUpNames = Arrays.asList("John Woo", "Jeff Dean", "Josh Bloch", "Josh Long").stream() 38 | .map(name -> name.split(" ")) 39 | .collect(Collectors.toList()); 40 | 41 | // Use a Java 8 stream to print out each tuple of the list 42 | splitUpNames.forEach(name -> log.info(String.format("Inserting customer record for %s %s", name[0], name[1]))); 43 | 44 | // Uses JdbcTemplate's batchUpdate operation to bulk load data 45 | jdbcTemplate.batchUpdate("INSERT INTO customers(first_name, last_name) VALUES (?,?)", splitUpNames); 46 | 47 | log.info("Querying for customer records where first_name = 'Josh':"); 48 | jdbcTemplate.query( 49 | "SELECT id, first_name, last_name FROM customers WHERE first_name = ?", new Object[] { "Josh" }, 50 | (rs, rowNum) -> new Customer(rs.getLong("id"), rs.getString("first_name"), rs.getString("last_name")) 51 | ).forEach(customer -> log.info(customer.toString())); 52 | } 53 | } -------------------------------------------------------------------------------- /gs-relational-data-access/gs-relational-data-access/src/main/java/hello/Customer.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | public class Customer { 4 | private long id; 5 | private String firstName, lastName; 6 | 7 | public Customer(long id, String firstName, String lastName) { 8 | this.id = id; 9 | this.firstName = firstName; 10 | this.lastName = lastName; 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return String.format( 16 | "Customer[id=%d, firstName='%s', lastName='%s']", 17 | id, firstName, lastName); 18 | } 19 | 20 | public void setId(long id) { 21 | this.id = id; 22 | } 23 | 24 | public void setFirstName(String firstName) { 25 | this.firstName = firstName; 26 | } 27 | 28 | public void setLastName(String lastName) { 29 | this.lastName = lastName; 30 | } 31 | 32 | public long getId() { 33 | return id; 34 | } 35 | 36 | public String getFirstName() { 37 | return firstName; 38 | } 39 | 40 | public String getLastName() { 41 | return lastName; 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /gs-rest-service/README.adoc: -------------------------------------------------------------------------------- 1 | == RESTful 웹 서비스 만들기 2 | 이 가이드는 Spring으로 "hello world" http://spring.io/understanding/REST[RESTful 웹 서비스]를 만드는 과정을 안내한다. 3 | 4 | == 무엇을 만들게 되는가 5 | 다음 HTTP GET 요청을 수락하는 서비스를 만들것이다: 6 | 7 | [source,indent=0] 8 | ---- 9 | http://localhost:8080/greeting 10 | ---- 11 | 12 | 그리고 JSON 방식으로 greeting을 응답한다. 13 | 14 | [source,json,indent=0] 15 | ---- 16 | {"id":1,"content":"Hello, World!"} 17 | ---- 18 | 19 | 쿼리 문자열에 선택적 `name` 파라미터를 사용하여 greeting을 사용자 정의할 수 있다. 20 | 21 | [source,indent=0] 22 | ---- 23 | http://localhost:8080/greeting?name=User 24 | ---- 25 | 26 | `name` 파라미터 값은 기본값 "World"를 대체하여 응답에 반영된다: 27 | 28 | [source,json,indent=0] 29 | ---- 30 | {"id":1,"content":"Hello, User!"} 31 | ---- 32 | 33 | == 무엇이 필요한가 34 | * 약 15분 35 | * 선호하는 텍스트 에디터 혹은 IDE 36 | * http://www.oracle.com/technetwork/java/javase/downloads/index.html[JDK 1.8] 혹은 그 이상 37 | * http://www.gradle.org/downloads[Gradle 4+] 혹은 https://maven.apache.org/download.cgi[Maven 3.2+] 38 | * 코드를 IDE로 직접 가져올 수도 있다. 39 | ** http://spring.io/guides/gs/sts[Spring Tool Suite (STS)] 40 | ** http://spring.io/guides/gs/intellij-idea/[IntelliJ IDEA] 41 | 42 | == 이 가이드를 완료하는 방법 43 | 대부분의 http://spring.io/guides[Spring Getting Started] 가이드와 마찬가지로, 처음부터 시작하여 각 단계를 완료하거나 이미 익숙한 기본 설정 단계를 건너뛸 수 있다. 어느 쪽이든 코드가 작동한다. 44 | 45 | 처음부터 시작하려면 <>로 이동하시오. 46 | 47 | 기본 사항을 건너뛰려면 다음을 수행하라: 48 | 49 | * 이 가이드의 소스 저장소를 https://github.com/spring-guides/gs-rest-service/archive/master.zip[다운로드]하여 압축을 풀거나 http://spring.io/understanding/Git[Git]: `git clone https://github.com/spring-guides/gs-rest-service.git` 을 사용하여 clone 하시오. 50 | * cd into `gs-rest-service/initial` 51 | * <>로 넘어가시오. 52 | 53 | **끝나면** `gs-rest-service/complete` 코드와 결과를 비교할 수 있다. 54 | 55 | [[build-with-gradle]] 56 | == Gradle로 빌드하기 57 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 http://gradle.org/[Gradle] 및 https://maven.apache.org/[Maven]으로 작업하는 데 필요한 코드가 여기에 있다. 둘다 익숙하지 않은 경우 http://spring.io/guides/gs/gradle[Gradle로 Java 프로젝트 만들기] 또는 http://spring.io/guides/gs/maven[Maven으로 Java 프로젝트 만들기]를 참조하시오. 58 | 59 | === 디렉토리 구조 만들기 60 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 mkdir -p src/main/java/hello를 사용하여 다음 하위 디렉토리 구조를 작성한다: 61 | 62 | [source,indent=0] 63 | ---- 64 | └── src 65 | └── main 66 | └── java 67 | └── hello 68 | ---- 69 | 70 | === Gradle 빌드 파일 만들기 71 | 아래는 https://github.com/spring-guides/gs-rest-service/blob/master/initial/build.gradle[초기 Gradle 빌드 파일]이다. 72 | 73 | `build.gradle` 74 | 75 | [source,gradle,indent=0] 76 | ---- 77 | buildscript { 78 | repositories { 79 | mavenCentral() 80 | } 81 | dependencies { 82 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 83 | } 84 | } 85 | 86 | apply plugin: 'java' 87 | apply plugin: 'eclipse' 88 | apply plugin: 'idea' 89 | apply plugin: 'org.springframework.boot' 90 | apply plugin: 'io.spring.dependency-management' 91 | 92 | bootJar { 93 | baseName = 'gs-rest-service' 94 | version = '0.1.0' 95 | } 96 | 97 | repositories { 98 | mavenCentral() 99 | } 100 | 101 | sourceCompatibility = 1.8 102 | targetCompatibility = 1.8 103 | 104 | dependencies { 105 | compile("org.springframework.boot:spring-boot-starter-web") 106 | testCompile('org.springframework.boot:spring-boot-starter-test') 107 | } 108 | ---- 109 | 110 | https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html[Spring Boot Gralde 플러그인]은 다음과 같은 여러 편리한 기능을 제공한다: 111 | 112 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 113 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 114 | * https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml[Spring Boot 의존성]과 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 115 | 116 | == Maven으로 빌드하기 117 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 https://maven.apache.org/[Maven]으로 작업하는 데 필요한 코드가 여기에 있다. Maven이 익숙하지 않은 경우 http://spring.io/guides/gs/maven[Maven으로 Java 프로젝트 만들기]를 참조하시오. 118 | 119 | === 디렉토리 구조 만들기 120 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 mkdir -p src/main/java/hello를 사용하여 다음 하위 디렉토리 구조를 작성한다: 121 | 122 | [source,indent=0] 123 | ---- 124 | └── src 125 | └── main 126 | └── java 127 | └── hello 128 | ---- 129 | 130 | `pom.xml` 131 | 132 | [source,xml,indent=0] 133 | ---- 134 | 135 | 137 | 4.0.0 138 | 139 | org.springframework 140 | gs-rest-service 141 | 0.1.0 142 | 143 | 144 | org.springframework.boot 145 | spring-boot-starter-parent 146 | 2.0.5.RELEASE 147 | 148 | 149 | 150 | 151 | org.springframework.boot 152 | spring-boot-starter-web 153 | 154 | 155 | org.springframework.boot 156 | spring-boot-starter-test 157 | test 158 | 159 | 160 | com.jayway.jsonpath 161 | json-path 162 | test 163 | 164 | 165 | 166 | 167 | 1.8 168 | 169 | 170 | 171 | 172 | 173 | 174 | org.springframework.boot 175 | spring-boot-maven-plugin 176 | 177 | 178 | 179 | 180 | 181 | 182 | spring-releases 183 | https://repo.spring.io/libs-release 184 | 185 | 186 | 187 | 188 | spring-releases 189 | https://repo.spring.io/libs-release 190 | 191 | 192 | 193 | ---- 194 | 195 | https://docs.spring.io/spring-boot/docs/current/maven-plugin[Spring Boot Maven 플러그인]은 다음과 같은 여러 편리한 기능을 제공한다: 196 | 197 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 198 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 199 | * https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml[Spring Boot 의존성]과 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 200 | 201 | == IDE로 빌드하기 202 | * http://spring.io/guides/gs/sts/[Spring Tool Suite]에서 import 하는 가이드를 읽으시오. 203 | * http://spring.io/guides/gs/intellij-idea[IntelliJ IDEA]에서 가이드를 읽으시오. 204 | 205 | [[create-resource-representation-class]] 206 | == resource representation 클래스 생성하기 207 | 이제 프로젝트와 빌드 시스템을 구축했으므로 웹 서비스를 만들 수 있다. 208 | 209 | 서비스 상호 작용에 대해 생각하며 단계를 진행하세요. 210 | 211 | 서비스는 `/greeting` 에 대한 `GET` 요청을 처리하며 선택적으로 쿼리 문자열에 `name` 매개 변수를 사용한다. `GET` 요청은 greeting을 JSON body에 표현하여 `200 OK` 를 함께 리턴해야 한다. 다음과 같이 보일 것이다: 212 | 213 | [source,json,indent=0] 214 | ---- 215 | { 216 | "id": 1, 217 | "content": "Hello, World!" 218 | } 219 | ---- 220 | 221 | `id` 필드는 greeting에 대한 고유한 식별자이며 `content` 는 greeting의 텍스트이다. 222 | 223 | greeting을 모델링하려면 resource representation 클래스를 작성하시오. `id` 및 `content` 데이터에 대한 필드, 생성자 및 접근자를 POJO (Plain Old Java Object)로 제공하시오. 224 | 225 | `src/main/java/hello/Greeting.java` 226 | 227 | [source,java,indent=0] 228 | ---- 229 | package hello; 230 | 231 | public class Greeting { 232 | 233 | private final long id; 234 | private final String content; 235 | 236 | public Greeting(long id, String content) { 237 | this.id = id; 238 | this.content = content; 239 | } 240 | 241 | public long getId() { 242 | return id; 243 | } 244 | 245 | public String getContent() { 246 | return content; 247 | } 248 | } 249 | ---- 250 | 251 | ==== 252 | 아래 단계에서 볼 수 있듯이, Spring은 https://github.com/FasterXML/jackson[Jackson JSON] 라이브러리를 사용하여 `Greeting` 유형의 인스턴스를 JSON으로 자동 정리한다. 253 | ==== 254 | 255 | 그런 다음 greetings를 지원하는 리소스 컨트롤러를 생성한다. 256 | 257 | == 리소스 컨트롤러 생성 258 | RESTful 웹 서비스 구축에 대한 Spring의 접근 방식에서 HTTP 요청은 컨트롤러에 의해 처리된다. 이런 컴포넌트는 `@RestController` 어노테이션을 통해 쉽게 식별할 수 있으며, `GreetingController` 는 `Greeting` 클래스의 새 인스턴스를 반환하여 `/greeting` 에 대한 `GET` 요청을 처리한다: 259 | 260 | `src/main/java/hello/GreetingController.java` 261 | 262 | [source,java,indent=0] 263 | ---- 264 | package hello; 265 | 266 | import java.util.concurrent.atomic.AtomicLong; 267 | import org.springframework.web.bind.annotation.RequestMapping; 268 | import org.springframework.web.bind.annotation.RequestParam; 269 | import org.springframework.web.bind.annotation.RestController; 270 | 271 | @RestController 272 | public class GreetingController { 273 | 274 | private static final String template = "Hello, %s!"; 275 | private final AtomicLong counter = new AtomicLong(); 276 | 277 | @RequestMapping("/greeting") 278 | public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) { 279 | return new Greeting(counter.incrementAndGet(), 280 | String.format(template, name)); 281 | } 282 | } 283 | ---- 284 | 285 | 이 컨트롤러는 간단하지만 내부에서 많은 일들이 일어나고 있다. 단계별로 진행을 해봅시다. 286 | 287 | `@RequestMapping` 어노테이션은 `/greeting` 에 대한 HTTP 요청이 `greeting()` 메소드에 매핑되도록 한다. 288 | 289 | ==== 290 | `@RequestMapping` 은 기본적으로 모든 HTTP 작업을 매핑하기 때문에 위의 예에서는 `GET` vs `PUT`, `POST` 등을 지정하지 않는다. `@RequestMapping(method=GET)` 을 사용하여 매핑의 범위를 좁힌다. 291 | ==== 292 | 293 | `@RequestParam` 은 쿼리 문자열 매개 변수 `name` 의 값을 greeting() 메소드의 `name` 매개 변수에 바인딩한다. 요청에 `name` 매개 변수가 없으면 `defaultValue` "World"가 사용된다. 294 | 295 | 메소드 본문을 구현하면 `counter`의 다음 값을 기반으로 `id` 와 `content` 속성을 갖는 새 Greeting 객체가 만들어지고 반환되며 greeting `템플릿` 을 사용하여 지정된 `name` 의 서식이 지정된다. 296 | 297 | 기존 MVC 컨트롤러와 RESTful 웹 서비스 컨트롤러 간의 주요 차이점은 HTTP response body를 만드는 방법이다. http://spring.io/understanding/view-templates[뷰 기술]을 사용하여 greeting 데이터를 HTML로 server-side 렌더링하는 대신 RESTful 웹 서비스 컨트롤러는 `Greeting` 객체를 채우고 반환한다. 객체 데이터는 JSON으로 HTTP 응답에 직접 작성된다. 298 | 299 | 이 코드는 모든 메소드가 뷰가 아닌 도메인 객체를 반환하는 컨트롤러로 클래스를 표시한다는 Spring 4의 새로운 어노테이션 `@RestController` 을 사용한다. 이것은 `@Controller` 와 `@ResponseBody` 를 함께 사용한 것의 단축형이다. 300 | 301 | `Greeting` 객체는 JSON으로 반환해야 한다. Spring의 HTTP 메시지 컨버터 지원 덕분에 이 변환을 수동으로 수행할 필요가 없다. http://wiki.fasterxml.com/JacksonHome[Jackson 2]가 클래스 경로에 있기 때문에 Spring의 `MappingJackson2HttpMessageConverter` 가 자동으로 선택되어 `Greeting` 인스턴스를 JSON으로 변환한다. 302 | 303 | == 실행 가능한 어플리케이션 만들기 304 | 이 서비스를 외부 어플리케이션 서버에 배포하기 위해 기존의 http://spring.io/understanding/WAR[WAR] 파일로 패키징할 수 있지만, 아래에서 설명하는 더 간단한 접근 방식으로 독립 실행형 어플리케이션을 생성할 수 있다. Java `main()` 메소드로 구동되는 실행 가능한 단일 JAR 파일로 모든 것을 패키징한다. 이 과정에서 외부 인스턴스에 배포하는 대신 HTTP 런타임으로 Spring에서 지원하는 내장형 http://spring.io/understanding/Tomcat[Tomcat] 서블릿 컨테이너를 사용한다. 305 | 306 | `src/main/java/hello/Application.java` 307 | 308 | [source,java,indent=0] 309 | ---- 310 | package hello; 311 | 312 | import org.springframework.boot.SpringApplication; 313 | import org.springframework.boot.autoconfigure.SpringBootApplication; 314 | 315 | @SpringBootApplication 316 | public class Application { 317 | 318 | public static void main(String[] args) { 319 | SpringApplication.run(Application.class, args); 320 | } 321 | } 322 | ---- 323 | 324 | `@SpringBootApplication` 은 다음을 모두 추가하는 편리한 주석이다: 325 | 326 | * `@Configuration` 은 클래스를 어플리케이션 context의 bean 정의 소스로 태그 지정한다. 327 | * `@EnableAutoConfiguration` 은 Spring Boot에게 클래스 경로 설정, 다른 bean 및 다양한 프로퍼티 설정을 기반으로 bean 추가를 시작하도록 한다. 328 | * 일반적으로 `@EnableWebMvc` 를 Spring MVC app에 추가할 것이지만, Spring Boot는 클래스 경로에서 **spring-webmvc**를 발견할 때 그것을 자동으로 추가한다. 이것은 어플리케이션에 웹 어플리케이션으로 플래그를 지정하고 `DispatcherServlet` 설정과 같은 주요 동작을 활성화 한다. 329 | * `@ComponentScan` 은 `hello` 패키지에서 다른 컴포넌트, 구성 및 서비스를 찾아서 컨트롤러를 찾을 수 있도록 Spring에 지시한다. 330 | 331 | `main()` 메소드는 `Spring Boot의 SpringApplicaiton.run()` 메소드를 사용하여 어플리케이션을 시작한다. 한줄의 XML이 없다는 것을 알고 있었는가? **web.xml** 파일도 없다. 이 웹 어플리케이션은 100% 순수 자바이며 인프라 구성에 대해 다룰 필요가 없다. 332 | 333 | === 실행 가능한 JAR 만들기 334 | Gradle 또는 Maven을 사용하여 커맨드 라인에서 어플리케이션을 실행할 수 있다. 또는 모든 필요한 의존성, 클래스 및 리소스 포함하는 단일 실행 가능한 JAR 파일을 빌드하고 실행할 수 있다. 따라서 개발 생명주기(life cycle), 다양한 환경에 걸쳐 어플리케이션으로 서비스를 쉽게 제공 및 배포할 수 있다. 335 | 336 | Gradle을 사용하는 경우 `./gradlew bootRun` 을 사용하여 어플리케이션을 실행할 수 있다. 또는 `./gradlew build` 를 사용하여 JAR 파일을 작성할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 337 | 338 | [source,bash,indent=0] 339 | ---- 340 | java -jar build/libs/gs-rest-service-0.1.0.jar 341 | ---- 342 | 343 | Maven을 사용하는 경우 ./mvnw spring-boot:run을 사용하여 어플리케이션을 실행할 수 있다. 또는 ./mvnw clean package로 JAR 파일을 빌드할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 344 | 345 | [source,bash,indent=0] 346 | ---- 347 | java -jar target/gs-rest-service-0.1.0.jar 348 | ---- 349 | 350 | ==== 351 | 위 절차는 실행 가능한 JAR를 생성한다. 고전의 http://spring.io/guides/gs/convert-jar-to-war/[WAR 파일을 빌드]하도록 선택할 수도 있다. 352 | ==== 353 | 354 | 로깅 출력이 표시된다. 몇 초 이내에 서비스가 실행되어야 한다. 355 | 356 | == 서비스 테스트 357 | 이제 서비스가 시작되었으니 http://localhost:8080/greeting을 방문해 보시오: 358 | 359 | [source,json,indent=0] 360 | ---- 361 | {"id":1,"content":"Hello, World!"} 362 | ---- 363 | 364 | http://localhost:8080/greeting?name=User와 같이 name 쿼리 문자열 매개 변수를 제공하시오. content 속성의 값이 "Hello World!"에서 "Hello User!"로 변경되는지 확인하시오: 365 | 366 | [source,json,indent=0] 367 | ---- 368 | {"id":2,"content":"Hello, User!"} 369 | ---- 370 | 371 | 이 변경은 `GreetingController` 의 `@RequestParam` 방식이 예상대로 작동함을 보여준다. `name` 매개 변수에는 기본값 "World"가 지정되었지만 항상 쿼리 문자열을 통해 명시적으로 재정의될 수 있다. 372 | 373 | `id` 속성이 `1` 에서 `2` 로 어떻게 바뀌었는지 확인하시오. 이는 여러 요청에서 동일한 `GreetingController` 인스턴스에 대해 작업 중이며 `counter` 필드가 예상대로 각 호출에서 증가되고 있음을 증명한다. 374 | 375 | == 요약 376 | 축하합니다! 방금 Spring과 함께 RESTful 웹 서비스를 개발했다. 377 | 378 | == 다른 예제들 379 | 다음 가이드들도 도움이 될 것이다: 380 | 381 | * https://spring.io/guides/gs/accessing-gemfire-data-rest/[Accessing GemFire Data with REST] 382 | * https://spring.io/guides/gs/accessing-mongodb-data-rest/[Accessing MongoDB Data with REST] 383 | * https://spring.io/guides/gs/accessing-data-mysql/[Accessing data with MySQL] 384 | * https://spring.io/guides/gs/accessing-data-rest/[Accessing JPA Data with REST] 385 | * https://spring.io/guides/gs/accessing-neo4j-data-rest/[Accessing Neo4j Data with REST] 386 | * https://spring.io/guides/gs/consuming-rest/[Consuming a RESTful Web Service] 387 | * https://spring.io/guides/gs/consuming-rest-angularjs/[Consuming a RESTful Web Service with AngularJS] 388 | * https://spring.io/guides/gs/consuming-rest-jquery/[Consuming a RESTful Web Service with jQuery] 389 | * https://spring.io/guides/gs/consuming-rest-restjs/[Consuming a RESTful Web Service with rest.js] 390 | * https://spring.io/guides/gs/securing-web/[Securing a Web Application] 391 | * https://spring.io/guides/tutorials/bookmarks/[Building REST services with Spring] 392 | * https://spring.io/guides/tutorials/react-and-spring-data-rest/[React.js and Spring Data REST] 393 | * https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot] 394 | * https://spring.io/guides/gs/testing-restdocs/[Creating API Documentation with Restdocs] 395 | * https://spring.io/guides/gs/rest-service-cors/[Enabling Cross Origin Requests for a RESTful Web Service] 396 | * https://spring.io/guides/gs/rest-hateoas/[Building a Hypermedia-Driven RESTful Web Service] 397 | * https://spring.io/guides/gs/circuit-breaker/[Circuit Breaker] -------------------------------------------------------------------------------- /gs-rest-service/gs-rest-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework 7 | gs-rest-service 8 | 0.1.0 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.0.5.RELEASE 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-web 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-test 24 | test 25 | 26 | 27 | com.jayway.jsonpath 28 | json-path 29 | test 30 | 31 | 32 | 33 | 34 | 1.8 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-maven-plugin 43 | 44 | 45 | 46 | 47 | 48 | 49 | spring-releases 50 | https://repo.spring.io/libs-release 51 | 52 | 53 | 54 | 55 | spring-releases 56 | https://repo.spring.io/libs-release 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /gs-rest-service/gs-rest-service/src/main/java/hello/Application.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /gs-rest-service/gs-rest-service/src/main/java/hello/Greeting.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | public class Greeting { 4 | 5 | private final long id; 6 | private final String content; 7 | 8 | public Greeting(long id, String content) { 9 | this.id = id; 10 | this.content = content; 11 | } 12 | 13 | public long getId() { 14 | return id; 15 | } 16 | 17 | public String getContent() { 18 | return content; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /gs-rest-service/gs-rest-service/src/main/java/hello/GreetingController.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestParam; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | public class GreetingController { 10 | 11 | private static final String template = "Hello, %s!"; 12 | private final AtomicLong counter = new AtomicLong(); 13 | 14 | @RequestMapping("/greeting") 15 | public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) { 16 | return new Greeting(counter.incrementAndGet(), 17 | String.format(template, name)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gs-scheduling-tasks/README.adoc: -------------------------------------------------------------------------------- 1 | == 스케쥴링 작업 2 | 이 가이드는 Spring으로 스케쥴링 작업을 만드는 과정을 안내한다. 3 | 4 | == 무엇을 만들게 되는가 5 | Spring의 `@Scheduled` 어노테이션을 사용하여 5초마다 현재 시간을 출력하는 어플리케이션을 만들 것이다. 6 | 7 | == 무엇이 필요한가 8 | * 약 15분 9 | * 선호하는 텍스트 에디터 혹은 IDE 10 | * http://www.oracle.com/technetwork/java/javase/downloads/index.html[JDK 1.8] 혹은 그 이상 11 | * http://www.gradle.org/downloads[Gradle 4+] 혹은 https://maven.apache.org/download.cgi[Maven 3.2+] 12 | * 코드를 IDE로 직접 가져올 수도 있다. 13 | ** http://spring.io/guides/gs/sts[Spring Tool Suite (STS)] 14 | ** http://spring.io/guides/gs/intellij-idea/[IntelliJ IDEA] 15 | 16 | == 이 가이드를 완료하는 방법 17 | 대부분의 http://spring.io/guides[Spring Getting Started] 가이드와 마찬가지로, 처음부터 시작하여 각 단계를 완료하거나 이미 익숙한 기본 설정 단계를 건너뛸 수 있다. 어느 쪽이든 코드가 작동한다. 18 | 19 | 처음부터 시작하려면 <>로 이동하시오. 20 | 21 | 기본 사항을 건너뛰려면 다음을 수행하라: 22 | 23 | * 이 가이드의 소스 저장소를 https://github.com/spring-guides/gs-scheduling-tasks/archive/master.zip[다운로드]하여 압축을 풀거나 http://spring.io/understanding/Git[Git]: `git clone https://github.com/spring-guides/gs-scheduling-tasks.git` 을 사용하여 clone 하시오. 24 | * cd into `gs-scheduling-tasks/initial` 25 | * <>로 넘어가시오. 26 | 27 | **끝나면** `gs-scheduling-tasks/complete` 코드와 결과를 비교할 수 있다. 28 | 29 | [[build-with-gradle]] 30 | == Gradle로 빌드하기 31 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 http://gradle.org/[Gradle] 및 https://maven.apache.org/[Maven]으로 작업하는 데 필요한 코드가 여기에 있다. 둘다 익숙하지 않은 경우 http://spring.io/guides/gs/gradle[Gradle로 Java 프로젝트 만들기] 또는 http://spring.io/guides/gs/maven[Maven으로 Java 프로젝트 만들기]를 참조하시오. 32 | 33 | === 디렉토리 구조 만들기 34 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 mkdir -p src/main/java/hello를 사용하여 다음 하위 디렉토리 구조를 작성한다: 35 | 36 | [source,indent=0] 37 | ---- 38 | └── src 39 | └── main 40 | └── java 41 | └── hello 42 | ---- 43 | 44 | === Gradle 빌드 파일 만들기 45 | 아래는 https://github.com/spring-guides/gs-scheduling-tasks/blob/master/initial/build.gradle[초기 Gradle 빌드 파일]이다. 46 | 47 | `build.gradle` 48 | 49 | [source,gradle,indent=0] 50 | ---- 51 | buildscript { 52 | repositories { 53 | mavenCentral() 54 | } 55 | dependencies { 56 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 57 | } 58 | } 59 | 60 | apply plugin: 'java' 61 | apply plugin: 'eclipse' 62 | apply plugin: 'idea' 63 | apply plugin: 'org.springframework.boot' 64 | apply plugin: 'io.spring.dependency-management' 65 | 66 | bootJar { 67 | baseName = 'gs-scheduling-tasks' 68 | version = '0.1.0' 69 | } 70 | 71 | repositories { 72 | mavenCentral() 73 | } 74 | 75 | sourceCompatibility = 1.8 76 | targetCompatibility = 1.8 77 | 78 | dependencies { 79 | compile("org.springframework.boot:spring-boot-starter") 80 | testCompile("junit:junit") 81 | } 82 | ---- 83 | 84 | https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html[Spring Boot Gralde 플러그인]은 다음과 같은 여러 편리한 기능을 제공한다: 85 | 86 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 87 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 88 | * https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml[Spring Boot 의존성]과 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 89 | 90 | == Maven으로 빌드하기 91 | 먼저 기본 빌드 스크립트를 설정한다. Spring으로 app을 만들 때 원하는 빌드 시스템을 사용할 수 있지만 https://maven.apache.org/[Maven]으로 작업하는 데 필요한 코드가 여기에 있다. Maven이 익숙하지 않은 경우 http://spring.io/guides/gs/maven[Maven으로 Java 프로젝트 만들기]를 참조하시오. 92 | 93 | === 디렉토리 구조 만들기 94 | 선택한 프로젝트 디렉토리에서 *nix 시스템의 mkdir -p src/main/java/hello를 사용하여 다음 하위 디렉토리 구조를 작성한다: 95 | 96 | [source,indent=0] 97 | ---- 98 | └── src 99 | └── main 100 | └── java 101 | └── hello 102 | ---- 103 | 104 | `pom.xml` 105 | 106 | [source,xml,indent=0] 107 | ---- 108 | 109 | 111 | 4.0.0 112 | 113 | org.springframework 114 | gs-scheduling-tasks 115 | 0.1.0 116 | 117 | 118 | org.springframework.boot 119 | spring-boot-starter-parent 120 | 2.0.5.RELEASE 121 | 122 | 123 | 124 | 1.8 125 | 126 | 127 | 128 | 129 | org.springframework.boot 130 | spring-boot-starter 131 | 132 | 133 | 134 | 135 | 136 | 137 | org.springframework.boot 138 | spring-boot-maven-plugin 139 | 140 | 141 | 142 | 143 | 144 | ---- 145 | 146 | https://docs.spring.io/spring-boot/docs/current/maven-plugin[Spring Boot Maven 플러그인]은 다음과 같은 여러 편리한 기능을 제공한다: 147 | 148 | * 클래스 경로에 있는 모든 jar를 모으고 서비스를 전송하고 실행하는데 좀 더 편하게 만들어주는 실행 가능한 "über-jar"를 빌드한다. 149 | * `public static void main()` 메소드를 검색하여 실행 가능 클래스로 플래그를 지정한다. 150 | * https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml[Spring Boot 의존성]과 일치하도록 버전 번호를 설정하는 빌트인 의존성 리졸버를 제공한다. 모든 버전을 재정의할 수 있지만 기본적으로 Boot에서 선택한 버전으로 설정된다. 151 | 152 | == IDE로 빌드하기 153 | * http://spring.io/guides/gs/sts/[Spring Tool Suite]에서 import 하는 가이드를 읽으시오. 154 | * http://spring.io/guides/gs/intellij-idea[IntelliJ IDEA]에서 가이드를 읽으시오. 155 | 156 | [[create-a-scheduled-task]] 157 | == 스케쥴 작업 생성하기 158 | 이제 프로젝트를 구축했으므로 스케쥴 작업을 만들 수 있다. 159 | 160 | `src/main/java/hello/ScheduledTasks.java` 161 | 162 | [source,java,indent=0] 163 | ---- 164 | package hello; 165 | 166 | import java.text.SimpleDateFormat; 167 | import java.util.Date; 168 | 169 | import org.slf4j.Logger; 170 | import org.slf4j.LoggerFactory; 171 | import org.springframework.scheduling.annotation.Scheduled; 172 | import org.springframework.stereotype.Component; 173 | 174 | @Component 175 | public class ScheduledTasks { 176 | 177 | private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class); 178 | 179 | private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); 180 | 181 | @Scheduled(fixedRate = 5000) 182 | public void reportCurrentTime() { 183 | log.info("The time is now {}", dateFormat.format(new Date())); 184 | } 185 | } 186 | ---- 187 | 188 | `Scheduled` 어노테이션은 특정 메소드가 실행될 시기를 정의한다. 참고: 이 예제에서는 각 호출의 시작 시간으로부터 측정된 메소드 호출 간격을 지정하는 `fixedRate` 를 사용한다. `fixedDelay` 와 같은 https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-scheduled[다른 옵션]이 있는데, 이 옵션은 작업 완료시 측정된 호출 간격을 지정한다. 더 정교한 작업 스케쥴링을 위해 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/support/CronSequenceGenerator.html[`@Scheduled(cron=". . .")` 표현식을 사용]할 수도 있다. 189 | 190 | == 스케쥴링 사용 191 | 스케줄링 작업을 웹 어플리케이션 및 WAR 파일에 포함할 수 있지만, 아래서 설명하는 더 간단한 접근 방식으로 독립 실행형 어플리케이션을 생성한다. Java `main()` 메소드로 구동되는 실행 가능한 단일 JAR 파일로 모든 것을 패키징한다. 192 | 193 | `src/main/java/hello/Application.java` 194 | 195 | [source,java,indent=0] 196 | ---- 197 | package hello; 198 | 199 | import org.springframework.boot.SpringApplication; 200 | import org.springframework.boot.autoconfigure.SpringBootApplication; 201 | import org.springframework.scheduling.annotation.EnableScheduling; 202 | 203 | @SpringBootApplication 204 | @EnableScheduling 205 | public class Application { 206 | 207 | public static void main(String[] args) { 208 | SpringApplication.run(Application.class); 209 | } 210 | } 211 | ---- 212 | 213 | `@SpringBoot어플리케이션` 은 다음을 모두 추가하는 편리한 주석이다: 214 | 215 | * `@Configuration` 은 클래스를 어플리케이션 context의 bean 정의 소스로 태그 지정한다. 216 | * `@EnableAutoConfiguration` 은 Spring Boot에게 클래스 경로 설정, 다른 bean 및 다양한 프로퍼티 설정을 기반으로 bean 추가를 시작하도록 한다. 217 | * 일반적으로 `@EnableWebMvc` 를 Spring MVC app에 추가할 것이지만, Spring Boot는 클래스 경로에서 **spring-webmvc**를 발견할 때 그것을 자동으로 추가한다. 이것은 어플리케이션에 웹 어플리케이션으로 플래그를 지정하고 `DispatcherServlet` 설정과 같은 주요 동작을 활성화 한다. 218 | * `@ComponentScan` 은 `hello` 패키지에서 다른 컴포넌트, 구성 및 서비스를 찾아서 컨트롤러를 찾을 수 있도록 Spring에 지시한다. 219 | 220 | `main()` 메소드는 `Spring Boot의 SpringApplicaiton.run()` 메소드를 사용하여 어플리케이션을 시작한다. 한줄의 XML이 없다는 것을 알고 있었는가? **web.xml** 파일도 없다. 이 웹 어플리케이션은 100% 순수 자바이며 인프라 구성에 대해 다룰 필요가 없다. 221 | 222 | `@EnableScheduling` 은 백그라운드 작업 실행자를 생성하도록 보장한다. 그것 없이는 아무것도 스케쥴되지 않는다. 223 | 224 | === 실행 가능한 JAR 만들기 225 | Gradle 또는 Maven을 사용하여 커맨드 라인에서 어플리케이션을 실행할 수 있다. 또는 모든 필요한 의존성, 클래스 및 리소스 포함하는 단일 실행 가능한 JAR 파일을 빌드하고 실행할 수 있다. 따라서 개발 생명주기(life cycle), 다양한 환경에 걸쳐 어플리케이션으로 서비스를 쉽게 제공 및 배포할 수 있다. 226 | 227 | Gradle을 사용하는 경우 `./gradlew bootRun` 을 사용하여 어플리케이션을 실행할 수 있다. 또는 `./gradlew build` 를 사용하여 JAR 파일을 작성할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 228 | 229 | [source,bash,indent=0] 230 | ---- 231 | java -jar build/libs/gs-scheduling-tasks-0.1.0.jar 232 | ---- 233 | 234 | Maven을 사용하는 경우 ./mvnw spring-boot:run을 사용하여 어플리케이션을 실행할 수 있다. 또는 ./mvnw clean package로 JAR 파일을 빌드할 수 있다. 그런 다음 JAR 파일을 실행할 수 있다: 235 | 236 | [source,bash,indent=0] 237 | ---- 238 | java -jar target/gs-scheduling-tasks-0.1.0.jar 239 | ---- 240 | 241 | ==== 242 | 위 절차는 실행 가능한 JAR를 생성한다. 고전의 http://spring.io/guides/gs/convert-jar-to-war/[WAR 파일을 빌드]하도록 선택할 수도 있다. 243 | ==== 244 | 245 | 로그 출력이 표시되고 백그라운드 스레드에 있는 로그를 통해 확인할 수 있다. 5초마다 예약된 작업이 표시되는 것을 볼 수 있다: 246 | 247 | [source,indent=0] 248 | ---- 249 | [...] 250 | 2016-08-25 13:10:00.143 INFO 31565 --- [pool-1-thread-1] hello.ScheduledTasks : The time is now 13:10:00 251 | 2016-08-25 13:10:05.143 INFO 31565 --- [pool-1-thread-1] hello.ScheduledTasks : The time is now 13:10:05 252 | 2016-08-25 13:10:10.143 INFO 31565 --- [pool-1-thread-1] hello.ScheduledTasks : The time is now 13:10:10 253 | 2016-08-25 13:10:15.143 INFO 31565 --- [pool-1-thread-1] hello.ScheduledTasks : The time is now 13:10:15 254 | ---- 255 | 256 | == 요약 257 | 축하합니다! 스케줄 작업 어플리케이션을 개발했다. 실제 코드는 빌드 파일보다 짧았다! 이 기술은 모든 유형의 어플리케이션에도 작동된다. 258 | 259 | == 다른 예제들 260 | 다음 가이드들도 도움이 될 것이다: 261 | 262 | * https://spring.io/guides/gs/spring-boot/[Building an Application with Spring Boot] 263 | * https://spring.io/guides/gs/batch-processing/[Creating a Batch Service] -------------------------------------------------------------------------------- /gs-scheduling-tasks/gs-scheduling-tasks/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework 7 | gs-scheduling-tasks 8 | 0.1.0 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.0.5.RELEASE 14 | 15 | 16 | 17 | 1.8 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter 24 | 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-maven-plugin 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /gs-scheduling-tasks/gs-scheduling-tasks/src/main/java/hello/Application.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableScheduling; 6 | 7 | @SpringBootApplication 8 | @EnableScheduling 9 | public class Application { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(Application.class); 13 | } 14 | } -------------------------------------------------------------------------------- /gs-scheduling-tasks/gs-scheduling-tasks/src/main/java/hello/ScheduledTasks.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.scheduling.annotation.Scheduled; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class ScheduledTasks { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class); 15 | 16 | private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); 17 | 18 | @Scheduled(fixedRate = 5000) 19 | public void reportCurrentTime() { 20 | log.info("The time is now {}", dateFormat.format(new Date())); 21 | } 22 | } -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework 7 | gs-uploading-files 8 | 0.1.0 9 | 10 | 11 | org.springframework.boot 12 | spring-boot-starter-parent 13 | 2.0.5.RELEASE 14 | 15 | 16 | 17 | 1.8 18 | 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-thymeleaf 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-test 34 | test 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-maven-plugin 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/java/hello/Application.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import org.springframework.boot.CommandLineRunner; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | import hello.storage.StorageProperties; 10 | import hello.storage.StorageService; 11 | 12 | @SpringBootApplication 13 | @EnableConfigurationProperties(StorageProperties.class) 14 | public class Application { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(Application.class, args); 18 | } 19 | 20 | @Bean 21 | CommandLineRunner init(StorageService storageService) { 22 | return (args) -> { 23 | storageService.deleteAll(); 24 | storageService.init(); 25 | }; 26 | } 27 | } -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/java/hello/FileUploadController.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import java.io.IOException; 4 | import java.util.stream.Collectors; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.core.io.Resource; 8 | import org.springframework.http.HttpHeaders; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.ui.Model; 12 | import org.springframework.web.bind.annotation.ExceptionHandler; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.PostMapping; 16 | import org.springframework.web.bind.annotation.RequestParam; 17 | import org.springframework.web.bind.annotation.ResponseBody; 18 | import org.springframework.web.multipart.MultipartFile; 19 | import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; 20 | import org.springframework.web.servlet.mvc.support.RedirectAttributes; 21 | 22 | import hello.storage.StorageFileNotFoundException; 23 | import hello.storage.StorageService; 24 | 25 | @Controller 26 | public class FileUploadController { 27 | 28 | private final StorageService storageService; 29 | 30 | @Autowired 31 | public FileUploadController(StorageService storageService) { 32 | this.storageService = storageService; 33 | } 34 | 35 | @GetMapping("/") 36 | public String listUploadedFiles(Model model) throws IOException { 37 | 38 | model.addAttribute("files", storageService.loadAll().map( 39 | path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class, 40 | "serveFile", path.getFileName().toString()).build().toString()) 41 | .collect(Collectors.toList())); 42 | 43 | return "uploadForm"; 44 | } 45 | 46 | @GetMapping("/files/{filename:.+}") 47 | @ResponseBody 48 | public ResponseEntity serveFile(@PathVariable String filename) { 49 | 50 | Resource file = storageService.loadAsResource(filename); 51 | return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, 52 | "attachment; filename=\"" + file.getFilename() + "\"").body(file); 53 | } 54 | 55 | @PostMapping("/") 56 | public String handleFileUpload(@RequestParam("file") MultipartFile file, 57 | RedirectAttributes redirectAttributes) { 58 | 59 | storageService.store(file); 60 | redirectAttributes.addFlashAttribute("message", 61 | "You successfully uploaded " + file.getOriginalFilename() + "!"); 62 | 63 | return "redirect:/"; 64 | } 65 | 66 | @ExceptionHandler(StorageFileNotFoundException.class) 67 | public ResponseEntity handleStorageFileNotFound(StorageFileNotFoundException exc) { 68 | return ResponseEntity.notFound().build(); 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/java/hello/storage/FileSystemStorageService.java: -------------------------------------------------------------------------------- 1 | package hello.storage; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.net.MalformedURLException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | import java.nio.file.StandardCopyOption; 10 | import java.util.stream.Stream; 11 | 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.core.io.Resource; 14 | import org.springframework.core.io.UrlResource; 15 | import org.springframework.stereotype.Service; 16 | import org.springframework.util.FileSystemUtils; 17 | import org.springframework.util.StringUtils; 18 | import org.springframework.web.multipart.MultipartFile; 19 | 20 | @Service 21 | public class FileSystemStorageService implements StorageService { 22 | 23 | private final Path rootLocation; 24 | 25 | @Autowired 26 | public FileSystemStorageService(StorageProperties properties) { 27 | this.rootLocation = Paths.get(properties.getLocation()); 28 | } 29 | 30 | @Override 31 | public void store(MultipartFile file) { 32 | String filename = StringUtils.cleanPath(file.getOriginalFilename()); 33 | try { 34 | if (file.isEmpty()) { 35 | throw new StorageException("Failed to store empty file " + filename); 36 | } 37 | if (filename.contains("..")) { 38 | // This is a security check 39 | throw new StorageException( 40 | "Cannot store file with relative path outside current directory " 41 | + filename); 42 | } 43 | try (InputStream inputStream = file.getInputStream()) { 44 | Files.copy(inputStream, this.rootLocation.resolve(filename), 45 | StandardCopyOption.REPLACE_EXISTING); 46 | } 47 | } 48 | catch (IOException e) { 49 | throw new StorageException("Failed to store file " + filename, e); 50 | } 51 | } 52 | 53 | @Override 54 | public Stream loadAll() { 55 | try { 56 | return Files.walk(this.rootLocation, 1) 57 | .filter(path -> !path.equals(this.rootLocation)) 58 | .map(this.rootLocation::relativize); 59 | } 60 | catch (IOException e) { 61 | throw new StorageException("Failed to read stored files", e); 62 | } 63 | 64 | } 65 | 66 | @Override 67 | public Path load(String filename) { 68 | return rootLocation.resolve(filename); 69 | } 70 | 71 | @Override 72 | public Resource loadAsResource(String filename) { 73 | try { 74 | Path file = load(filename); 75 | Resource resource = new UrlResource(file.toUri()); 76 | if (resource.exists() || resource.isReadable()) { 77 | return resource; 78 | } 79 | else { 80 | throw new StorageFileNotFoundException( 81 | "Could not read file: " + filename); 82 | 83 | } 84 | } 85 | catch (MalformedURLException e) { 86 | throw new StorageFileNotFoundException("Could not read file: " + filename, e); 87 | } 88 | } 89 | 90 | @Override 91 | public void deleteAll() { 92 | FileSystemUtils.deleteRecursively(rootLocation.toFile()); 93 | } 94 | 95 | @Override 96 | public void init() { 97 | try { 98 | Files.createDirectories(rootLocation); 99 | } 100 | catch (IOException e) { 101 | throw new StorageException("Could not initialize storage", e); 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/java/hello/storage/StorageException.java: -------------------------------------------------------------------------------- 1 | package hello.storage; 2 | 3 | public class StorageException extends RuntimeException { 4 | 5 | public StorageException(String message) { 6 | super(message); 7 | } 8 | 9 | public StorageException(String message, Throwable cause) { 10 | super(message, cause); 11 | } 12 | } -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/java/hello/storage/StorageFileNotFoundException.java: -------------------------------------------------------------------------------- 1 | package hello.storage; 2 | 3 | public class StorageFileNotFoundException extends StorageException { 4 | 5 | public StorageFileNotFoundException(String message) { 6 | super(message); 7 | } 8 | 9 | public StorageFileNotFoundException(String message, Throwable cause) { 10 | super(message, cause); 11 | } 12 | } -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/java/hello/storage/StorageProperties.java: -------------------------------------------------------------------------------- 1 | package hello.storage; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties("storage") 6 | public class StorageProperties { 7 | 8 | /** 9 | * Folder location for storing files 10 | */ 11 | private String location = "upload-dir"; 12 | 13 | public String getLocation() { 14 | return location; 15 | } 16 | 17 | public void setLocation(String location) { 18 | this.location = location; 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/java/hello/storage/StorageService.java: -------------------------------------------------------------------------------- 1 | package hello.storage; 2 | 3 | import org.springframework.core.io.Resource; 4 | import org.springframework.web.multipart.MultipartFile; 5 | 6 | import java.nio.file.Path; 7 | import java.util.stream.Stream; 8 | 9 | public interface StorageService { 10 | 11 | void init(); 12 | 13 | void store(MultipartFile file); 14 | 15 | Stream loadAll(); 16 | 17 | Path load(String filename); 18 | 19 | Resource loadAsResource(String filename); 20 | 21 | void deleteAll(); 22 | 23 | } -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.servlet.multipart.max-file-size=128KB 2 | spring.servlet.multipart.max-request-size=128KB 3 | spring.http.multipart.enabled=false -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/main/resources/templates/uploadForm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |

6 |

7 | 8 |
9 |
10 | 11 | 12 | 13 |
File to upload:
14 |
15 |
16 | 17 |
18 | 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /gs-uploading-files/gs-uploading-files/src/test/java/hello/FileUploadTests.java: -------------------------------------------------------------------------------- 1 | package hello; 2 | 3 | import java.nio.file.Paths; 4 | import java.util.stream.Stream; 5 | 6 | import org.hamcrest.Matchers; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.boot.test.mock.mockito.MockBean; 14 | import org.springframework.mock.web.MockMultipartFile; 15 | import org.springframework.test.context.junit4.SpringRunner; 16 | import org.springframework.test.web.servlet.MockMvc; 17 | 18 | import static org.mockito.BDDMockito.given; 19 | import static org.mockito.BDDMockito.then; 20 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload; 21 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 22 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; 23 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 24 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 25 | 26 | import hello.storage.StorageFileNotFoundException; 27 | import hello.storage.StorageService; 28 | 29 | @RunWith(SpringRunner.class) 30 | @AutoConfigureMockMvc 31 | @SpringBootTest 32 | public class FileUploadTests { 33 | 34 | @Autowired 35 | private MockMvc mvc; 36 | 37 | @MockBean 38 | private StorageService storageService; 39 | 40 | @Test 41 | public void shouldListAllFiles() throws Exception { 42 | given(this.storageService.loadAll()) 43 | .willReturn(Stream.of(Paths.get("first.txt"), Paths.get("second.txt"))); 44 | 45 | this.mvc.perform(get("/")).andExpect(status().isOk()) 46 | .andExpect(model().attribute("files", 47 | Matchers.contains("http://localhost/files/first.txt", 48 | "http://localhost/files/second.txt"))); 49 | } 50 | 51 | @Test 52 | public void shouldSaveUploadedFile() throws Exception { 53 | MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt", 54 | "text/plain", "Spring Framework".getBytes()); 55 | this.mvc.perform(fileUpload("/").file(multipartFile)) 56 | .andExpect(status().isFound()) 57 | .andExpect(header().string("Location", "/")); 58 | 59 | then(this.storageService).should().store(multipartFile); 60 | } 61 | 62 | @SuppressWarnings("unchecked") 63 | @Test 64 | public void should404WhenMissingFile() throws Exception { 65 | given(this.storageService.loadAsResource("test.txt")) 66 | .willThrow(StorageFileNotFoundException.class); 67 | 68 | this.mvc.perform(get("/files/test.txt")).andExpect(status().isNotFound()); 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /gs-validating-form-input/README.md: -------------------------------------------------------------------------------- 1 | ## 폼에 입력된 값에 대한 유효성 검증하기 2 | 이 가이드는 유효성 확인을 사용하기 위해 웹 어플리케이션을 구성하는 방법을 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 여러분은 표준 유효성 어노테이션을 사용해 유효성을 검사하는 간단한 유저 입력 스프링 MVC를 만들어봅니다. 6 | 그리고 사용자의 유효한 재입력을 도와주는 에러 메시지를 어떻게 화면에 표시하는지 볼 것입니다. 7 | 8 | ## 무엇이 필요한가? 9 | * 15분의 시간 10 | * 선호하는 텍스트 에디터나 IDE 11 | * [JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 이상 12 | * [Gradle 4+](http://www.gradle.org/downloads) 또는 [Maven 3.2+](https://maven.apache.org/download.cgi) 13 | * 또한 아래의 IDE를 이용해 코드를 바로 불러올 수 있습니다: 14 | - [Spring Tool Suite (STS)](http://spring.io/guides/gs/sts) 15 | - [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea/) 16 | 17 | ## 이 가이드를 완료하는 방법 18 | 대부분의 [스프링 시작 가이드](http://spring.io/guides)처럼 처음부터 하나씩 완성해 가거나 19 | 익숙한 시작 부분은 건너뛰어도 됩니다. 어느 방법을 선택하시더라도 작동되는 코드만 완성시키면 됩니다. 20 | 21 | **처음부터 작업하실 분**은 [Gradle을 사용한 빌드](#Gradle을-사용한-빌드)로 가세요. 22 | 23 | **시작부분을 건너뛰실 분**은 아래방법을 따라하세요. 24 | 25 | * [다운로드](https://github.com/spring-guides/gs-validating-form-input/archive/master.zip) 하시고 압축파일을 풀어주시거나 [GIT](http://spring.io/understanding/Git)을 사용해 복제해주세요 (명령어): `git clone https://github.com/spring-guides/gs-validating-form-input.git` 26 | * 소스의 압축을 해제한 폴더에서 `gs-validating-form-input/initial`로 이동합니다.(cd) 27 | * [PersonForm 객체만들기](#PersonForm 객체만들기)로 이동합니다. 28 | 29 | **다 끝나고나서**, `gs-validating-form-input/complete`의 코드와 비교해서 맞는지 확인해보세요. 30 | 31 | ## Gradle을 사용한 빌드 32 | 첫 번째로 여러분은 빌드 스크립트를 만들어야 합니다. 여러분은 스프링 어플리케이션을 빌드 할 때 원하는 시스템을 사용할 수 있습니다만, 코드가 작동하기 위해서는 [Gradle](http://gradle.org/)이나 [Maven](https://maven.apache.org/)이 포함되어 있어야 합니다. Gradle이나 Maven에 익숙하지 않은 경우, [Building Java Projects with Gradle](http://spring.io/guides/gs/gradle) 또는 [Building Java Projects with Maven (http://spring.io/guides/gs/maven)을 참조하세요. 33 | 34 | ### 폴더 구조 만들기 35 | 프로젝트 폴더를 선택하시고 안에 다음과 같이 하위 폴더를 만들어주세요 예를 들면, *nix(linux, unix)에서는 `mkdir -p src/main/java/hello`를 입력하면 됩니다: 36 | 37 | ``` 38 | └── src 39 | └── main 40 | └── java 41 | └── hello 42 | ``` 43 | 44 | ### Gradle 빌드 파일 만들기 45 | [초기 Gradle build file](https://github.com/spring-guides/gs-validating-form-input/blob/master/initial/build.gradle)은 아래와 같습니다. 46 | 47 | `build.gradle` 48 | 49 | ```gradle 50 | buildscript { 51 | repositories { 52 | mavenCentral() 53 | } 54 | dependencies { 55 | classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE") 56 | } 57 | } 58 | 59 | apply plugin: 'java' 60 | apply plugin: 'eclipse' 61 | apply plugin: 'idea' 62 | apply plugin: 'org.springframework.boot' 63 | apply plugin: 'io.spring.dependency-management' 64 | 65 | bootJar { 66 | baseName = 'gs-validating-form-input' 67 | version = '0.1.0' 68 | } 69 | 70 | repositories { 71 | mavenCentral() 72 | } 73 | 74 | sourceCompatibility = 1.8 75 | targetCompatibility = 1.8 76 | 77 | dependencies { 78 | compile("org.springframework.boot:spring-boot-starter-thymeleaf") 79 | compile("org.springframework.boot:spring-boot-starter-web") 80 | compile("org.hibernate.validator:hibernate-validator") 81 | compile("org.apache.tomcat.embed:tomcat-embed-el") 82 | testCompile("org.springframework.boot:spring-boot-starter-test") 83 | } 84 | ``` 85 | 86 | [Spring Boot gradle plugin](https://docs.spring.io/spring-boot/docs/current/gradle-plugin/reference/html)은 많고 편리한 기능을 제공합니다: 87 | * 이 플러그인은 클래스패스 위의 jar를 하나의 실행 가능한 jar로 모아서 여러분의 서비스를 실행하고 전송하는데 편리하게 만들어줍니다. 88 | * 이 플러그인은 `public static void main()`메소드를 찾아 실행 가능한 클래스로 표시를 해줍니다. 89 | * 이 플러그인은 [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)에 맞는 내장된 의존성 해석자를 제공합니다. 여러분이 원하는 버전을 사용할 수도 있습니다만 기본적으로 Spring Boot에서 선택한 버전이 기본 제공됩니다. 90 | 91 | ## Maven을 사용한 빌드 92 | 첫번째로 여러분은 빌드 스크립트를 만들어야 합니다. 여러분은 스프링 어플리케이션을 빌드할때 원하는 시스템을 사용할 수 있습니다만, 코드가 작동하기 위해서는 [Maven](https://maven.apache.org/)이 포함되어 있어야 합니다. Maven에 익숙하지 않은 경우, [Building Java Projects with Maven](http://spring.io/guides/gs/maven)을 참조하세요. 93 | 94 | ### 폴더 구조 만들기 95 | 프로젝트 폴더를 선택하시고 안에 다음과 같이 하위 폴더를 만들어주세요. 예를 들면, *nix(linux, unix)에서는 `mkdir -p src/main/java/hello`를 입력하면 됩니다: 96 | 97 | ``` 98 | └── src 99 | └── main 100 | └── java 101 | └── hello 102 | ``` 103 | 104 | `pom.xml` 105 | 106 | ```xml 107 | 108 | 110 | 4.0.0 111 | 112 | org.springframework 113 | gs-validating-form-input 114 | 0.1.0 115 | 116 | 117 | org.springframework.boot 118 | spring-boot-starter-parent 119 | 2.0.5.RELEASE 120 | 121 | 122 | 123 | 1.8 124 | 125 | 126 | 127 | 128 | 129 | org.springframework.boot 130 | spring-boot-maven-plugin 131 | 132 | 133 | 134 | 135 | 136 | 137 | org.springframework.boot 138 | spring-boot-starter-thymeleaf 139 | 140 | 141 | org.springframework.boot 142 | spring-boot-starter-web 143 | 144 | 145 | org.hibernate.validator 146 | hibernate-validator 147 | 148 | 149 | org.apache.tomcat.embed 150 | tomcat-embed-el 151 | 152 | 153 | org.springframework.boot 154 | spring-boot-starter-test 155 | test 156 | 157 | 158 | 159 | 160 | ``` 161 | 162 | 이 [Spring Boot Maven plugin](https://docs.spring.io/spring-boot/docs/current/maven-plugin)은 많고 편리한 기능을 제공합니다.: 163 | 164 | * 이 플러그인은 클래스패스 위의 jar를 하나의 실행가능한 jar로 모아서 여러분의 서비스를 실행하고 전송하는데 편리하게 만들어줍니다. 165 | * 이 플러그인은 `public static void main()`메소드를 찾아 실행 가능한 클래스로 표시를 해줍니다. 166 | * 이 플러그인은 [Spring Boot dependencies](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-dependencies/pom.xml)에 맞는 내장된 의존성 해석자를 제공합니다. 167 | 168 | ## 여러분의 IDE를 사용한 빌드 하기 169 | * 이 가이드를 STS에 직접 포함하는 방법을 알고싶으면 [Spring Tool Suite](http://spring.io/guides/gs/sts/)을 읽어주세요. 170 | * 이 가이드를 Intellij IDEA에서 작동시키는 법을 알고 싶으면 [IntelliJ IDEA](http://spring.io/guides/gs/intellij-idea)을 읽어주세요. 171 | 172 | ## PersonForm 객체 만들기 173 | 이 어플리케이션은 사용자의 이름과 나이의 유효성 체크를 포함합니다. 그래서 먼저 사용자를 만들기 위한 폼 클래스를 만들어 보겠습니다. 174 | 175 | `src/main/java/hello/PersonForm.java` 176 | 177 | ```java 178 | package hello; 179 | 180 | import javax.validation.constraints.Min; 181 | import javax.validation.constraints.NotNull; 182 | import javax.validation.constraints.Size; 183 | 184 | public class PersonForm { 185 | 186 | @NotNull 187 | @Size(min=2, max=30) 188 | private String name; 189 | 190 | @NotNull 191 | @Min(18) 192 | private Integer age; 193 | 194 | public String getName() { 195 | return this.name; 196 | } 197 | 198 | public void setName(String name) { 199 | this.name = name; 200 | } 201 | 202 | public Integer getAge() { 203 | return age; 204 | } 205 | 206 | public void setAge(Integer age) { 207 | this.age = age; 208 | } 209 | 210 | public String toString() { 211 | return "Person(Name: " + this.name + ", Age: " + this.age + ")"; 212 | } 213 | } 214 | ``` 215 | 216 | 작성한 `PersonForm` 클래스는 `name`과 `age`를 가지고 있습니다. 그리고 이 속성들은 많고 다양한 표준 유효성 어노테이션을 가지고 있습니다: 217 | 218 | * `@Size(min=2, max=30)`은 이름을 2~30글자만 입력하도록 허용합니다. 219 | * `@NotNull`은 빈값은 들어올 수 없습니다. 220 | * `@Min(18)`은 18미만의 숫자는 허용하지 않습니다. 221 | 222 | 그 외에도 `name`과 `age`를 활용한 getters/setters와 편리한 `toString()`메서드를 볼 수 있습니다. 223 | 224 | ## 웹 컨트롤러 만들기 225 | 방금 폼에 쓰일 오브젝트를 만들었으므로, 이제 간단한 웹 컨트롤러를 만들 시간입니다. 226 | 227 | `src/main/java/hello/WebController.java` 228 | 229 | ```java 230 | package hello; 231 | 232 | import javax.validation.Valid; 233 | 234 | import org.springframework.stereotype.Controller; 235 | import org.springframework.validation.BindingResult; 236 | import org.springframework.web.bind.annotation.GetMapping; 237 | import org.springframework.web.bind.annotation.PostMapping; 238 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 239 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 240 | 241 | 242 | @Controller 243 | public class WebController implements WebMvcConfigurer { 244 | 245 | @Override 246 | public void addViewControllers(ViewControllerRegistry registry) { 247 | registry.addViewController("/results").setViewName("results"); 248 | } 249 | 250 | @GetMapping("/") 251 | public String showForm(PersonForm personForm) { 252 | return "form"; 253 | } 254 | 255 | @PostMapping("/") 256 | public String checkPersonInfo(@Valid PersonForm personForm, BindingResult bindingResult) { 257 | 258 | if (bindingResult.hasErrors()) { 259 | return "form"; 260 | } 261 | 262 | return "redirect:/results"; 263 | } 264 | } 265 | ``` 266 | 267 | 이 컨트롤러는 `/`로 작동하는 GET, POST메소드를 가지고 있습니다. 268 | 269 | `showForm`메소드는 `form` 템플릿을 반환합니다. 이 템플릿은 `PersonForm`을 연상시켜 템플릿을 반환하게 하는 메소드를 가지고 있습니다. 270 | 271 | `checkPersonFormInfo` 메소드는 두 개의 인수를 받습니다. 272 | 273 | * 여러분이 만들 폼 양식에 맞는 속성을 가지고 `@Valid`가 표시된 `personForm` 오브젝트 274 | * 유효성 에러를 테스트할 수 있는 `bindingResult`객체 275 | 276 | 여러분은 폼과 바운드된 `PersonForm`객체로부터 모든 속성을 얻을 수 있습니다. 그리고 원래의 유저 `form` 템플릿을 보낼 때 여러분은 에러를 테스트할 수 있습니다. 이러한 테스트 중에서, 모든 에러 속성을 화면에 표시합니다. 277 | 278 | 모든 유저 객체의 속성이 조건에 맞으면 최종 `results` 템플릿으로 이동합니다. 279 | 280 | ## HTML 화면 만들기 281 | 이제 메인페이지를 만들어봅시다. 282 | 283 | `src/main/resources/templates/form.html` 284 | 285 | ```html 286 | 287 | 288 |
289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 |
Name:Name Error
Age:Age Error
304 |
305 | 306 | 307 | ``` 308 | 309 | 이 페이지는 테이블에서 각 필드를 분리된 슬롯으로 나눈 간단한 폼입니다. 이 폼은 `/`의 POST 메소드를 보도록 되어있습니다. 그리고 이 폼은 `personForm` 객체로 백업되며 웹 컨트롤러에서 GET 메소드로 볼 수 있습니다. 이것이 **bean-backed form**으로 우리에게 알려진 것입니다. `PersonForm`빈은 두 개의 필드가 있고, 여러분은 `th:field="{name}"` **그리고** `th:field="{age}"`으로 볼 수 있습니다. 그리고 각 필드의 두 번째 요소(td)는 유효성 에러를 볼 수 있습니다. 310 | 311 | 마지막으로, 여러분은 제출(submit)을 할 수 있는 버튼을 가지고 있습니다. 제출하고 나서 이름이나 나이에 있는 `@Valid` 조건을 위반한 값을 입력할 경우 이 페이지로 돌아가서 에러 메시지를 화면에 보여줄 것입니다. 만약 이름과 나이를 조건에 맞게 입력할 경우 다음 페이지로 이동할 것입니다. 312 | 313 | `src/main/resources/templates/results.html` 314 | 315 | ```html 316 | 317 | 318 | Congratulations! You are old enough to sign up for this site. 319 | 320 | 321 | ``` 322 | 323 | > 이 예제에서 어느 페이지도 복잡한 CSS나 JavaScript를 가지고 있지는 않습니다. 그러나 여러분이 웹페이지 꾸미는 것을 배우는 것은 매우 가치 있는 일입니다. 324 | 325 | 326 | ## 어플리케이션 클래스 만들기 327 | 이 어플리케이션을 위해 여러분은 [Thymeleaf](http://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html) 템플릿 언어를 사용하고 있습니다. 그리고 이 어플리케이션은 순수 HTML보다 더 많은 것을 필요로 합니다. 328 | 329 | `src/main/java/hello/Application.java` 330 | 331 | ```java 332 | package hello; 333 | 334 | import org.springframework.boot.SpringApplication; 335 | import org.springframework.boot.autoconfigure.SpringBootApplication; 336 | 337 | @SpringBootApplication 338 | public class Application { 339 | 340 | public static void main(String[] args) throws Exception { 341 | SpringApplication.run(Application.class, args); 342 | } 343 | 344 | } 345 | ``` 346 | 347 | Spring에서는 MVC 활성화를 위해 어플리케이션 클래스에 보통 `@EnableWebMvc`를 더합니다. 그러나 Spring Boot에서는 클래스 패스 안에 **spring-webmvc**를 찾아서 이미 `@SpringBootApplication` 어노테이션이 더해져 있습니다. 이 어노테이션은 `@Controller`가 표시된 클래스와 안에 포함된 메소드를 찾습니다. 348 | 349 | Thymeleaf 환경설정은 또한 `@SpringBootApplication`안에 포함되어 있습니다. 그리고 `templates/` 폴더 아래에 있는 템플릿들의 '.html'의 접미어를 제거하여 뷰로 보여줍니다. Thymeleaf 세팅은 여러분의 원하는 바에 따라 다양하게 변경 가능합니다만 이 가이드에서는 다루지 않습니다. 350 | 351 | ## 실행가능한 JAR로 빌드하기 352 | 여러분은 Gradle이나 Maven을 이용한 커맨드 라인으로 이 어플리케이션을 실행할 수 있습니다. 또는 모든 필요한 의존성, 클래스, 자원 등을 포함한 하나의 실행 가능한 JAR로 빌드 할 수도 있습니다. 그래서 다양한 환경에서 개발 주기 전반에 걸쳐 버전을 올리고 서비스를 배포하는 것이 쉬워집니다. 353 | 354 | Gradle을 사용할 경우 `./gradlew bootRun` 명령어로 실행할 수 있습니다. 또는 `./gradlew build` 명령어로 JAR 파일을 만들고 다음과 같이 JAR 파일을 실행할 수 있습니다. 355 | 356 | ``` 357 | java -jar build/libs/gs-validating-form-input-0.1.0.jar 358 | ``` 359 | 360 | Maven을 사용할 경우 `./mvnw spring-boot:run` 명령어로 실행할 수 있습니다. 또는 `./mvnw clean package` 명령어로 JAR 파일을 만들고 다음과 같이 JAR 파일을 실행할 수 있습니다. 361 | 362 | ``` 363 | java -jar target/gs-validating-form-input-0.1.0.jar 364 | ``` 365 | 366 | > 이 행동은 실행 가능한 JAR 파일을 만드는 방법입니다. 물론 [WAR파일로 만드는 방법](http://spring.io/guides/gs/convert-jar-to-war/)도 대신 선택할 수 있습니다. 367 | 368 | 이 어플리케이션은 잠시 후 실행됩니다. 369 | 370 | 웹브라우저에서 http://localhost:8080/을 입력하면 다음과 같이 볼 수 있습니다. 371 | 372 | ![](http://spring.io/guides/gs/validating-form-input/images/valid-01.png) 373 | 374 | 이름에 **A**를 입력하고 나이에 **15**를 입력하고 **Submit**을 클릭해 봅시다. 375 | 376 | ![](http://spring.io/guides/gs/validating-form-input/images/valid-02.png) 377 | 378 | ![](http://spring.io/guides/gs/validating-form-input/images/valid-03.png) 379 | 380 | `PersonForm`클래스의 유효한 입력 조건에 맞지 않아 메인 페이지로 강제 이동된 것을 볼 수 있습니다. 입력란을 비우고 Submit 버튼을 누르면 또 다른 오류가 발생합니다. 381 | 382 | ![](http://spring.io/guides/gs/validating-form-input/images/valid-04.png) 383 | 384 | 유효한 이름과 나이를 입력하고 Submit 버튼을 누르면 `results` 페이지를 만날 수 있습니다. 385 | 386 | ![](http://spring.io/guides/gs/validating-form-input/images/valid-05.png) 387 | 388 | ## 요약 389 | 축하합니다! 유효성을 체크가 내장되어 있는 domain object를 활용하여 간단한 웹 어플리케이션을 만들었습니다. 이 방법대로 하면 데이터가 특정 기준을 충족시키고 사용자가 올바르게 입력했는지 확인할 수 있습니다. 390 | 391 | ## 추가로 볼만한 것 392 | 이 가이드들을 따라 하면 도움이 될 것입니다: 393 | * [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) 394 | * [Handling Form Submission](https://spring.io/guides/gs/handling-form-submission/) 395 | * [Securing a Web Application](https://spring.io/guides/gs/securing-web/) 396 | * [Building an Application with Spring Boot](https://spring.io/guides/gs/spring-boot/) 397 | -------------------------------------------------------------------------------- /restful-service-with-angularjs/README.md: -------------------------------------------------------------------------------- 1 | ## AngularJS로 RESTful 웹서비스 사용하기 2 | 이 가이드는 스프링 MVC 기반의 [RESTful web service](http://spring.io/understanding/REST)를 사용해서 간단한 AngularJS 클라이언트를 만드는 과정으로 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 여러분은 스프링 기반의 RESTful 웹서비스를 사용하는 AngularJS 클라이언트를 만들 것입니다. 특히 클라이언트는 [Building a RESTful Web Service with CORS](http://spring.io/guides/gs/rest-service-cors/)로 만들어진 서비스를 사용해 볼 것입니다. 6 | 7 | 이 AngularJS 클라이언트는 여러분의 브라우저에서 `index.html`파일에 접근해서 다음의 서비스를 요청할 것입니다: 8 | 9 | ``` 10 | http://rest-service.guides.spring.io/greeting 11 | ``` 12 | 13 | 이 서비스는 greeting 요청에 대해 [JSON](http://spring.io/understanding/JSON)으로 대답할 것입니다. 14 | 15 | ```json 16 | {"id":1,"content":"Hello, World!"} 17 | ``` 18 | 19 | 그리고 이 AngularJS 클라이언트는 ID와 content를 DOM에 넣을 것입니다. 20 | 21 | > 이 rest-service.guides.spring.io 서비스는 [CORS guide](http://spring.io/guides/gs/rest-service-cors/)에서 약간 수정을 거쳤고 `/greeting` 접근에 `@CrossOrigin`이 사용되어 공개적으로 접근할 수 있도록 되어있습니다. 22 | 23 | ## 무엇이 필요한가? 24 | * 약 15분의 시간 25 | * 좋아하는 텍스트 에디터 26 | * 최근에 나온 웹 브라우저 27 | * 인터넷 연결 28 | 29 | ## AngularJS 컨트롤러 만들기 30 | 첫 번째로, 여러분은 REST 서비스를 사용하는 AngularJS 컨트롤러 모듈을 만들어 볼 것입니다. 31 | 32 | `public/hello.js` 33 | 34 | ```js 35 | angular.module('demo', []) 36 | .controller('Hello', function($scope, $http) { 37 | $http.get('http://rest-service.guides.spring.io/greeting'). 38 | then(function(response) { 39 | $scope.greeting = response.data; 40 | }); 41 | }); 42 | ``` 43 | 44 | 이 컨트롤러 모듈은 AngularJS의 `$scope`와 `$http` 컴포넌트를 가지는 간단한 자바스크립트 함수를 제공받습니다. 그리고 "/greeting" 요청의 REST 서비스를 사용하기 위해 `$http` 컴포넌트를 사용합니다. 45 | 46 | 성공적으로 응답을 받으면, 이 컨트롤러는 서비스 요청에 대한 응답으로 온 JSON을 `$scope.greeting`에 넣고 "greeting"이라는 모델 오브젝트를 설정할 것입니다. 모델 오브젝트가 설정되면 AngularJS는 어플리케이션 페이지 DOM에 바인딩 할 수 있으며 유저에게 보여주도록 렌더링 할 수 있습니다. 47 | 48 | ## 어플리케이션 페이지 만들기 49 | 컨트롤러를 사용자의 웹 브라우저에 로드할 HTML 페이지를 만들어 보겠습니다. 50 | 51 | `public/index.html` 52 | 53 | ```html 54 | 55 | 56 | 57 | Hello AngularJS 58 | 59 | 60 | 61 | 62 | 63 |
64 |

The ID is {{greeting.id}}

65 |

The content is {{greeting.content}}

66 |
67 | 68 | 69 | ``` 70 | 71 | `head` 태그 안에 두 개의 스크립트 태그를 확인해보겠습니다. 72 | 73 | ```html 74 | 75 | 76 | ``` 77 | 78 | 첫 번째 스크립트 태그는 압축된 AngularJS 라이브러리(**angular.min.js**)를 CDN으로부터 불러오는 태그입니다. 그래서 여러분은 직접 라이브러리를 다운받아 프로젝트에 넣을 필요가 없습니다. 그리고 나머지 태그는 어플리케이션 폴더 안에 컨트롤러 코드(**hello.js**)를 로드됩니다. 79 | 80 | AngularJS 라이브러리는 표준 HTML 태그에서 몇 개의 커스텀 속성을 이용할 수 있게 합니다. index.html에서는 두 개의 속성을 사용합니다: 81 | 82 | * `` 태그 안의 `ng-app` 속성은 이 페이지가 AngularJS 어플리케이션 페이지인 것을 알려줍니다. 83 | * `
` 태그 안의 `ng-controller` 속성은 컨트롤러 모듈에서 `Hello` 속성을 참조하도록 설정합니다. 84 | 85 | 또한 두 개의 `

` 태그는 데이터를 바인딩 하기 위한 이중 중괄호({{}}) 구문(placeholders)을 사용합니다. 86 | 87 | ```html 88 |

The ID is {{greeting.id}}

89 |

The content is {{greeting.content}}

90 | ``` 91 | 92 | 바인딩 하기 위한 구문(placeholders)은 REST 서비스의 응답을 성공적으로 받은 후 설정 돠는 `greeting` 모델 객체의`id`와 `content` 속성을 참조하게 됩니다. 93 | 94 | ## 클라이언트 실행시키기 95 | 클라이언트를 실행하려면, 여러분은 웹 서버에서 브라우저로 콘텐츠를 제공해야 합니다. 스프링 부트 CLI(Command Line Interface)는 여러분이 웹 콘텐츠를 간단히 제공할 수 있도록 내장된 톰캣 서버를 포함하고 있습니다. CLI에 대해 많은 정보를 얻으시려면 [Building an Application with Spring Boot](http://spring.io/guides/gs/spring-boot/)를 보세요. 96 | 97 | 여러분은 내장된 톰캣 서버로 스프링 부트의 정적인 콘텐츠를 제공하기 위해 스프링 부트가 톰캣 서버에서 어플리케이션 코드를 실행하기 위한 최소한의 코드를 제공해야 합니다. 하단의 `app.groovy` 스크립트는 스프링 부트에게 여러분이 톰캣을 실행시키고 싶다고 알려주기 위한 충분한 단어입니다. 98 | 99 | `app.groovy` 100 | 101 | ```groovy 102 | @Controller class JsApp { } 103 | ``` 104 | 105 | 이제 여러분은 스프링 부트 CLI로 앱을 실행시킬 수 있습니다: 106 | 107 | ``` 108 | spring run app.groovy 109 | ``` 110 | 111 | 앱이 시작하면 브라우저를 열어서 http://localhost:8080 를 입력하세요. 그러면 아래와 같은 화면을 불 수 있습니다: 112 | 113 | ![](http://spring.io/guides/gs/consuming-rest-angularjs/images/hello.png) 114 | 115 | ID 값은 여러분이 페이지를 새로고침 할 때마다 증가할 것입니다. 116 | 117 | ## 요약 118 | 축하합니다! 여러분은 방금 스프링 기반의 RESTful 웹서비스를 사용한 AngularJS 클라이언트를 만들었습니다. 119 | 120 | ## 추가로 볼만한 것 121 | 아래 가이드를 따라 하면 도움이 될 것입니다: 122 | 123 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 124 | * [Consuming a RESTful Web Service](https://spring.io/guides/gs/consuming-rest/) 125 | * [Consuming a RESTful Web Service with jQuery](https://spring.io/guides/gs/consuming-rest-jquery/) 126 | * [Consuming a RESTful Web Service with rest.js](https://spring.io/guides/gs/consuming-rest-restjs/) 127 | * [Accessing GemFire Data with REST](https://spring.io/guides/gs/accessing-gemfire-data-rest/) 128 | * [Accessing MongoDB Data with REST](https://spring.io/guides/gs/accessing-mongodb-data-rest/) 129 | * [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/) 130 | * [Accessing JPA Data with REST](https://spring.io/guides/gs/accessing-data-rest/) 131 | * [Accessing Neo4j Data with REST](https://spring.io/guides/gs/accessing-neo4j-data-rest/) 132 | * [Securing a Web Application](https://spring.io/guides/gs/securing-web/) 133 | * [Building an Application with Spring Boot](https://spring.io/guides/gs/spring-boot/) 134 | * [Creating API Documentation with Restdocs](https://spring.io/guides/gs/testing-restdocs/) 135 | * [Enabling Cross Origin Requests for a RESTful Web Service](https://spring.io/guides/gs/rest-service-cors/) 136 | * [Building a Hypermedia-Driven RESTful Web Service](https://spring.io/guides/gs/rest-hateoas/) 137 | -------------------------------------------------------------------------------- /restful-service-with-jquery/README.md: -------------------------------------------------------------------------------- 1 | ## jQuery로 RESTful 웹서비스 사용하기 2 | 이 가이드는 스프링-MVC 기반의 [RESTful web service](http://spring.io/understanding/REST)를 사용하는 간단한 jQuery 클라이언트를 만드는 과정으로 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 여러분은 스프링 기반의 RESTful 웹서비스를 사용하는 jQuery 클라이언트를 만들 것입니다. 특히 클라이언트는 [Building a RESTful Web Service with CORS](http://spring.io/guides/gs/rest-service-cors/)로 만들어진 서비스를 사용해 볼 것입니다. 6 | 7 | jQuery 클라이언트는 여러분의 브라우저에서 `index.html`파일에 접근해서 다음의 서비스를 요청할 것입니다: 8 | 9 | ``` 10 | http://rest-service.guides.spring.io/greeting 11 | ``` 12 | 13 | 해당 서비스는 greeting 요청에 대해 [JSON](http://spring.io/understanding/JSON)으로 대답할 것입니다. 14 | 15 | ```json 16 | {"id":1,"content":"Hello, World!"} 17 | ``` 18 | 19 | 그리고 이 jQuery 클라이언트는 ID와 content를 DOM에 넣을 것입니다. 20 | 21 | ## 무엇이 필요한가? 22 | * 약 15분의 시간 23 | * 좋아하는 텍스트 편집기 24 | * 최근에 나온 웹 브라우저 25 | * 인터넷 연결 26 | 27 | ## jQuery 컨트롤러 만들기 28 | 첫 번째로, 여러분은 REST 서비스를 사용하는 jQuery 컨트롤러 모듈을 만들어야 합니다. 29 | 30 | `public/hello.js` 31 | 32 | ```js 33 | $(document).ready(function() { 34 | $.ajax({ 35 | url: "http://rest-service.guides.spring.io/greeting" 36 | }).then(function(data) { 37 | $('.greeting-id').append(data.id); 38 | $('.greeting-content').append(data.content); 39 | }); 40 | }); 41 | ``` 42 | 43 | 컨트롤러 모듈은 간단한 자바스크립트 함수로 표현되었습니다. 그리고 jQuery의 `$.ajax()` 메소드를 사용하여 http://rest-service.guides.spring.io/greeting의 REST 서비스를 사용합니다. 성공적으로 가져오면, JSON으로 받은 `data`를 활용하여 `Greeting` 모델 객체를 만듭니다. 그리고 `id`와 `content`는 각각 `greeting-id`과 `greeting-content` DOM 요소에 추가됩니다. 44 | 45 | jQuery가 `.then()`이라는 프로미스를 사용하는 것을 주목하세요. 이 메소드는 jQuery에서 익명 함수를 실행 시 사용된 `$.ajax()`라는 비동기 메소드가 완료될 때 AJAX 응답이 끝나면 `data`라는 결과를 넘겨줍니다. 46 | 47 | 48 | ## 어플리케이션 페이지 만들기 49 | 여러분은 jQuery 컨트롤러를 만들었습니다. 이제는 웹브라우저 안으로 불러올 HTML 페이지를 만들어 보겠습니다. 50 | 51 | `public/index.html` 52 | 53 | ```html 54 | 55 | 56 | 57 | Hello jQuery 58 | 59 | 60 | 61 | 62 | 63 |
64 |

The ID is

65 |

The content is

66 |
67 | 68 | 69 | ``` 70 | 71 | `` 태그 안에 들어있는 두 개의 스크립트를 확인해 보겠습니다. 72 | 73 | ```html 74 | 75 | 76 | ``` 77 | 78 | 첫 번째 스크립트는 CDN으로부터 압축된 jQuery 라이브러리(jquery.min.js)를 불러옵니다. 그래서 여러분은 jQuery를 다운로드 후 프로젝트 안에 놓을 필요가 없습니다. 79 | 80 | 이 스크립트는 또한 여러분의 어플리케이션 경로 안에 있는 컨트롤러 코드(hello.js)를 불러옵니다. 81 | 82 | 이번에는 `

`태그 안에 포함된 `class` 속성을 확인해 보겠습니다. 83 | 84 | ```html 85 |

The ID is

86 |

The content is

87 | ``` 88 | 89 | 이 `class`속성은 jQuery가 HTML 요소를 참조하는 것과 REST 서비스에서 받아온 JSON의 `id`와 `content`값을 사용해 업데이트하는 것을 도와줍니다. 90 | 91 | ## 클라이언트 실행시키기 92 | 클라이언트를 실행하려면, 여러분은 웹 서버에서 브라우저로 콘텐츠를 제공해야 합니다. 스프링 부트 CLI(Command Line Interface)는 여러분이 웹 콘텐츠를 간단히 제공할 수 있도록 내장된 톰캣 서버를 포함하고 있습니다. CLI에 대해 많은 정보를 얻으시려면 [Building an Application with Spring Boot](http://spring.io/guides/gs/spring-boot/)를 보세요. 93 | 94 | 여러분은 내장된 톰캣 서버로 스프링 부트의 정적인 콘텐츠를 제공하기 위해 스프링 부트가 톰캣 서버에서 어플리케이션 코드를 실행하기 위한 최소한의 코드를 제공해야 합니다. 하단의 `app.groovy` 스크립트는 스프링 부트에게 여러분이 톰캣을 실행시키고 싶다고 알려주기 위한 충분한 단어입니다. 95 | 96 | `app.groovy` 97 | 98 | ```groovy 99 | @Controller class JsApp { } 100 | ``` 101 | 102 | 이제 여러분은 스프링 부트 CLI로 앱을 실행시킬 수 있습니다. 103 | 104 | ``` 105 | spring run app.groovy 106 | ``` 107 | 108 | 앱이 시작하면 브라우저를 열어서 http://localhost:8080를 입력하세요. 그러면 아래와 같은 화면을 불 수 있습니다: 109 | 110 | ![](http://spring.io/guides/gs/consuming-rest-jquery/images/hello.png) 111 | 112 | ID 값은 여러분이 페이지를 새로고침 할 때마다 증가할 것입니다. 113 | 114 | ## 요약 115 | 축하합니다! 여러분은 방금 스프링 기반의 RESTful 웹서비스를 사용한 jQuery 클라이언트를 만들었습니다. 116 | 117 | ## 추가로 볼만한 것 118 | 아래 가이드를 따라 하면 도움이 될 것입니다: 119 | 120 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 121 | * [Consuming a RESTful Web Service](https://spring.io/guides/gs/consuming-rest/) 122 | * [Consuming a RESTful Web Service with AngularJS](https://spring.io/guides/gs/consuming-rest-angularjs/) 123 | * [Consuming a RESTful Web Service with rest.js](https://spring.io/guides/gs/consuming-rest-restjs/) 124 | * [Accessing GemFire Data with REST](https://spring.io/guides/gs/accessing-gemfire-data-rest/) 125 | * [Accessing MongoDB Data with REST](https://spring.io/guides/gs/accessing-mongodb-data-rest/) 126 | * [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/) 127 | * [Accessing JPA Data with REST](https://spring.io/guides/gs/accessing-data-rest/) 128 | * [Accessing Neo4j Data with REST](https://spring.io/guides/gs/accessing-neo4j-data-rest/) 129 | * [Securing a Web Application](https://spring.io/guides/gs/securing-web/) 130 | * [Building an Application with Spring Boot](https://spring.io/guides/gs/spring-boot/) 131 | * [Creating API Documentation with Restdocs](https://spring.io/guides/gs/testing-restdocs/) 132 | * [Enabling Cross Origin Requests for a RESTful Web Service](https://spring.io/guides/gs/rest-service-cors/) 133 | * [Building a Hypermedia-Driven RESTful Web Service](https://spring.io/guides/gs/rest-hateoas/) -------------------------------------------------------------------------------- /restful-service-with-restjs/README.md: -------------------------------------------------------------------------------- 1 | ## rest.js를 이용하여 RESTful 웹 서비스 만들기 2 | 이 가이드는 스프링 MVC 기반의 [RESTful web service](http://spring.io/understanding/REST)를 사용하여 간단한 rest.js 클라이언트를 만드는 과정으로 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 여러분은 스프링 기반의 RESTful 웹 서비스를 사용한 rest.js 클라이언트를 만들 것입니다. 특히 이 클라이언트는 [Building a RESTful Web Service with CORS](http://spring.io/guides/gs/rest-service-cors/)로 만들어진 서비스를 사용해서 만들 예정입니다. 6 | 7 | 이 rest.js 클라이언트를 브라우저에서 열면 `index.html` 파일에 접근하게 됩니다. 그리고 이 클라이언트는 다음의 서비스에 접근을 시도할 것입니다: 8 | 9 | ``` 10 | http://rest-service.guides.spring.io/greeting 11 | ``` 12 | 13 | 이 서비스는 greeting 요청에 대한 응답으로 아레와 같은 [JSON](http://spring.io/understanding/JSON)을 돌려줄 것입니다. 14 | 15 | ```json 16 | {"id":1,"content":"Hello, World!"} 17 | ``` 18 | 19 | 이 클라이언트는 서비스의 응답으로 받은 ID와 콘텐츠를 DOM 안에 넣을 것입니다. 20 | 21 | 여러분은 url 안의 **쿼리 스트링**을 넣어서 greeting에 대한 요청을 임의로 변경할 수 있습니다. 22 | 23 | ``` 24 | http://localhost:8080/?User 25 | ``` 26 | 27 | 그리고 코드에서는 REST 파라미터를 보내서 greeting에 대한 응답을 DOM 안에 표시할 것입니다. 28 | 29 | ## 무엇이 필요한가? 30 | * 약 15분의 시간 31 | * 좋아하는 텍스트 에디터 32 | * 최신의 웹 브라우저 33 | * 인터넷 연결 34 | * Node.js 와 [Git](http://spring.io/understanding/Git)이 설치된 환경 35 | * 글로벌로 설치 된 Bower node.js [JavaScript package](http://spring.io/understanding/javascript-package-managers) 36 | 37 | ## bower 환경설정 파일 만들기 38 | 첫째로 bower 컨트롤 파일인 `.bowerrc`를 만듭니다. 이 파일은 bower가 자바스크립트 의존 파일을 어디 놓을 것인지 알려줍니다. `.bowerrc`파일은 프로젝트의 루트 기준으로 ({project_id}/initial) 폴더 아래에 JSON 포맷으로 생성 후하는 것이 좋습니다: 39 | 40 | `.bowerrc` 41 | 42 | ```json 43 | { 44 | "directory": "public/lib" 45 | } 46 | ``` 47 | 48 | 커맨드 프롬프트에서 프로젝트의 루트 폴더로 이동 후 `bower init`을 입력하여 실행시킵니다. 그러면 프로젝트에서 필요한 [JavaScript package](http://spring.io/understanding/javascript-package-managers)가 쓰인 `bower.json` 파일이 만들어집니다. 또한 Bower는 프로젝트 명이나 라이센스 등 여러 가지 정보를 물어볼 것입니다. 잘 모르겠고 의심스럽다면, `Enter`를 눌러서 기본값으로 지정된 것을 사용하세요. 49 | 50 | 다음으로 Bower를 사용해서 rest.js와 curl.js 같은 [AMD module](http://spring.io/understanding/javascript-modules)을 설치합니다. 커맨드 프롬프트에서 입력하세요: 51 | 52 | ``` 53 | bower install --save rest#~1 54 | ``` 55 | 56 | ``` 57 | bower install --save curl#~0.8 58 | ``` 59 | 60 | Bower는 `.bowerrc`에 지정한 디렉토리로 rest.js와 curl.js를 설치할 것입니다. 우리가 설치할 때 옵션을 `--save`로 지정하면 Bower는 그 이후 `bower.json` 파일에 패키지 정보를 저장하게 됩니다. 61 | 62 | > Bower는 rest.js가 when.js에 의존하며 호환 가능한 버전을 설치해야 한다는 것을 발견합니다. 63 | 64 | 완료되면 `bower.json`파일은 "dependencies" 오브젝트의 속성으로 semver 정보가 표시된 "curl"과 "rest"속성을 가질 것입니다: 65 | 66 | `bower.json` 67 | 68 | ```json 69 | { 70 | "name": "consuming-rest-rest.js", 71 | "version": "0.0.1", 72 | "authors": [ 73 | "John Hann " 74 | ], 75 | "license": "http://www.apache.org/licenses/LICENSE-2.0", 76 | "ignore": [ 77 | "**/.*", 78 | "node_modules", 79 | "public/lib", 80 | "test", 81 | "tests" 82 | ], 83 | "dependencies": { 84 | "curl": "~0.8", 85 | "rest": "~1" 86 | } 87 | } 88 | ``` 89 | 90 | ## 화면에 표시될(render) 모듈 만들기 91 | 첫째로 HTML 문서에 데이터를 집어넣을 render 함수를 만듭니다. 92 | 93 | `public/hello/render.js` 94 | 95 | ```js 96 | define(function (require) { 97 | 98 | var ready = require('curl/domReady'); 99 | 100 | return render; 101 | 102 | function render (entity) { 103 | ready(function () { 104 | var idElement, nameElement; 105 | 106 | idElement = document.querySelector('[data-name="id"]'); 107 | nameElement = document.querySelector('[data-name="content"]'); 108 | 109 | idElement.textContent += entity.id; 110 | nameElement.textContent += entity.content; 111 | }); 112 | } 113 | 114 | }); 115 | ``` 116 | 117 | 이 [AMD module](http://spring.io/understanding/javascript-modules)은 간단한 DOM 쿼리 스트링을 이용해서 문서에 텍스트를 집어넣습니다. DOM이 준비되기 전에 사용하는 것을 막기 위해서 render 모듈은 curl.js 안의 `domReady` 함수 모듈을 사용합니다. 118 | 119 | > 실제 서비스에서 여러분은 현재 DOM 조작한 부분에 **데이터 바인딩**이나 **템플릿 작업**을 할 확률이 높습니다. 120 | 121 | ## 어플리케이션을 구성하는 모듈 만들기 122 | 다음에는 어플리케이션을 구성하는 모듈을 만들겠습니다. 123 | 124 | `public/hello/main.js` 125 | 126 | ```js 127 | define(function (require) { 128 | 129 | var rest = require('rest'); 130 | var mime = require('rest/interceptor/mime'); 131 | var entity = require('rest/interceptor/entity'); 132 | var render = require('./render'); 133 | 134 | var endpointUrl, name, client; 135 | 136 | endpointUrl = 'http://rest-service.guides.spring.io/greeting'; 137 | name = document.location.search.slice(1); 138 | 139 | client = rest 140 | .chain(mime, { mime: 'application/json' }) 141 | .chain(entity); 142 | 143 | client({ path: endpointUrl, params: { name: name } }) 144 | .then(render); 145 | 146 | }); 147 | ``` 148 | 149 | 메인 모듈은 document.location 오브젝트로부터 쿼리 스트링을 읽어 rest.js의 mime 오브젝트를 구성하고 호출에 대한 REST 응답을 호출합니다. 150 | 151 | rest.js는 [Promises/A+ promise](http://spring.io/understanding/javascript-promises)를 리턴합니다, 그러므로 나중에 데이터를 받으면 `render` 함수 모듈을 호출할 것입니다. `render` 함수는 즉시 사용 가능한 개체(entity)를 원하는데 rest.js는 보통 response 오브젝트를 반환합니다. 그래서 "rest/interceptor/entity" 인터셉터를 사용해서 response 오브젝트로부터 개체(entity)를 뽑아 `render` 함수로 전달할 것입니다. 152 | 153 | ## 부트 스크립트 만들기 154 | 다음으로는 부트 스크립트인 `run.js`를 만들어 보겠습니다: 155 | 156 | `public/run.js` 157 | 158 | ```js 159 | var curl; 160 | (function () { 161 | 162 | curl.config({ 163 | main: 'hello', 164 | packages: { 165 | // Your application's packages 166 | hello: { location: 'hello' }, 167 | // Third-party packages 168 | curl: { location: 'lib/curl/src/curl' }, 169 | rest: { location: 'lib/rest', main: 'rest' }, 170 | when: { location: 'lib/when', main: 'when' } 171 | } 172 | }); 173 | 174 | }()); 175 | ``` 176 | 177 | 이 스크립트는 `curl.config()`로 AMD 로더를 설정합니다. 그리고 curl.js는 메인 모듈의 `main` 속성으로 지정된 경로에서 파일을 찾아 자동으로 불러옵니다. `packages` 속성은 curl.js에게 이 어플리케이션의 패키지와 다른 사람이 제작한 패키지를 참조할 위치를 알려줍니다. 178 | 179 | ## 어플리케이션 페이지 만들기 180 | 마지막으로 `index.html`를 만들어 보겠습니다. 181 | 182 | `public/index.html` 183 | 184 | ```html 185 | 186 | 187 | 188 | Hello rest.js 189 | 190 | 191 | 192 |
193 |

The ID is

194 |

The content is

195 |
196 | 197 | 198 | ``` 199 | 200 | `script` 요소는 curl.js를 로드하고 "run.js"라는 **어플리케이션 시작 스크립트**를 로드합니다. 이 시작 스크립트는 AMD 모듈 환경설정을 구성하고 초기화 후 클라이언트의 코드를 실행합니다. 201 | 202 | ## 클라이언트 실행하기 203 | 클라이언트를 실행하려면, 여러분은 웹 서버에서 브라우저로 콘텐츠를 제공해야 합니다. 스프링 부트 CLI(Command Line Interface)는 여러분이 웹 콘텐츠를 간단히 제공할 수 있도록 내장된 톰캣 서버를 포함하고 있습니다. CLI에 대해 많은 정보를 얻으시려면 [Building an Application with Spring Boot](http://spring.io/guides/gs/spring-boot/)를 보세요. 204 | 205 | 여러분은 내장된 톰캣 서버로 스프링 부트의 정적인 콘텐츠를 제공하기 위해 스프링 부트가 톰캣 서버에서 어플리케이션 코드를 실행하기 위한 최소한의 코드를 제공해야 합니다. 하단의 `app.groovy` 스크립트는 스프링 부트에게 여러분이 톰캣을 실행시키고 싶다고 알려주기 위한 충분한 단어입니다: 206 | 207 | `app.groovy` 208 | 209 | ```groovy 210 | @Controller class JsApp { } 211 | ``` 212 | 213 | 이제 여러분은 스프링 부트 CLI로 앱을 실행시킬 수 있습니다: 214 | 215 | ``` 216 | spring run app.groovy 217 | ``` 218 | 219 | 앱이 시작하면 브라우저를 열어서 http://localhost:8080를 입력하세요. 그러면 아래와 같은 화면을 불 수 있습니다: 220 | 221 | ![](http://spring.io/guides/gs/consuming-rest-restjs/images/hello.png) 222 | 223 | ID 값은 여러분이 페이지를 새로고침 할 때마다 증가할 것입니다. 224 | 225 | ## 요약 226 | 축하합니다! 여러분은 방금 스프링 기반의 RESTful 웹서비스를 사용한 rest.js 클라이언트를 만드셨습니다. 227 | 228 | ## 추가로 볼만한 것 229 | 아래 가이드를 따라 하면 도움이 될 것입니다: 230 | 231 | * [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) 232 | * [Consuming a RESTful Web Service](https://spring.io/guides/gs/consuming-rest/) 233 | * [Consuming a RESTful Web Service with AngularJS](https://spring.io/guides/gs/consuming-rest-angularjs/) 234 | * [Consuming a RESTful Web Service with jQuery](https://spring.io/guides/gs/consuming-rest-jquery/) 235 | * [Accessing GemFire Data with REST](https://spring.io/guides/gs/accessing-gemfire-data-rest/) 236 | * [Accessing MongoDB Data with REST](https://spring.io/guides/gs/accessing-mongodb-data-rest/) 237 | * [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/) 238 | * [Accessing JPA Data with REST](https://spring.io/guides/gs/accessing-data-rest/) 239 | * [Accessing Neo4j Data with REST](https://spring.io/guides/gs/accessing-neo4j-data-rest/) 240 | * [Securing a Web Application](https://spring.io/guides/gs/securing-web/) 241 | * [Building an Application with Spring Boot](https://spring.io/guides/gs/spring-boot/) 242 | * [Creating API Documentation with Restdocs](https://spring.io/guides/gs/testing-restdocs/) 243 | * [Enabling Cross Origin Requests for a RESTful Web Service](https://spring.io/guides/gs/rest-service-cors/) 244 | * [Building a Hypermedia-Driven RESTful Web Service](https://spring.io/guides/gs/rest-hateoas/) -------------------------------------------------------------------------------- /start-guid-with-intellij/README.md: -------------------------------------------------------------------------------- 1 | ## IntelliJ IDEA로 스프링 가이드 시작하기 2 | 이 가이드는 시작 가이드 하나를 IntelliJ IDEA를 사용하여 만드는 과정을 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 여러분은 스프링 가이드를 선택하여 IntelliJ IDEA 안으로 넣을 것입니다. 그러고 나서 가이드를 읽으며 예제 코드를 작업하고 여러분이 생성한 프로젝트를 실행할 수 있습니다. 6 | 7 | ## 무엇이 필요한가? 8 | * 약 15분의 시간 9 | * [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) 10 | * [JDK 6](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 이상 11 | 12 | ## IntelliJ IDEA 설치하기 13 | 여러분이 아직 IntelliJ IDEA (Ultimate Edition)를 설치하지 않으셨다면, [링크](https://www.jetbrains.com/idea/download/)를 방문해 주십시오. 그리고 여기서 여러분의 플랫폼에 맞게 다운로드 받으세요. 그리고 압축을 해제해주세요. 14 | 모두 다 완료되면 IntelliJ IDEA를 실행해주세요. 15 | 16 | ## 스프링 시작가이드를 불러오기 17 | 스프링 가이드 중 여러분이 필요한 프로젝트 하나만 선택해서 불러오겠습니다. 예를들어 [REST Service](https://spring.io/guides/gs/rest-service/) 가이드의 경우는 : 18 | 19 | ```bash 20 | $ git clone https://github.com/spring-guides/gs-rest-service.git 21 | ``` 22 | 23 | IntelliJ IDEA가 실행되면 **시작 화면**에서 **Import Project**를 선택하시거나 메인 메뉴에서 **File | Open**를 클릭해주세요. 24 | 25 | ![](http://spring.io/guides/gs/intellij-idea/images/spring_guide_welcome_import.png) 26 | 27 | 팝업창이 뜨면 **complete**폴더 아래에서 [Maven](http://spring.io/guides/gs/maven)의 **pom.xml**이나 [Gradle](http://spring.io/guides/gs/gradle)의 **build.gradle**중 하나를 클릭해주세요: 28 | 29 | ![](http://spring.io/guides/gs/intellij-idea/images/spring_guide_select_gradle_file.png) 30 | 31 | IntelliJ IDEA는 선택한 가이드를 실행 가능한 상태로 생성할 것입니다. 32 | 33 | ## 처음부터 프로젝트 생성하기 34 | 여러분이 새롭게 빈 프로젝트를 생성해서 가이드를 따라하고 싶은 경우, **Project Wizard**를 선택하셔서 **Maven** 이나 **Gradle** 프로젝트를 만들 수 있습니다. 35 | 36 | ![](http://spring.io/guides/gs/intellij-idea/images/spring_guide_new_project.png) 37 | 38 | ## 추가로 볼만한 것 39 | 이 가이드들을 따라 하면 도움이 될 것입니다: 40 | 41 | * [STS로 스프링 가이드 시작하기](https://spring.io/guides/gs/sts/) -------------------------------------------------------------------------------- /working-with-sts/README.md: -------------------------------------------------------------------------------- 1 | ## STS로 스프링 가이드 시작하기 2 | 이 가이드는 시작 가이드 하나를 Spring Tool Suite (STS)를 사용하여 만드는 과정을 안내합니다. 3 | 4 | ## 무엇을 만들게 되는가? 5 | 여러분은 스프링 가이드를 선택하여 Spring Tool Suite 안으로 넣을 것입니다. 그러고 나서 가이드를 읽으며 예제 코드를 작업하고 여러분이 생성한 프로젝트를 실행할 수 있습니다. 6 | 7 | ## 무엇이 필요한가? 8 | * 약 15분의 시간 9 | * [Spring Tool Suite (STS)](https://spring.io/tools/sts/all) 10 | * [JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 또는 그 이상 11 | 12 | ## STS 설치하기 13 | 아직 STS를 설치하지 않았다면, [링크](http://spring.io/tools)를 방문하십시오. 여기서 여러분의 환경에 맞게 다운로드하셔서 압축만 푸시면 설치가 완료됩니다. 14 | 15 | 모든 과정을 마치셨으면 STS를 실행해봅시다. 16 | 17 | ## 스프링 시작가이드를 불러오기 18 | STS가 켜지면 상단의 **File** 메뉴를 클릭하시고 **Import Spring Getting Started Content**를 선택합니다. 19 | 20 | ![](http://spring.io/guides/gs/sts/images/1_open_wizard.png) 21 | 팝업으로 뜬 마법사가 여러분에게 스프링 웹사이트에 나와있는 가이드 중 하나를 선택할 수 있도록 도와줄 것입니다. 목록을 건너뛰거나 검색어를 입력해서 옵션을 바꿀 수 있습니다. 22 | 23 | > 검색어는 제목과 설명 둘 다 반영해서 검색됩니다. 그리고 와일드카드 문자를 사용할 수 있습니다. 24 | 25 | 여러분은 [Maven](http://spring.io/guides/gs/maven) 이나 [Gradle](http://spring.io/guides/gs/gradle)을 사용해서 프로젝트를 만들 수 있습니다. 26 | 27 | 그리고 여러분은 또한 **initial** 코드와 **complete** 중 선택해서 가져오거나 둘 다 가져올 수 있습니다. 대부분의 프로젝트에서는 **initial**코드는 비어있는 프로젝트입니만 가이드에 따라서 복사 및 붙여넣기가 가능하게 되어있습니다. **complete**코드의 경우는 모든 코드가 가이드의 진행 순서에 따라서 미리 입력되어 있습니다. 만약 둘 다 가져온다면 여러분이 작성한 코드와 완성된 코드를 비교할 수 있을 것입니다. 28 | 29 | 모두 마치면 STS는 여러분이 선택한 가이드가 표시된 웹사이트를 열 것입니다. STS 안에서도 가이드를 보며 여러분은 작업을 할 수 있습니다. 30 | 31 | 이 가이드에서는 검색창에 **rest**를 입력할 것이며 [Consuming Rest](http://spring.io/guides/gs/consuming-rest)를 선택할 것입니다. 그리고 빌드 툴로 **Maven**을 선택할 것이며 **initial**과 **complete** 코드 셋을 선택할 것입니다. 또한 웹페이지를 열도록 하는 옵션을 선택했습니다: 32 | 33 | ![](http://spring.io/guides/gs/sts/images/3_wizard.png) 34 | 35 | STS는 [Consuming Rest](http://spring.io/guides/gs/consuming-rest)의 initial과 complete의 코드가 들어있는 두 개의 새로운 프로젝트를 여러분이 선택한 폴더 안에 만듭니다. 그리고 STS의 내장 브라우저가 열립니다: 36 | 37 | ![](http://spring.io/guides/gs/sts/images/4_after-import.png) 38 | 39 | 여러분은 이 화면에서 브라우저에 표시된 가이드를 보며 코드 파일을 찾아갈 수 있습니다. 40 | 41 | ## 요약 42 | 축하합니다! 여러분은 STS를 설치하고 스프링 시작 가이드 중 Consuming Rest 프로젝트를 만들었으며 해당 가이드의 브라우저를 열었습니다. 43 | 44 | ## 추가로 볼만한 것 45 | 이 가이드들을 따라 하면 도움이 될 것입니다: 46 | 47 | * [IntelliJ IDEA로 스프링 가이드 시작하기](https://spring.io/guides/gs/intellij-idea/) 48 | --------------------------------------------------------------------------------