使用Spring Boot进行Java EE开发

  Spring Boot是Spring社区较新的一个项目。该项目的目的是帮助开发者更容易得创建基于Spring的应用程序和服务,让更多人的人更快的对Spring进行入门体验,让Java开发也能够实现Ruby on Rails那样的生产效率。为Spring生态系统提供了一种固定的、约定优于配置风格的框架。

  多年以来,Spring IO平台饱受非议的一点就是大量的XML配置以及复杂的依赖管理。在SpringOne 2GX会议上,Pivotal的CTO Adrian Colyer回应了这些批评,并且特别提到该平台将来的目标之一就是实现免XML配置的开发体验。Boot所实现的功能超出了这个任务的描述,开发人员不仅不再需要编写XML,而且在一些场景中甚至不需要编写繁琐的import语句。

  然而,Spring Boot并不是要成为Spring IO平台里面众多“Foundation”层项目的替代者。Spring Boot的目标不在于为已解决的问题提供新的解决方案,而是为平台带来另一种开发体验,从而简化对这些已有技术的使用。对于已经熟悉Spring生态系统的开发人员来说,Boot是一个很理想的选择,不过对于采用Spring技术的新人来说,Boot提供一种更简洁的方式来使用这些技术。

1、Spring Boot简介

  Spring Boot使用“习惯优先配置”(项目中存在大量的配置,此外还内置一个习惯的配置,让你无须手动进行配置)的理念让你的项目快速运行起来。使用Spring Boot可以很容易地创建一个独立运行(运行jar,内嵌Servlet容器)、准生产级别的基于Spring框架的项目,使用Spring Boot你可以不用或者只需很少的Spring配置,它能够改变开发Spring应用程序的方式。它提供了以下几个主要特性:

  • Spring Boot Starter:它将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Maven中,Spring Boot也提供了一系列的starter pom来简化Maven的依赖加载

  • 自动配置:Spring Boot的自动配置特性利用了Spring4.0对条件化配置的支持,合理地推测所需的bean并自动化配置它们;

  • 独立运行的项目:Spring Boot可以以jar包的形式独立运行,运行一个Spring Boot项目只需要通过java -jar xx.jar来运行;

  • 内嵌Servlet容器:Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow,这样我们无须以war包形式部署项目

  • 准生产级别的应用监控:Spring Boot提供基于http、ssh、telnet对运行时的项目进行监控;

  Spring Boot的优点总结如下:

  • 快速构建项目;

  • 对主流开发框架的无配置集成;

  • 项目可独立运行,无须外部依赖Servlet容器;

  • 提供运行时的应用监控;

  • 极大地提高了开发、部署效率;

2、用Maven构建Spring Boot入门级Demo

  (1)在pom.xml中添加Spring Boot的父级依赖,这样当前项目就是Spring Boot项目了。spring-boot-starter-parent是一个特殊的starter,它用来提供相关的Maven默认依赖,使用它之后,常用的包依赖可以省略version标签。

<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>1.5.2.RELEASEversion>
parent>

  (2)在dependencies标签对中添加Web支持的starter pom这样就添加了Web的依赖。Starter使用了Maven的依赖传递方案,这些依赖本身可能也会有其他的依赖,一个starter可能会传递性地引入几十个依赖。例如,mobile starter引用了Web starter,而后者又引用了Tomcat Starter。大多数的Starter都会引用spring-boot-starter,它实际上是一个基础的starter(当然,它也依赖了logging starter)。依赖是传递性的,将mobile starter添加为依赖之后,就相当于添加了它下面的所有starter。

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

  (3)添加Spring Boot的编译插件。

<build>
   <finalName>Spring_Boot_TestfinalName>
   <plugins>
        <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
        plugin>           
    plugins>
build>

  完整的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>com.wiselygroupId>
    <artifactId>Spring_Boot_TestartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <packaging>warpackaging>

    <parent>
        
        
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>1.5.2.RELEASEversion>
    parent>

    <dependencies>  
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    dependencies>
    <build>
       <finalName>Spring_Boot_TestfinalName>
       <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>           
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-war-pluginartifactId>
                <configuration>
                   <failOnMissingWebXml>falsefailOnMissingWebXml>
                   
                configuration>        
            plugin>
        plugins>
    build>
project>

  (4)使用上述方法建立Spring Boot项目后,生成的项目在根包目录下会有一个artifactId + Application命名规则的入口类,为了测试方便,不再新建控制器类,而是直接在入口类中编写控制器代码:

package com.wisely.Spring_Boot_Test;
import org.springframework.beans.factory.annotation.Value;
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;

@RestController
@SpringBootApplication
public class Application {

    @RequestMapping("/")
    String index() {
        return "Hello Spring Boot";
    }
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        SpringApplication.run(Application.class, args);
    }

}

  @SpringBootApplication是Spring Boot项目的核心注解,它是一个组合注解,主要组合了@Configuration、@EnableAutoConfiguration、@ComponentScan,主要目的是开启自动配置。@RestController注解相当于@ResponseBody+@Controller合在一起的作用,返回String或者JSON数据的话就直接用@RestController,如果只是使用@RestController注解了Controller,则Controller中的@RequestMapping注解修饰的方法无法返回jsp或html页面,配置的视图解析器InternalResourceViewResolver不起作用,返回的内容就是Return里的内容。如果想要页面跳转的话,返回到指定的jsp或html页面,则需要用@Controller配合视图解析器InternalResourceViewResolver才行,如果需要返回JSON,XML或自定义mediaType内容到页面,则需要在对应的方法上加上@ResponseBody注解。

  引申:使用@Responsebody标识的方法表示该方法的返回结果直接写入HTTP response body中,一般在异步获取数据时使用,在使用@RequestMapping后,返回值通常解析为跳转路径,加上@Responsebody后返回结果不会被解析为跳转路径,而是直接写入HTTP response body中。@ResponseBody注解直接将controller返回的bean对象或map对象等自动进行JSON或XML格式的转换。

  (5)启动工程,启动方法有多种。第一种是在命令行使用命令”mvn spring-boot:run”启动该应用;第二种是在Eclipse中(或者IDEA)单击Application.java右键,在右键菜单中选择以Java Application运行项目;第三种先是运行”mvn package”进行打包,该命令会将工程打包成一个可以直接运行的 JAR 文件,然后在命令行使用”java -jar”命令就可以直接运行应用。应用启动后在控制台上打印的日志如下图所示:

使用Spring Boot进行Java EE开发_第1张图片

  (6)访问http://localhost:8080/,结果如图所示:

使用Spring Boot进行Java EE开发_第2张图片

  Spring Boot使用一个全局的配置文件application.properties或application.yml,放置在src/main/resources目录或者类路径的/config下

  Spring Boot不仅支持常规的.properties文件,还支持yaml语言的配置文件。yaml是以数据为中心的语言,在配置数据的时候具有面向对象的特征。Spring Boot的全局配置文件的作用是对一些默认配置的值进行修改。

  例如,将Tomcat的默认端口号8080修改为9090,并将默认的访问路径”/”修改为”/helloboot”。可以在application.properties中添加如下语句。

server.port=9090
server.context-path=/helloboot

  Spring Boot允许使用properties文件、yaml文件或者命令行参数作为外部配置。注入properties文件里的值的方式,通过@PropertySource指明properties文件的位置,然后通过@Value注入值。在Spring Boot里,只需要在application.properties中定义属性,直接使用@Value注入即可。

  在上面的基础上,对application.properties增加属性后如下:

server.port=9090
server.context-path=/helloboot
book.author=fzm
book.name=spring boot

  修改入口类:

@RestController
@SpringBootApplication
public class Application {
    @Value("${book.author}")
    private String bookAuthor;
    @Value("${book.name}")
    private String bookName;

    @RequestMapping("/")
    String index() {
        return "Hello Spring Boot" + 
                        ", and Book Name:" + bookName + 
                        ",and Book Author" + bookAuthor;
        //return "Hello Spring Boot";
    }
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        SpringApplication.run(Application.class, args);
    }
}

  运行入口类,访问http://localhost:9090/helloboot/,效果如图所示:

  整个工程的目录结构如下:

使用Spring Boot进行Java EE开发_第3张图片

3、使用Spring Boot构建应用

  在剩余的内容里,将使用Spring Boot构建完整且符合现实要求的应用程序,该应用是一个简单的联系人列表,它允许用户输入联系人信息(名字、电话以及Email),并且能够列出用户之前输入的所有联系人信息。

  利用Maven来构建应用程序,完整的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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0modelVersion>
    <groupId>com.wiselygroupId>
    <artifactId>SpringBootContactsartifactId>
    <packaging>jarpackaging>
    <version>0.0.1-SNAPSHOTversion>
    <name>SpringBootContacts Maven Webappname>
    <url>http://maven.apache.orgurl>

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>1.5.2.RELEASEversion>
    parent>

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

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

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

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

        <dependency>
            <groupId>com.h2databasegroupId>
            <artifactId>h2artifactId>
            <version>1.4.191version>
        dependency>

        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
    dependencies>
    <build>
       <finalName>SpringBootContactsfinalName>
        <plugins>
        
            <plugin>
                <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
            plugin>           
        plugins>
    build>
