ZetCode-Spring-Boot-教程-二-
ZetCode Spring Boot 教程(二)
原文:ZetCode
Spring Boot @Controller
Spring Boot @Controller
教程显示了如何在 Spring 应用中使用@Controller
注解来构建 Web 控制器。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
Spring MVC
Spring MVC 是基于 Servlet API 构建的原始 Web 框架。 它基于流行的 MVC 设计模式。 MVC(模型-视图-控制器)是一种软件架构模式,它将应用分为三个区域:模型,视图和控制器。 该模型表示一个携带数据的 Java 对象。 该视图表示模型包含的数据的可视化。 控制器控制数据流入模型对象并在数据更改时更新视图。 它使视图和模型分离。
Spring Framework 5.0 引入了一个名为 Spring WebFlux 的并行反应式栈 Web 框架。
@Controller
@Controller
注解指示已注解的类是控制器。 它是@Component
的特化,可通过类路径扫描自动检测。 它通常与基于@RequestMapping
注解的注解处理器方法结合使用。 @RestController
是用于创建 Restful 控制器的同级便利注解。
Spring Boot @Controller
示例
在以下应用中,我们演示@Controller
的用法。 该应用将当前数据和时间返回给客户端。
$ tree
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── Application.java
│ │ └── controller
│ │ └── MyController.java
│ └── resources
│ ├── static
│ │ └── index.html
│ └── templates
│ └── showMessage.ftl
└── test
└── java
这是 Spring 应用的项目结构。
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.zetcode</groupId>
<artifactId>controllerex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 spring-boot-starter-parent
是父 POM,它为使用 Maven 构建的应用提供依赖关系和插件管理。 spring-boot-starter-freemarker
是 Freemarker 模板引擎的依赖项。 此依赖项还将在项目中包含 Spring MVC。 spring-boot-maven-plugin
将 Spring 应用打包到可执行的 JAR 或 WAR 归档文件中。
com/zetcode/MyController.java
package com.zetcode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
@Controller
public class MyController {
@RequestMapping(value = "/getDateAndTime")
public ModelAndView getDateAndTime() {
var now = LocalDateTime.now();
var dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
var date_time = dtf.format(now);
var params = new HashMap<String, Object>();
params.put("date_time", date_time);
return new ModelAndView("showMessage", params);
}
}
这是MyController
。 它响应来自客户端的请求。 它找出当前日期和时间,并将处理过程解析为showMessage.ftl
模板,并将其传递给数据。
@Controller
public class MyController {
MyController
带有@Controller
注解。
@RequestMapping(value = "/getDateAndTime")
public ModelAndView getDateAndTime() {
getDateAndTime()
方法映射到getDateAndTime
URL 模式; 它返回ModelAndView
,它是 Web MVC 框架中 Model 和 View 的持有者。
var now = LocalDateTime.now();
var dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
var date_time = dtf.format(now);
我们获取并格式化本地日期和时间。
var params = new HashMap<String, Object>();
params.put("date_time", date_time);
日期和时间字符串将添加到参数映射中。
return new ModelAndView("showMessage", params);
我们返回ModelAndView
。 由于 POM 文件中存在 Freemarker 依赖项,因此 Spring 将处理解析为showMessage.ftl
模板文件,并将params
对象传递给它。
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>
<a href="getDateAndTime">Get date and time</a>
</p>
</body>
</html>
这是主页。 它包含一个调用 Spring 控制器的链接。 它是静态资源,位于预定义的src/main/resources/static
目录中。
resources/templates/showMessage.ftl
<!DOCTYPE html>
<html>
<head>
<title>Show message</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
Date and time: ${date_time}
</body>
</html>
showMessage.ftl
是一个 Freemarker 模板文件。 它位于预定义的src/main/resources/templates
目录中。 它使用${}
语法输出日期和时间。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。 在扫描过程中,将查找@Controller
注解,并从MyController
类创建一个 Spring bean。
$ mvn spring-boot:run
应用运行后,我们可以导航到localhost:8080
。
在本教程中,我们展示了如何在 Spring 应用中使用@Controller
注解。 您可能也对相关教程感兴趣: Spring Boot @RestController
教程, Java Servlets 教程, Spring Boot @ResponseStatus
教程, Spring Boot @ExceptionHandler
教程, Spring Boot 上传文件, Spring Boot @Component
教程, Spring Boot @RequestParam
教程, Java 教程。
Spring Boot @RestController
Spring Boot @RestController
教程展示了如何在 Spring 应用中使用@RestController
注解来构建 Restful 控制器。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
Spring MVC
Spring MVC 是基于 Servlet API 构建的主要 Web 框架。 它基于流行的 MVC 设计模式。 MVC(模型-视图-控制器)是一种软件架构模式,它将应用分为三个区域:模型,视图和控制器。 该模型表示一个携带数据的 Java 对象。 该视图表示模型包含的数据的可视化。 控制器控制数据流到模型对象中,并在数据更改时更新视图。 它将视图和模型分开。
Spring Framework 5.0 引入了一个名为 Spring WebFlux 的并行反应式栈 Web 框架。
@RestController
@RestController
是用于创建 Restful 控制器的便捷注解。 它是@Component
的特化,可通过类路径扫描自动检测。 它添加了@Controller
和@ResponseBody
注解。 它将响应转换为 JSON 或 XML。 它不适用于视图技术,因此方法无法返回ModelAndView
。 它通常与基于@RequestMapping
注解的注解处理器方法结合使用。
@Controller
注解与视图技术一起使用。
RESTFul 应用
RESTFul 应用遵循 REST 架构样式,该样式用于设计网络应用。 RESTful 应用生成对资源执行 CRUD(创建/读取/更新/删除)操作的 HTTP 请求。 RESTFul 应用通常以 JSON 或 XML 格式返回数据。
Spring Boot @RestController
示例
在以下应用中,我们演示@RestController
的用法。 该应用返回城市列表作为 JSON 数据。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ ├───controller
│ │ │ MyController.java
│ │ ├───model
│ │ │ City.java
│ │ └───service
│ │ CityService.java
│ │ ICityService.java
│ └───resources
│ └───static
│ index.html
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>springbootrestcontrollerex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 spring-boot-starter-parent
是父 POM,它为使用 Maven 构建的应用提供依赖关系和插件管理。 spring-boot-starter-web
是使用 Spring MVC 构建 Web(包括 RESTful)应用的入门工具。 它使用 Tomcat 作为默认的嵌入式容器。 spring-boot-maven-plugin
将 Spring 应用打包到可执行的 JAR 或 WAR 归档文件中。
com/zetcode/model/City.java
package com.zetcode.model;
import java.util.Objects;
public class City {
private Long id;
private String name;
private int population;
public City() {
}
public City(Long id, String name, int population) {
this.id = id;
this.name = name;
this.population = population;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
City city = (City) o;
return population == city.population &&
Objects.equals(id, city.id) &&
Objects.equals(name, city.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, population);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("City{");
sb.append("id=").append(id);
sb.append(", name='").append(name).append('\'');
sb.append(", population=").append(population);
sb.append('}');
return sb.toString();
}
}
这是一个City
bean。 它具有id
,name
和population
属性。
com/zetcode/controller/MyController.java
package com.zetcode.controller;
import com.zetcode.model.City;
import com.zetcode.service.ICityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class MyController {
@Autowired
private ICityService cityService;
@GetMapping(value = "/cities")
public List<City> getCities() {
List<City> cities = cityService.findAll();
return cities;
}
}
这是MyController
。 它以 JSON 格式返回城市列表。
@RestController
public class MyController {
MyController
带有@RestController
注解。
@Autowired
private ICityService cityService;
我们用@Autowired
注解注入CityService
。
@GetMapping(value = "/cities")
public List<City> getCities() {
getCities()
方法映射到getCities
URL 模式; 它返回城市列表,并通过消息转换器将其转换为 JSON。
com/zetcode/service/ICityService.java
package com.zetcode.service;
import com.zetcode.bean.City;
import java.util.List;
public interface ICityService {
public List<City> findAll();
}
ICityService
包含findAll()
合约方法。
com/zetcode/service/CityService.java
package com.zetcode.service;
import com.zetcode.model.City;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
@Service
public class CityService implements ICityService {
@Override
public List<City> findAll() {
var cities = new ArrayList<City>();
cities.add(new City(1L, "Bratislava", 432000));
cities.add(new City(2L, "Budapest", 1759000));
cities.add(new City(3L, "Prague", 1280000));
cities.add(new City(4L, "Warsaw", 1748000));
cities.add(new City(5L, "Los Angeles", 3971000));
cities.add(new City(6L, "New York", 8550000));
cities.add(new City(7L, "Edinburgh", 464000));
cities.add(new City(8L, "Berlin", 3671000));
return cities;
}
}
CityService
包含findAll()
方法的实现。
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>
<a href="cities">Get all cities</a>
</p>
</body>
</html>
这是主页。 它包含一个获取所有城市的链接。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。 在扫描过程中,将查找@RestController
注解,并从MyController
类创建一个 Spring bean。
$ mvn spring-boot:run
应用运行后,我们可以导航到localhost:8080
。
在本教程中,我们展示了如何在 Spring 应用中使用@RestController
注解。 您可能也对相关教程感兴趣: Spring Boot RestTemplate
教程, Spring Boot @Controller
教程, Spring Boot @ExceptionHandler
教程, Java 教程 或列出所有 Spring Boot 教程。
Spring Boot @PostConstruct
Spring Boot @PostConstruct
教程显示了如何在 Spring 应用中使用@PostConstruct
注解。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
@PostConstruct
@PostConstruct
是在依赖注入完成以执行任何初始化之后需要执行的方法上使用的注解。
Spring Boot @PostConstruct
示例
以下应用演示了@PostConstruct
的用法。 它使用注解创建两个日志方法,在初始化它们的 bean 之后调用它们。 这些消息在应用运行后显示。 应用本身向客户端发送一条消息。 从配置文件中读取文本消息。
$ tree
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── Application.java
│ │ ├── controller
│ │ │ └── MyController.java
│ │ └── service
│ │ ├── IMessageService.java
│ │ └── MessageService.java
│ └── resources
│ ├── application.properties
│ └── static
│ └── index.html
└── test
└── java
这是项目结构。
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.zetcode</groupId>
<artifactId>SpringBootPostConstruct</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 spring-boot-starter-parent
是父 POM,它为使用 Maven 构建的应用提供依赖关系和插件管理。 spring-boot-starter-web
是使用 Spring MVC 构建 Web(包括 RESTful)应用的入门工具。 它使用 Tomcat 作为默认的嵌入式容器。 spring-boot-maven-plugin
将 Spring 应用打包到可执行的 JAR 或 WAR 归档文件中。
application.properties
my.msg=Hello there
spring.main.banner-mode=off
logging.level.org.springframework=ERROR
application.properties
是 Spring Boot 中的主要配置文件。 我们设置了一个message
属性,该属性将由应用返回给客户端。 我们关闭 Spring 横幅并减少 Spring 框架的日志记录量。
MyController.java
package com.zetcode.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.zetcode.service.IMessageService;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RestController
public class MyController {
private static final Logger logger = LoggerFactory.getLogger(MyController.class);
@Autowired
IMessageService messageService;
@RequestMapping(value = "/getMessage")
public String getMessage() {
String message = messageService.getMessage();
return message;
}
@PostConstruct
public void doLog() {
logger.info("Info message in MyController");
}
}
这是MyController
。 它向客户端发送一条消息。
@RequestMapping(value = "/getMessage")
public String getMessage() {
String message = messageService.getMessage();
return message;
}
从消息服务生成一条消息,并将其返回给客户端。
@PostConstruct
public void doLog() {
logger.info("Info message in MyController");
}
doLog()
方法用@PostConstruct
注解修饰。 在初始化MyController
bean 之后调用该方法。 它记录一条简单的参考消息。
IMessageService.java
package com.zetcode.service;
public interface IMessageService {
public String getMessage();
}
IMessageService
包含getMessage()
合约方法。
MessageService.java
package com.zetcode.service;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class MessageService implements IMessageService {
private static final Logger logger = LoggerFactory.getLogger(MessageService.class);
@Value(value = "${my.msg}")
private String message;
@Override
public String getMessage() {
return message;
}
@PostConstruct
public void doLog() {
logger.info("Info message in MessageService");
}
}
MessageService
包含getMessage()
方法的实现。
@Value(value = "${my.msg}")
private String message;
从带有@Value
注解的application.properties
文件中读取返回给客户端的消息,并将其设置为message
字段。
@Override
public String getMessage() {
return message;
}
getMessage()
返回消息字符串。
@PostConstruct
public void doLog() {
logger.info("Info message in MessageService");
}
MessageService
还包含用@PostConstruct
装饰的doLog()
方法。 在 bean 初始化之后调用它。
index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>
<a href="getMessage">Get Message</a>
</p>
</body>
</html>
这是主页。 它包含一个获取消息的链接。
Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。
$ mvn -q spring-boot:run
...
2017-12-14 21:35:30.788 INFO 10665 --- [main] com.zetcode.service.MessageService : Info message in MessageService
2017-12-14 21:35:30.791 INFO 10665 --- [main] com.zetcode.controller.MyController : Info message in MyController
...
应用运行后,我们可以在控制台上看到这两个日志消息。
在本教程中,我们展示了如何在 Spring 应用中使用@PostConstruct
注解。 您可能也对相关教程感兴趣: Java Servlets 教程, Spring Boot @Controller
教程, Spring Boot @ExceptionHandler
教程, Spring Boot 上传文件, Spring Boot @PathVariable
教程, Spring Boot @RequestParam
教程, Spring Boot @ResponseBody
教程, Java 教程。
Spring Boot @Component
Spring Boot @Component
教程显示了如何在 Spring 应用中使用@Component
注解。 在示例中,我们创建一个 Spring Boot 控制台应用。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
@Component
@Component
是最通用的 Spring 注解。 在类路径扫描期间找到装饰有@Component
的 Java 类,并在上下文中注册为 Spring Bean。 @Service
,@Repository
和@Controller
是@Component
的专业,用于更具体的情况。
@ComponentScan
确保找到用@Component
装饰的类并将其注册为 Spring Bean。 @ComponentScan
自动包含在@SpringBootApplication
中。
@Bean
具有与@Component
类似的目的。 不会自动检测到。 用@Bean
装饰的方法会在配置阶段生成一个由 Spring 容器管理的 bean。
Spring Boot @Component
示例
以下应用演示了@Component
的用法。 它使用注解创建一个随机生成名称的 bean。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ │ MyRunner.java
│ │ └───service
│ │ RandomNameGenerator.java
│ └───resources
│ application.properties
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>springbootcomponentex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 spring-boot-starter-parent
是父 POM,它为使用 Maven 构建的应用提供依赖关系和插件管理。 spring-boot-starter
是一个核心启动器,包括自动配置支持,日志记录和 YAML。 spring-boot-maven-plugin
将 Spring 应用打包到可执行的 JAR 或 WAR 归档文件中。
resources/application.properties
spring.main.banner-mode=off
logging.level.org.springframework=ERROR
logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n
application.properties
是 Spring Boot 中的主要配置文件。 我们关闭 Spring 横幅,通过仅选择错误消息来减少 Spring 框架的日志记录数量,并设置控制台日志记录模式
com/zetcode/service/RandomNameGenerator.java
package com.zetcode.service;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Random;
@Component
public class RandomNameGenerator {
public String generate() {
var names = List.of("Peter", "Roland", "Lucy", "Robert", "Jane");
var r = new Random();
int i = r.nextInt(names.size());
return names.get(i);
}
}
RandomNameGenerator
是装饰有@Component
的 Java 类。 在组件扫描过程中将检测到它,并将其注册为 Spring Bean。
com/zetcode/MyRunner.java
package com.zetcode;
import com.zetcode.service.RandomNameGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);
@Autowired
private RandomNameGenerator randGenerator;
@Override
public void run(String... args) {
logger.info("Generating random name: {}", randGenerator.generate());
logger.info("Generating random name: {}", randGenerator.generate());
logger.info("Generating random name: {}", randGenerator.generate());
}
}
通过实现CommandLineRunner
,将在应用启动后执行MyRunner
类的run()
方法。
@Component
public class MyRunner implements CommandLineRunner {
MyRunner
也装饰有@Component
,因此也会自动检测并注册。
@Autowired
private RandomNameGenerator randGenerator;
使用@Autowired
注解,我们将RandomNameGenerator
bean 注入到randGenerator
字段中。
@Override
public void run(String... args) {
logger.info("Generating random name: {}", randGenerator.generate());
logger.info("Generating random name: {}", randGenerator.generate());
logger.info("Generating random name: {}", randGenerator.generate());
}
在run()
方法中,我们记录包含随机名称的消息。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。 它是@Configuration
,@EnableAutoConfiguration
和@ComponentScan
注解的便捷注解。
$ mvn -q spring-boot:run
...
30-04-2019 12:22:44 [main] INFO com.zetcode.MyRunner.run - Generating random name: Roland
30-04-2019 12:22:44 [main] INFO com.zetcode.MyRunner.run - Generating random name: Peter
30-04-2019 12:22:44 [main] INFO com.zetcode.MyRunner.run - Generating random name: Lucy
应用运行后,我们可以在控制台中看到日志消息。
在本教程中,我们展示了如何在 Spring 应用中使用@Component
注解。 您可能也对相关教程感兴趣: Spring Boot @Controller
教程, Spring Boot @Repository
教程, Java 教程或列出全部 Spring 入门教程。
Spring Boot @ConfigurationProperties
教程
Spring Boot @ConfigurationProperties
教程展示了如何在 Spring Boot 应用中使用@ConfigurationProperties
将属性绑定到对象。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
@ConfigurationProperties
@ConfigurationProperties
允许轻松地将整个属性和 Yaml 文件映射到一个对象。 它还允许使用 JSR-303 bean 验证来验证属性。 默认情况下,注解从application.properties
文件中读取。 可以使用@PropertySource
注解来更改源文件。
Spring Boot @ConfigurationProperties
示例
以下应用从application.properties
文件读取配置数据,该文件是默认的 Spring Boot 配置文件。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ │ MyRunner.java
│ │ └───conf
│ │ AppProperties.java
│ └───resources
│ application.properties
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>springbootconfigurationproperties</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。
resources/application.properties
spring.main.banner-mode=off
app.colour=steelblue
app.lang=en
app.theme=dark
在application.properties
文件中,我们具有三个自定义属性。 它们具有app
前缀。
com/zetcode/conf/AppProperties.java
package com.zetcode.conf;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "app")
public class AppProperties {
private String colour;
private String lang;
private String theme;
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public String getTheme() {
return theme;
}
public void setTheme(String theme) {
this.theme = theme;
}
}
这些属性将绑定到此配置对象。
@Configuration
@ConfigurationProperties(prefix = "app")
public class AppProperties {
@Configuration
注解使它成为 Spring 管理的 bean。 在@ConfigurationProperties
中,我们为属性设置前缀。
com/zetcode/MyRunner.java
package com.zetcode;
import com.zetcode.conf.AppProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
@Autowired
private AppProperties appProperties;
@Override
public void run(String... args) throws Exception {
logger.info("Colour: {}", appProperties.getColour());
logger.info("Language: {}", appProperties.getLang());
logger.info("Theme: {}", appProperties.getTheme());
}
}
在MyRunner
中,我们将AppProperties
注入字段中并读取其值。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。
Spring Boot @ConfigurationProperties
示例 II
在第二个应用中,我们还将验证属性。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ │ MyRunner.java
│ │ └───config
│ │ MailProperties.java
│ └───resources
│ application.properties
│ mail.properties
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>springbootconfigurationpropertiesvalidation</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是pom.xml
文件。 我们还有一个hibernate-validator
依赖项。
resources/application.properties
spring.main.banner-mode=off
这是application.properties
文件。
resources/mail.properties
hostname=info@example.com
port=9000
from=admin@example.com
recipients[0]=user1@example.com
recipients[1]=user2@example.com
recipients[2]=user3@example.com
recipients[3]=user4@example.com
我们有一个自定义的mail.properties
文件。
com/zetcode/config/MailProperties.java
package com.zetcode.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.List;
@Configuration
@PropertySource("classpath:mail.properties")
@ConfigurationProperties
@Validated
public class MailProperties {
@NotNull
private String hostname;
@Min(1000)
@Max(10000)
private int port;
@NotNull
private String from;
@NotNull
private List<String> recipients;
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public List<String> getRecipients() {
return recipients;
}
public void setRecipients(List<String> recipients) {
this.recipients = recipients;
}
}
我们使用@PropertySource
注解设置自定义属性文件的路径。 @Validated
注解验证属性。
com/zetcode/MyRunner.java
package com.zetcode;
import com.zetcode.config.MailProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
@Autowired
private MailProperties mailProperties;
@Override
public void run(String... args) throws Exception {
logger.info("Hostname: {}", mailProperties.getHostname());
logger.info("Port: {}", mailProperties.getPort());
logger.info("From: {}", mailProperties.getFrom());
logger.info("Recipients: {}", mailProperties.getRecipients());
}
}
我们注入MailProperties
并以run()
方法读取它们。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这是Application
类。
我们使用mvn -q spring-boot:run
运行该应用。
在本教程中,我们展示了如何使用@ConfigurationProperties
从外部文件读取配置属性。 您可能也对相关教程感兴趣: Spring PropertySource
教程, Spring Boot CommandLineRunner
教程, Java 教程或列出所有 Spring Boot 教程。
Spring Boot @Repository
Spring Boot @Repository
教程显示了如何在 Spring 应用中使用@Repository
注解。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
@Repository
@Repository
是 Spring 注解,指示装饰的类是存储库。 存储库是一种用于封装存储,检索和搜索行为的机制,该机制模仿对象的集合。 它是@Component
注解的一种特殊功能,允许通过类路径扫描自动检测实现类。
@ComponentScan
确保找到用@Component
和其派生词包括@Repository
装饰的类并将其注册为 Spring Bean。 @ComponentScan
自动包含在@SpringBootApplication
中。
Spring Boot @Repository
示例
以下应用演示了@Repository
的用法。 它向用户显示 HTML 表中的国家/地区列表。 在本应用中,我们使用 Spring Boot 版本 2.1.0。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ ├───controller
│ │ │ MyController.java
│ │ ├───model
│ │ │ Country.java
│ │ ├───repository
│ │ │ CountryRepository.java
│ │ └───service
│ │ CountryService.java
│ │ ICountryService.java
│ └───resources
│ │ application.yml
│ │ import.sql
│ ├───static
│ │ index.html
│ └───templates
│ showCountries.ftl
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>repositoryex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven 构建文件。 h2
依赖项包括 H2 数据库驱动程序。
Spring Boot 启动器是一组方便的依赖项描述符,可以极大地简化 Maven 配置。 spring-boot-starter-parent
具有 Spring Boot 应用的一些常用配置。 spring-boot-devtools
包含一些 Spring Boot 开发者工具。 spring-boot-starter-web
支持经典和 RESTFul Web 应用。 spring-boot-starter-web-freemarker
是使用 Freemarker 模板引擎构建 Web 应用的入门工具。 它使用 Tomcat 作为默认的嵌入式容器。 spring-boot-starter-data-jpa
是将 Spring Data JPA 与 Hibernate 结合使用的入门工具。
spring-boot-maven-plugin
在 Maven 中提供了 Spring Boot 支持,使我们可以打包可执行的 JAR 或 WAR 档案。 它的spring-boot:run
目标运行 Spring Boot 应用。
resources/application.yml
server:
port: 8086
servlet:
context-path: /SpringBootRepository
spring:
main:
banner-mode: "off"
jpa:
database: h2
hibernate:
dialect: org.hibernate.dialect.H2Dialect
ddl-auto: create-drop
logging:
level:
org:
springframework: ERROR
在application.yml
文件中,我们编写了 Spring Boot 应用的各种配置设置。 port
设置服务器端口和context-path
上下文路径(应用名称)。 完成这些设置后,我们可以通过localhost:8086/SpringBootRepository/
访问该应用。 使用banner-mode
属性,我们可以关闭 Spring 横幅。
JPA database
值指定要操作的目标数据库。 在本例中,我们指定了 Hibernate 方言org.hibernate.dialect.H2Dialect
。 ddl-auto
是数据定义语言模式; create-drop
选项将自动创建和删除数据库模式。
H2 数据库在内存中运行。 另外,我们将 spring 框架的日志记录级别设置为ERROR
。 在application.yml
文件位于中src/main/resources
目录。
resources/import.sql
INSERT INTO countries(name, population) VALUES('China', 1382050000);
INSERT INTO countries(name, population) VALUES('India', 1313210000);
INSERT INTO countries(name, population) VALUES('USA', 324666000);
INSERT INTO countries(name, population) VALUES('Indonesia', 260581000);
INSERT INTO countries(name, population) VALUES('Brazil', 207221000);
INSERT INTO countries(name, population) VALUES('Pakistan', 196626000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Bangladesh', 162099000);
INSERT INTO countries(name, population) VALUES('Nigeria', 186988000);
INSERT INTO countries(name, population) VALUES('Russia', 146838000);
INSERT INTO countries(name, population) VALUES('Japan', 126830000);
INSERT INTO countries(name, population) VALUES('Mexico', 122273000);
INSERT INTO countries(name, population) VALUES('Philippines', 103738000);
INSERT INTO countries(name, population) VALUES('Ethiopia', 101853000);
INSERT INTO countries(name, population) VALUES('Vietnam', 92700000);
INSERT INTO countries(name, population) VALUES('Egypt', 92641000);
INSERT INTO countries(name, population) VALUES('Germany', 82800000);
INSERT INTO countries(name, population) VALUES('the Congo', 82243000);
INSERT INTO countries(name, population) VALUES('Iran', 82800000);
INSERT INTO countries(name, population) VALUES('Turkey', 79814000);
INSERT INTO countries(name, population) VALUES('Thailand', 68147000);
INSERT INTO countries(name, population) VALUES('France', 66984000);
INSERT INTO countries(name, population) VALUES('United Kingdom', 60589000);
INSERT INTO countries(name, population) VALUES('South Africa', 55908000);
INSERT INTO countries(name, population) VALUES('Myanmar', 51446000);
INSERT INTO countries(name, population) VALUES('South Korea', 68147000);
INSERT INTO countries(name, population) VALUES('Colombia', 49129000);
INSERT INTO countries(name, population) VALUES('Kenya', 47251000);
INSERT INTO countries(name, population) VALUES('Spain', 46812000);
INSERT INTO countries(name, population) VALUES('Argentina', 43850000);
INSERT INTO countries(name, population) VALUES('Ukraine', 42603000);
INSERT INTO countries(name, population) VALUES('Sudan', 41176000);
INSERT INTO countries(name, population) VALUES('Algeria', 40400000);
INSERT INTO countries(name, population) VALUES('Poland', 38439000);
模式是由 Hibernate 自动创建的。 之后,将执行import.sql
文件以将数据填充到表中。
com/zetcode/model/Country.java
package com.zetcode.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Objects;
@Entity
@Table(name = "countries")
public class Country {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int population;
public Country() {
}
public Country(Long id, String name, int population) {
this.id = id;
this.name = name;
this.population = population;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Country country = (Country) o;
return population == country.population &&
Objects.equals(id, country.id) &&
Objects.equals(name, country.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, population);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Country{");
sb.append("id=").append(id);
sb.append(", name='").append(name).append('\'');
sb.append(", population=").append(population);
sb.append('}');
return sb.toString();
}
}
这是Country
实体。 每个实体必须至少定义两个注解:@Entity
和@Id
。 以前,我们将ddl-auto
选项设置为create-drop
,这意味着 Hibernate 将根据该实体创建表模式。
@Entity
@Table(name = "countries")
public class Country {
@Entity
注解指定该类是一个实体,并映射到数据库表。 @Table
注解指定要用于映射的数据库表的名称。
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Id
注解指定实体的主键,@GeneratedValue
给出主键值的生成策略。
com/zetcode/repository/CountryRepository.java
package com.zetcode.repository;
import com.zetcode.bean.Country;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CountryRepository extends CrudRepository<Country, Long> {
}
CountryRepository
用@Repository
注解修饰。
通过从 Spring CrudRepository
扩展,我们为数据库实现了一些方法,包括findAll()
。 这样可以节省一些样板代码。
com/zetcode/service/ICountryService.java
package com.zetcode.service;
import com.zetcode.bean.Country;
import java.util.List;
public interface ICountryService {
public List<Country> findAll();
}
ICountryService
包含findAll()
契约方法。
com/zetcode/service/CountryService.java
package com.zetcode.service;
import com.zetcode.model.Country;
import com.zetcode.repository.CountryRepository;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CountryService implements ICountryService {
@Autowired
private CountryRepository repository;
@Override
public List<Country> findAll() {
var countries = (List<Country>) repository.findAll();
return countries;
}
}
CountryService
包含findAll()
方法的实现。
@Autowired
private CountryRepository repository;
CountryRepository
注入了@Autowired
注解。
@Override
public List<Country> findAll() {
var countries = (List<Country>) repository.findAll();
return countries;
}
findAll()
方法从数据库返回所有国家的列表。
com/zetcode/controller/MyController.java
package com.zetcode.controller;
import com.zetcode.model.Country;
import com.zetcode.service.ICountryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.List;
@Controller
public class MyController {
@Autowired
ICountryService countryService;
@RequestMapping("/showCountries")
public ModelAndView findCities() {
var countries = (List<Country>) countryService.findAll();
var params = new HashMap<String, Object>();
params.put("countries", countries);
return new ModelAndView("showCountries", params);
}
}
MyController
处理来自客户端的请求。
@Controller
public class MyController {
控制器带有@Controller
注解。
@Autowired
ICountryService countryService;
ICountryService
注入到countryService
字段中。
var countries = (List<Country>) countryService.findAll();
从服务对象中,我们使用findAll()
方法检索所有国家。
var params = new HashMap<String, Object>();
params.put("countries", countries);
return new ModelAndView("showCountries", params);
处理和国家列表一起发送到showCountries.ftl
模板文件。 我们已经在 Maven POM 文件中提供了 Freemarker 依赖项; 因此,Spring Boot 会找出视图的扩展名。
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>
<a href="showCountries">Show countries</a>
</p>
</body>
</html>
这是主页。 它包含一个获取所有国家的链接。
resources/templates/showCountries.ftl
<!DOCTYPE html>
<html>
<head>
<title>Show countries</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>List of countries</h2>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Population</th>
</tr>
<#list countries as country>
<tr>
<td>${country.id}</td>
<td>${country.name}</td>
<td>${country.population}</td>
</tr>
</#list>
</table>
</body>
</html>
这是showCountries.ftl
模板文件。 使用#list
指令,我们显示列表中的所有项目。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。 它是@Configuration
,@EnableAutoConfiguration
和@ComponentScan
注解的便捷注解。
$ mvn -q spring-boot:run
我们运行该应用。
在本教程中,我们展示了如何在 Spring 应用中使用@Repository
注解。 您可能也对相关教程感兴趣: Spring Boot @Controller
教程, Spring Boot @RequestParam
教程和 Java 教程,或列出全部 Spring Boot 教程。
Spring Boot MongoDB 教程
Spring Boot MongoDB 教程展示了如何在 Spring Boot 框架中访问 MongoDB 中的数据。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
MongoDB
MongoDB 是 NoSQL 跨平台的面向文档的数据库。 它是可用的最受欢迎的数据库之一。 MongoDB 由 MongoDB Inc. 开发,并作为免费和开源软件发布。
Spring Data MongoDB 项目提供了与 MongoDB 文档数据库的集成。
安装 MongoDB
以下命令可用于在基于 Debian 的 Linux 上安装 MongoDB。
$ sudo apt-get install mongodb
该命令将安装 MongoDB 随附的必要包。
$ sudo service mongodb status
mongodb start/running, process 975
使用sudo service mongodb status
命令,我们检查mongodb
服务器的状态。
$ sudo service mongodb start
mongodb start/running, process 6448
mongodb
服务器由sudo service mongodb start
命令启动。
Spring Boot MongoDB 示例
在以下示例中,我们创建一个使用 MongoDB 数据库的简单 Spring Boot 应用。 请注意,默认情况下,没有任何特定配置,Spring Boot 会尝试使用test
数据库名称连接到本地托管的 MongoDB 实例。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ │ MyRunner.java
│ │ ├───model
│ │ │ Country.java
│ │ └───repository
│ │ CountryRepository.java
│ └───resources
│ application.properties
└───test
└───java
└───com
└───zetcode
MongoTest.java
这是 Spring 应用的项目结构。
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.zetcode</groupId>
<artifactId>springbootmongodb</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。
Spring Boot 启动器是一组方便的依赖项描述符,可以极大地简化 Maven 配置。 spring-boot-starter-parent
具有 Spring Boot 应用的一些常用配置。 spring-boot-starter-data-mongodb
是使用 MongoDB 面向文档的数据库和 Spring Data MongoDB 的入门。 spring-boot-starter-test
是使用包含 JUnit,Hamcrest 和 Mockito 的库测试 Spring Boot 应用的入门程序。
在spring-boot-maven-plugin
提供了 Maven 的 Spring Boot 支持,使我们能够打包可执行的 JAR 或 WAR 档案。 它的spring-boot:run
目标运行 Spring Boot 应用。
resources/application.properties
spring.main.banner-mode=off
logging.level.org.springframework=ERROR
在application.properties
中,我们打开 Spring Boot 横幅并设置日志记录属性。 默认情况下,Spring Boot 会尝试使用测试数据库连接到 MongoDB 的本地托管实例。
# mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=testdb
如果要配置 MongoDB,可以设置相应的属性。
com/zetcode/model/Country.java
package com.zetcode.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Objects;
@Document
public class Country {
@Id
private String id;
private String name;
private int population;
public Country(String name, int population) {
this.name = name;
this.population = population;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Country country = (Country) o;
return population == country.population &&
Objects.equals(id, country.id) &&
Objects.equals(name, country.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, population);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Country{");
sb.append("id='").append(id).append('\'');
sb.append(", name='").append(name).append('\'');
sb.append(", population=").append(population);
sb.append('}');
return sb.toString();
}
}
这是Country
bean,具有三个属性:id
,name
和population
。
@Document
public class Country {
Bean 用可选的@Document
注解修饰。
@Id
private String id;
id
用@Id
注解修饰。 Spring 会自动为一个新生成的国家对象生成一个新的 ID。
com/zetcode/repository/CountryRepository.java
package com.zetcode.repository;
import com.zetcode.model.Country;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface CountryRepository extends MongoRepository<Country, String> {
}
通过从MongoRepository
扩展,我们可以直接使用许多操作,包括标准 CRUD 操作。
com/zetcode/MyRunner.java
package com.zetcode;
import com.zetcode.model.Country;
import com.zetcode.repository.CountryRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);
@Autowired
private CountryRepository repository;
@Override
public void run(String... args) throws Exception {
repository.deleteAll();
repository.save(new Country("China", 1382050000));
repository.save(new Country("India", 1313210000));
repository.findAll().forEach((country) -> {
logger.info("{}", country);
});
}
}
我们有一个命令行运行器。 在其run()
方法中,我们访问 MongoDB。
@Autowired
private CountryRepository repository;
CountryRepository
注入了@Autowired
注解。
repository.deleteAll();
如果有,我们将使用deleteAll()
删除所有国家。
repository.save(new Country("China", 1382050000));
我们用save()
保存一个国家。
repository.findAll().forEach((country) -> {
logger.info("{}", country);
});
我们使用findAll()
方法遍历数据库中的所有国家。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这段代码设置了 Spring Boot 应用。
com/zetcode/MongoTest.java
package com.zetcode;
import com.zetcode.model.Country;
import com.zetcode.repository.CountryRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Example;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Optional;
import static junit.framework.TestCase.assertEquals;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MongoTest {
@Autowired
private CountryRepository repository;
private static final int NUMBER_OF_COUNTRIES = 6;
@Before
public void init() {
repository.deleteAll();
repository.save(new Country("China", 1382050000));
repository.save(new Country("India", 1313210000));
repository.save(new Country("USA", 324666000));
repository.save(new Country("Indonesia", 260581000));
repository.save(new Country("Brazil", 207221000));
repository.save(new Country("Pakistan", 196626000));
}
@Test
public void countAllCountries() {
var countries = repository.findAll();
assertEquals(NUMBER_OF_COUNTRIES, countries.size());
}
@Test
public void countOneCountry() {
Example<Country> example = Example.of(new Country("China", 1382050000));
assertThat(repository.count(example)).isEqualTo(1L);
}
@Test
public void setsIdOnSave() {
Country nigeria = repository.save(new Country("Nigeria", 186988000));
assertThat(nigeria.getId()).isNotNull();
}
@Test
public void findOneCountry() {
Example<Country> example = Example.of(new Country("India", 1313210000));
Optional<Country> country = repository.findOne(example);
assertThat(country.get().getName()).isEqualTo("India");
}
}
我们有四种测试方法。
@Before
public void init() {
repository.deleteAll();
repository.save(new Country("China", 1382050000));
repository.save(new Country("India", 1313210000));
repository.save(new Country("USA", 324666000));
repository.save(new Country("Indonesia", 260581000));
repository.save(new Country("Brazil", 207221000));
repository.save(new Country("Pakistan", 196626000));
}
在init()
方法中,我们保存了六个国家。
@Test
public void countAllCountries() {
var countries = repository.findAll();
assertEquals(NUMBER_OF_COUNTRIES, countries.size());
}
我们测试数据库中有六个国家。
@Test
public void countOneCountry() {
Example<Country> example = Example.of(new Country("China", 1382050000));
assertThat(repository.count(example)).isEqualTo(1L);
}
此方法测试数据库中只有一个中国。
@Test
public void setsIdOnSave() {
Country nigeria = repository.save(new Country("Nigeria", 186988000));
assertThat(nigeria.getId()).isNotNull();
}
我们测试了在保存新国家/地区时,自动生成的 ID 不等于null
。
@Test
public void findOneCountry() {
Example<Country> example = Example.of(new Country("India", 1313210000));
Optional<Country> country = repository.findOne(example);
assertThat(country.get().getName()).isEqualTo("India");
}
我们测试findOne()
方法找到一个国家,即印度。
在本教程中,我们学习了如何在 Spring Boot 应用中使用 MongoDB。 您可能也对相关教程感兴趣: Spring Boot REST 数据 JPA 教程, Spring Boot REST H2 教程, MongoDB Java 教程, Java 教程 或列出所有 Spring Boot 教程。
Spring Boot MongoDB 反应式教程
Spring Boot MongoDB 反应式教程展示了如何在 Spring Boot 应用中使用 MongoDB 进行反应式编程。
MongoDB
MongoDB 是 NoSQL 跨平台的面向文档的数据库。 它是可用的最受欢迎的数据库之一。 MongoDB 由 MongoDB Inc. 开发,并作为免费和开源软件发布。
Spring Data MongoDB 项目提供了与 MongoDB 文档数据库的集成。
反应式编程
反应式编程是一种编程范例,它是函数式的,基于事件的,非阻塞的,异步的,并且以数据流处理为中心。 术语反应式来自以下事实:我们对诸如鼠标单击或 I/O 事件之类的更改做出反应。
当我们处理大量流数据时,响应式应用可以更好地扩展,并且效率更高。 反应性应用是非阻塞的; 他们没有使用资源等待流程完成。
在构建反应式应用时,我们需要它一直到整个数据库都是反应式的。 我们需要使用支持反应式编程的数据库。 MongoDB 是具有响应式支持的数据库。
响应式应用实现基于事件的模型,在该模型中将数据推送到使用者。 数据的使用者称为订阅者,因为它订阅了发布者,后者发布异步数据流。
Spring 反应式
Spring 反应式是一个反应式库,用于根据反应式流规范在 JVM 上构建非阻塞应用。
反应式项目提供两种类型的发布者:Mono
和Flux
。 Flux
是产生 0 到 N 个值的发布者。 返回多个元素的操作使用此类型。 Mono
是产生 0 到 1 值的发布者。 它用于返回单个元素的操作。
Spring Boot MongoDB 反应式示例
在以下应用中,我们对 MongoDB 数据库使用反应式编程。
注意:默认情况下,没有任何特定配置,Spring Boot 会尝试使用
test
数据库名称连接到本地托管的 MongoDB 实例。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ │ MyRunner.java
│ │ ├───model
│ │ │ City.java
│ │ ├───repository
│ │ │ CityRepository.java
│ │ └───service
│ │ CityService.java
│ │ ICityService.java
│ └───resources
│ application.properties
└───test
└───java
这是 Spring 应用的项目结构。
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.zetcode</groupId>
<artifactId>springbootmongodbreactive</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 spring-boot-starter-data-mongodb-reactive
是用于使用 MongoDB 面向文档的数据库和 Spring Data MongoDB 反应式的 Spring Boot 入门程序。
resources/application.properties
spring.main.banner-mode=off
在application.properties
中,我们关闭 Spring Boot 横幅并设置日志记录属性。 默认情况下,Spring Boot 会尝试使用测试数据库连接到 MongoDB 的本地托管实例。
# mongodb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=testdb
如果要配置 MongoDB,可以设置相应的属性。
com/zetcode/model/City.java
package com.zetcode.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Objects;
@Document(value="cities")
public class City {
@Id
private String id;
private String name;
private int population;
public City() {
}
public City(String name, int population) {
this.name = name;
this.population = population;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + Objects.hashCode(this.id);
hash = 79 * hash + Objects.hashCode(this.name);
hash = 79 * hash + this.population;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final City other = (City) obj;
if (this.population != other.population) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return Objects.equals(this.id, other.id);
}
@Override
public String toString() {
var builder = new StringBuilder();
builder.append("City{id=").append(id).append(", name=")
.append(name).append(", population=")
.append(population).append("}");
return builder.toString();
}
}
这是City
bean,具有三个属性:id
,name
和population
。
@Document(value="cities")
public class City {
Bean 用可选的@Document
注解修饰。
@Id
private String id;
id
用@Id
注解修饰。 Spring 会为一个新生成的城市对象自动生成一个新的 ID。
com/zetcode/repository/CityRepository.java
package com.zetcode.repository;
import com.zetcode.model.City;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
@Configuration
public interface CityRepository extends ReactiveMongoRepository<City, String> {
}
通过从ReactiveMongoRepository
扩展,我们有了一个反应性 MongoDB 存储库。
com/zetcode/service/ICityService.java
package com.zetcode.service;
import com.zetcode.model.City;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
public interface ICityService {
Mono<City> insert(City city);
Flux<City> saveAll(List<City> cities);
Mono<City> findById(String id);
Flux<City> findAll();
Mono<Void> deleteAll();
}
ICityService
包含五种契约方法。
com/zetcode/MyRunner.java
package com.zetcode;
import com.zetcode.model.City;
import com.zetcode.service.CityService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
@Component
public class MyRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);
@Autowired
private CityService cityService;
@Override
public void run(String... args) throws Exception {
logger.info("Creating cities");
var cities = List.of(new City("Bratislava", 432000),
new City("Budapest", 1759000),
new City("Prague", 1280000),
new City("Warsaw", 1748000));
Mono<Void> one = cityService.deleteAll();
Flux<City> two = cityService.saveAll(cities);
Flux<City> three = cityService.findAll();
three.subscribe(city -> logger.info("{}", city));
Mono<Void> all = Mono.when(one, two, three);
all.block();
}
}
我们有一个命令行运行器。 在其run()
方法中,我们使用反应式编程访问 MongoDB。
Mono<Void> one = cityService.deleteAll();
如果集合中有城市,我们将删除所有城市。
Flux<City> two = cityService.saveAll(cities);
我们保存城市列表。
Flux<City> three = cityService.findAll();
three.subscribe(System.out::println);
我们从集合中找到所有城市。 我们使用subscribe()
方法订阅发布者,并将检索到的城市打印到终端。
Mono<Void> all = Mono.when(one, two, three);
使用Mono.when()
,我们将三个发布者汇总到一个新的Mono
中,当所有来源完成后,这些Mono
将实现。
all.block();
使用block()
,我们将触发所有三个操作并等待完成。 由于我们具有控制台应用,因此我们引入了阻塞操作,以便在终端上获得结果。
subscribe()
方法开始工作并立即返回。 我们不能保证在应用的其他部分运行操作完成。 block()
是一项阻止操作:它触发该操作并等待其完成。
注意:通常,我们很少在应用中使用阻塞调用。 控制台应用中的操作是少数例外之一。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这段代码设置了 Spring Boot 应用。
在本教程中,我们学习了如何在 Spring Boot 应用中使用反应式编程模型对 MongoDB 进行编程。
Spring Boot PostgreSQL 教程
Spring Boot PostgreSQL 教程展示了如何在 Spring Boot 应用中使用 PostgreSQL 数据库。
Spring 是用于创建企业应用的流行 Java 应用框架。 Spring Boot 是 Spring 框架的演进,可帮助您轻松创建独立的,生产级的基于 Spring 的应用。
PostgreSQL
PostgreSQL 是一个功能强大的开源对象关系数据库系统。 它是一个多用户数据库管理系统。 它可以在包括 Linux,FreeBSD,Solaris,Microsoft Windows 和 Mac OSX 在内的多个平台上运行。PostgreSQL 由 PostgreSQL 全球开发小组开发。
PostgreSQL 设置
我们将展示如何在 Debian Linux 系统上安装 PostgreSQL 数据库。
$ sudo apt-get install postgresql
此命令将安装 PostgreSQL 服务器和相关包。
$ /etc/init.d/postgresql status
我们使用postgresql status
命令检查数据库的状态。
$ sudo -u postgres psql postgres
psql (9.5.10)
Type "help" for help.
postgres=# \password postgres
Enter new password:
Enter it again:
安装后,将使用空的默认密码创建一个具有管理权限的postgres
用户。 第一步,我们需要为postgres
设置密码。
$ sudo -u postgres createuser --interactive --password user12
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) y
Shall the new role be allowed to create more new roles? (y/n) n
Password:
我们创建一个新的数据库用户。
$ sudo -u postgres createdb testdb -O user12
我们使用createdb
命令创建一个新的testdb
数据库,该数据库将由user12
拥有。
$ sudo vi /etc/postgresql/9.5/main/pg_hba.conf
我们编辑pg_hba.conf
文件。
# "local" is for Unix domain socket connections only
local all all trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
为了能够在本地 PostgreSQL 安装中运行 Spring Boot 应用,我们将 Unix 域套接字和本地连接的认证方法更改为trust
。
$ sudo service postgresql restart
我们重新启动 PostgreSQL 以启用更改。
$ psql -U user12 -d testdb -W
Password for user user12:
psql (9.5.10)
Type "help" for help.
testdb=>
现在我们可以使用psql
工具连接到数据库。
Spring Boot PostgreSQL 示例
以下应用是一个简单的 Spring Boot Web 应用,它使用 PostgreSQL 数据库。 我们有一个主页,带有一个链接,用于显示数据库表中的数据。 我们使用 Thymeleaf 模板系统将数据与 HTML 连接。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ ├───controller
│ │ │ MyController.java
│ │ ├───model
│ │ │ City.java
│ │ ├───repository
│ │ │ CityRepository.java
│ │ └───service
│ │ CityService.java
│ │ ICityService.java
│ └───resources
│ │ application.properties
│ │ data-postgres.sql
│ │ schema-postgres.sql
│ ├───static
│ │ index.html
│ └───templates
│ showCities.html
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>springbootpostgreex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Boot 启动器是一组方便的依赖项描述符,可以极大地简化 Maven 配置。 spring-boot-starter-parent
具有 Spring Boot 应用的一些常用配置。 spring-boot-starter-web
是使用 Spring MVC 构建 Web(包括 RESTful)应用的入门工具。 它使用 Tomcat 作为默认的嵌入式容器。 spring-boot-starter-thymeleaf
是使用 Thymeleaf 视图构建 MVC Web 应用的入门工具。 spring-boot-starter-data-jpa
是将 Spring Data JPA 与 Hibernate 结合使用的入门工具。
postgresql
依赖项适用于 PostgreSQL 数据库驱动程序。
在spring-boot-maven-plugin
提供了 Maven 的 Spring Boot 支持,使我们能够打包可执行的 JAR 或 WAR 档案。 它的spring-boot:run
目标运行 Spring Boot 应用。
resources/application.properties
spring.main.banner-mode=off
logging.level.org.springframework=ERROR
spring.jpa.hibernate.ddl-auto=none
spring.datasource.initialization-mode=always
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/testdb
spring.datasource.username=postgres
spring.datasource.password=s$cret
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
在application.properties
文件中,我们编写了 Spring Boot 应用的各种配置设置。
使用spring.main.banner-mode
属性,我们可以关闭 Spring 横幅。 要加载未嵌入的数据库,在 Spring Boot 2 中,我们需要添加spring.datasource.initialization-mode=always
。 为避免冲突,我们使用spring.jpa.hibernate.ddl-auto=none
关闭自动模式创建。
在 spring 数据源属性中,我们设置了 PostgreSQL 数据源。
设置spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation
选项可以避免最近发生的问题。 没有此选项,我们将收到以下错误:
java.sql.SQLFeatureNotSupportedException: Method org.postgresql.jdbc.PgConnection.createClob()
is not yet implemented.
com/zetcode/model/City.java
package com.zetcode.model;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "cities")
public class City {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private int population;
public City() {
}
public City(Long id, String name, int population) {
this.id = id;
this.name = name;
this.population = population;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + Objects.hashCode(this.id);
hash = 79 * hash + Objects.hashCode(this.name);
hash = 79 * hash + this.population;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final City other = (City) obj;
if (this.population != other.population) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return Objects.equals(this.id, other.id);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("City{");
sb.append("id=").append(id);
sb.append(", name='").append(name).append('\'');
sb.append(", population=").append(population);
sb.append('}');
return sb.toString();
}
}
这是City
实体。 每个实体必须至少定义两个注解:@Entity
和@Id
。
@Entity
@Table(name = "cities")
public class City {
@Entity
注解指定该类是一个实体,并映射到数据库表。 @Table
注解指定要用于映射的数据库表的名称。
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Id
注解指定实体的主键,@GeneratedValue
提供规范主键值的生成策略。
resources/schema-postgres.sql
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id serial PRIMARY KEY, name VARCHAR(255), population integer);
启动应用后,如果关闭了自动模式创建,则将执行schema-postgres.sql
脚本。 该脚本将创建一个新的数据库表。
resources/data-postgres.sql
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
之后,执行data-postgres.sql
文件以用数据填充表。
com/zetcode/repository/CityRepository.java
package com.zetcode.repository;
import com.zetcode.model.City;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CityRepository extends CrudRepository<City, Long> {
}
通过从 Spring CrudRepository
扩展,我们将为我们的数据存储库实现一些方法,包括findAll()
。 这样,我们节省了大量样板代码。
com/zetcode/service/ICityService.java
package com.zetcode.service;
import com.zetcode.model.City;
import java.util.List;
public interface ICityService {
List<City> findAll();
}
ICityService
提供了一种从数据源获取所有城市的契约方法。
com/zetcode/service/CityService.java
package com.zetcode.service;
import com.zetcode.model.City;
import com.zetcode.repository.CityRepository;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CityService implements ICityService {
@Autowired
private CityRepository repository;
@Override
public List<City> findAll() {
var cities = (List<City>) repository.findAll();
return cities;
}
}
CityService
包含findAll()
方法的实现。 我们使用存储库从数据库检索数据。
@Autowired
private CityRepository repository;
注入CityRepository
。
var cities = (List<City>) repository.findAll();
存储库的findAll()
方法返回城市列表。
com/zetcode/MyController.java
package com.zetcode.controller;
import com.zetcode.model.City;
import com.zetcode.service.ICityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
@Controller
public class MyController {
@Autowired
private ICityService cityService;
@GetMapping("/showCities")
public String findCities(Model model) {
var cities = (List<City>) cityService.findAll();
model.addAttribute("cities", cities);
return "showCities";
}
}
MyController
包含一个映射。
@Autowired
private ICityService cityService;
我们在countryService
字段中插入ICityService
。
@GetMapping("/showCities")
public String findCities(Model model) {
var cities = (List<City>) cityService.findAll();
model.addAttribute("cities", cities);
return "showCities";
}
我们将带有showCities
路径的请求映射到控制器的findCities()
方法。 默认请求是 GET 请求。 该模型将获取城市列表,并将处理过程发送到showCities.html
Thymeleaf 模板文件。
resources/templates/showCities.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Cities</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>List of cities</h2>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Population</th>
</tr>
<tr th:each="city : ${cities}">
<td th:text="${city.id}">Id</td>
<td th:text="${city.name}">Name</td>
<td th:text="${city.population}">Population</td>
</tr>
</table>
</body>
</html>
在showCities.html
模板文件中,我们在 HTML 表中显示数据。
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<a href="showCities">Show cities</a>
</body>
</html>
index.html
中有一个链接,显示所有城市。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
设置 Spring Boot 应用。 @SpringBootApplication
启用自动配置和组件扫描。
$ mvn spring-boot:run
应用运行后,我们可以导航到localhost:8080
。
在本教程中,我们展示了如何在 Spring Boot 应用中使用 PostgreSQL 数据库。 您可能也对相关教程感兴趣:
- Spring Boot MySQL 教程
- Spring Boot H2 REST 教程
- Spring Boot Thymeleaf 教程
- Spring Web 应用介绍
- Spring Boot RESTFul 应用
Spring Boot @ModelAttribute
Spring Boot @ModelAttribute
教程显示了如何在 Spring 应用中使用@ModelAttribute
注解。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
@ModelAttribute
@ModelAttribute
将方法参数或方法返回值绑定到已公开的 Web 视图的命名模型属性。 用@ModelAttribute
注解的方法在使用@RequestMapping
的控制器方法之前被调用。
Spring Boot @ModelAttribute
示例
以下应用演示了@ModelAttribute
的用法。 它用于在应用中生成当天的消息。 该消息是从属性文件中读取的。
pom.xml
src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── Application.java
│ │ ├── controller
│ │ │ └── MyController.java
│ │ └── service
│ │ ├── IMessageService.java
│ │ └── MessageService.java
│ └── resources
│ ├── application.properties
│ ├── static
│ │ └── index.html
│ └── templates
│ ├── pageOne.html
│ └── pageTwo.html
└── test
└── java
这是项目结构。
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.zetcode</groupId>
<artifactId>springbootmodelattributeex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 spring-boot-starter-parent
是父 POM,它为使用 Maven 构建的应用提供依赖关系和插件管理。 spring-boot-starter-thymeleaf
是使用 Thymeleaf 视图构建 MVC Web 应用的入门工具。 spring-boot-maven-plugin
将 Spring 应用打包到可执行的 JAR 或 WAR 归档文件中。
resources/application.properties
spring.main.banner-mode=off
logging.level.org.springframework=ERROR
messages.motd=Welcome
application.properties
是 Spring Boot 中的主要配置文件。 我们通过选择错误消息来关闭 Spring 横幅,并减少 Spring 框架的日志记录量。
messages.motd
属性包含该消息。
com/zetcode/service/IMessageService.java
package com.zetcode.service;
public interface IMessageService {
String getMessage();
}
IMessageService
包含getMessage()
合约方法。
com/zetcode/service/MessageService.java
package com.zetcode.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class MessageService implements IMessageService {
@Value("${messages.motd}")
private String motd="Hello";
@Override
public String getMessage() {
return motd;
}
}
getMessage()
方法的实现使用@Value
注解从属性文件中检索消息。
com/zetcode/controller/MyController.java
package com.zetcode.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.zetcode.service.IMessageService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
@Controller
public class MyController {
@Autowired
private IMessageService messageService;
@GetMapping("/pageOne")
public String getPageOne() {
return "pageOne";
}
@GetMapping("/pageTwo")
public String getPageTwo() {
return "pageTwo";
}
@ModelAttribute("motd")
public String message() {
return messageService.getMessage();
}
}
由于MyController
带有@Controller
注解,因此它成为 Spring MVC 控制器类。 使用@GetMapping
注解,我们将两个 URL 模式映射到 Thymeleaf 视图。 这两个模板都接收motd
模型属性。
@ModelAttribute("motd")
public String message() {
return messageService.getMessage();
}
在@RequestMapping
方法及其特化(例如@GetMapping
)之前,执行带有@ModelAttribute
注解的方法。 从messageService
生成的消息存储在motd
模型属性中,并且可用于两个 Thymeleaf 视图。
resources/templates/pageOne.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Page one</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>Page one</h2>
<p th:text="'Message of the day: ' + ${motd}"></p>
</body>
</html>
这是pageOne.html
视图。 使用${}
语法访问motd
属性。
resources/templates/pageTwo.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Page two</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>Page two</h2>
<p th:text="'Message of the day:' + ${motd}"></p>
</body>
</html>
这是pageTwo.html
视图。
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<a href="pageOne">Go to page one</a><br>
<a href="pageTwo">Go to page two</a>
</body>
</html>
这是主页。 它包含两个链接。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。 它是@Configuration
,@EnableAutoConfiguration
和@ComponentScan
注解的便捷注解。
$ mvn spring-boot:run
应用运行后,我们可以导航到localhost:8080
。
在本教程中,我们展示了如何在 Spring 应用中使用@ModelAttribute
注解。 您可能也对相关教程感兴趣: Spring Boot 模型教程, Spring Boot @PathVariable
教程, Spring Boot @RequestParam
教程, Spring Boot @ResponseBody
教程, Java 教程或列出所有 Spring Boot 教程。
{% raw %}
Spring Boot CORS 教程
Spring Boot CORS 教程显示了如何在 Spring Boot 应用中设置跨域资源共享。
CORS
跨域资源共享(CORS)是一种安全策略,它使用 HTTP 标头来告诉浏览器,让运行在一个来源(域)上的 Web 应用有权访问来自另一个来源的服务器中的选定资源。
网页可以嵌入跨域图像,样式表,脚本,iframe
和视频。 默认情况下,同源安全策略禁止某些跨域请求,尤其是 Ajax 请求。
XMLHttpRequest
和 Fetch API 遵循同源策略。 因此; 使用这些 API 的 Web 应用只能从加载应用的相同来源请求 HTTP 资源,除非来自其他来源的响应包括正确的 CORS 标头。
Spring Boot CORS 示例
以下 Spring Boot 应用将 Angular 用作前端。 Angular SPA 在localhost:4200
上运行,并向在localhost:8080
上运行的 Spring Boot 后端发出请求。 为此,我们需要在 Spring Boot 应用中启用 CORS。
Spring Boot 后端
后端将在 Spring Boot 中创建。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ │ MyRunner.java
│ │ ├───config
│ │ │ AppConf.java
│ │ ├───controller
│ │ │ MyController.java
│ │ ├───model
│ │ │ City.java
│ │ └───repository
│ │ CityRepository.java
│ └───resources
│ │ application.properties
│ └───static
│ index.html
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>corsex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven 构建文件。
resources/application.properties
spring.main.banner-mode=off
application.properties
是主要的 Spring Boot 配置文件。 使用spring.main.banner-mode
属性,我们可以关闭 Spring 横幅。
com/zetcode/model/City.java
package com.zetcode.model;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "cities")
public class City {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private int population;
public City() {
}
public City(String name, int population) {
this.name = name;
this.population = population;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + Objects.hashCode(this.id);
hash = 79 * hash + Objects.hashCode(this.name);
hash = 79 * hash + this.population;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final City other = (City) obj;
if (this.population != other.population) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return Objects.equals(this.id, other.id);
}
@Override
public String toString() {
var builder = new StringBuilder();
builder.append("City{id=").append(id).append(", name=")
.append(name).append(", population=")
.append(population).append("}");
return builder.toString();
}
}
这是City
实体。 它包含以下属性:id
,name
和population
。
com/zetcode/repository/CityRepository.java
package com.zetcode.repository;
import com.zetcode.model.City;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CityRepository extends JpaRepository<City, Long> {
}
CityRepository
从JpaRepository
延伸。 它提供了实体的类型及其主键。
com/zetcode/controller/MyController.java
package com.zetcode.controller;
import com.zetcode.model.City;
import com.zetcode.repository.CityRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class MyController {
@Autowired
private CityRepository cityRepository;
@GetMapping(value = "/cities")
public List<City> cities() {
return cityRepository.findAll();
}
}
在MyController
中,我们有一个返回所有城市的端点。
注意:在Java企业应用中,定义与存储库一起使用的服务层是一个好习惯。 为简单起见,我们跳过服务层。
com/zetcode/conf/AppConf.java
package com.zetcode.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class AppConf implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods("GET");
}
}
使用CorsRegistry
,我们启用 CORS。 我们设置允许的来源和请求方法。
com/zetcode/MyRunner.java
package com.zetcode;
import com.zetcode.model.City;
import com.zetcode.repository.CityRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class MyRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);
@Autowired
private CityRepository cityRepository;
@Override
public void run(String... args) throws Exception {
logger.info("Saving cities");
cityRepository.save(new City("Bratislava", 432000));
cityRepository.save(new City("Budapest", 1759000));
cityRepository.save(new City("Prague", 1280000));
cityRepository.save(new City("Warsaw", 1748000));
cityRepository.save(new City("Los Angeles", 3971000));
cityRepository.save(new City("New York", 8550000));
cityRepository.save(new City("Edinburgh", 464000));
}
}
在MyRunner
中,我们将数据添加到内存 H2 数据库中。
resources/static/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home page</title>
</head>
<body>
<p>
This is home page
</p>
<script>
fetch('http://localhost:8080/cities')
.then(res => res.json())
.then(data => console.log('Output: ', data))
.catch(err => console.error(err));
</script>
</body>
</html>
在主页中,我们使用 Fetch API 创建一个获取所有城市的请求。 该请求来自同一来源,因此此处不需要 CORS。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
设置 Spring Boot 应用。
Angular 前端
应用的前端是使用 Angular 创建的。
$ npm i -g @angular/cli
$ ng new frontend
$ cd frontend
我们创建一个新的 Angular 应用。
src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
在app.module.ts
中,我们启用了 http 模块,该模块用于发出请求。
src/app/app.component.ts
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(private http: HttpClient) { }
title = 'frontend';
httpdata;
ngOnInit() {
this.http.get('http://localhost:8080/cities')
.subscribe((data) => this.displaydata(data));
}
displaydata(data) { this.httpdata = data; }
}
在ngOnInit()
方法中,我们向后端创建一个 GET 请求。 数据存储在httpdata
中。
src/app/app.component.html
<h2>List of cities</h2>
<ul *ngFor = "let data of httpdata">
<li>Name : {{data.name}} Population: {{data.population}}</li>
</ul>
我们使用*ngFor
指令在 HTML 列表中显示数据。
$ ng serve
我们启动 Angular 服务器。
$ mvn spring-boot:run
我们运行后端服务器。 现在我们找到localhost:4200
。 加载页面后,会将请求发送到 Spring Boot 应用以获取城市列表。
在本教程中,我们为具有 Angular 前端的 Spring Boot 应用启用了 CORS 支持。 由于这两个部分在不同的域上运行,因此需要 CORS。
{% endraw %}
Spring Boot 提交表单教程
SpringBoot 提交表单教程展示了如何在 Spring Boot 应用中提交表单。
Spring 是流行的 Java 应用框架。 Spring Boot 致力于以最小的努力创建独立的,基于生产级别的基于 Spring 的应用。
Spring Boot 提交表单示例
以下应用包含一个简单的表格。 来自表单的数据会自动插入到 UI Bean 中,并且可用于视图。 Thymeleaf 用作视图引擎。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ ├───bean
│ │ │ User.java
│ │ └───controller
│ │ MyController.java
│ └───resources
│ └───templates
│ addUser.html
│ showMessage.html
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>SpringBootSubmitFormEx</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<dependencies>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven 构建文件。 spring-boot-starter-web
是使用 Spring MVC 构建 Web(包括 RESTful)应用的入门程序。 spring-boot-starter-thymeleaf
是 Thymeleaf 发动机的启动器。 当 Spring 在pom.xml
中找到依赖项时,它将自动为我们配置 Thymeleaf。
com/zetcode/bean/User.java
package com.zetcode.bean;
public class User {
private String name;
private String occupation;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOccupation() {
return occupation;
}
public void setOccupation(String occupation) {
this.occupation = occupation;
}
}
这是User
bean。 它会自动填充表单请求中的数据。 这些属性必须与表单字段匹配。
com/zetcode/controller/MyController.java
package com.zetcode.controller;
import com.zetcode.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class MyController {
@GetMapping("/addUser")
public String sendForm(User user) {
return "addUser";
}
@PostMapping("/addUser")
public String processForm(User user) {
return "showMessage";
}
}
控制器类发送和读取表单视图。
@PostMapping("/addUser")
public String processForm(User user) {
return "showMessage";
}
User
bean 作为参数传递给processForm()
处理器。 Spring 尝试用请求数据填充 Bean。 数据也可自动用于 Thymeleaf showMessage
视图。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
设置 Spring Boot 应用
resources/templates/addUser.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Add user</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Add User</h1>
<form action="#" th:action="@{/addUser}" th:object="${user}" method="post">
<p>
Name: <input type="text" th:field="*{name}">
</p>
<p>
Occupation: <input type="text" th:field="*{occupation}">
</p>
<p>
<input type="submit" value="Submit"/> <input type="reset" value="Reset">
</p>
</form>
</body>
</html>
该视图包含表单。
<form action="#" th:action="@{/addUser}" th:object="${user}" method="post">
th:object
引用user
表单 bean。 这不是一个类名,而是一个 Spring bean 名称。 因此它是小写的。
<p>
Name: <input type="text" th:field="*{name}">
</p>
使用*{}
语法,我们引用已定义的对象。
resources/templates/showMessage.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Show message</title>
<meta charset="UTF-8">
</head>
<body>
<h1>Result</h1>
<p th:text="'Name: ' + ${user.name}"></p>
<p th:text="'Occupation: ' + ${user.occupation}"></p>
<a href="/addUser">Submit another message</a>
</body>
</html>
该模板显示在表单中输入的数据。
<p th:text="'Name: ' + ${user.name}"></p>
我们使用${}
语法引用表单 bean 属性。
导航至localhost:8080/addUser
以测试应用。
在本教程中,我们展示了如何在 Spring Boot 应用中提交简单表单。 您可能也对相关教程感兴趣: Spring Boot 第一个 Web 应用, Spring Boot RESTFul 应用, Spring Boot @Controller
教程,独立 Spring 应用和 Java 教程。
Spring Boot Model
Spring Boot Model
教程展示了如何在 Spring Boot 应用中使用模型。 在 Spring,模型由Model
,ModelMap
和ModelAndView
表示。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
MVC
MVC(模型-视图-控制器)是一种软件架构模式,它将应用分为三个部分:模型,视图和控制器。 该模型表示一个携带数据的 Java 对象。 该视图使模型包含的数据可视化。 控制器管理流入模型对象的数据流,并在数据更改时更新视图。 它使视图和模型分离。
Spring MVC
Spring MVC 是基于 Servlet API 构建的原始 Web 框架。 它基于 MVC 设计模式。 Spring Framework 5.0 引入了一个名为 Spring WebFlux 的并行反应式栈 Web 框架。
Model
,ModelMap
,ModelAndView
Model
,ModelMap
和ModelAndView
用于在 Spring MVC 应用中定义模型。 Model
定义了模型属性的持有者,并且主要用于向模型添加属性。 ModelMap
是Model
的扩展,具有在映射和链式方法调用中存储属性的能力。 ModelAndView
是模型和视图的支架; 它允许在一个返回值中返回模型和视图。
Spring Boot Model
示例
以下简单的 Web 应用在控制器方法中使用Model
,ModelMap
和ModelAndView
。 该模型保存应用数据,该数据显示在视图中。 我们将 Freemaker 库用于视图层。
pom.xml
src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── Application.java
│ │ └── controller
│ │ └── MyController.java
│ └── resources
│ ├── application.properties
│ ├── static
│ │ └── index.html
│ └── templates
│ └── show.ftl
└── test
└── java
这是 Spring 应用的项目结构。
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.zetcode</groupId>
<artifactId>springbootmodelex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 spring-boot-starter-parent
是父 POM,它为使用 Maven 构建的应用提供依赖关系和插件管理。 spring-boot-starter-freemarker
是 Freemarker 模板引擎的依赖项。 此依赖项还将在项目中包含 Spring MVC。 spring-boot-maven-plugin
将 Spring 应用打包到可执行的 JAR 或 WAR 归档文件中。
resources/application.properties
spring.main.banner-mode=off
logging.level.org.springframework=ERROR
mymessage=Hello there
application.properties
是 Spring Boot 中的主要配置文件。 我们通过选择错误消息来关闭 Spring 横幅,并减少 Spring 框架的日志记录量。 mymessage
属性包含该消息。
com/zetcode/MyController.java
package com.zetcode.controller;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class MyController {
@Value("${mymessage}")
private String message;
@GetMapping("/getMessage")
public String getMessage(Model model) {
model.addAttribute("message", message);
return "show";
}
@GetMapping("/getMessage2")
public ModelAndView getMessage() {
var mav = new ModelAndView();
mav.addObject("message", message);
mav.setViewName("show");
return mav;
}
@GetMapping("/getMessageAndTime")
public String getMessageAndTime(ModelMap map) {
var ldt = LocalDateTime.now();
var fmt = DateTimeFormatter.ofLocalizedDateTime(
FormatStyle.MEDIUM);
fmt.withLocale(new Locale("sk", "SK"));
fmt.withZone(ZoneId.of("CET"));
var time = fmt.format(ldt);
map.addAttribute("message", message).addAttribute("time", time);
return "show";
}
}
这是MyController
。 它具有三种响应客户端请求的方法。
@Controller
public class MyController {
MyController
带有@Controller
注解。
@Value("${mymessage}")
private String message;
使用@Value
注解,我们将application.properties
文件中的mymessage
属性插入到message
属性中。
@GetMapping("/getMessage")
public String getMessage(Model model) {
model.addAttribute("message", message);
return "show";
}
@GetMapping
将/getMessage
URL 模式映射到getMessage()
方法。 在getMessage()
方法中,我们使用Model
。 它使用addAttribute()
方法接收message
属性。 return 关键字返回视图的名称,该名称将解析为show.ftl
,因为我们使用的是 Freemarker 模板系统。
@GetMapping("/getMessage2")
public ModelAndView getMessage() {
var mav = new ModelAndView();
mav.addObject("message", message);
mav.setViewName("show");
return mav;
}
在第二种情况下,我们使用ModelAndView
。 我们使用addObject()
和setViewName()
添加模型数据和视图名称。 该方法返回ModelAndView
对象。
@GetMapping("/getMessageAndTime")
public String getMessageAndTime(ModelMap map) {
var ldt = LocalDateTime.now();
var fmt = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
fmt.withLocale(new Locale("sk", "SK"));
fmt.withZone(ZoneId.of("CET"));
var time = fmt.format(ldt);
map.addAttribute("message", message).addAttribute("time", time);
return "show";
}
在getMessageAndTime()
方法中,我们使用ModelMap
。 模型图接收两个属性:消息和时间。
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<ul>
<li><a href="getMessage">Get message</a></li>
<li><a href="getMessage2">Get message 2</a></li>
<li><a href="getMessageAndTime">Get message and time</a></li>
</ul>
</body>
</html>
这是主页。 它包含三个调用 Spring 控制器方法的链接。 它是静态资源,位于预定义的src/main/resources/static
目录中。
resources/templates/show.ftl
<!DOCTYPE html>
<html>
<head>
<title>Message</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>
Message: ${message}
</p>
<#if time??>
<p>Date and time: ${time}</p>
</#if>
</body>
</html>
show.ftl
是一个 Freemarker 模板文件。 它位于预定义的src/main/resources/templates
目录中。 它使用${}
语法输出消息和时间(可选)。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。 在扫描过程中,将查找@Controller
注解,并从MyController
类创建一个 Spring bean。
$ mvn spring-boot:run
启动应用后,我们导航到localhost:8080
。
在本教程中,我们已经在 Spring 应用中使用了模型。 您可能也对相关教程感兴趣: Spring Boot @ModelAttribute
教程, Spring Boot @Controller
教程, Spring Boot Freemaker 教程, Spring Boot @RequestParam
教程, Java 教程或列出所有 Spring Boot 教程。
Spring Boot MySQL 教程
Spring Boot MySQL 教程展示了如何在 Spring Boot 应用中使用 MySQL 数据库。
Spring 是用于创建企业应用的流行 Java 应用框架。 Spring Boot 是 Spring 框架的演进,可帮助您轻松创建独立的,生产级的基于 Spring 的应用。
MySQL
MySQL 是领先的开源数据库管理系统。 它是一个多用户,多线程的数据库管理系统。 MySQL 在网络上特别流行。 它是非常流行的 LAMP 平台的一部分,该平台包括 Linux,Apache,MySQL 和 PHP。 MySQL 数据库在最重要的 OS 平台上可用。 它可以在 BSD Unix,Linux,Windows 和 Mac 上运行。
MySQL 设置
我们将展示如何在 Debian Linux 系统上安装 MySQL 数据库。
$ sudo apt-get install mysql-server
此命令将安装 MySQL 服务器和相关包。
$ sudo service mysql start
$ sudo service mysql stop
这两个命令用于启动和停止 MySQL。
$ sudo service mysql status
我们使用service mysql status
命令检查数据库的状态。
$ mysql -u root -p
现在我们需要重置根密码。 我们启动 mysql 命令行工具。 (服务器必须正在运行。)我们以root
用户身份连接。
mysql> SET PASSWORD = PASSWORD('newpassowrd');
我们为root
设置了新密码。
$ mysql_secure_installation
我们可以使用mysql_secure_installation
来提高 MySQL 服务器的安全性。 我们可以选择改进 MySQL 的root
密码,删除匿名用户帐户,禁用 localhost 外部的root
登录以及删除测试数据库。
mysql> CREATE DATABASE testdb;
我们创建一个新的testdb
数据库。
mysql> CREATE USER user12@localhost IDENTIFIED BY 's$cret';
mysql> GRANT ALL ON testdb.* TO user12@localhost;
我们创建一个新的 MySQL 用户并将其特权授予testdb
数据库。
创建 MySQL 表
现在,我们将创建一个名为cities
的新 MySQL 表。
cities_mysql.sql
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255),
population INT);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
这是用于创建cities
表的 SQL。
mysql> use testdb;
mysql> source cities_mysql.sql
使用source
命令,执行 SQL 语句。
Spring Boot MySQL 示例
以下应用是一个简单的 Spring Boot Web 应用,它使用 MySQL 数据库。 我们有一个主页,带有一个链接,用于显示数据库表中的数据。 我们使用 Freemarker 模板系统将数据与 HTML 连接。
pom.xml
src
└── main
├── java
│ └── com
│ └── zetcode
│ ├── Application.java
│ ├── model
│ │ └── City.java
│ ├── controller
│ │ └── MyController.java
│ ├── repository
│ │ └── CityRepository.java
│ └── service
│ ├── CityService.java
│ └── ICityService.java
└── resources
├── application.properties
├── static
│ └── index.html
└── templates
└── showCities.ftl
这是项目结构。
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.zetcode</groupId>
<artifactId>springbootmysqlex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Boot 启动器是一组方便的依赖项描述符,可以极大地简化 Maven 配置。 spring-boot-starter-parent
具有 Spring Boot 应用的一些常用配置。 spring-boot-starter-web
是使用 Spring MVC 构建 Web(包括 RESTful)应用的入门工具。 spring-boot-starter-freemarker
是使用 Freemarker 视图构建 MVC Web 应用的入门工具。 spring-boot-starter-data-jpa
是将 Spring Data JPA 与 Hibernate 结合使用的入门工具。
mysql-connector-java
依赖项是针对 MySQL 数据库驱动程序的。
spring-boot-maven-plugin
在 Maven 中提供了 Spring Boot 支持,使我们可以打包可执行的 JAR 或 WAR 档案。 它的spring-boot:run
目标运行 Spring Boot 应用。
resources/application.properties
spring.main.banner-mode=off
logging.level.org.springframework=ERROR
spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false
spring.datasource.username=user12
spring.datasource.password=s$cret
在application.properties
文件中,我们编写了 Spring Boot 应用的各种配置设置。 使用spring.main.banner-mode
属性,我们可以关闭 Spring 横幅。 使用logging.level.org.springframework
,我们将 spring 框架的日志记录级别设置为ERROR
。 在 spring 数据源属性中,我们设置了 MySQL 数据源。
com/zetcode/model/City.java
package com.zetcode.model;
import java.util.Objects;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "cities")
public class City {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private int population;
public City() {
}
public City(Long id, String name, int population) {
this.id = id;
this.name = name;
this.population = population;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + Objects.hashCode(this.id);
hash = 79 * hash + Objects.hashCode(this.name);
hash = 79 * hash + this.population;
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final City other = (City) obj;
if (this.population != other.population) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return Objects.equals(this.id, other.id);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("City{");
sb.append("id=").append(id);
sb.append(", name='").append(name).append('\'');
sb.append(", population=").append(population);
sb.append('}');
return sb.toString();
}
}
这是City
实体。 每个实体必须至少定义两个注解:@Entity
和@Id
。
@Entity
@Table(name = "cities")
public class City {
@Entity
注解指定该类是一个实体,并映射到数据库表,而@Table
注解指定要用于映射的数据库表的名称。
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
实体的主键由@Id
注解指定。 @GeneratedValue
提供了一种用于生成主键值的策略。
com/zetcode/CityRepository.java
package com.zetcode.repository;
import com.zetcode.model.City;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CityRepository extends CrudRepository<City, Long> {
}
通过从 Spring CrudRepository
扩展,我们将为我们的数据存储库实现一些方法,包括findAll()
。 这样,我们节省了大量样板代码。
com/zetcode/service/ICityService.java
package com.zetcode.service;
import com.zetcode.model.City;
import java.util.List;
public interface ICityService {
List<City> findAll();
}
ICityService
提供findAll()
契约方法声明,以从数据源获取所有城市。
com/zetcode/service/CityService.java
package com.zetcode.service;
import com.zetcode.model.City;
import com.zetcode.repository.CityRepository;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class CityService implements ICityService {
@Autowired
private CityRepository repository;
@Override
public List<City> findAll() {
return (List<City>) repository.findAll();
}
}
CityService
包含findAll()
方法的实现。 我们使用存储库从数据库检索数据。
@Autowired
private CityRepository repository;
注入CityRepository
。
return (List<City>) repository.findAll();
存储库的findAll()
方法返回城市列表。
com/zetcode/MyController.java
package com.zetcode.controller;
import com.zetcode.model.City;
import com.zetcode.service.ICityService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MyController {
@Autowired
private ICityService cityService;
@GetMapping("/showCities")
public String findCities(Model model) {
var cities = (List<City>) cityService.findAll();
model.addAttribute("cities", cities);
return "showCities";
}
}
MyController
类用@Controller
注解。
@Autowired
private ICityService cityService;
我们将ICityService
注入countryService
字段。
@GetMapping("/showCities")
public String findCities(Model model) {
var cities = (List<City>) cityService.findAll();
model.addAttribute("cities", cities);
return "showCities";
}
我们将带有/showCities
路径的请求映射到控制器的findCities()
方法。 @GetMapping
注解将 GET 请求映射到该方法。 该模型将获取城市列表,并将处理过程发送到showCities.ftl
Freemarker 模板文件。
resources/templates/showCities.ftl
<!DOCTYPE html>
<html>
<head>
<title>Cities</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>List of cities</h2>
<table>
<tr>
<th>Id</th>
<th>Name</th>
<th>Population</th>
</tr>
<#list cities as city>
<tr>
<td>${city.id}</td>
<td>${city.name}</td>
<td>${city.population}</td>
</tr>
</#list>
</table>
</body>
</html>
在showCities.ftl
模板文件中,我们在 HTML 表中显示数据。
resources/static/index.html
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<a href="showCities">Show cities</a>
</body>
</html>
index.html
中有一个链接,显示所有城市。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
设置 Spring Boot 应用。 @SpringBootApplication
启用自动配置和组件扫描。
$ mvn spring-boot:run
应用运行后,我们可以导航到localhost:8080
。
在本教程中,我们展示了如何在 Spring Boot 应用中使用 MySQL 数据库。 您可能也对相关教程感兴趣:
- Spring Boot PostgreSQL 教程
- Spring Boot H2 REST 教程
- Spring Boot Thymeleaf 教程
- Spring Web 应用介绍
- Spring Boot RESTFul 应用
Spring Boot GenericApplicationContext
原文: http://zetcode.com/springboot/genericapplicationcontext/
Spring Boot GenericApplicationContext
教程展示了如何在 Spring 应用中使用GenericApplicationContext
。 在示例中,我们创建一个 Spring Boot 控制台应用。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
GenericApplicationContext
GenericApplicationContext
是ApplicationContext
的实现,它不采用特定的 bean 定义格式; 例如 XML 或注解。
Spring Boot GenericApplicationContext
示例
在以下应用中,我们创建一个GenericApplicationContext
,并使用上下文的registerBean()
方法注册一个新 bean。 稍后,我们使用getBean()
从应用上下文中检索 bean。
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.zetcode</groupId>
<artifactId>genappctx</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>genappctx</name>
<description>Using GenericApplicationContext</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.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>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 spring-boot-starter-parent
是父 POM,它为使用 Maven 构建的应用提供依赖关系和插件管理。 spring-boot-starter
是一个核心启动器,包括自动配置支持,日志记录和 YAML。 spring-boot-starter-test
在 Spring 中增加了测试支持。 spring-boot-maven-plugin
将 Spring 应用打包到可执行的 JAR 或 WAR 归档文件中。
application.properties
spring.main.banner-mode=off
logging.level.root=ERROR
logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n
application.properties
是 Spring Boot 中的主要配置文件。 我们关闭 Spring 横幅,减少仅记录错误的错误,并设置控制台记录模式。
TimeService.java
package com.zetcode.service;
import java.time.Instant;
public class TimeService {
public Instant getNow() {
return Instant.now();
}
}
TimeService
包含一个返回当前日期和时间的简单方法。 该服务类将在我们的通用应用上下文中注册。
MyApplication.java
package com.zetcode;
import com.zetcode.service.TimeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.support.GenericApplicationContext;
@SpringBootApplication
public class MyApplication implements CommandLineRunner {
@Autowired
private GenericApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
context.registerBean("com.zetcode.Service.TimeService",
TimeService.class, () -> new TimeService());
var timeService = (TimeService) context.getBean(TimeService.class);
System.out.println(timeService.getNow());
context.registerShutdownHook();
}
}
MyApplication
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。 它是@Configuration
,@EnableAutoConfiguration
和@ComponentScan
注解的便捷注解。
@Autowired
private GenericApplicationContext context;
我们注入GenericApplicationContext
。
context.registerBean("com.zetcode.Service.TimeService",
TimeService.class, () -> new TimeService());
使用registerBean()
方法注册了一个新的TimeService
bean。
var timeService = (TimeService) context.getBean(TimeService.class);
我们使用getBean()
检索 bean。
System.out.println(timeService.getNow());
最后,我们调用 bean 的getNow()
方法。
MyApplicationTests.java
package com.zetcode;
import com.zetcode.service.TimeService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import java.time.Instant;
import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyApplicationTests {
@Autowired
private GenericApplicationContext context;
@Test
public void testNow() {
var timeService = (TimeService) context.getBean("com.zetcode.Service.TimeService");
var now = timeService.getNow();
assertThat(now.isBefore(Instant.now()));
}
}
我们有一个使用TimeService
的getNow()
方法的简单测试。
var timeService = (TimeService) context.getBean("com.zetcode.Service.TimeService");
这次,我们通过给定名称引用 Bean。
$ mvn -q spring-boot:run
2018-11-24T16:31:32.146393700Z
我们运行该应用。
在本教程中,我们展示了如何在 Spring 应用中使用GenericApplicationContext
。 您可能也对相关教程感兴趣: Spring Boot @PostConstruct
教程, Spring Boot @Controller
教程, Spring Boot @ExceptionHandler
教程, Spring Boot 上传文件, Spring Boot @PathVariable
教程, Spring Boot @RequestParam
教程, Spring Boot @ResponseBody
教程, Java 教程。
SpringApplicationBuilder
教程
SpringApplicationBuilder
教程展示了如何使用SpringApplicationBuilder
创建一个简单的 Spring Boot 应用。
Spring 是用于创建企业应用的流行 Java 应用框架。 Spring Boot 是 Spring 框架的演进,可帮助您轻松创建独立的,生产级的基于 Spring 的应用。
SpringApplication
SpringApplication
是一个类,用于从 Java main
方法引导 Spring 应用。 它创建一个适当的ApplicationContext
实例(取决于类路径),注册一个CommandLinePropertySource
以将命令行参数公开为 Spring 属性,刷新应用上下文,加载所有单例 bean,并触发任何CommandLineRunner
bean。
SpringApplicationBuilder
SpringApplicationBuilder
是SpringApplication
和ApplicationContext
实例的构建器,具有便利的流利的 API 和上下文层次结构支持。
Spring Boot 示例
以下应用是一个简单的 Spring Boot 控制台应用,它使用SpringApplicationBuilder
设置 Spring Boot 应用。
该应用从用户那里获取参数。 它需要网站的完整 URL 并返回其标题。
$ tree
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── Application.java
│ │ └── MyRunner.java
│ └── resources
│ └── application.properties
└── test
└── java
这是项目结构。
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.zetcode</groupId>
<artifactId>SpringBootAppEx</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Boot 启动器是一组方便的依赖项描述符,可以极大地简化 Maven 配置。 spring-boot-starter-parent
具有 Spring Boot 应用的一些常用配置。 spring-boot-starter
是核心 Spring 启动器。 jsoup
依赖关系用于 JSoup 库。
在spring-boot-maven-plugin
提供了 Maven 的 Spring Boot 支持,使我们能够打包可执行的 JAR 或 WAR 档案。 它的spring-boot:run
目标运行 Spring Boot 应用。
application.properties
logging.level.org.springframework=ERROR
在application.properties
文件中,我们编写了 Spring Boot 应用的各种配置设置。 在这里,我们将 Spring 框架的日志记录级别设置为ERROR
。
MyRunner.java
package com.zetcode;
import java.util.List;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class MyRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
if (!args.containsOption("website")) {
System.err.println("no website specified");
} else {
List<String> vals = args.getOptionValues("website");
String url = vals.get(0);
Document doc = Jsoup.connect(url).get();
String title = doc.title();
System.out.printf("The title is: %s%n", title);
}
}
}
加载 Spring 应用后,将执行实现ApplicationRunner
的所有 bean。
if (!args.containsOption("website")) {
我们检查命令行上是否指定了--website
选项。
List<String> vals = args.getOptionValues("website");
String url = vals.get(0);
我们得到可选的值。
Document doc = Jsoup.connect(url).get();
String title = doc.title();
System.out.printf("The title is: %s%n", title);
通过JSoup
,我们获得了指定网站的标题。
Application.java
package com.zetcode;
import org.springframework.boot.Banner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class)
.bannerMode(Banner.Mode.OFF)
.logStartupInfo(false)
.build()
.run(args);
}
}
Application
是设置 Spring Boot 应用的入口。 @SpringBootApplication
注解启用自动配置和组件扫描。
new SpringApplicationBuilder(Application.class)
.bannerMode(Banner.Mode.OFF)
.logStartupInfo(false)
.build()
.run(args);
SpringApplicationBuilder
用于构建 Spring 应用。 我们关闭横幅和启动信息。
$ mvn -q spring-boot:run -Drun.arguments=--website=http://www.something.com
The title is: Something.
这是输出。 命令行参数与run.arguments
一起传递。
在本教程中,我们介绍了SpringApplicationBuilder
。
您可能对 JSoup 教程, Spring Boot Environment
教程感兴趣。 Spring Boot PostgreSQL 教程, Spring Boot MySQL 教程或 Spring Boot @PostConstruct
。
Spring Boot Undertow 教程
Spring Boot Undertow 教程展示了如何在 Spring Boot 应用中使用 Undertow 服务器。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
Undertow
Undertow 是一种灵活的高性能 Web 服务器,它提供阻止和非阻止 API。 它来自 JBoss 项目。
Spring Boot Undertow 示例
默认情况下,Spring Boot 使用 Tomcat 嵌入式 Web 服务器。 以下示例显示了如何使用 Undertow。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ ├───config
│ │ │ AppConfig.java
│ │ └───controller
│ │ MyController.java
│ └───resources
│ application.properties
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>undertowex</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven 构建文件。 我们明确排除了 Tomcat 服务器依赖项,并包括了 Undertow 依赖项。
resources/application.properties
spring.main.banner-mode=off
logging.pattern.console=%clr(%d{yy-MM-dd E HH:mm:ss.SSS}){blue} %clr(%-5p) %clr(%logger{0}){blue} %clr(%m){faint}%n
在application.properties
文件中,我们有一个 Spring 启动应用的各种配置设置。 使用spring.main.banner-mode
属性,我们可以关闭 Spring 横幅。 logging.pattern.console
配置控制台日志记录模式。
com/zetcode/controller/MyController.java
package com.zetcode.controller;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@GetMapping(value="/", produces = MediaType.TEXT_PLAIN_VALUE)
public String home() {
return "Home page";
}
}
主页返回一条简单的文本消息。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口点。
$ mvn -q spring-boot:run
我们运行该应用并导航到localhost:8080
。
...
19-06-28 Fri 17:37:08.557 INFO nio XNIO NIO Implementation Version 3.3.8.Final
19-06-28 Fri 17:37:08.629 INFO UndertowServletWebServer Undertow started on port(s) 8080 (http) with context path ''
19-06-28 Fri 17:37:08.634 INFO Application Started Application in 3.716 seconds (JVM running for 4.352)
在控制台中,我们可以看到 Undertow 服务器正在启动。
在本教程中,我们展示了如何在 Spring Boot 应用中使用 Undertow 服务器。
Spring Boot 登录页面教程
Spring Boot 登录页面教程显示了如何使用默认登录页面。 Spring Security 默认情况下会保护所有 HTTP 端点。 用户必须以默认的 HTTP 形式登录。
为了启用 Spring Boot 安全性,我们将spring-boot-starter-security
添加到依赖项中。
Spring Boot 登录页面示例
以下示例显示了如何在 Spring Boot 应用中设置简单的登录页面。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ └───controller
│ │ MyController.java
│ └───resources
│ application.properties
└───test
└───java
这是 Spring Boot 应用的项目结构。
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.zetcode</groupId>
<artifactId>springbootloginpage</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven 构建文件。 我们有网络和安全性的入门者。
resources/application.properties
spring.main.banner-mode=off
logging.pattern.console=%d{dd-MM-yyyy HH:mm:ss} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n
在application.properties
文件中,我们关闭 Spring Boot 横幅并配置控制台日志记录模式。
com/zetcode/controller/MyController.java
package com.zetcode.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@GetMapping("/")
public String home() {
return "This is home page";
}
}
我们有一个简单的主页。
我们运行该应用并导航到localhost:8080
。 我们被重定向到http://localhost:8080/login
页面。
...
17-06-2019 17:48:45 [main] INFO org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration.getOrDeducePassword -
Using generated security password: df7ce50b-abae-43a1-abe1-0e17fd81a454
...
在控制台中,我们可以看到为默认用户user
生成的密码。 这些凭据将提供给认证表单。
图:登录表单
Spring 使用 Bootstrap 定义 UI。
spring.security.user.name = admin
spring.security.user.password = s$cret
通过这两个选项,我们可以拥有一个新的用户名和密码。 使用这些设置将自动生成的用户关闭。
在本教程中,我们使用了默认的登录表单。 您可能也对相关教程感兴趣: Spring Boot @Lazy
教程, Java 教程或列出 Spring Boot 教程。
Spring Boot RouterFunction
教程
Spring Boot RouterFunction
教程展示了如何在 Spring Boot 应用中创建函数式路由。
反应式编程
反应式编程是一种编程范例,它是函数式的,基于事件的,非阻塞的,异步的,并且以数据流处理为中心。 术语反应式来自以下事实:我们对诸如鼠标单击或 I/O 事件之类的更改做出反应。
传统的 Spring MVC 应用使用诸如@GetMapping
之类的注解将请求路径映射到控制器动作。 函数式路由 API 是此映射的替代方法。
RouterFunction
RouterFunction
表示路由到处理器函数的函数。
Spring Boot RouterFunction
示例
在以下应用中,我们创建具有函数式路由的反应式 Spring Boot 应用。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ │ Application.java
│ │ └───routes
│ │ MyRoutes.java
│ └───resources
└───test
└───java
└───com
└───zetcode
└───routes
MyRoutesTest.java
这是 Spring 应用的项目结构。
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.zetcode</groupId>
<artifactId>springbootrouterfunction</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。 RouterFunction
依赖于spring-boot-starter-webflux
。
com/zetcode/routes/MyRoutes.java
package com.zetcode.routes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
@Configuration
public class MyRoutes {
@Bean
RouterFunction<ServerResponse> home() {
return route(GET("/"), request -> ok().body(fromObject("Home page")));
}
@Bean
RouterFunction<ServerResponse> about() {
return route(GET("/about"), request -> ok().body(fromObject("About page")));
}
}
我们定义了两个函数式路由。
@Bean
RouterFunction<ServerResponse> home() {
return route(GET("/"), request -> ok().body(fromObject("Home page")));
}
通过函数式路由,我们可以编写简单而优雅的代码。 在这里,我们返回主页的简单文本消息。
com/zetcode/routes/MyRoutesTest.java
package com.zetcode.routes;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyRoutesTest {
@Autowired
private WebTestClient client;
@Test
public void test_home_page() {
client.get().uri("/").exchange().expectStatus().isOk()
.expectBody(String.class).isEqualTo("Home page");
}
@Test
public void test_about_page() {
client.get().uri("/about").exchange().expectStatus().isOk()
.expectBody(String.class).isEqualTo("About page");
}
}
使用WebTestClient
,我们测试了两个路由。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这段代码设置了 Spring Boot 应用。
$ mvn spring-boot:run
我们运行该应用并导航到localhost:8080
。
在本教程中,我们学习了如何通过RouterFunction
使用函数式路由。
列出所有 Spring Boot 教程。
Spring Boot @Order
教程
Spring Boot @Order
教程展示了如何使用@Order
注解来规定 bean。
Spring 是流行的 Java 应用框架,而 Spring Boot 是 Spring 的演进,可以帮助轻松地创建独立的,生产级的基于 Spring 的应用。
@Order
@Order
定义带注解的组件的排序顺序。 value()
是可选的,表示订单值。 较低的值具有较高的优先级。
Spring Boot @Order
示例
以下应用命令执行CommandLineRunner
的 bean 的执行。
pom.xml
src
├───main
│ ├───java
│ │ └───com
│ │ └───zetcode
│ │ Application.java
│ │ MyRunner.java
│ │ MyRunner2.java
│ └───resources
└───test
└───java
这是项目结构。
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.zetcode</groupId>
<artifactId>springbootorder</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这是 Maven pom.xml
文件。
com/zetcode/MyRunner.java
package com.zetcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(value = 2)
public class MyRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);
@Override
public void run(String... args) throws Exception {
logger.info("Running MyRunner");
}
}
在应用启动时启动 Bean。 使用@Order
注解,我们为其赋予了优先级。
com/zetcode/MyRunner2.java
package com.zetcode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(value = 1)
public class MyRunner2 implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(MyRunner.class);
@Override
public void run(String... args) throws Exception {
logger.info("Running MyRunner2");
}
}
这是MyRunner2
。 通过@Order
设置了更高的优先级,因此在MyRunner
之前执行。
com/zetcode/Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
是设置 Spring Boot 应用的入口。
我们使用mvn -q spring-boot:run
运行该应用。
在本教程中,我们展示了如何使用@Order
接口来设置 bean 的执行顺序。 您可能也对相关教程感兴趣: Spring Boot @Repository
教程, Spring Boot CommandLineRunner
教程, Java 教程或列出所有 Spring Boot 教程。
Spring Boot @Lazy
教程
Spring Boot @Lazy
教程展示了如何使用 Spring @Lazy
注解懒惰地初始化 bean。
Spring 是用于创建企业应用的流行 Java 应用框架。 Spring Boot 是 Spring 框架的演进,可帮助您轻松创建独立的,生产级的基于 Spring 的应用。
@Lazy
@Lazy
注解指示是否要延迟初始化 bean。 它可以用于@Component
和@Bean
定义。 @Lazy
bean 不会被初始化,直到被另一个 bean 引用或从BeanFactory
中显式检索。 不使用@Lazy
注解的 Bean 会被初始化。
Spring Boot @Lazy
示例
在下面的示例中,我们创建延迟懒惰地初始化的 bean。 它说明了两种类型的 bean 之间的区别。 该应用是一个简单的 Spring Boot Web 应用,可在嵌入式 Tomcat 服务器上运行。 我们使用 Freemarker 模板引擎。
$ tree
.
├── pom.xml
├── SpringBootLazy.iml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── zetcode
│ │ ├── Application.java
│ │ ├── bean
│ │ │ ├── MyBean.java
│ │ │ ├── MyLazyBean.java
│ │ │ └── StartUpBean.java
│ │ └── controller
│ │ └── MyController.java
│ └── resources
│ ├── application.properties
│ ├── static
│ │ └── index.html
│ └── templates
│ └── showMessages.ftl
└── test
└── java
这是项目结构。
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.zetcode</groupId>
<artifactId>SpringBootLazy</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Boot 启动器是一组方便的依赖项描述符,可以极大地简化 Maven 配置。 spring-boot-starter-parent
具有 Spring Boot 应用的一些常用配置。 spring-boot-starter-freemarker
是使用 Freemarker 视图构建 MVC Web 应用的入门工具。
在spring-boot-maven-plugin
提供了 Maven 的 Spring Boot 支持,使我们能够打包可执行的 JAR 或 WAR 档案。 它的spring-boot:run
目标运行 Spring Boot 应用。
application.properties
server.port=8086
server.contextPath=/myapp
spring.main.banner-mode=off
logging.level.org.springframework=ERROR
在application.properties
文件中,我们编写了 Spring Boot 应用的各种配置设置。 完成这些设置后,我们可以通过localhost:8086/myapp/
访问该应用。
MyBean.java
package com.zetcode.bean;
import org.springframework.stereotype.Component;
import java.util.logging.Logger;
@Component
public class MyBean {
static Logger log = Logger.getLogger(MyBean.class.getName());
public MyBean() {
log.info("MyBean initialized");
}
public String getMessage() {
return "Message from MyBean";
}
}
这是MyBean
。 急切地初始化该 bean,即在 Spring 框架开始时。
MyLazyBean.java
package com.zetcode.bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.logging.Logger;
@Component
@Lazy
public class MyLazyBean {
static Logger log = Logger.getLogger(MyLazyBean.class.getName());
public MyLazyBean() {
log.info("MyLazyBean initialized");
}
public String getMessage() {
return "Message from MyLazyBean";
}
}
MyLazyBean
包含@Lazy
注解。 第一次请求时,它会延迟地初始化。 从控制器请求。
StartUpBean.java
package com.zetcode.bean;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.util.logging.Logger;
@Component
public class StartUpBean implements
ApplicationListener<ApplicationReadyEvent> {
static Logger log = Logger.getLogger(StartUpBean.class.getName());
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
log.info("Application is ready");
}
}
StartUpBean
实现一个应用监听器; 当应用准备就绪时,它将记录一条消息。
MyController.java
package com.zetcode.controller;
import com.zetcode.bean.MyBean;
import com.zetcode.bean.MyLazyBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MyController {
@Autowired
private BeanFactory factory;
@GetMapping(value="messages")
public String getMessages(Model model) {
MyLazyBean myLazyBean = factory.getBean(MyLazyBean.class);
MyBean myBean = factory.getBean(MyBean.class);
model.addAttribute("mybean", myBean.getMessage());
model.addAttribute("mylazybean", myLazyBean.getMessage());
return "showMessages";
}
}
这是一个控制器类。 它创建两个 bean 并接收它们的消息。 消息显示在 Freemarker 模板中。
@Autowired
private BeanFactory factory;
我们注入BeanFactory
。 工厂用于访问 Spring bean。
MyLazyBean myLazyBean = factory.getBean(MyLazyBean.class);
此时,MyLazyBean
被初始化。
MyBean myBean = factory.getBean(MyBean.class);
我们从工厂获得了MyBean
; MyBean
在 Spring 的启动时初始化。
showMessages.ftl
<!DOCTYPE html>
<html>
<head>
<title>Show data</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<p>
MyBean: ${mybean}
</p>
<p>
MyLazyBean: ${mylazybean}
</p>
</body>
</html>
Freemarker 模板显示来自两个 bean 的消息。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home page</title>
</head>
<body>
<a href="messages">Get messages</a>
</body>
</html>
index.html
中有一个链接,用于从 Bean 获取消息。
Application.java
package com.zetcode;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Application
设置 Spring Boot 应用。 @SpringBootApplication
启用自动配置和组件扫描。
$ mvn spring-boot:run
应用运行后,我们可以导航到localhost:8086/myapp/
。
Initializing Spring embedded WebApplicationContext
com.zetcode.bean.MyBean : MyBean initialized
com.zetcode.bean.StartUpBean : Application is ready
当 Spring 启动时,我们可以看到这些日志消息。 请注意,MyBean
在启动时已初始化。
com.zetcode.bean.MyLazyBean : MyLazyBean initialized
调用控制器时,将初始化MyLazyBean
。
在本教程中,我们展示了如何使用 Spring @Lazy
注解。 您可能也对相关教程感兴趣: