1.概述
依賴管理是任何復雜項目的關鍵方面。手動完成這些操作並不理想; 你花在它上面的時間越多,你在項目的其他重要方面所花費的時間就越少。
構建Spring Boot啟動器是為了解決這個問題。Starter POM是一組方便的依賴描述符,您可以在應用程序中包含這些描述符。您可以獲得所需的所有Spring和相關技術的一站式服務,而無需搜索示例代碼,並復制粘貼依賴描述符。
2.The Web Starter
首先,我們來看看開發REST服務; 我們可以使用像Spring MVC,Tomcat和Jackson這樣的庫 - 對於單個應用程序來說有很多依賴關系。
Spring Boot啟動器可以通過添加一個依賴項來幫助減少手動添加的依賴項的數量。因此,不是手動指定依賴項,而是添加一個啟動器,如以下示例所示:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
現在我們可以創建一個REST控制器。為簡單起見,我們不會使用數據庫並只專注於REST控制器:
@RestController
public class GenericEntityController {
private List<GenericEntity> entityList = new ArrayList<>();
@RequestMapping("/entity/all")
public List<GenericEntity> findAll() {
return entityList;
}
@RequestMapping(value = "/entity", method = RequestMethod.POST)
public GenericEntity addEntity(GenericEntity entity) {
entityList.add(entity);
return entity;
}
@RequestMapping("/entity/findby/{id}")
public GenericEntity findById(@PathVariable Long id) {
return entityList.stream().
filter(entity -> entity.getId().equals(id)).
findFirst().get();
}
}
該GenericEntity是一個簡單的bean,包含與Long類型id屬性和String類型的value屬性。
在應用程序運行時,您可以訪問http://localhost:8080/entity/all 並檢查控制器是否正常工作。
我們已經創建了一個具有相當小配置的REST應用程序。
3.The Test Starter
對於測試,我們通常使用以下一組庫:Spring Test,JUnit,Hamcrest和Mockito。我們可以手動包含所有這些庫,但也可以使用Spring Boot starter以下列方式自動包含這些庫:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
請注意,您無需指定artifact的版本號。Spring Boot將確定要使用的版本 - 您需要指定的是spring-boot-starter-parent的版本。如果以后需要升級Boot庫和依賴項,只需在一個地方升級Boot版本,它將負責其余的工作。
讓我們實際測試我們在前一個例子中創建的控制器。
有兩種方法可以測試控制器:
使用模擬環境
使用嵌入式Servlet容器(如Tomcat或Jetty)
在這個例子中,我們將使用模擬環境:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class SpringBootApplicationIntegrationTest {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before
public void setupMockMvc() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void givenRequestHasBeenMade_whenMeetsAllOfGivenConditions_thenCorrect()
throws Exception {
MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
mockMvc.perform(MockMvcRequestBuilders.get("/entity/all")).
andExpect(MockMvcResultMatchers.status().isOk()).
andExpect(MockMvcResultMatchers.content().contentType(contentType)).
andExpect(jsonPath("$", hasSize(4)));
}
}
上面的測試調用/entity/all端點並驗證JSON響應是否包含4個元素。要通過此測試,我們還必須在控制器類中初始化我們的列表:
public class GenericEntityController {
private List<GenericEntity> entityList = new ArrayList<>();
{
entityList.add(new GenericEntity(1l, "entity_1"));
entityList.add(new GenericEntity(2l, "entity_2"));
entityList.add(new GenericEntity(3l, "entity_3"));
entityList.add(new GenericEntity(4l, "entity_4"));
}
//...
}
這里重要的是@WebAppConfiguration注釋和MockMVC是spring-test模塊的一部分,hasSize是一個Hamcrest匹配器,而@Before是一個JUnit注釋。這些都可以通過導入這一個啟動器依賴項來獲得。
4. The Data JPA Starter
大多數Web應用程序都有需要某種持久性 - 這通常是JPA。
不需要手動定義所有相關的依賴項 - 讓我們改為使用啟動器:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
請注意,我們可以開箱即用自動支持以下數據庫:H2,Derby和Hsqldb。在我們的例子中,我們將使用H2。
現在讓我們為我們的實體創建存儲庫:
public interface GenericEntityRepository extends JpaRepository<GenericEntity, Long> {}
這是JUnit測試:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class SpringBootJPATest {
@Autowired
private GenericEntityRepository genericEntityRepository;
@Test
public void givenGenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() {
GenericEntity genericEntity =
genericEntityRepository.save(new GenericEntity("test"));
GenericEntity foundedEntity =
genericEntityRepository.findOne(genericEntity.getId());
assertNotNull(foundedEntity);
assertEquals(genericEntity.getValue(), foundedEntity.getValue());
}
}
我們沒有花時間指定數據庫供應商,URL連接和憑據。不需要額外的配置,因為我們從可靠的Boot默認值中受益; 但當然,如有必要,仍可配置所有這些細節。
5.The Mail Starter
企業開發中一個非常常見的任務是發送電子郵件,直接處理Java Mail API通常很困難。
Spring Boot啟動程序隱藏了這種復雜性 - 可以通過以下方式指定郵件依賴項:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
現在我們可以直接使用JavaMailSender,所以讓我們編寫一些測試。
出於測試目的,我們需要一個簡單的SMTP服務器。在這個例子中,我們將使用Wiser。這就是我們如何將它包含在我們的POM中:
<dependency>
<groupId>org.subethamail</groupId>
<artifactId>subethasmtp</artifactId>
<version>3.1.7</version>
<scope>test</scope>
</dependency>
可以在Maven中央存儲庫中找到最新版本的Wiser 。
以下是測試的源代碼:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class SpringBootMailTest {
@Autowired
private JavaMailSender javaMailSender;
private Wiser wiser;
private String userTo = "user2@localhost";
private String userFrom = "user1@localhost";
private String subject = "Test subject";
private String textMail = "Text subject mail";
@Before
public void setUp() throws Exception {
final int TEST_PORT = 25;
wiser = new Wiser(TEST_PORT);
wiser.start();
}
@After
public void tearDown() throws Exception {
wiser.stop();
}
@Test
public void givenMail_whenSendAndReceived_thenCorrect() throws Exception {
SimpleMailMessage message = composeEmailMessage();
javaMailSender.send(message);
List<WiserMessage> messages = wiser.getMessages();
assertThat(messages, hasSize(1));
WiserMessage wiserMessage = messages.get(0);
assertEquals(userFrom, wiserMessage.getEnvelopeSender());
assertEquals(userTo, wiserMessage.getEnvelopeReceiver());
assertEquals(subject, getSubject(wiserMessage));
assertEquals(textMail, getMessage(wiserMessage));
}
private String getMessage(WiserMessage wiserMessage)
throws MessagingException, IOException {
return wiserMessage.getMimeMessage().getContent().toString().trim();
}
private String getSubject(WiserMessage wiserMessage) throws MessagingException {
return wiserMessage.getMimeMessage().getSubject();
}
private SimpleMailMessage composeEmailMessage() {
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setTo(userTo);
mailMessage.setReplyTo(userFrom);
mailMessage.setFrom(userFrom);
mailMessage.setSubject(subject);
mailMessage.setText(textMail);
return mailMessage;
}
}
在測試中,@Before和@After方法負責啟動和停止郵件服務器。
請注意,我們在程序中使用的JavaMailSender bean - 這個bean是由Spring Boot自動創建的。
與Boot中的任何其他默認值一樣,JavaMailSender的電子郵件設置可以在application.properties中自定義:
spring.mail.host=localhost
spring.mail.port=25
spring.mail.properties.mail.smtp.auth=false
我們在localhost:25上配置了郵件服務器,並且不需要身份驗證。