SpringBoot in Action——初识SpringBoot

现在,我们里利用了整本书的篇幅来介绍Spring。尽管Spring带来的主要益处就是简化Java开发,但本章将会介绍Spring Boot如何让这项任务变得更简单。
Spring Boot在Spring之上,构建了全新的开发模式,移除了开发Spring应用中很多单调乏味的东西。
我们首先整体了解一下Spring Boot,看它是怎么简化Spring的。

Spring Boot简介

在Spring家族中,Spring Boot主要提供了四个特性,能够改变Spring应用程序的方式:

  • Spring Boot Starter:它将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Mvn或Gradle构建中。
  • 自动配置:Spring Boot的自动配置特性利用了Spring4对条件化配置的支持,合理地推测应用所需的bean并自动化配置它们。
  • 命令行接口(Command-line interface,CLI):CLI发挥了Groovy编程语言的优势,并结合自动配置进一步简化Spring应用的开发。
  • Actuator:它为SpringBoot应用添加了一定的管理特性。

添加Starter依赖
有两种制作蛋糕的方式:一种是买好面粉、鸡蛋、糖、发酵粉、奶油等等,自己搅拌成糊状制作;另一种是购买打包好的蛋糕,我们只需要加入一些其他的辅料即可。
Spring boot就是后面一种方法。
Spring Boot Starter 依赖将所需的常见依赖按组聚集在一起,形成单条依赖。

自动配置
Spring boot的Starter减少了pom.xml中依赖的长度。而Spring boot的自动配置功能则能削减Spring配置的数量。它在实现时,会考虑应用中的其他因素并推断你所需要的Spring配置。

CLI
Spring boot CLI充分利用了Spring boot starter和自动配置的魔力,并添加了一些Groovy的功能。它简化了Spring的开发流程,通过CLI,我们能够运行一个或多个Groovy脚本,并查看它是如何运行的。在应用的运行过程中,CLI能够自动导入Spring类型并解析依赖。

用来阐述Spring Boot CLI最有趣的例子就是如下的Groovy脚本:

@RestController
class Hi{
	@RequestMapping("/")
	String hi(){
		"Hi!"
	}
}

很难相信这是一个完整的Spring应用吧?但是它的确是对的。如果你已经安装过Spring Boot CLI,我们可以使用如下的命令行来运行它:
$ spring run Hi.groovy

Actuator
Spring Boot Actuator为Spring Boot项目带来很多游泳的特性,包括:

  • 管理端点
  • 合理的异常处理以及默认的“/error”映射端点
  • 获取应用信息的“/info”端点
  • 当启用Spring Security时,会有一个审计事件框架

之后我们会介绍到。接下来,我们将使用以上4个主要特性构建一个微小但完整的应用程序。

使用SpringBoot构建应用

我们的应用程序是一个简单的联系人列表,它允许用户输入联系人信息(名字、电话、EMail),并且能够列出用户之前输入的所有联系人信息。

你可以使用Mvn或者Gradle来构建。
Gradle:

buildscript {
	repositories {
		mavenCentral()
	}

	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:1.1.4.RELEASE")
	}
}

apply plugin: 'java'
apply plugin: 'spring-boot'

//构建Jar文件
jar {
	baseName = 'contacts'
	version  = '0.1.0'
}

repositories {
	mavenCentral()
}

//依赖
dependencies {
	compile("org.springframework.boot:spring-boot-starter-web")
	compile("org.springframework.boot:spring-boot-starter-jdbc")
	compile("org.thymeleaf:thymeleaf-spring4")
	compile("com.h2database:h2")
}

task wrapper(type: Wrapper) {
	gradleVersion = '2.0'
}

Maven

<?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
    http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.habuma</groupId>
  <artifactId>contacts</artifactId>
  <version>0.1.0</version>
  <packaging>jar</packaging>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.1.4.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.thymeleaf</groupId>
      <artifactId>thymeleaf-spring4</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
    </dependency>
  </dependencies> 

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

Gradle的好处就在于精简,往往Maven三四行的代码,Gradle一行就能概括。比如maven里面的spring-boot插件,使用,在Gradle里面使用一行:apply plugin: 'spring-boot'

处理请求
因为我们要使用SpringMVC来开发应用Web层,因此需要将Spring Mvc作为依赖添加到构建中。我们已经讨论过,Spring Boot的Web Starter能够将Spring MVC需要的所有内容一站式添加到构建中。
gradle:

compile("org.springframework.boot:spring-boot-starter-web")

maven:

<dependency>
	<groupId>org.springframework.bootgroupId>
	<artifactId>spring-boot-starter-webartifactId>
dependency>

注意为什么这里没有版本号呢?因为Spring Boot parent项目已经制定了版本。

现在我们编写控制器类:

package com.promusician;

import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
@RequestMapping("/")
public class ContactController {

    private ContactRepository contactRepo;

    @Autowired
    public ContactController(ContactRepository contactRepo) {
        this.contactRepo = contactRepo;
    }

    @RequestMapping(method=RequestMethod.GET)
    public String home(Map<String,Object> model) {
        List<Contact> contacts = contactRepo.findAll();
        model.put("contacts", contacts);
        return "home";
    }

    @RequestMapping(method=RequestMethod.POST)
    public String submit(Contact contact) {
        contactRepo.save(contact);
        return "redirect:/";
    }
}

有了前面的基础,这个程序很好理解,不做赘述。

按照传统方式,Java Web应用会使用JSP作为视图层的技术。但是,正如在第六章所说(不好意思我跳过了)。在这个领域有一个新的参与者。Thymeleaf的原生模版比JSP更加便于使用,而且它能够让我们以HTML的形式编写模版。鉴于此,我们将使用Thymeleaf来定义“home”视图。

    <dependency>
      <groupId>org.thymeleafgroupId>
      <artifactId>thymeleaf-spring4artifactId>
    dependency>

或者import("org.thymeleaf:thymeleaf-spring4")
需要记住的是,只要我们将Thymeleaf添加到项目的类路径下,就启用了Spring Boot的自动配置。当应用运行时,Spring Boot将会探测到类路径中的Thymeleaf,然后会自动配置视图解析器、模版解析器以及模版引擎。因此,在我们的应用中,不需要显示Spring配置的方法来定义Thymeleaf。

现在来定义视图模版:
如下是home.html:


<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Spring Boot Contactstitle>
    <link rel="stylesheet" th:href="@{/style.css}" />
  head>

  <body>
    <h2>Spring Boot Contactsh2>
    <form method="POST">
      <label for="firstName">First Name:label>
      <input type="text" name="firstName">input><br/>
      <label for="lastName">Last Name:label>
      <input type="text" name="lastName">input><br/>
      <label for="phoneNumber">Phone #:label>
      <input type="text" name="phoneNumber">input><br/>
      <label for="emailAddress">Email:label>
      <input type="text" name="emailAddress">input><br/>
      <input type="submit">input>
    form>

    <ul th:each="contact : ${contacts}">
      <li>
        <span th:text="${contact.firstName}">Firstspan>
        <span th:text="${contact.lastName}">Lastspan> :
        <span th:text="${contact.phoneNumber}">phoneNumberspan>,
        <span th:text="${contact.emailAddress}">emailAddressspan>
      li>
    ul>
  body>
html>

因为ContactController中home()方法所返回的逻辑视图名为home,因此模版应该放在指定位置:"src/main/resources/templates"中。

持久化数据

		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-jdbcartifactId>
		dependency>
		<dependency>
			<groupId>com.h2databasegroupId>
			<artifactId>h2artifactId>
		dependency>

或者gradle略。
现在编写Repository类:

package com.promusician;

import java.util.List;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

@Repository
public class ContactRepository {

    private JdbcTemplate jdbc;

    @Autowired
    public ContactRepository(JdbcTemplate jdbc) {
        this.jdbc = jdbc;
    }

    public List<Contact> findAll() {
        return jdbc.query(
                "select id, firstName, lastName, phoneNumber, emailAddress " +
                        "from contacts order by lastName",
                new RowMapper<Contact>() {
                    public Contact mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Contact contact = new Contact();
                        contact.setId(rs.getLong(1));
                        contact.setFirstName(rs.getString(2));
                        contact.setLastName(rs.getString(3));
                        contact.setPhoneNumber(rs.getString(4));
                        contact.setEmailAddress(rs.getString(5));
                        return contact;
                    }
                }
        );
    }

    public void save(Contact contact) {
        jdbc.update(
                "insert into contacts " +
                        "(firstName, lastName, phoneNumber, emailAddress) " +
                        "values (?, ?, ?, ?)",
                contact.getFirstName(), contact.getLastName(),
                contact.getPhoneNumber(), contact.getEmailAddress());
    }

}

我们仔细看,这个Repository类非常简单,简单的增删改查。不过JdbcTemplate呢????我们为啥不用去声明一个DataSource,然后在声明一个JdbcTemplate?
这种问题的回答就是,自动配置!

那数据库模式该怎么处理呢?我们必须自己定义contacts表的模式,因为Spring Boot再强大也没法猜测contacts表的样子。于是,我们这样设置:

create table contacts (
	id identity,
	firstName varchar(30) not null,
	lastName varchar(50) not null,
	phoneNumber varchar(13),
	emailAddress varchar(30)
);

现在我们只需要一种方式加载这个"create table"的SQL并将其在H2数据库中执行就行了。

尝试运行
最后不需要配置DispatcherServlet,启用自动配置就行了。

package com.promusician;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan
@EnableAutoConfiguration
public class PromusicianApplication {

	public static void main(String[] args) {
		SpringApplication.run(PromusicianApplication.class, args);
	}
}

本书结束,我们换本书。

你可能感兴趣的:(SpringBoot in Action——初识SpringBoot)