(window.webpackJsonp=window.webpackJsonp||[]).push([[371],{804:function(e,t,r){"use strict";r.r(t);var n=r(56),a=Object(n.a)({},(function(){var e=this,t=e.$createElement,r=e._self._c||t;return r("ContentSlotsDistributor",{attrs:{"slot-key":e.$parent.slotKey}},[r("h1",{attrs:{id:"构建-restful-web-服务"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#构建-restful-web-服务"}},[e._v("#")]),e._v(" 构建 RESTful Web 服务")]),e._v(" "),r("p",[e._v("本指南将引导您完成使用 Spring 创建“Hello, World” RESTful Web项目。")]),e._v(" "),r("h2",{attrs:{id:"你将开发什么"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#你将开发什么"}},[e._v("#")]),e._v(" 你将开发什么")]),e._v(" "),r("p",[e._v("您将开发一个HTTP服务,可以接收如下GET 请求:"),r("code",[e._v("http://localhost:8080/greeting")]),e._v("。")]),e._v(" "),r("p",[e._v("它将以JSON格式返回值响应请求,如以下清单所示:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('{"id":1,"content":"Hello, World!"}\n')])])]),r("p",[e._v("您可以在请求链接中使用"),r("code",[e._v("name")]),e._v("参数发送请求,如以下清单所示:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("http://localhost:8080/greeting?name=User\n")])])]),r("p",[e._v("请求返回报文中,"),r("code",[e._v("name")]),e._v("参数值将覆盖默认值"),r("code",[e._v("World")]),e._v(",如下所示:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('{"id":1,"content":"Hello, User!"}\n')])])]),r("h2",{attrs:{id:"你需要什么"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#你需要什么"}},[e._v("#")]),e._v(" 你需要什么")]),e._v(" "),r("ul",[r("li",[e._v("约15分钟")]),e._v(" "),r("li",[e._v("最喜欢的文本编辑器或IDE")]),e._v(" "),r("li",[r("a",{attrs:{href:"http://www.oracle.com/technetwork/java/javase/downloads/index.html",target:"_blank",rel:"noopener noreferrer"}},[e._v("JDK 1.8"),r("OutboundLink")],1),e._v("或更高版本")]),e._v(" "),r("li",[r("a",{attrs:{href:"http://www.gradle.org/downloads",target:"_blank",rel:"noopener noreferrer"}},[e._v("Gradle 4+"),r("OutboundLink")],1),e._v("或"),r("a",{attrs:{href:"https://maven.apache.org/download.cgi",target:"_blank",rel:"noopener noreferrer"}},[e._v("Maven 3.2+"),r("OutboundLink")],1)]),e._v(" "),r("li",[e._v("您还可以将代码直接导入 IDE:\n"),r("ul",[r("li",[r("a",{attrs:{href:"https://spring.io/guides/gs/sts",target:"_blank",rel:"noopener noreferrer"}},[e._v("Spring 工具套件 (STS)"),r("OutboundLink")],1)]),e._v(" "),r("li",[r("a",{attrs:{href:"https://spring.io/guides/gs/intellij-idea/",target:"_blank",rel:"noopener noreferrer"}},[e._v("IntelliJ IDEA"),r("OutboundLink")],1)])])])]),e._v(" "),r("h2",{attrs:{id:"如何完成本指南"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#如何完成本指南"}},[e._v("#")]),e._v(" 如何完成本指南")]),e._v(" "),r("p",[e._v("像大多数 Spring"),r("a",{attrs:{href:"https://spring.io/guides",target:"_blank",rel:"noopener noreferrer"}},[e._v("入门指南"),r("OutboundLink")],1),e._v("一样,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。无论哪种方式,您最终都会获得可用的代码。")]),e._v(" "),r("p",[e._v("要"),r("strong",[e._v("从头开始")]),e._v(",请跳转到"),r("a",{attrs:{href:"https://spring.io/guides/gs/rest-service/#scratch",target:"_blank",rel:"noopener noreferrer"}},[e._v("从 Spring Initializr 开始"),r("OutboundLink")],1),e._v("。")]),e._v(" "),r("p",[e._v("要"),r("strong",[e._v("跳过基础知识")]),e._v(",请执行以下操作:")]),e._v(" "),r("ul",[r("li",[r("a",{attrs:{href:"https://github.com/spring-guides/gs-rest-service/archive/main.zip",target:"_blank",rel:"noopener noreferrer"}},[e._v("下载"),r("OutboundLink")],1),e._v("并解压缩本指南的源存储库,或使用"),r("a",{attrs:{href:"https://spring.io/understanding/Git",target:"_blank",rel:"noopener noreferrer"}},[e._v("Git"),r("OutboundLink")],1),e._v(" Clone:"),r("code",[e._v("git clone https://github.com/spring-guides/gs-rest-service.git")])]),e._v(" "),r("li",[e._v("cd into "),r("code",[e._v("gs-rest-service/initial")])]),e._v(" "),r("li",[e._v("继续"),r("a",{attrs:{href:"https://spring.io/guides/gs/rest-service/#initial",target:"_blank",rel:"noopener noreferrer"}},[e._v("创建资源表示类"),r("OutboundLink")],1),e._v("。")])]),e._v(" "),r("p",[r("strong",[e._v("完成后")]),e._v(",您可以从如下目录查看结果代码 "),r("code",[e._v("gs-rest-service/complete")]),e._v("。")]),e._v(" "),r("h2",{attrs:{id:"从-spring-initializr-开始"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#从-spring-initializr-开始"}},[e._v("#")]),e._v(" 从 Spring Initializr 开始")]),e._v(" "),r("p",[e._v("您可以使用这个[预先初始化的项目](https://start.spring.io/#!type=maven-project&language=java&platformVersion=2.5.5&packaging=jar&jvmVersion=11&groupId=com.example&artifactId=rest-service&name=rest-service&description=Demo project for Spring Boot&packageName=com.example.rest-service&dependencies=web)并单击 Generate 下载 ZIP 文件。此项目配置兼容本教程中的示例。")]),e._v(" "),r("p",[e._v("手动初始化项目:")]),e._v(" "),r("ol",[r("li",[e._v("导航到"),r("a",{attrs:{href:"https://start.spring.io/",target:"_blank",rel:"noopener noreferrer"}},[e._v("https://start.spring.io"),r("OutboundLink")],1),e._v("。该服务提取应用程序所需的所有依赖项,并为您完成大部分设置。")]),e._v(" "),r("li",[e._v("选择 Gradle 或 Maven 以及您要使用的开发语言。本指南假定您选择了 Java。")]),e._v(" "),r("li",[e._v("单击"),r("strong",[e._v("Dependencies")]),e._v("并选择"),r("strong",[e._v("Spring Web")]),e._v("。")]),e._v(" "),r("li",[e._v("单击"),r("strong",[e._v("生成")]),e._v("。")]),e._v(" "),r("li",[e._v("下载生成的 ZIP 文件,该文件是根据您的选择配置的 Web 应用程序的存档。")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("如果您的 IDE 具有 Spring Initializr 集成,您可以从您的 IDE 完成此过程。\n")])])]),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("你也可以从 Github 上 fork 项目并在你的 IDE 或其他编辑器中打开它。\n")])])]),r("h2",{attrs:{id:"创建资源表示类"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#创建资源表示类"}},[e._v("#")]),e._v(" 创建资源表示类")]),e._v(" "),r("p",[e._v("现在您已经设置了项目和构建系统,您可以创建您的 Web 服务。")]),e._v(" "),r("p",[e._v("首先考虑服务交互流程。")]),e._v(" "),r("p",[e._v("该服务将处理访问"),r("code",[e._v("/greeting")]),e._v("的"),r("code",[e._v("GET")]),e._v("请求,请求可选参数 "),r("code",[e._v("name")]),e._v("。该"),r("code",[e._v("GET")]),e._v("请求在返回"),r("code",[e._v("200 OK")]),e._v("的情况下,JSON返回值如下:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('{\n "id": 1,\n "content": "Hello, World!"\n}\n')])])]),r("p",[e._v("该"),r("code",[e._v("id")]),e._v("字段是返回内容的唯一标识符,是返回内容"),r("code",[e._v("content")]),e._v("的文本表示。")]),e._v(" "),r("p",[e._v("要对返回内容建模,请创建一个资源表示类。为此,需要创建一个普通的Java 对象,其中包含"),r("code",[e._v("id")]),e._v("和"),r("code",[e._v("content")]),e._v("两个数据字段、构造函数和访问器,如以下(来自"),r("code",[e._v("src/main/java/com/example/restservice/Greeting.java")]),e._v(")所示:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("package com.example.restservice;\n\npublic class Greeting {\n\n\tprivate final long id;\n\tprivate final String content;\n\n\tpublic Greeting(long id, String content) {\n\t\tthis.id = id;\n\t\tthis.content = content;\n\t}\n\n\tpublic long getId() {\n\t\treturn id;\n\t}\n\n\tpublic String getContent() {\n\t\treturn content;\n\t}\n}\n")])])]),r("p",[e._v("此应用程序使用"),r("a",{attrs:{href:"https://github.com/FasterXML/jackson",target:"_blank",rel:"noopener noreferrer"}},[e._v("Jackson JSON"),r("OutboundLink")],1),e._v("库,将实例"),r("code",[e._v("Greeting")]),e._v("转换为JSON。web启动器默认包含Jackson。")]),e._v(" "),r("h2",{attrs:{id:"创建资源控制器"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#创建资源控制器"}},[e._v("#")]),e._v(" 创建资源控制器")]),e._v(" "),r("p",[e._v("在 Spring 构建的 RESTful Web 服务中,HTTP 请求由控制器处理。这些组件由"),r("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html",target:"_blank",rel:"noopener noreferrer"}},[r("code",[e._v("@RestController")]),r("OutboundLink")],1),e._v("注释标识,如下 "),r("code",[e._v("GreetingController")]),e._v("实例(参看 "),r("code",[e._v("src/main/java/com/example/restservice/GreetingController.java")]),e._v(")处理"),r("code",[e._v("GET")]),e._v("请求:"),r("code",[e._v("/greeting")])]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('package com.example.restservice;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.RestController;\n\n@RestController\npublic class GreetingController {\n\n\tprivate static final String template = "Hello, %s!";\n\tprivate final AtomicLong counter = new AtomicLong();\n\n\t@GetMapping("/greeting")\n\tpublic Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {\n\t\treturn new Greeting(counter.incrementAndGet(), String.format(template, name));\n\t}\n}\n')])])]),r("p",[e._v("这个控制器简洁明了,但底层有很多事情要做。我们一步一步分解。")]),e._v(" "),r("p",[r("code",[e._v("@GetMapping")]),e._v("注解确保 HTTP GET 请求"),r("code",[e._v("/greeting")]),e._v(" 可以映射到"),r("code",[e._v("greeting()")]),e._v("方法。")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("还有其他 HTTP 请求注解(例如`@PostMapping`POST)。所有注解均继承`@RequestMapping`,同时也可以使用如下注解方式(例如`@RequestMapping(method=GET)`)。\n")])])]),r("p",[r("code",[e._v("@RequestParam")]),e._v("将查询参数"),r("code",[e._v("name")]),e._v("的值绑定到方法"),r("code",[e._v("greeting()")]),e._v("的参数"),r("code",[e._v("name")]),e._v("上。如果请求中没有"),r("code",[e._v("name")]),e._v("参数,则使用参数默认值 "),r("code",[e._v("World")]),e._v("。")]),e._v(" "),r("p",[e._v("此方法创建并返回一个新"),r("code",[e._v("Greeting")]),e._v("对象,该对象包含"),r("code",[e._v("id")]),e._v("和"),r("code",[e._v("content")]),e._v("属性,并通过counter.incrementAndGet(), String.format(template, name) 分别进行参数赋值")]),e._v(" "),r("p",[e._v("传统 MVC 控制器和前面显示的 RESTful Web 服务控制器之间的一个关键区别是 HTTP 请求响应的创建方式。这个 RESTful Web 服务控制器不是依靠视图技术直接返回HTML类型的响应内容,而是填充并返回一个"),r("code",[e._v("Greeting")]),e._v("对象。对象数据将以 JSON 类型直接写入 HTTP 响应。")]),e._v(" "),r("p",[e._v("此代码使用 Spring"),r("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html",target:"_blank",rel:"noopener noreferrer"}},[r("code",[e._v("@RestController")]),r("OutboundLink")],1),e._v("注解,它将类标记为控制器,其中每个方法都返回域对象而不是视图。它是"),r("code",[e._v("@Controller")]),e._v("和"),r("code",[e._v("@ResponseBody")]),e._v("的简写。")]),e._v(" "),r("p",[e._v("该"),r("code",[e._v("Greeting")]),e._v("对象必须转换为 JSON 格式。依赖于 Spring 的 HTTP 消息转换器支持,您无需手动进行此转换。因为classpath里面已经包含"),r("a",{attrs:{href:"https://github.com/FasterXML/jackson",target:"_blank",rel:"noopener noreferrer"}},[e._v("Jackson 2"),r("OutboundLink")],1),e._v(",所以会自动选择Spring的"),r("a",{attrs:{href:"https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/converter/json/MappingJackson2HttpMessageConverter.html",target:"_blank",rel:"noopener noreferrer"}},[r("code",[e._v("MappingJackson2HttpMessageConverter")]),r("OutboundLink")],1),e._v("将"),r("code",[e._v("Greeting")]),e._v("实例转换为JSON格式。")]),e._v(" "),r("p",[r("code",[e._v("@SpringBootApplication")]),e._v("是一个方便的注释,它包含了以下所有内容:")]),e._v(" "),r("ul",[r("li",[r("code",[e._v("@Configuration")]),e._v(": 在应用程序上下文中,将类标记为bean。")]),e._v(" "),r("li",[r("code",[e._v("@EnableAutoConfiguration")]),e._v(":告诉 Spring Boot 根据类路径设置、其他 bean 和各种属性设置扫描并添加bean。例如,如果"),r("code",[e._v("spring-webmvc")]),e._v("位于类路径上,则此注释将应用程序标记为 Web 应用程序并激活关键行为,例如设置"),r("code",[e._v("DispatcherServlet")]),e._v(".")]),e._v(" "),r("li",[r("code",[e._v("@ComponentScan")]),e._v(": 告诉 Spring 在包"),r("code",[e._v("com/example")]),e._v("中扫描其他components, configurations及services类")])]),e._v(" "),r("p",[e._v("该"),r("code",[e._v("main()")]),e._v("方法使用 Spring Boot 的"),r("code",[e._v("SpringApplication.run()")]),e._v("方法来启动应用程序。您是否注意到我们没有配置一行 XML?也没有"),r("code",[e._v("web.xml")]),e._v("文件。这个 Web 应用程序是 100% 纯 Java,您不必处理任何管道或基础设施的配置。")]),e._v(" "),r("h3",{attrs:{id:"构建一个可执行的-jar"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#构建一个可执行的-jar"}},[e._v("#")]),e._v(" 构建一个可执行的 JAR")]),e._v(" "),r("p",[e._v("您可以使用 Gradle 或 Maven 从命令行运行应用程序。您还可以构建一个包含所有必要依赖项、类和资源的单个可执行 JAR 文件并运行它。构建可执行 jar 可以在整个开发生命周期、跨不同环境等中轻松地作为应用程序交付、版本化和部署服务。")]),e._v(" "),r("p",[e._v("如果您使用 Gradle,则可以使用"),r("code",[e._v("./gradlew bootRun")]),e._v(". 或者,您可以使用构建 JAR 文件"),r("code",[e._v("./gradlew build")]),e._v(",然后运行 JAR 文件,如下所示:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("java -jar build/libs/gs-rest-service-0.1.0.jar\n")])])]),r("p",[e._v("如果您使用 Maven,则可以使用"),r("code",[e._v("./mvnw spring-boot:run")]),e._v(". 或者,您可以使用构建 JAR 文件,"),r("code",[e._v("./mvnw clean package")]),e._v("然后运行该 JAR 文件,如下所示:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v("java -jar target/gs-rest-service-0.1.0.jar\n")])])]),r("p",[e._v("此处描述的步骤创建了一个可运行的 JAR。您还可以"),r("a",{attrs:{href:"https://spring.io/guides/gs/convert-jar-to-war/",target:"_blank",rel:"noopener noreferrer"}},[e._v("构建经典的 WAR 文件"),r("OutboundLink")],1),e._v("。")]),e._v(" "),r("p",[e._v("该服务会在几秒钟内启动并运行。")]),e._v(" "),r("h2",{attrs:{id:"测试服务"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#测试服务"}},[e._v("#")]),e._v(" 测试服务")]),e._v(" "),r("p",[e._v("现在服务已经启动,访问"),r("code",[e._v("http://localhost:8080/greeting")]),e._v(",您应该会看到:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('{"id":1,"content":"Hello, World!"}\n')])])]),r("p",[e._v("通过访问提供"),r("code",[e._v("name")]),e._v("查询字符串参数"),r("code",[e._v("http://localhost:8080/greeting?name=User")]),e._v("。"),r("code",[e._v("content")]),e._v("请注意属性的值如何从"),r("code",[e._v("Hello, World!")]),e._v("变为"),r("code",[e._v("Hello, User!")]),e._v(",如以下所示:")]),e._v(" "),r("div",{staticClass:"language- extra-class"},[r("pre",{pre:!0,attrs:{class:"language-text"}},[r("code",[e._v('{"id":2,"content":"Hello, User!"}\n')])])]),r("p",[e._v("这一变化表明,"),r("code",[e._v("@RequestParam")]),e._v("在"),r("code",[e._v("GreetingController")]),e._v("按预期工作。该"),r("code",[e._v("name")]),e._v("参数的默认值"),r("code",[e._v("World")]),e._v(" 已被参数"),r("code",[e._v("name")]),e._v("的值覆盖")]),e._v(" "),r("p",[e._v("还要注意"),r("code",[e._v("id")]),e._v("属性是如何从"),r("code",[e._v("1")]),e._v("变为 的"),r("code",[e._v("2")]),e._v("。这证明是使用同一个"),r("code",[e._v("GreetingController")]),e._v("处理多个请求,并且其"),r("code",[e._v("counter")]),e._v("字段在每次调用时都按预期递增。")]),e._v(" "),r("h2",{attrs:{id:"概括"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#概括"}},[e._v("#")]),e._v(" 概括")]),e._v(" "),r("p",[e._v("恭喜!您刚刚使用 Spring 开发了一个 RESTful Web 服务。")]),e._v(" "),r("p",[e._v("原文链接: https://spring.io/guides/gs/rest-service/")])])}),[],!1,null,null,null);t.default=a.exports}}]);