如何构建 Spring Boot 12 因素应用

【注】本文译自:How to build a Spring Boot 12-Factor app (theserverside.com)
在这里,我们看看 Spring Boot 框架如何支持十二因素应用的方法,以及 GitHub、Docker 和 Kubernetes 等工具填补了哪些空白。
    没有国际标准组织指定 Spring Boot 应用作为微服务必须满足的标准。Heroku 联合创始人 Adam Wiggins 向部署到 Heroku 平台的开发人员提供的 12 条建议是开发人员最接近的一套云原生开发指南。
    这 12 条戒律被称为“十二因素应用方法论”,已成为创建现代的以 Docker 和 Kubernetes 为部署目标的现代云原生微服务的事实标准。
    开发基于 Java 的微服务最流行的平台是 Spring Boot。以下是 Spring Boot 如何支持十二因素应用方法论的原则。

1. Spring Boot 代码库

    并非每个 12 因素的原则都直接映射到 Spring Boot。代码库原则就是责任落在 Spring 框架之外的一个例子。
    根据十二因素应用,每个 Spring Boot 微服务都应该有自己独立的代码库。这可以通过创建单个 Git 存储库来实现,开发人员可以在其中贡献代码、合并分支和修复错误。如果您的 Spring Boot 应用托管在其自己的 Git 存储库中,那么您已经正确地实现了 12 因素代码库要求。

2. 外部化依赖管理

    如果您使用 Spring Boot 初始化器创建一个项目,则必须在 Gradle 或 Maven 之间进行选择作为项目的构建工具。这两个工具都将管理依赖项外部化。
    如果您将 JAR 文件放在项目的 lib 目录之外,并在 Maven POM 或 Gradle 构建文件中列出程序的所有外部依赖项,则您的 Spring Boot 应用程序将正确实现 12 因素 依赖项管理。

3. Spring Boot 和 Kubernetes 配置

    根据十二因素应用方法论,Spring Boot 应用程序应该从环境中读取其配置数据。 例如,如果将云原生 Spring Boot 应用程序部署到 Docker 容器并在 Kubernetes 集群中进行管理,则应用程序应该从 Kubernetes ConfigMap 读取其配置数据——而不是从 JavaBean 字段甚至应用程序属性文件。Spring 的级联配置处理系统完全满足了这个 12-因素要求。
    任何用 Spring @ConfigurationProperties 注解修饰的 JavaBean 都会在多个地方寻找配置数据。 @ConfigurationProperties 修饰的 bean 的规则是始终使用最高外部化级别的配置。在 JavaBean 中硬编码的属性将被 ApplicationProperties 文件中的数据覆盖,这些数据将被 JVM 参数覆盖,最终将被 Docker 或 Kubernetes ConfigMap 提供的参数覆盖。
    使用 @ConfigurationProperties 注解,您的 12 因素 Spring Boot 应用将符合配置。

4. 支持服务和 Spring Boot

    将支持服务视为附加资源的能力自 Java 语言一开始就已经融入到 Java 语言中,因此即使开发人员齐心协力,也很难违反这个 12 因素 约束。
    例如,所有通过 Java 数据库连接 (JDBC) 访问的数据库都需要一个 URL 和驱动程序,这隐式地使数据库成为附加资源。 如果不将数据库视为支持服务,就不可能在 Java 中执行 JDBC 或 JPA。 NoSQL 数据库、Kafka 队列和 RESTful Web 服务也是如此。如果您在 Jakarta EE 或 Spring Boot 中编写代码,则几乎必须按照 12-因素指南将所有外部资源视为支持服务。

5. 构建、发布和运行

    开发人员遵循严格的构建、发布和运行策略的建议似乎有些不言而喻。 具有讽刺意味的是,这也可能是最常违反的 12 因素规则之一。
    这里的想法是您应该始终从您的代码库构建您的代码。发布是与版本化配置文件相关联的标记构建。它是您在服务器上部署和运行的标记构建和版本化配置数据的组合。
    不应更新在服务器上运行的代码来修复错误。不应在运行时调整配置设置来克服 Java 性能问题。进入部署的所有代码都来自构建,它基于在裸 Git 存储库中进行版本控制的代码。
    一旦与构建配对以创建发布,配置数据就不得更改。如果需要更改,团队必须再次经历完整的构建、发布和运行周期。 不应该有违反 12 因素构建、发布和运行原则的捷径。

6. 无状态 Spring Boot 进程

    Java 和 Jakarta EE API 有许多类和接口,它们隐式地向应用程序添加状态,其中最重要的是 Servlet 和 JSP API 的 HttpSession 对象。
    为了实现 12 因素合规性,Spring Boot 为 HttpSession 提供了一个替代品,称为 Spring Session。这有助于外部化数据,否则这些数据将被有状态地保存在 Tomcat 或 Jetty 等应用程序服务器上。这是 Spring Boot 如何提供额外 API 并重新实现常用类以确保应用程序和微服务保持 12 因素合规性的一个主要示例。
    此外,Spring Boot 允许开发人员轻松地将 NoSQL 数据库(如 Cassandra 和 MongoDB)中的状态外部化,这也有助于简化无状态微服务的开发。
    必须指出的是,确保微服务作为无状态进程运行的责任也很大程度上落在了软件开发人员的肩上。如果开发人员决定将用户状态保存在一个实例变量中,而不是在共享资源中将该数据外部化,那么 Spring、Docker 或 Kubernetes 无法让该应用程序作为无状态进程进行扩展。

