原文链接:http://www.dubby.cn/detail.html?id=9040
构建一个web应用,我们可以请求:
http://localhost:8080/greeting
返回一个JSON
:
{"id":1,"content":"Hello, World!"}
还可以发起一个带参数的请求:
http://localhost:8080/greeting?name=User
返回一个JSON
:
{"id":1,"content":"Hello, User!"}
创建一个maven项目,项目结构如下:
└── src
└── main
└── java
└── hello
pom.xml
:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.springframeworkgroupId>
<artifactId>gs-rest-serviceartifactId>
<version>0.1.0version>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.8.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>com.jayway.jsonpathgroupId>
<artifactId>json-pathartifactId>
<scope>testscope>
dependency>
dependencies>
<properties>
<java.version>1.8java.version>
properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
<repositories>
<repository>
<id>spring-releasesid>
<url>https://repo.spring.io/libs-releaseurl>
repository>
repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releasesid>
<url>https://repo.spring.io/libs-releaseurl>
pluginRepository>
pluginRepositories>
project>
其中,spring-boot-maven-plugin
给我们提供了这么几个功能:
+ 他会把classpath下的jar统一打包成一个可直接运行的”über-jar”,方便我们运行。
+ 他会自动搜索public static void main()
作为程序执行的入口。
+ 他内置一个依赖版本决定者。也就是他会指定依赖的版本。当然你也可以指定版本,如果你不指定,默认由他来决定版本。
根据
{
"id": 1,
"content": "Hello, World!"
}
来写出一个表达这个json的beansrc/main/java/hello/Greeting.java
package hello;
public class Greeting {
private final long id;
private final String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
}
Spring会使用Jackson JSON自动把
Greeting
的实例序列化成JSON
。
在Spring构建的restful应用中,HTTP请求是由controller接收并处理的。想要创建一个controller可以使用@RestController
修饰一个类,那么这个类就变成了一个controller。一个controller里的每个方法都可以接收一个特定的URI,需要使用@RequestMapping
来修饰每个方法,来制定URI的路径,参数,方法等。
src/main/java/hello/GreetingController.java
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
return new Greeting(counter.incrementAndGet(),
String.format(template, name));
}
}
这个controller很简洁明了,但是在背后隐藏了很多事先细节,我们一点点来分解。
@RequestMapping
这个注解确保/greeting
这个HTTP请求会被路由到greeting()
这个方法上来处理。
上面的例子没有指明
GET
,PUST
或者是PUT
等HTTP方法,因为@RequestMapping
默认是映射所有的方法。如果你只希望某个方法被映射到这个方法,可以使用@RequestMapping(method=GET)
来缩小映射范围。
@RequestParam
把请求参数中的name
的值绑定到greeting()
的参数name
上。这个参数被标记为可选的,也就是可传可不传的,(默认情况下,required=true
是必须要传的),在这里,如果没有传name
,就会使用defaultValue
的值。
greeting()
方法里创建了一个Greeting
对象,然后返回,用一个自增的int作为id
,用name
的值拼接成content
。
传统的MVC的controller和RESTful的controller的最大的区别就是返回的HTTP的response。传统的controller返回的是一个由后端渲染的HTML
,而RESTful返回的是一个对象,然后被序列化成JSON
字符串。
@RestController
是Spring4新加的一个注解,用它修饰的controller返回的是一个对象(也就是JSON
),而不是一个视图(也就是HTML
)。这个注解等同于同时使用@Controller
和@ResponseBody
。
上面提到Spring会自动把对象转化成JSON
,我们还不需要手动来转换,那么是谁帮我们做的呢?真相是,只要Jackson 2在classpath下,Spring就会使用MappingJackson2HttpMessageConverter
来自动转换。
虽然也可以打包成传统的war包然后交给servlet容器来执行,但是更多的时候是打包成一个可以直接执行的Jar。
src/main/java/hello/Application.java
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@SpringBootApplication
注解等同于同时使用一下注解:
+ @Configuration
修饰的类会被作为定义context上下文的bean。
+ @EnableAutoConfiguration
允许Spring从配置文件,其他bean,等各种方式来加载bean。
+ 一般来说,对于Spirng MVC项目,你需要使用@EnableWebMvc
,不过对于Spring Boot来说,只要你的classpath里包含spring-webmvc,他就会自动帮你加上这个,比如,设置DispatcherServlet
。
+ @ComponentScan
告诉Spirng去扫描hello
包下的其他组件,包含controller,service等。
main()
就是这个应用的入口。发现了吗,整个应用没有一个XML文件,全部都是Java代码,没有任何配置,这就是Spring Boot想带给你的礼物。
java -jar restful-web-1.0-SNAPSHOT.jar
结果:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.8.RELEASE)
2017-10-19 19:38:00.944 INFO 3923 --- [ main] hello.Application : Starting Application v1.0-SNAPSHOT on teedeMacBook-Pro.local with PID 3923 (/Users/teeyoung/Desktop/code4me/spring-demo/restful-web/target/restful-web-1.0-SNAPSHOT.jar started by teeyoung in /Users/teeyoung/Desktop/code4me/spring-demo/restful-web/target)
2017-10-19 19:38:00.949 INFO 3923 --- [ main] hello.Application : No active profile set, falling back to default profiles: default
2017-10-19 19:38:01.019 INFO 3923 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4f6ee6e4: startup date [Thu Oct 19 19:38:01 CST 2017]; root of context hierarchy
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils$1 (jar:file:/Users/teeyoung/Desktop/code4me/spring-demo/restful-web/target/restful-web-1.0-SNAPSHOT.jar!/BOOT-INF/lib/spring-core-4.3.12.RELEASE.jar!/) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of org.springframework.cglib.core.ReflectUtils$1
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
2017-10-19 19:38:02.374 INFO 3923 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
……
2017-10-19 19:38:03.219 INFO 3923 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-19 19:38:03.219 INFO 3923 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-19 19:38:03.263 INFO 3923 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-19 19:38:03.396 INFO 3923 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-10-19 19:38:03.465 INFO 3923 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-10-19 19:38:03.474 INFO 3923 --- [ main] hello.Application : Started Application in 2.924 seconds (JVM running for 3.436)
项目源代码:https://github.com/dubby1994/spring-demo