project>

  因为我们使用Spring MVC来开发应用的Web层,因此需要将Spring MVC作为依赖添加到构建中。Spring Boot的Web Starter能够将Spring MVC需要的所有内容一站式添加到构建中。

3.1 处理请求

  控制器相对会非常简单,包含展示联系人表单的HTTP GET请求以及处理表单提交的POST请求。它本身并没有做太多的事情,而是委托给ContactRepository类来持久化联系人信息,控制器程序清单如下:

@Controller
@RequestMapping("/")
public class ContactController {
    private ContactRepository contactRepo;

    @Autowired      //注入ContactReposity
    public ContactController(ContactRepository contactRepo){
        this.contactRepo = contactRepo;
    }

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

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

  ContactController是一个典型的Spring MVC控制器,本例中ContactController遵循了Spring MVC控制器的典型模式,它会展现表单并处理表单的提交。其中home()方法使用注入的ContactRepository来获取所有Contact对象的列表,并将它们放到模型中,然后把请求转交给home视图。这个视图会展示联系人的列表以及添加新Contact的表单。submit()方法将会处理表单提交的POST请求,保存提交的Contact,并重定向到首页。

  因为ContactController使用了@Controller注解,所以组件扫描将会找到它,因此,我们不需要在Spring应用上下文中明确将其声明为bean

  Contact模型类是一个简单的POJO,具有一些属性和存取方法,程序如下:

public class Contact {
    private Long id;
    private String firstName;
    private String lastName;
    private String phoneNumber;
    private String emailAddress;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress) {
        this.emailAddress = emailAddress;
    }
}

3.2 创建视图

  接下来定义视图。按照传统的方式,Java Web应用会使用JSP作为视图层的技术。但是,Thymeleaf的原生模板比JSP更加便于使用,而且它能够让我们以HTML的形式编写模板。鉴于此,这里使用Thymeleaf来定义Contacts应用的home视图。

  首先要将Thymeleaf添加到项目的构建中:

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

  需要记住的是,只要我们将Tymeleaf添加到项目的类路径下,就启用了Spring Boot的自动配置。当应用运行时,Spring Boot将会探测到类路径中的Thymeleaf,然后会自动配置视图解析器、模板解析器以及模板引擎,这些都是在Spring MVC中使用Thymeleaf所需要的,因此,在应用中,不需要用显式Spring配置的方式来定义Thymeleaf

  将Thymeleaf的依赖添加到构建中以后,需要在application.properties文件里对刚才添加的Thymeleaf依赖进行一些必要的配置。Thymeleaf缓存在开发过程中默认开启,这肯定是不行的,那么就要在开发的时候把缓存关闭,只需要在application.properties进行配置即可:

spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.cache=false

  定义home视图的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>

  它实际上是一个非常简单的Thymeleaf模板,分为两部分:一个表单和一个联系人列表。表单将会POST数据到ContactController的submit()方法上,用来创建新的Contact。列表部分将会循环列出模型中的Contact对象。

  为了使用这个模板,我们需要对其进行慎重地命名并放在项目的正确目录位置下。因为ContactController中的home()方法所返回的逻辑视图名为”home”,因此模板文件命名为home.html,自动配置的模板解析器会在指定目录下查找Thymeleaf模板,这个目录也就是相对于根类路径下的templates目录,所以在Maven项目中,需要将home.html放置在”src/main/resources/templates”中