7. 端口绑定

    端口绑定是另一个 12 因素 原则,它超出了 Spring Boot 框架的范围。相反,Docker 容器会将 Tomcat 或 Undertow 服务器使用的内部端口映射到公共端口。在集群环境中,kubectl 实用程序会将 Kubernetes Pod 的端口绑定为公共服务。无论哪种方式,Spring Framework 都不负责端口绑定要求。
    Spring 确实提供了更改打包的 Spring Boot 应用程序内部使用的端口的能力,但 Kubernetes 或 Docker 将负责外部端口绑定,使云原生应用程序可公开访问。

8. 并发性

    根据十二因素应用方法论,云原生应用应该能够横向扩展,以支持来自客户端的大容量并发请求-响应周期。只要 Spring Boot 应用是无状态的,Kubernetes 副本集就会负责使用 Docker 容器创建新的 Pod,这些容器可以同时处理不断增加的工作负载。

9. 快速启动和关闭

    十二因素应用方法论的第 9 条原则是可处置性,它坚持微服务应该快速启动并优雅地关闭。
    为了便于处理,Spring Boot 实现了延迟加载设计模式。它还执行智能初始化以减少在云原生微服务启动时创建的对象数量。此外,当开发人员使用 Spring 框架提供的资源类时,控制能力的反转确保资源在 Kubernetes 节点耗尽或 Docker 容器下线时优雅地终止。

10. 环境之间的奇偶校验

    开发、用户验收测试、预生产和生产环境之间总会存在差异。但十二因素方法坚持这些环境尽可能相似。
    为了促进环境对等,Spring Boot 构建将创建一个可运行的 JAR 文件,其中嵌入了一个应用程序服务器,例如 Tomcat。 打包在 Docker 容器中的相同嵌入式 Tomcat JAR 文件将用于每个不同的部署环境。 由于每个环境都部署了相同的编译代码和应用服务器,最终实现了环境间的对等。
    此外,Spring Profiles 提供了一种简单的方法来定义和配置需要从一个环境更改到另一个环境的属性,从而允许开发人员解决不可避免地发生的环境之间的差异。

11. 日志作为事件流

    十二因素应用坚持将日志视为事件流。
    Spring Boot 使用的所有标准 Java 日志框架都将它们的数据写入事件流,该事件流被保存到运行 Docker 容器的 Kubernetes 节点上的公共目录中。然后这些日志文件很容易被 Kubernetes DaemonSets 使用,比如 FluentD 或 Logstash。这些 DaemonSet 然后将日志流式传输到 Elasticsearch 和 Logstash 等工具以供使用。
    只要您使用框架标准的 Java 日志框架,您就可以放心,在日志消耗方面,您拥有一个符合 12 因素标准的 Spring Boot 应用程序。

12. 管理进程管理

    应用通常需要运行管理进程,这些进程与处理客户端-服务器交互的请求-响应循环没有直接联系的。根据十二因素应用,不应将实现这些过程的代码放在单独的代码库中。管理进程应打包为标准的、受版本控制的构建的一部分,并且进程本身应在应用使用的相同运行时环境中执行。
    在云原生 Spring Boot 应用程序中添加对管理进程的支持非常容易。Spring Batch 项目可以轻松添加对运行一次并退出的作业的支持。 此外,任何 Git 存储库都可以配置为包含文件夹,这些文件夹允许添加可以在需要时在 REPL shell 中运行的脚本。
    云原生微服务的开发没有明确的标准,但十二要素应用方法很接近。如果您是一名 Java 开发人员并且想要创建 12 因素应用,Spring Boot 将帮助您的团队保持云原生合规性。

Spring 依赖注入最佳实践

【注】本文译自:https://springframework.guru/best-practices-for-dependency-injection-with-spring/

  在本文中,我将向你展示如何在 Spring Framework 的依赖项注入中使用 Project Lombok 以获得最佳实践。
  Spring 框架本身具有多种执行依赖项注入的方式。选项的灵活性是 Spring 框架的优势。但是,并非所有的依赖项注入选项都被视为最佳实践。有些实际上不太好。

依赖注入示例

  我提供了一些设置示例,供我们查看必须使用的各种依赖项注入选项。
  让我们以 Spring Service 为例。就我们的目的而言,该服务具有一种返回字符串的方法。我们将使用“service”,并使用 Spring将其注入一些模拟控制器中。请记住,我们只是在探索如何使用 Spring Framework 进行依赖项注入。

示例 Service

public class MyService {
    public String getHello(){
        return "Hello";
    }
}

  我们的 Field 拥有一项公有属性的服务。我们可以注解该字段,Spring 将注入该服务的实例。

属性注入

Field Controller

@Controller
public class FieldController {
    @Autowired
    MyService myService;
    public String saySomething(){
        return myService.getHello();
    }
}

  这只是一个公有属性,没有 setter。显然,这不是一个好的实践,不推荐这样做。
  我们可以对此进行一些改进,将该字段的访问权限设为私有。Spring Framework 确实允许你自动装配私有字段。你确实看到有人这样做。Spring 将执行一些反射魔术来执行依赖项注入

私有 Field Controller

public class PrivateFieldController {
    @Autowired
    private MyService myService;
    public String saySomething(){
        return myService.getHello();
    }
}

  尽管只使用私有字段比较好,但是测试却成了一个令人头痛。你要么需要启动 Spring Context,要么使用一些 Spring 实用程序来执行依赖注入以进行测试。不是世界末日,但总的来说很烦人。
  我们可以通过为私有属性提供 setter 来改善这一点。Getter 和 Setter 通常被认为是面向对象编程中的最佳实践。通过注解 setter 方法,指示 Spring 使用 setter 进行依赖项注入很简单。

方法注入

Setter Controller

@Controller
public class SetterController {
    private MyService myService;
    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }
    public String saySomething(){
        return myService.getHello();
    }
}

  这是使用私有字段时的明显改进。有人会抱怨这要写太多代码。但是实际上,自 South Park 的第一季以来,此类任务已在现代 IDE 中实现了自动化。

构造函数注入

  下一个选项是使用构造函数。到目前为止,这是我们研究过的最佳方法。 使用构造函数设置注入的属性时,不必提供自动装配注释。这是一个很好的功能,可以节省一些键入时间。从 Spring Framework 版本4.2开始,用于依赖项注入的构造函数的注释是可选的。

Constructor Controller

@Controller
public class ConstructorController {
    private MyService myService;
    public ConstructorController(MyService myService) {
        this.myService = myService;
    }
    public String saySomething(){
        return myService.getHello();
    }
}

  基于构造函数的依赖注入无疑被认为是最佳实践。曾经有一段时间我个人偏爱基于 setter 的注入,但是后来又转向基于构造函数的注入。
  我们仍然可以改善我们的示例。现在有两个主要问题。 第一,我们的服务类型是具体类型。硬类型的依赖注入不是最佳实践。
  第二个问题是,我们要注入的属性未声明为final。因此,从理论上讲,该类可以在实例化注入的属性后对其进行修改。依# 赖注入最佳实践
  依赖项注入的最佳实践是利用接口,构造函数和 final 属性。
  我已经设置了“最佳实践”服务接口,并提供了服务实现—使用了 Spring Service 注解。

最佳实践服务接口

public interface BpService {
    String getHello();
}

最佳实践服务实现

@Service
public class BpServiceImpl implements BpService {
    @Override
    public String getHello() {
        return "The Best Hello!";
    }
}

使用 Project Lombok

  现在,使用 Project Lombok 进行依赖注入的最佳实践的秘诀在于:

  • 声明一个 final 属性接口
  • 为类添加 Project Lomboc 注解 @RequiredArgsConstructor

  现在,Project Lombok 将为声明为 final 的所有属性生成一个构造函数。Spring 会自动使用 Lombok 提供的构造函数来自动装配该片段。

Lombok Controller

@RequiredArgsConstructor
@Controller
public class BpFinalConstructorController {
    private final BpService bpService;
    public String saySomething(){
        return bpService.getHello();
    }
}

  这是执行此操作的真正好方法。您的代码保持非常干净。使用 Spring时,通常需要多个自动装配属性。
  当您需要添加另一个 bean 时,只需声明一个 final 属性。
  如果您重构并且不再需要 Spring 托管的依赖项,则只需删除 final 属性。
  你不再需要维护设置器或构造函数代码。Project Lombok 减轻了您的日常工作。
  我在日常编码中一直使用这种技术。绝对是节省时间。并导致更干净的代码。未使用的属性和未使用的构造函数参数已一去不复返了。重构现在不那么痛苦了!
  本文的源代码可在 GitHub 上找到。

使用 Eureka 注册服务

【注】本文译自:https://www.tutorialspoint.com/spring_boot/spring_boot_service_registration_with_eureka.htm

  本文将带你深入学习如何将 Spring Boot 微服务应用注册到 Eureka 服务器中。在注册应用前,请确保 Eureka Server 已经运行在 8761 端口或者先构建 Eureka 服务器并运行起来。有关搭建 Eureka 服务器的信息,可以参考本系列教程的相关部分。
  首先,你需要在构建配置文件中加入以下依赖,以注册微服务到 Eureka 服务器。
  Maven 用户可以加上下面的依赖到 pom.xml 文件:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

  Gradle 用户可以加上下面的依赖到 build.gradle 文件:

compile('org.springframework.cloud:spring-cloud-starter-eureka')

  现在,我们需要在 Spring Boot 应用类文件中加上 @EnableEurekaClient 注解。@EnableEurekaClient 注解可以使你的 Spring Boot 应用作为 Eureka 客户端。
  主 Spring Boot 就用如下所示:

package com.tutorialspoint.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

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

  要注册 Spring Boot 应用到 Eureka 服务器中,我们要加上以下配置到 application.properties 或 application.yml 文件,并指定 Eureka 服务器的 URL。
  application.yml 文件的代码如下:

eureka:
  client:
     serviceUrl:
        defaultZone: http://localhost:8761/eureka
     instance:
     preferIpAddress: true
spring:
  application:
     name: eurekaclient

  application.properties 文件的代码如下:
eureka.client.serviceUrl.defaultZone = http://localhost:8761/eureka
eureka.client.instance.preferIpAddress = true
spring.application.name = eurekaclient
  现在,在主 Spring Boot 应用中加上 Rest 端点以返回字符串,在构建配置文件中要加上相应的应用描述。示例代码如下:

package com.tutorialspoint.eurekaclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableEurekaClient
@RestController
public class EurekaclientApplication {
   public static void main(String[] args) {
      SpringApplication.run(EurekaclientApplication.class, args);
   }
   @RequestMapping(value = "/")
   public String home() {
      return "Eureka Client application";
   }
}

  整个配置文件如下:
  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 
   http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>eurekaclient</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>eurekaclient</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.9.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-eureka</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>

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

