赞
踩
在学习新技术的时候我们都喜欢先写一个Hello World程序,一方面可以验证基础环境的搭建是否正确,另一方面可以快速了解整个开发流程。本节课我们就来学习Spring Boot的第一个Hello World程序。
BUILD ANYTHING.Spring Boot is designed to get you up and running as quickly as possible,with minimal upfront configuration of Spring.Spring Boot takes an opinionated view of building productionready applications.
中文翻译:Spring Boot 可以构建一切。Spring Boot设计之初就是为了最少的配置,以最快的速度来启动和运行Spring 项目。Spring Boot 使用特定的配置来构建生产就绪型的项目。
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
pom.xml 文件中默认有个模块:
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>org.junit.vintage</groupId>
- <artifactId>junit-vintage-engine</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
在目录 src\main\java\com\neo\web 下创建 HelloController:
- package com.neo.hello;
-
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- @SpringBootApplication
- @RestController
- public class HelloApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(HelloApplication.class, args);
- }
-
- @RequestMapping("/helloworld")
- public String hello(){
-
- return "hello world!";
- }
- }
@RestController的意思是Controller里面的方法都以JSON格式输出,不需要有其他额外的配置;如果配置@Controller,代表输出内容到页面。
@RequestMapping("/hello")提供路由信息,"/hello”路径的HTTP Request 都会被映射到hello()方法上进行处理。
右键单击项目中的 HelloApplication | run 命令,就可以启动项目了,若出现以下内容表示启动成功:
这里以debug的方式启动。方便测试。以下为启动输出的日志信息。
- D:\software\java1.8.40\jdk1.8.0_40\bin\java.exe -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\software\idea2019\IntelliJ IDEA 2019.1.3\lib\idea_rt.jar=59074:D:\software\idea2019\IntelliJ IDEA 2019.1.3\bin" -Dfile.encoding=UTF-8 -classpath D:\software\java1.8.40\jdk1.8.0_40\jre\lib\charsets.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\deploy.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\access-bridge-64.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\cldrdata.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\dnsns.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\jaccess.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\jfxrt.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\localedata.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\nashorn.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\sunec.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\sunjce_provider.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\sunmscapi.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\sunpkcs11.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\ext\zipfs.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\javaws.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\jce.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\jfr.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\jfxswt.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\jsse.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\management-agent.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\plugin.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\resources.jar;D:\software\java1.8.40\jdk1.8.0_40\jre\lib\rt.jar;G:\work\topfounder\projects\hello\target\classes;C:\Users\Mac\.m2\repository\org\springframework\boot\spring-boot-starter\2.2.2.RELEASE\spring-boot-starter-2.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\boot\spring-boot\2.2.2.RELEASE\spring-boot-2.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\spring-context\5.2.2.RELEASE\spring-context-5.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.2.2.RELEASE\spring-boot-autoconfigure-2.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.2.2.RELEASE\spring-boot-starter-logging-2.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;C:\Users\Mac\.m2\repository\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;C:\Users\Mac\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.12.1\log4j-to-slf4j-2.12.1.jar;C:\Users\Mac\.m2\repository\org\apache\logging\log4j\log4j-api\2.12.1\log4j-api-2.12.1.jar;C:\Users\Mac\.m2\repository\org\slf4j\jul-to-slf4j\1.7.29\jul-to-slf4j-1.7.29.jar;C:\Users\Mac\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\Users\Mac\.m2\repository\org\springframework\spring-core\5.2.2.RELEASE\spring-core-5.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\spring-jcl\5.2.2.RELEASE\spring-jcl-5.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\yaml\snakeyaml\1.25\snakeyaml-1.25.jar;C:\Users\Mac\.m2\repository\org\slf4j\slf4j-api\1.7.29\slf4j-api-1.7.29.jar;C:\Users\Mac\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.2.2.RELEASE\spring-boot-starter-web-2.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.2.2.RELEASE\spring-boot-starter-json-2.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.10.1\jackson-databind-2.10.1.jar;C:\Users\Mac\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.10.1\jackson-annotations-2.10.1.jar;C:\Users\Mac\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.10.1\jackson-core-2.10.1.jar;C:\Users\Mac\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.10.1\jackson-datatype-jdk8-2.10.1.jar;C:\Users\Mac\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.10.1\jackson-datatype-jsr310-2.10.1.jar;C:\Users\Mac\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.10.1\jackson-module-parameter-names-2.10.1.jar;C:\Users\Mac\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.2.2.RELEASE\spring-boot-starter-tomcat-2.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.29\tomcat-embed-core-9.0.29.jar;C:\Users\Mac\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.29\tomcat-embed-el-9.0.29.jar;C:\Users\Mac\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.29\tomcat-embed-websocket-9.0.29.jar;C:\Users\Mac\.m2\repository\org\springframework\boot\spring-boot-starter-validation\2.2.2.RELEASE\spring-boot-starter-validation-2.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\jakarta\validation\jakarta.validation-api\2.0.1\jakarta.validation-api-2.0.1.jar;C:\Users\Mac\.m2\repository\org\hibernate\validator\hibernate-validator\6.0.18.Final\hibernate-validator-6.0.18.Final.jar;C:\Users\Mac\.m2\repository\org\jboss\logging\jboss-logging\3.4.1.Final\jboss-logging-3.4.1.Final.jar;C:\Users\Mac\.m2\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;C:\Users\Mac\.m2\repository\org\springframework\spring-web\5.2.2.RELEASE\spring-web-5.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\spring-beans\5.2.2.RELEASE\spring-beans-5.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\spring-webmvc\5.2.2.RELEASE\spring-webmvc-5.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\spring-aop\5.2.2.RELEASE\spring-aop-5.2.2.RELEASE.jar;C:\Users\Mac\.m2\repository\org\springframework\spring-expression\5.2.2.RELEASE\spring-expression-5.2.2.RELEASE.jar com.neo.hello.HelloApplication
-
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
- ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v2.2.2.RELEASE)
-
- 2020-01-04 22:42:32.738 INFO 15812 --- [ main] com.neo.hello.HelloApplication : Starting HelloApplication on DESKTOP-V68NSD8 with PID 15812 (G:\work\topfounder\projects\hello\target\classes started by Mac in G:\work\topfounder\projects\hello)
- 2020-01-04 22:42:32.741 INFO 15812 --- [ main] com.neo.hello.HelloApplication : No active profile set, falling back to default profiles: default
- 2020-01-04 22:42:33.482 INFO 15812 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
- 2020-01-04 22:42:33.489 INFO 15812 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
- 2020-01-04 22:42:33.489 INFO 15812 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.29]
- 2020-01-04 22:42:33.557 INFO 15812 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
- 2020-01-04 22:42:33.557 INFO 15812 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 782 ms
- 2020-01-04 22:42:33.684 INFO 15812 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
- 2020-01-04 22:42:33.836 INFO 15812 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
- 2020-01-04 22:42:33.840 INFO 15812 --- [ main] com.neo.hello.HelloApplication : Started HelloApplication in 1.412 seconds (JVM running for 3.687)
如果启动过程中出现 java ClassNotFoundException 异常,请检查 Maven 配置是否正确,具体如下。
- # 进⾏行行项⽬目根⽬目录
- cd ../hello
- # 执⾏行行打包命令
- mvn clean package
- # 以 Jar 包的形式启动
- java -jar target/hello-0.0.1-SNAPSHOT.jar
启动成功后,打开浏览器输⼊网址:http://localhost:8080/helloworld,就可以看到以下内容了了:
开发阶段建议使用第⼀一种方式启动,便于开发过程中调试。
请求传参⼀一般分为 URL 地址传参和表单传参两种方式,两者各有优缺点,但基本都以键值对的方式将参数传递到后端。作为后端程序不用关注前端采用的那种方式,只需要根据参数的键来获取值,Spring 提供了很多种参数接收方式,今天我们了解最简单的方式:通过 URL 传参。只要后端处理请求的方法中存在参数键相同名称的属性,在请求的过程中Spring会自动将参数值赋值到属性中,最后在方法中直接使用即可。下面我们以hello()为例进行演示。
- @RequestMapping("/helloworld")
- public String hello(String username){
-
- // 获取username
- System.out.println("前端传递的参数为: "+username);
- return "hello world!"+username;
- }
- }
到这里,我们的第一个 Spring Boot 项目就开发完成了,有没有感觉很简单?经过测试发现,修改 Controller内相关的代码,需要重新启动项⽬目才能⽣生效,这样做很麻烦是不是?别着急,Spring Boot ⼜给我们提供了另外⼀个组件来解决。
热启动就需要用到我们在一开始就引入的另外一个组件:spring-boot-devtools。它是Spring Boot提供的一组开发工具包,其中就包含我们需要的热部署功能,在使用这个功能之前还需要再做一些配置。
在pom.xml 文件中添加spring-boot-devtools组件。
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-Devtools</artifactId>
- <optional>true</optional>
- </dependency>
在 plugin 中配置另外一个属性 fork,并且配置为 true。
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
-
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <configuration>
- <fork>true</fork>
- </configuration>
- </plugin>
- </plugins>
- </build>
OK,以上的配置就完成了,如果你使用的是 Eclipse 集成开发环境,那么恭喜你大功告成了;如果你使用的是 IDEA 集成开发环境,那么还需要做以下配置。
配置 IDEA选择File I Settings I Compiler 命令,然后勾选Build project automatically 复选框,低版本的IDEA 请勾选make project automatically 复选框。
使用快捷键Ctrl+Shift+A,在输入框中输入Registry,勾选compile.automake.allow.when.app.running复选框:
全部配置完成后,IDEA 就支持热部署了,大家可以试着去改动⼀一下代码就会发现 Spring Boot 会自动重新加载,再也不需要手动单击重新部署了。
为什么 IDEA 需要多配置后面这一步呢?因为 IDEA 默认不是自动编译的,需要我们手动去配置后才会自动编译,⽽热部署依赖于项目的自动编译功能。
该模块在完整的打包环境下运行的时候会被禁用,如果你使⽤用 java-jar 启动应用或者用⼀一个特定的classloader 启动,它会认为这是一个“⽣生产环境”。
单元测试在我们日常开发中必不可少,一个优秀的程序员,单元测试开发也非常完善。下面我们看下Spring Boot 对单元测试又做了哪些支持?
如果我们只想运行一个hello World,只需要一个@Test 注解就可以了。在src/test目录下新建一个HelloTest类,代码如下:
- package com.neo.hello;
-
- import org.junit.jupiter.api.Test;
-
- public class HelloWorldTest {
- @Test
- public void testHelloWorld(){
- System.out.println("Test hello world!");
- }
- }
右键单击“运行”按钮,发现控制台会输出:hello world。如果需要测试Web层的请求呢?Spring Boot也给出了支持。
以往我们在测试Web请求的时候,需要手动输入相关参数在页面测试查看效果,或者自己写post请求。在Spring Boot体系中,Spring给出了一个简单的解决方案,使用MockMVC进行Web 测试,MockMVC内置了很多工具类和方法,可以模拟post、get 请求,并且判断返回的结果是否正确等,也可以利用print()打印执行结果。
- @SpringBootTest
- public class HelloTest {
- private MockMvc mockMvc;
- @Before
- public void setUp() throws Exception {
- mockMvc = MockMvcBuilders.standaloneSetup(new HelloController()).build();
- }
- @Test
- public void getHello() throws Exception {
- mockMvc.perform(MockMvcRequestBuilders.post("/hello?name=⼩小明")
- .accept(MediaType.APPLICATION_JSON_UTF8)).andDo(print());
- }
- }
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
因为 print() 等⽅法都是 MockMvcResultHandlers 类的静态⽅法。在类的上面添加 @SpringBootTest,系统会自动加载 Spring Boot 容器。在日常测试中,可以注入 bean 来做一些局部的业务测试。MockMvcRequestBuilders 可以支持 post、get 请求,使⽤ print() ⽅法会将请求和相应的过程都打印出来,如下:
- MockHttpServletRequest:
- HTTP Method = POST
- Request URI = /hello
- Parameters = {name=[⼩小明]}
- Headers = {Accept=[application/json;charset=UTF-8]}
- Body = <no character encoding set>
- Session Attrs = {}
- Handler:
- Type = com.neo.hello.web.HelloController
- Method = public java.lang.String com.neo.hello.web.HelloController.hell
- o(java.lang.String)
- ...
- MockHttpServletResponse:
- Status = 200
- Error message = null
- Headers = {Content-Type=[application/json;charset=UTF-8], Content-Length
- =[19]}
- Content type = application/json;charset=UTF-8
- Body = hello world ,⼩小明
- Forwarded URL = null
- Redirected URL = null
- Cookies = []
从返回的Body=hello world,neo可以看出请求成功了。
当然每次请求都看这么多返回结果,不太容易识别,MockMVC提供了更多方法来判断返回结果,其中就有判断返回值。我们将上面的 getHello()方法稍稍进行改造,具体如下所示:
- @Test
- public void getHello() throws Exception {
- mockMvc.perform(MockMvcRequestBuilders.post("/hello?name=⼩小明")
- .accept(MediaType.APPLICATION_JSON_UTF8))/*.andDo(print())*/
- .andExpect(MockMvcResultMatchers.content().string(Matchers.containsStr
- ing("⼩小明")));
- }
把刚才的 .andDo(print()) 方法注释掉,添加以下代码:
.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("⼩小明")));
MockMvcResultMatchers.content(),这段代码的意思是获取到 Web 请求执行后的结果;
Matchers.containsString("⼩小明"),判断返回的结果集中是否包含“⼩小明”这个字符串。
我们先将上面代码改为:
.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("微笑")));
然后执行 test 即可返回以下结果:
- java.lang.AssertionError: Response content
- Expected: a string containing "微笑"
- but: was "hello world ,⼩小明"
- ...
抛出异常说明:期望的结果是包含“微笑”,结果返回内容是“hello world ,⼩小明”,不不符合预期。
接下来我们把代码改回:
.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("⼩小明")));
再次执行测试方法,测试用例执行成功,说明请求的返回结果中包含了“小明”字段。
以上实践的测试方法,只是spring-boot-starter-test 组件中的一部分功能,spring-boot-starter-test对测试的支持是全方位的,后面会一一介绍到。
我们简单做一下对比,使用Spring Boot之前和使用之后。
使用Spring Boot之前:
·
配置 web.xml,加载 Spring和 Spring MVC
配置数据库连接、配置Spring事务
配置加载配置文件的读取,开启注解
配置日志文件
配置完成之后部署 Tomcat 调试现在非常流行微服务,如果项目只是简单发送邮件的需求,我们也需要这样操作一遍。
使用Spring Boot之后,仅仅三步即可快速搭建起一个Web项目:
⻚⾯配置导⼊到开发工具中
进行代码编写
运行
通过对比可以发现 Spring Boot 在开发阶段做了大量优化,非常容易快速构建⼀一个项目。
本课学习了如何搭建Spring Boot 开发项目所需的基础环境,了解了如何开发一个Spring Boot的Hello World 项目。使用Spring Boot可以非常方便地快速搭建项目,不用关心框架之间的兼容性、组件版本差异化等问题;项目中使用组件,仅仅添加一个配置即可,所以使用Spring Boot 非常适合构建微服务。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。