3.3 添加静态内容

  模板中引用了名为style.css的样式表,因此,需要将这个静态文件放到项目中。当采用Spring Boot的Web自动配置来定义Spring MVC bean时,这些bean中会包含一个资源处理器(resource handler),它会将”/**”映射到几个资源路径中。这些资源路径(相对于类路径的根)包括:

  • /META-INF/resources

  • /resources

  • /static

  • /public

  在传统的基于Maven构建的项目中,通常会将静态内容放置在”src/main/webapp”目录下,这样在构建所生成WAR文件里面,这些内容就会位于WAR文件的根目录下,如果使用Spring Boot构建WAR文件的话,这依然是可选的方案。但是,我们也可以将静态内容放置在资源处理器所映射的上述四个路径下。为了满足Thymeleaf模板对”/style.css”文件的引用,我们将style.css文件放置在”/src/main/resources/static”目录下。style.css文件内容如下:

body {
  background-color: #eeeeee;
  font-family: sans-serif;
}

label {
  display: inline-block;
  width: 120px;
  text-align: right;
}

3.4 持久化数据

  在Spring应用中,有多种使用数据库的方式。可以使用JPA或Hibernate将对象映射为关系型数据库中的表和列。对于Contacts应用来说,关系型数据库是不错的选择,这里选用H2数据库和JDBC(使用Spring的JdbcTemplate),让这个过程尽可能地简单。H2是一个短小精干的嵌入式内存数据库引擎,主要的特性包括:免费、开源、快速;嵌入式的数据库服务器,支持集群;提供JDBC、ODBC访问接口,提供基于浏览器的控制台管理程序;纯Java编写,不受平台的限制。

  选择这种方案就需要在构建中添加一些依赖。JDBC starter依赖会将Spring JdbcTemplate需要的所有内容都引入进来。此外,还需要添加H2依赖:

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

<dependency>
    <groupId>com.h2databasegroupId>
    <artifactId>h2artifactId>
    <version>1.4.191version>
dependency>

  将这两项依赖添加到构建之中后,就可以编写ContactRepository类了,如下程序清单中的ContactRepository将会使用注入的JdbcTemplate实现在数据库中读取和写入Contact对象。

@Repository
public class ContactRepository {
    private JdbcTemplate jdbc;
    //注入JdbcTemplate
    @Autowired
    public ContactRepository(JdbcTemplate jdbc){
        this.jdbc = jdbc;
    }
    //查询联系人
    public List findAll(){
        return jdbc.query(
                "select id, firstName, lastName, phoneNumber, emailAddress " + "from contacts order by lastName",
                new RowMapper() {
                  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代表仓库. 一般注解在DAO实现类上, 别人看代码时, 就知道这个类是一个跟数据存储有关的类。@Repository、@Service、@Controller,它们分别对应存储层Bean,业务层Bean,和展示层Bean。

  与ContactController类似,这个Repository类非常简单。它与传统Spring应用中的Repository类并没有什么差别。从实现中,根本无法看出它要用于Spring Boot的应用程序中。findAll()方法使用JdbcTemplate从数据库中获取Contact对象,save()方法使用JdbcTemplate保存新的Contact对象。因为ContactRepository使用了@Repository注解,因此在组件扫描的时候,它会被发现并创建为Spring应用上下文中的bean。

  那么,JdbcTemplate呢?不需要在Spring应用上下文中声明JdbcTemplate bean吗?为了声明它,我们是不是需要声明一个H2 DataSource?

  答案是”不需要“,当Spring Boot探测到Spring的JDBC模块和H2在类路径下的时候,自动配置就会发挥作用,它将自动配置JdbcTemplate bean和H2 DataSource bean。Spring Boot再一次为我们处理了所有的Spring配置

  那么数据库模式该怎么处理呢?我们必须自己定义创建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数据库中的执行就可以了。幸好,Spring Boot也涵盖了这项功能。如果我们将这个文件命名为schema.sql并将其放置在类路径根下(也就是Maven项目的”src/main/resources”目录下),当应用启动的时候,就会找到这个文件并进行数据加载。

  整个项目的目录结构如下图所示:

使用Spring Boot进行Java EE开发_第4张图片

3.5 尝试运行

  Contacts应用非常简单,但是也算得上现实中的Spring应用。它具有Spring MVC控制器和Thymeleaf模板所定义的Web层,并且具有Repository和Spring JdbcTemplate所定义的持久层。在完成Contacts所需的应用级别代码过程中,没有编写任何形式的配置,没有编写任何Spring配置,也没有在web.xml或Servlet初始化类中配置DispatcherServlet。

  通常来讲,Spring Boot的自动配置特性消除了绝大部分或者全部的配置。因此,完全可能编写出没有任何配置的Spring应用程序,当然,自动配置并不能涵盖所有的场景。因此典型的Spring Boot应用程序依然会需要一点配置。具体到Contacts应用,我们不需要任何额外的配置,自动配置功能已经将所有的事情都做好了。

  但是,我们需要有个特殊的类来启动Spring Boot应用。Spring本身并不知道自动配置的任何信息。下面程序中的Application类就是Spring Boot启动类的典型例子:

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

  访问http://localhost:8080/,结果如图所示:

使用Spring Boot进行Java EE开发_第5张图片

  在表单中填写几个联系人信息,多次提交后,结果如图所示:

使用Spring Boot进行Java EE开发_第6张图片

  从最根本上来讲,Spring Boot就是一些库的集合,它能够被任意项目的构建系统所使用。Spring Boot用了两个技巧来消除Spring项目中的样板式配置:Spring Boot Starter和自动配置。自动配置充分利用了Spring4.0的条件化配置特性,能够自动配置特定的Spring bean,用来启用某些特性。例如,Spring Boot能够在应用的类路径中探测到Thymeleaf,然后自动将Thymeleaf模板配置为Spring MVC视图的bean。

你可能感兴趣的:(容器与编程框架,Java,Web学习笔记)