</project>

  Gradle – build.gradle

buildscript {
   ext {
      springBootVersion = '1.5.9.RELEASE'
   }
   repositories {
      mavenCentral()
   }
   dependencies {
      classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
   }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.tutorialspoint'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
   mavenCentral()
}
ext {
   springCloudVersion = 'Edgware.RELEASE'
}
dependencies {
   compile('org.springframework.cloud:spring-cloud-starter-eureka')
   testCompile('org.springframework.boot:spring-boot-starter-test')
   compile('org.springframework.boot:spring-boot-starter-web')   
}
dependencyManagement {
   imports {
      mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
   }
}

  你可以使用 Maven 或 Gradle 命令创建可执行 executable JAR 文件并运行 Spring Boot 应用:
  Maven 命令如下:

mvn clean install

  在 “BUILD SUCCESS” 之后,你可以在 target 目录下找到 JAR 文件。
  Gradle 可以使用以下命令:

gradle clean build

  在 “BUILD SUCCESSFUL” 之后,你可以在 build/libs 目录下找到 JAR 文件。
  使用以下命令运行 JAR 文件:

java –jar <JARFILE>

  现在,应用已经在 Tomcat 8080 端口启动,且 Eureka 客户端应用已经被注册到 Eureka 服务器,如下所示:

  在 Web 浏览器中输入 URL http://localhost:8761/,可以看到 Eureka 客户端应用已经被注册到 Eureka 服务器。

  在 Web 浏览器中输入 URL http://localhost:8080/,可以看到 Rest 端点输出。

Spring Boot 教程:Eureka 服务器

【注】本文译自: https://www.tutorialspoint.com/spring_boot/spring_boot_eureka_server.htm

  Eureka 服务器是一个应用,它包含所有客户端服务应用的信息。每个微服务都会注册到 Eureka 服务器并且 Eureka 服务器知道所有客户端应用的端口和 IP 地址。Eureka 服务器也被称为发现服务器。
  本文将带你学习如何搭建 Eureka 服务器。搭建 Eureka 服务器
  Eureka 服务器与 Spring Cloud 打包发布。基于此,我们需要开发 Eureka 服务器并将它运行于缺省的 8761 端口上。
  访问 Spring 初始化器主页 https://start.spring.io/ 并下载 Spring Boot 工程的 Eureka 服务器依赖。如下图所示:

  工程下载之后,在主 Spring Boot 应用类文件中,我们要加上 @EnableEurekaServer 注解。@EnableEurekaServer 注解可使你的 Spring Boot 应用用作 Eureka 服务器。
  主 Spring Boot 应用类文件如下所示:

package com.tutorialspoint.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

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

  确保你的构建配置文件中已经加入了 Spring cloud Eureka 服务器依赖。
  Maven 用户的依赖代码如下:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>

  Gradle 用户的依赖代码如下:

compile('org.springframework.cloud:spring-cloud-starter-eureka-server')

  完整的构建配置代码文件如下所示:
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 
   http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>eurekaserver</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>eurekaserver</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.9.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
      <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-eureka-server</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>

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

</project>

Gradle – build.gradle

buildscript {
   ext {
      springBootVersion = '1.5.9.RELEASE'
   }
   repositories {
      mavenCentral()
   }
   dependencies {
      classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
   }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.tutorialspoint'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
   mavenCentral()
}
ext {
   springCloudVersion = 'Edgware.RELEASE'
}
dependencies {
   compile('org.springframework.cloud:spring-cloud-starter-eureka-server')
   testCompile('org.springframework.boot:spring-boot-starter-test')
}
dependencyManagement {
   imports {
      mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
   }
}

  缺省情况下,Eureka 服务器会将自身注册到发现中。你应当加入以下配置到 application.properties 或 application.yml 文件中:
application.properties 文件如下所示:

eureka.client.registerWithEureka = false
eureka.client.fetchRegistry = false
server.port = 8761

application.yml 文件如下所示:

eureka:
  client:
     registerWithEureka: false
     fetchRegistry: false
server:
  port: 8761

  现在可以使用 Maven 或 Gradle 命令创建可执行 executable JAR 文件并运行 Spring Boot 应用了:
  Maven 命令如下:

mvn clean install

  在 “BUILD SUCCESS” 之后,你可以在 target 目录下找到 JAR 文件。
  Gradle 可以使用以下命令:

gradle clean build

  在 “BUILD SUCCESSFUL” 之后,你可以在 build/libs 目录下找到 JAR 文件。
  使用以下命令运行 JAR 文件:

java –jar <JARFILE>

  应用已在 Tomcat 8761 端口启动,如下图所示:

  接下来,在 web 浏览器中单击 URL http://localhost:8761/,可以发现 Eureka 服务器已经运行在 8761 端口,如下所示:

Spring Boot 教程:启用 HTTPS

【注】本文译自: https://www.tutorialspoint.com/spring_boot/spring_boot_enabling_https.htm

  Spring Boot 应用默认以 HTTP 8080 端口启动。

  你要在 Spring Boot 应用中执行以下步骤来配置 HTTPS 和端口 443:

  • 获取 SSL 证书:创建自签名证书或者从一个证书认证机构申请一个。
  • 启用 HTTPS 和 443 端口

    自签名证书

      Java 运行时环境已经内置了证书管理实用工具,可用于创建自签名证书。示例代码如下:

keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
Enter keystore password:
   Re-enter new password:
   What is your first and last name?
   [Unknown]:
   What is the name of your organizational unit?
   [Unknown]:
   What is the name of your organization?
   [Unknown]:
   What is the name of your City or Locality?
   [Unknown]:
   What is the name of your State or Province?
   [Unknown]:
   What is the two-letter country code for this unit?
   [Unknown]:
   Is CN = Unknown, OU=Unknown, O = Unknown, L = Unknown, ST = Unknown, C = Unknown correct?
   [no]: yes

  这段代码将产生一个名为 keystore.p12 的PKCS12 keystore 文件,证书别名为 tomcat。

配置 HTTPS

  我们要在 application.properties 文件中写入:服务端口为 443、key-store 文件路径、key-store-password、key-store-type 和 密钥别名。如下所示:

server.port: 443
server.ssl.key-store: keystore.p12
server.ssl.key-store-password: springboot
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat

  如果你使用 YAML 属性的话,你也可以使用下面的 application.yml 的代码:

server:
  port: 443
  ssl:
     key-store: keystore.p12
     key-store-password: springboot
     keyStoreType: PKCS12
     keyAlias: tomcat

  现在可以使用 Maven 或 Gradle 命令创建可执行 executable JAR 文件并运行 Spring Boot 应用了:
  Maven 命令如下:

mvn clean install

  在 “BUILD SUCCESS” 之后,你可以在 target 目录下找到 JAR 文件。
  Gradle 可以使用以下命令:

gradle clean build

  在 “BUILD SUCCESSFUL” 之后,你可以在 build/libs 目录下找到 JAR 文件。
  使用以下命令运行 JAR 文件:

java –jar <JARFILE>

  应用已在 Tomcat 443 端口启动,如下图所示:

Spring Boot 教程:调度

【注】本文译自: https://www.tutorialspoint.com/spring_boot/spring_boot_scheduling.htm

  调度用来处理特定时间周期的任务。Spring Boot 为 Spring 应用编写调度器提供了良好的支持。

Java Cron 表达式

  Java Cron 表达式用于配置 CronTrigger 实例,是 org.quartz.Trigger 的子类。关于 Java cron 表达式的更多信息可参考:https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.htm
  @EnableScheduling 注解用于使你的应用能够使用调度器。这个注解应当被加在主 Spring Boot 应用类文件中。

@SpringBootApplication
@EnableScheduling

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

  @Scheduled 注解用于触发一个特定时间周期的调度器。

@Scheduled(cron = "0 * 9 * * ?")
public void cronJobSch() throws Exception {
}

  以下代码展示了如何在每天的早上 9:00 到 9:59 之间每分钟执行任务:

package com.tutorialspoint.demo.scheduler;

import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class Scheduler {
   @Scheduled(cron = "0 * 9 * * ?")
   public void cronJobSch() {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
      Date now = new Date();
      String strDate = sdf.format(now);
      System.out.println("Java cron job expression:: " + strDate);
   }
}

  以下截图展示了应用在 09:03:23 启动之后如何每隔一分钟执行一次:

固定频度

  固定频度调度器被用于在特定时间执行任务。它不等待前一个任务完成,时间单位为毫秒。示例代码如下:

@Scheduled(fixedRate = 1000)
public void fixedRateSch() { 
}

  以下代码示例是应用启动后的每秒钟执行一个任务:

package com.tutorialspoint.demo.scheduler;

import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class Scheduler {
   @Scheduled(fixedRate = 1000)
   public void fixedRateSch() {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

      Date now = new Date();
      String strDate = sdf.format(now);
      System.out.println("Fixed Rate scheduler:: " + strDate);
   }
}

  观看以下截屏,可以看出应用在 09:12:00 启动后以每隔一秒钟的固定频度执行任务:

固定延迟

  固定延迟调度器用于在指定时间执行任务。它应当等待上一个任务完成,单位为毫秒。示例代码如下:

@Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void fixedDelaySch() {
}

  这里,initialDelay 是在初始化之后到首次执行间的延迟值。
  下面的例子中,是从应用启动完成后 3 秒后执行每秒一次的任务:

package com.tutorialspoint.demo.scheduler;

import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class Scheduler {
   @Scheduled(fixedDelay = 1000, initialDelay = 3000)
   public void fixedDelaySch() {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
      Date now = new Date();
      String strDate = sdf.format(now);
      System.out.println("Fixed Delay scheduler:: " + strDate);
   }
}

  下面看到的截屏显示的是应用在 09:18:39 启动完成 3 秒后,固定延迟调度器任务每秒执行一次的情况。

Spring Boot 教程:国际化

【注】本文译自: https://www.tutorialspoint.com/spring_boot/spring_boot_internationalization.htm

  国际化是一种处理机制,使得你的应用可以适配不同的语言和区域而无需更改源代码。换言之,国际化是为本地化而准备。
  本文将带你学习在 Spring Boot 中如何实现国际化的细节。

依赖

  在 Spring Boot 中开发 web 应用,我们需要依赖 Spring Boot Starter Web 和 Spring Boot Starter Thymeleaf 依赖项。

Maven

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Gradle

compile('org.springframework.boot:spring-boot-starter-web')
compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf'

LocaleResolver

  要确定你的应用的缺省本地化,需要在 Spring Boot 应用中 增加 LocaleResolver bean。

@Bean
public LocaleResolver localeResolver() {
   SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
   sessionLocaleResolver.setDefaultLocale(Locale.US);
   return sessionLocaleResolver;
}

LocaleChangeInterceptor

  LocaleChangeInterceptor 用于根据请求所带的语言参数来切换新的本地化。

@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
   LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
   localeChangeInterceptor.setParamName("language");
   return localeChangeInterceptor;
}

  要把 LocaleChangeInterceptor 加到应用注册拦截器中才能生效。这个配置类应当继承 WebMvcConfigurerAdapter 类且重载 addInterceptors() 方法。

消息资源

  Spring Boot 应用默认从 classpath 路径下的 src/main/resources 文件夹获取消息源。缺省本地化消息文件名应当是 message.properties,每个本地化文件名应当类似 messages_XX.properties。“XX” 代表本地化代号。
  所有的消息属性应当以键值方式表达。如果任意属性没有在本地化中找到,应用就从 messages.properties 文件中获取缺省值。
  缺省 messages.properties 如下所示:

welcome.text=Hi Welcome to Everyone

  法语 messages_cn.properties 如下所示:

welcome.text=Salut Bienvenue à tous

注意:消息源文件应当以 “UTF-8” 格式存储。

HTML 文件

  在 HTML 文件中,使用 #{key} 语法来显示属性文件中获取的消息。

<h1 th:text = "#{welcome.text}"></h1>

  完整的代码如下:

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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>demo</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.8.RELEASE</version>
      <relativePath />
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
   </dependencies>

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

Gradle – build.gradle

buildscript {
   ext {
      springBootVersion = '1.5.8.RELEASE'
   }
   repositories {
      mavenCentral()
   }
   dependencies {
      classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
   }
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.tutorialspoint'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
   mavenCentral()
}
dependencies {
   compile('org.springframework.boot:spring-boot-starter-web')
   compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf'
   testCompile('org.springframework.boot:spring-boot-starter-test')
}

  主 Spring Boot 应用类文件如下:

package com.tutorialspoint.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

  控制类文件如下:

package com.tutorialspoint.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ViewController {
   @RequestMapping("/locale")
   public String locale() {
      return "locale";
   }
}

  支持国际化的配置类:

package com.tutorialspoint.demo;

import java.util.Locale;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

@Configuration
public class Internationalization extends WebMvcConfigurerAdapter {
   @Bean
   public LocaleResolver localeResolver() {
      SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
      sessionLocaleResolver.setDefaultLocale(Locale.US);
      return sessionLocaleResolver;
   }
   @Bean
   public LocaleChangeInterceptor localeChangeInterceptor() {
      LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
      localeChangeInterceptor.setParamName("language");
      return localeChangeInterceptor;
   }
   @Override
   public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(localeChangeInterceptor());
   }
}

  消息源 – messages.properties 如下:

welcome.text = Hi Welcome to Everyone

  消息源 – message_fr.properties 文件如下:

welcome.text = Salut Bienvenue à tous
  HTML 文件 locale.html 应当放在 classpath 路径下的 templates 目录,如下所示:
```html


   
      
      Internationalization
   
   
      

  使用 Maven 或 Gradle 命令创建可执行 JAR 文件并运行 Spring Boot 应用:
  Maven 命令如下:

mvn clean install

  在 “BUILD SUCCESS” 之后,你可以在 target 目录下找到 JAR 文件。
  Gradle 可以使用以下命令:
  应用已在 Tomcat 8080 端口启动,如下图所示:

  在浏览器输入 URL http://localhost:8080/locale 可以看到如下输出:

URL http://localhost:8080/locale?language=fr 输出如下:

Spring Boot 教程:CORS 支持

【注】本文译自: https://www.tutorialspoint.com/spring_boot/spring_boot_cors_support.htm

  跨域资源共享 (CORS) 是一个安全概念,它允许在 web 浏览器中实现对资源访问的限制。它可避免 JavaScript 代码产生或消费别跨越不同域的请求。
  例如,你的运行在 8080 端口的 web 应用试图使用 JavaScript 消费来自 9090 端口的 RESTful web 服务。在这样的情形下,你将面对 web 浏览器上跨域资源共享的安全问题。
  这个问题有两个需求要处理:

  • RESTful web 服务应当支持跨域资源共享。
  • RESTful web 服务应用应当允许来自 8080 端口访问 API(s)。
      在本文中,我们将详细学习如何让一个 RESTful Web 服务应用能够进行跨域请求。

    在控制器方法中启用 CORS

      我们需要在控制器方法上对一个 RESTful web 服务使用 @CrossOrigin 设置源。@CrossOrigin 注解支持指定 REST API,而不是对整个应用。

    @RequestMapping(value = "/products")
    @CrossOrigin(origins = "http://localhost:8080")
    public ResponseEntity<Object> getProduct() {
    return null;
    }

    全局 CORS 配置

      要定义 @Bean 以对 Spring Boot 应用全局配置 CORS。

    @Bean
    public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {
      @Override
      public void addCorsMappings(CorsRegistry registry) {
         registry.addMapping("/products").allowedOrigins("http://localhost:9000");
      }    
    };
    }

      在主 Spring Boot 应用中全局配置 CORS 的代码如下:

package com.tutorialspoint.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@SpringBootApplication
public class DemoApplication {
   public static void main(String[] args) {
      SpringApplication.run(DemoApplication.class, args);
   }
   @Bean
   public WebMvcConfigurer corsConfigurer() {
      return new WebMvcConfigurerAdapter() {
         @Override
         public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/products").allowedOrigins("http://localhost:8080");
         }
      };
   }
}

  现在,你创建了一个 Spring Boot web 应用,运行在 8080 端口上,RESTful web 服务应用运行在 9090 端口上。关于如何实现 RESTful Web 服务,你可以参考本系列教程的另外一部分:消费 RESTful Web 服务

Spring Boot 教程:消费 Rest Web 服务

【注】本文译自: https://www.tutorialspoint.com/spring_boot/spring_boot_consuming_restful_web_services.htm

  本文将讨论如何使用 jQuery AJAX 来消费 RESTful Web 服务。
  创建一个简单的 Spring Boot web 应用并编写一个控制器类文件用于重定向到 HTML 文件中,以消费 RESTful web 服务。
  我们要在构件配置文件中加上 Spring Boot starter Thymeleaf 和 Web 依赖。
  对于 Maven 用户,在 pom.xml 文件中加上以下依赖:

<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>

  对于 Gradle 用户,在 build.gradle 中加上如下依赖:

compile group: ‘org.springframework.boot’, name: ‘spring-boot-starter-thymeleaf’
compile(‘org.springframework.boot:spring-boot-starter-web’)

  @Controller 类文件如下:

@Controller
public class ViewController {
}

  可以定义请求 URI 方法来重定向到 HTML 文件中,如下所示:

@RequestMapping(“/view-products”)
public String viewProducts() {
   return “view-products”;
}
@RequestMapping(“/add-products”)
public String addProducts() {
   return “add-products”;
}

  API http://localhost:9090/products 应当返回以下所示的 JSON 响应:

[
   {
      "id": "1",
      "name": "Honey"
   },
   {
      "id": "2",
      "name": "Almond"
   }
]

  现在,在 classpath 下的 templates 目录中创建 view-products.html 文件:
  在这个 HTML 文件中,我们加上了 jQuery 类,且编写代码在页面加载时消费 RESTful web 服务。

<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<script>
$(document).ready(function(){
   $.getJSON("http://localhost:9090/products", function(result){
      $.each(result, function(key,value) {
         $("#productsJson").append(value.id+" "+value.name+" ");
      }); 
   });
});
</script>

  POST 方法和 URL http://localhost:9090/products 应当包含以下请求体和响应体:
  请求体代码如下:

{
   "id":"3",
   "name":"Ginger"
}

  响应体代码如下:

Product is created successfully

  现在,在 classpath 下的 templates 目录中创建 add-products.html 文件。
  在 HTML 文件中,我们加上 jQuery 库并编写,在单击按钮时提交表单以消费 RESTful web 服务。

<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
   $(document).ready(function() {
      $("button").click(function() {
         var productmodel = {
            id : "3",
            name : "Ginger"
         };
         var requestJSON = JSON.stringify(productmodel);
         $.ajax({
            type : "POST",
            url : "http://localhost:9090/products",
            headers : {
               "Content-Type" : "application/json"
            },
            data : requestJSON,
            success : function(data) {
               alert(data);
            },
            error : function(data) {
            }
         });
      });
   });
</script>

  完整的代码如下:
  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 
   http://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>demo</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.8.RELEASE</version>
      <relativePath />
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
   </dependencies>

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

</project>

  Gradle – build.gradle 代码如下:

buildscript {
   ext {
      springBootVersion = ‘1.5.8.RELEASE’
   }
   repositories {
      mavenCentral()
   }
   dependencies {
      classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
   }
}

apply plugin: ‘java’
apply plugin: ‘eclipse’
apply plugin: ‘org.springframework.boot’

group = ‘com.tutorialspoint’
version = ‘0.0.1-SNAPSHOT’
sourceCompatibility = 1.8

repositories {
   mavenCentral()
}

dependencies {
   compile(‘org.springframework.boot:spring-boot-starter-web’)
   compile group: ‘org.springframework.boot’, name: ‘spring-boot-starter-thymeleaf’
   testCompile(‘org.springframework.boot:spring-boot-starter-test’)
}

  控制类代码如下:
  ViewController.java 如下:

package com.tutorialspoint.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class ViewController {
   @RequestMapping(“/view-products”)
   public String viewProducts() {
      return “view-products”;
   }
   @RequestMapping(“/add-products”)
   public String addProducts() {
      return “add-products”;   
   }   
}

  view-products.html 文件如下:

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "ISO-8859-1"/>
      <title>View Products</title>
      <script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

      <script>
         $(document).ready(function(){
            $.getJSON("http://localhost:9090/products", function(result){
               $.each(result, function(key,value) {
                  $("#productsJson").append(value.id+" "+value.name+" ");
               }); 
            });
         });
      </script>
   </head>

   <body>
      <div id = "productsJson"> </div>
   </body>
</html>

  add-products.html 文件如下:

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "ISO-8859-1" />
      <title>Add Products</title>
      <script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

      <script>
         $(document).ready(function() {
            $("button").click(function() {
               var productmodel = {
                  id : "3",
                  name : "Ginger"
               };
               var requestJSON = JSON.stringify(productmodel);
               $.ajax({
                  type : "POST",
                  url : "http://localhost:9090/products",
                  headers : {
                     "Content-Type" : "application/json"
                  },
                  data : requestJSON,
                  success : function(data) {
                     alert(data);
                  },
                  error : function(data) {
                  }
               });
            });
         });
      </script>
   </head>

   <body>
      <button>Click here to submit the form</button>
   </body>
</html>

  主 Spring Boot 应用类文件如下:

package com.tutorialspoint.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

  现在可以使用 Maven 或 Gradle 命令创建可执行 executable JAR 文件并运行 Spring Boot 应用了:
  Maven 命令如下:

mvn clean install

  在 “BUILD SUCCESS” 之后,你可以在 target 目录下找到 JAR 文件。
  Gradle 可以使用以下命令:

gradle clean build

  在 “BUILD SUCCESSFUL” 之后,你可以在 build/libs 目录下找到 JAR 文件。
  使用以下命令运行 JAR 文件:

java –jar <JARFILE>

  应用已在 Tomcat 8080 端口启动,如下图所示:

  在浏览器中输入下面的 URL 你会看到如下图所示的输出:
  http://localhost:8080/view-products

http://localhost:8080/add-products

  现在,单击按钮 Click here to submit the form 你可以看到如下图所示的结果:

  现在,单击如下查看产品 URL 查看所创建的产品。
  http://localhost:8080/view-products

Angular JS

  要使用 Angular JS 消费 APIs,如下所示:
  使用下面的代码创建 Angular JS 控制来消费 GET API – http://localhost:9090/products

angular.module('demo', [])
.controller('Hello', function($scope, $http) {
   $http.get('http://localhost:9090/products').
   then(function(response) {
      $scope.products = response.data;
   });
});

  使用下面的代码创建 Angular JS 控制来消费 POST API – http://localhost:9090/products

angular.module('demo', [])
.controller('Hello', function($scope, $http) {
   $http.post('http://localhost:9090/products',data).
   then(function(response) {
      console.log("Product created successfully");
   });
});

注意: Post 方法数据表示用于创建产品的 JSON 格式的请求体

Spring Boot 教程:Thymeleaf

【注】本文译自:https://www.tutorialspoint.com/spring_boot/spring_boot_thymeleaf.htm

  Thymeleaf 是一个基于 Java 的库【译注:模板引擎】,可用于创建 web 应用。它对于 web 应用中的 XHTML/HTML5 提供了良好的支持。在本文中,你将学会有关 Thymeleaf 细节。

Thymeleaf 模板

  Thymeleaf 将你的文件转换成格式良好的 XML 文件。它包含以下 6 种类型的模板:

  • XML
  • 有效 XML
  • XHTML
  • 有效 XHTML
  • HTML5
  • 遗留 HTML5
      除了遗留 HTML5 以外的所有模板都可参阅有效的 XML 文件。遗留 HTML5 允许我们在 web 页中渲染 HTML5 标签,包括没闭合的标签。

    Web 应用

      你可以使用 Thymeleaf 模板在 Spring Boot 中创建 web 应用,需要以下几个步骤。
      使用以下代码创建一个 @Controller 类文件以重定向请求 URI 到 HTML 文件:

package com.tutorialspoint.demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class WebController {
   @RequestMapping(value = "/index")
   public String index() {
      return "index";
   }
}

  在上述例子中,请求 URI 为 /index,控制重定向到 index.html 文件。注意,index.html 文件应当放到 templates 目录下面,所有的 JS 和 CSS 文件应当放到 classpath 路径下的 static 目录。在示例中,我们使用 CSS 文件改变文本颜色。
  你可以使用以下代码在一个独立的目录中创建 CSS 文件,文件名为 styles.css:

h4 {
   color: red;
}

  index.html 文件的代码如下:

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "ISO-8859-1" />
      <link href = "css/styles.css" rel = "stylesheet"/>
      <title>Spring Boot Application</title>
   </head>
   <body>
      <h4>Welcome to Thymeleaf Spring Boot web application</h4>
   </body>
</html>

  项目浏览器的截屏如下所示:

  现在,我们需要在我们的构建配置文件中加上 Spring Boot Starter Thymeleaf 依赖。
  Maven 用户可以将下面的依赖加入 pom.xml 文件:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

  Gradle 用户可以在 build.gradle 文件中加入以下依赖:

compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf'

  主 Spring Boot 应用类代码如下所示:

package com.tutorialspoint.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

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

   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>
   <name>demo</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>1.5.8.RELEASE</version>
      <relativePath />
   </parent>

   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
      </dependency>
   </dependencies>

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

</project>

  Gradle – build.gradle 代码如下:

buildscript {
   ext {
      springBootVersion = '1.5.8.RELEASE'
   }
   repositories {
      mavenCentral()
   }
   dependencies {
      classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
   }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.tutorialspoint'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
   mavenCentral()
}
dependencies {
   compile('org.springframework.boot:spring-boot-starter-web')
   compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf'
   testCompile('org.springframework.boot:spring-boot-starter-test')
}

  现在你可以使用 Maven 或 Gradle 命令创建可执行 executable JAR 文件并运行 Spring Boot 应用了:
  Maven 命令如下:

mvn clean install

  在 “BUILD SUCCESS” 之后,你可以在 target 目录下找到 JAR 文件。
  Gradle 可以使用以下命令:

gradle clean build

  在 “BUILD SUCCESSFUL” 之后,你可以在 build/libs 目录下找到 JAR 文件。
  使用以下命令运行 JAR 文件:

java –jar <JARFILE>

  现在应用已在 Tomcat 8080 端口启动,如下图所示:

  在浏览器中输入以下 URL,你将会看到下图所示的输出:
http://localhost:8080/index