1. Spring起步
希腊哲学家赫拉克利特:“唯一不变的就是变化。”
1.1 什么是Spring
Spring的核心是提供了一个容器(container),通常杯称为Spring 应用上下文(Spring application context),它们会创造和管理应用组件。
组件被称为是 bean,他们通过Spring应用上下文装配在一起,从而形成一个完整的应用程序。
将bean装配在一起的行为是通过一种基于 依赖注入 (dependency injection,DI)的模式实现的。此时,组件不会再去创建它所依赖的组件并管理它们的生命周期。
举例来说,假设有两个是我们需要处理的:库存服务(用来获取库存水平)和商品服务(用来提供基本的商品信息)。商品服务需要依赖于库存服务,这样它才能提供商品的完整信息。
XML装配
<bean id="inventoryService" class = "com.example.InventoryService" />
<bean id="productService" class="com.example.ProductService" >
<constructor-arg ref="inventoryService" />
</bean>
基于Java的配置
@Configuration
public class ServiceConfiguration{
@Bean
public InventoryService inventoryService(){
return new InventoryService();
}
@Bean
public ProductService roductService(){
return new InventoryService();
}
}
@Configuration 会告知Spring这是一个注解类,会为Spring应用上下文提供bean。这个配置类的方法使用@Bean 注解进行了标注,表明这些方法所返回的对象会以bean的形式添加到Spring的应用上下文中。
1.2 初始化Spring 应用
程序清单1.1 初始的Maven 构建规范
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>sia</groupId>
<artifactId>taco-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>taco-cloud</name>
<packaging>jar</packaging>
<description>taco-cloud</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
程序清单1.2 Taco Cloud的引导类
package sia.tacocloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TacoCloudApplication {
public static void main(String[] args) {
SpringApplication.run(TacoCloudApplication.class, args);
}
}
以下内容关于MockMvc的配置内容转自:https://blog.csdn.net/wo541075754/article/details/88983708
添加测试环境:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
编写测试类。实例化MockMvc有两种形式,一种是使用StandaloneMockMvcBuilder,另外一种是使用DefaultMockMvcBuilder。测试类及初始化MockMvc初始化:
//SpringBoot1.4版本之前用的是SpringJUnit4ClassRunner.class
@RunWith(SpringRunner.class)
//SpringBoot1.4版本之前用的是@SpringApplicationConfiguration(classes = Application.class)
@SpringBootTest
//测试环境使用,用来表示测试环境使用的ApplicationContext将是WebApplicationContext类型的
@WebAppConfiguration
public class HelloWorldTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Before
public void setup() {
// 实例化方式一
mockMvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build();
// 实例化方式二
// mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
单元测试方法:
@Test
public void testHello() throws Exception {
/*
* 1、mockMvc.perform执行一个请求。
* 2、MockMvcRequestBuilders.get("XXX")构造一个请求。
* 3、ResultActions.param添加请求传值
* 4、ResultActions.accept(MediaType.TEXT_HTML_VALUE))设置返回类型
* 5、ResultActions.andExpect添加执行完成后的断言。
* 6、ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情
* 比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息。
* 7、ResultActions.andReturn表示执行完成后返回相应的结果。
*/
mockMvc.perform(MockMvcRequestBuilders
.get("/hello")
// 设置返回值类型为utf-8,否则默认为ISO-8859-1
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)
.param("name", "Tom"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("Hello Tom!"))
.andDo(MockMvcResultHandlers.print());
}
程序请单1.3 应用测试类的概况:
package sia.tacocloud;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
class TacoCloudApplicationTests {
@Test // 测试方法
void contextLoads() {
}
}
1.3 编写Spring应用
1.3.1 处理Web请求
程序清单1.4 主页控制器
package sia.tacocloud.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller //控制器
public class HelloController {
@GetMapping("/") // 处理对根路径"/"的请求
public String home(){
return "home"; //返回视图名
}
}
@Controller 可以让组件扫描将这个类识别为一个组件,并创造一个HomeController实例,作为Spring应用上下文中的bean。
与@Controller有着类似的目的包括(@Controller, @Service, @Repository),也可以达到类似的效果,只不过这个更能够描述这个组件在应用中的角色。
1.3.2 定义视图
程序清单1.5 Taco Cloud的主页模板
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Taco Cloud</title>
</head>
<body>
<h1>Welcome to ...</h1>
<img th:src="@{/images/TacoCloud.png}" />
</body>
</html>
Thymeleaf 的th:src的属性和 @{…}表达式
静态资源存储在"/src/main/resources/static" 中,所以图片TacoCloud.png必须存放在"/src/main/resources/static/images/TacoCloud.png"。
1.3.3 测试控制器
程序清单 1.6 针对主页控制器的测试
package sia.tacocloud;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import sia.tacocloud.controller.HelloController;
@WebAppConfiguration
@RunWith(SpringRunner.class)
@WebMvcTest(HomeControllerTest.class)
public class HomeControllerTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc; //注入MockMvc
@Test
public void testHomePage() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(new HelloController()).build();
mockMvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.view().name("home"))
.andExpect(MockMvcResultMatchers.content().string(
containsString("welcome to...")
));
}
}