参考资料:
创建 Spring Boot 项目
项目环境
JDK1.8、Maven、SpringBoot2.2.4、IDEA
使用 IntelliJ IDEA创建
第一步 :菜单栏中选择:File => New => Project…,我们可以看到如下图所示的创建功能窗口。
其中 Initial Service Url 指向的地址就是 Spring 官方提供的 Spring Initializr 工具地址,所以这里创建的工程实际上也是基于它的 Web 工具来实现的。
第二步 :点击 Next,等待片刻后,我们可以看到如下图所示的工程信息窗口:
第三步 :继续点击Next,进入选择 Spring Boot 版本和依赖管理的窗口:
在这里值的我们关注的是,它不仅包含了Spring Boot Starter POMs中的各个依赖,还包含了 Spring Cloud 的各种依赖。
第四步 :点击 Next,进入最后关于工程物理存储的一些细节。最后,点击Finish就能完成工程的构建了。
项目解析
项目结构解析
src/main/java 下的程序入口:DemoApplication
src/main/resources 下的配置文件:application.properties
src/test/ 下的测试入口:DemoApplicationTests
生成的 DemoApplication 和 DemoApplicationTests 类都可以直接运行来启动当前创建的项目,由于目前该项目未配合任何数据访问或 Web 模块,程序会在加载完 Spring 之后结束运行。
项目依赖解析
打开 pom.xml,看看 Spring Boot 项目的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.2.4.RELEASE</version > <relativePath /> </parent > <groupId > com.example</groupId > <artifactId > demo</artifactId > <version > 0.0.1-SNAPSHOT</version > <name > demo</name > <description > Demo project for Spring Boot</description > <properties > <java.version > 1.8</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 > <exclusions > <exclusion > <groupId > org.junit.vintage</groupId > <artifactId > junit-vintage-engine</artifactId > </exclusion > </exclusions > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > </plugins > </build > </project >
如上所示,主要有四个部分:
项目元数据:创建时候输入的 Project Metadata 部分,也就是 Maven 项目的基本元素,包括:groupId、artifactId、version、name、description等
parent:继承 spring-boot-starter-parent 的依赖管理,控制版本与打包等内容
dependencies:项目具体依赖,这里包含了 spring-boot-starter-web 用于实现 HTTP 接口(该依赖中包含了Spring MVC);spring-boot-starter-test 用于编写单元测试的依赖包。更多功能模块的使用我们将在后面的教程中逐步展开。
build:构建配置部分。默认使用了 spring-boot-maven-plugin,配合 spring-boot-starter-parent就可以把 Spring Boot 应用打包成JAR来直接运行。
启动 Spring Boot 项目
编写一个HTTP接口
启动引导 Spring
创建 Spring Boot 项目后默认有一个 DemoApplication 类,其内容如下
1 2 3 4 5 6 7 8 9 @SpringBootApplication public class DemoApplication { public static void main (String[] args) { SpringApplication.run(DemoApplication.class, args); } }
@SpringBootApplication 开启了 Spring 的组件扫描和 Spring Boot 的自动配置功能。实际上,@SpringBootApplication 将三个有用的注解组合在了一起。
Spring 的 @Configuration :标明该类使用 Spring 基于 Java 的配置而不是 XML 的配置。
Spring 的 @ComponentScan :启用组件扫描,这样你写的 Web 控制器类和其他组件才能被自动发现并注册为 Spring 应用程序上下文里的 Bean。
Spring Boot 的 @EnableAutoConfiguration : 这个不起眼的小注解也可以称为 @Abracadabra ,就是这一行配置开启了 Spring Boot 自动配置的魔力,让你不用再写成篇的配置了。
DemoApplication 还是一个启动引导类,这里的 main() 方法让你可以在命令行里把该应用程序当作一个可执行 JAR 文件来运行。这里向 SpringApplication.run() 传递了一个 DemoApplication 类的引用,还有命令行参数,通过这些东西启动应用程序。
整合接口文档 Swagger
目前,大多数系统都采用前后端分离。在享受前后端分离的好处 的同时,接口联调往往成为团队效率的瓶颈,甚至产生前后端的矛盾。简单归结来说,有几方面的原因:
问题一,接口设计滞后 。后端团队往往不喜欢 API 接口设计先行,提前和前端沟通好接口。而在开发阶段的中后期,在后端提供 API 接口后,而这些接口和前端的预期有一些偏差,很容易就产生抱怨,特别是项目周期比较紧张的情况下。
问题二,接口不规范 。 当团队里没有同意明确的接口规范时,又或者代码 Review 做的不是很好的情况下,千奇百怪、各式各样的 API 接口可能就产生了。前端在对接这样的 API 接口,苦不堪言。
问题三,接口文档更新不及时,或者遗忘更新 。因为后端 API 代码和 API 接口在两个地方,我们无法保证提交 API 代码的同时,及时更新文档。有的时候,我们甚至会遗忘更新 API 接口。随着时间的流逝,API 文档和 API 接口不一致的地方越来越多,前端会对 API 接口的信任度越来越低,然后不知道不觉之中,回到原始时代,直接问后端开发 API 是什么样的。
对于以上问题有如下建议:
接口设计先行 。设计完成后,后端和前端进行简单沟通,看看是否能够满足诉求。
统一的接口规范 。一定要制定统一的接口规范文档,即使比较简陋,也能保证团队的 API 接口相对统一一致。即使错,咱也错的一模一样,而不是千奇百怪。当然,接口规范是无法覆盖到所有的场景的,借助于“接口设计先行”,我们可以提前去 Review 每个接口的设计。
对于问题三 ,就进入了本文的 主角 Swagger 。通过在 API 接口上,添加相应的 Swagger 提供的注解,自动生成 API 文档。
Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法、参数和模型紧密集成到服务器端的代码,允许 API 来始终保持同步。Swagger 让部署管理和使用功能强大的 API 从未如此简单。
引入依赖
在 pom.xml文件中,引入相关依赖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-swagger2</artifactId > <version > 2.9.2</version > </dependency > <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-swagger-ui</artifactId > <version > 2.9.2</version > </dependency > </dependencies >
SwaggerConfiguration
因为 Spring Boot 暂未提供 Swagger 内置的支持,所以我们需要自己定义配置类。
在 com.halo.helloswagger.config 包路径下,创建 SwaggerConfiguration 配置类,用于配置 Swagger 。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Configuration @EnableSwagger2 public class SwaggerConfiguration { @Bean public Docket createRestApi () { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(this .apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.halo.apidoc.controller" )) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo () { return new ApiInfoBuilder() .title("测试接口文档示例" ) .description("我是一段描述" ) .version("1.0.0" ) .contact(new Contact("Halo" , "https://halo123.top" , "lanqilu@foxmail.com" )) .build(); } }
在类上,添加 @EnableSwagger2 注解, 标记项目启用 Swagger API 接口文档。
Application
创建 HelloSwaggerApplication.java 类,配置 @SpringBootApplication 注解即可。代码如下:
1 2 3 4 5 6 @SpringBootApplication public class Application { public static void main (String[] args) { SpringApplication.run(Application.class, args); } }
先暂时不启动项目。等我们添加好 Controller
UserController
在 com.halo.helloswagger.controller 包路径下,创建 UserController 类,提供用户 API 接口。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 @RestController @RequestMapping("/users") @Api(tags = "用户 API 接口") public class UserController { @GetMapping("/list") @ApiOperation(value = "查询用户列表", notes = "目前仅仅是作为测试,所以返回用户全列表") public List<UserVO> list () { List<UserVO> result = new ArrayList<>(); result.add(new UserVO().setId(1 ).setUsername("yudaoyuanma" )); result.add(new UserVO().setId(2 ).setUsername("woshiyutou" )); result.add(new UserVO().setId(3 ).setUsername("chifanshuijiao" )); return result; } @GetMapping("/get") @ApiOperation("获得指定用户编号的用户") @ApiImplicitParam(name = "id", value = "用户编号", paramType = "query", dataTypeClass = Integer.class, required = true, example = "1024") public UserVO get (@RequestParam("id") Integer id) { return new UserVO().setId(id).setUsername(UUID.randomUUID().toString()); } @PostMapping("add") @ApiOperation("添加用户") public Integer add (UserAddDTO addDTO) { Integer returnId = UUID.randomUUID().hashCode(); return returnId; } @PostMapping("/update") @ApiOperation("更新指定用户编号的用户") public Boolean update (UserUpdateDTO updateDTO) { Boolean success = true ; return success; } @PostMapping("/delete") @ApiOperation(value = "删除指定用户编号的用户") @ApiImplicitParam(name = "id", value = "用户编号", paramType = "query", dataTypeClass = Integer.class, required = true, example = "1024") public Boolean delete (@RequestParam("id") Integer id) { Boolean success = false ; return success; } }
相比我们之前使用 SpringMVC 来说,我们在类和接口上,额外增加了 Swagger 提供的注解。
从使用习惯上,我比较喜欢先添加 SpringMVC 的注解,再添加 Swagger 的注解。
因为已经使用了 Swagger 的注解,所以类和方法上的注释,一般可以删除了,除非有特殊诉求。
其中涉及到的 POJO 类,有 UserAddDTO、UserUpdateDTO、UserVO 。
执行 Application 启动项目。然后浏览器访问 http://localhost:8080/swagger-ui.html 地址,就可以看到 Swagger 生成的 API 接口文档。如下图所示:
配置文件有关操作
演示如何获取配置文件的自定义配置,以及如何多环境下的配置文件信息的获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 main ├── java │ └── com │ └── halo │ └── properties │ ├── controller │ │ └── PropertyController.java │ ├── PropertiesApplication.java │ └── property │ ├── ApplicationProperty.java │ └── DeveloperProperty.java └── resources ├── application-dev.yml ├── application-prod.yml ├── application.yml └── META-INF └── additional-spring-configuration-metadata.json
通过修改 application.yml 的 spring.profiles.active 即可修改配置文件
1 2 3 4 5 6 7 server: port: 8080 servlet: context-path: /demo spring: profiles: active: prod
整合 Actuator 检查项目运行情况
演示了如何在 Spring Boot 中通过 actuator 检查项目运行情况
pom.xml 中添加相关依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-actuator</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-security</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework.security</groupId > <artifactId > spring-security-test</artifactId > <scope > test</scope > </dependency > </dependencies >
application.yml 中修改相关配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 server: port: 8080 servlet: context-path: /demo spring: security: user: name: root password: 123456 management: server: port: 8090 servlet: context-path: /sys endpoint: health: show-details: always endpoints: web: exposure: include: '*'
将项目运行起来之后,打开浏览器
集成 Spring Boot Admin 可视化监控
集成 spring-boot-admin 来可视化的监控 spring-boot 程序的运行状态,可以与 actuator 互相搭配使用
客户端示例
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.4.5</version > <relativePath /> </parent > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > de.codecentric</groupId > <artifactId > spring-boot-admin-starter-client</artifactId > <version > 2.4.1</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-actuator</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-security</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies >
服务端示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > de.codecentric</groupId > <artifactId > spring-boot-admin-server-ui</artifactId > <version > 2.4.1</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > </dependencies >
小坑
在配置过程中,Spring Boot 和版本要和 admin-starter-server 对应,不然不明会报错
在项目启动后,出现 Caused by: java.net.UnknownHostException: failed to resolve 'DESKTOP-V294IKA... 问题,说明需要配置计算机的 host ,例如
1 127.0.0.1 DESKTOP-V294IKA
便解决此问题
最后结果如下
集成 LogBack 日志
演示了如何使用 logback 记录程序运行过程中的日志,以及如何配置 logback,可以同时生成控制台日志和文件日志记录,文件日志以日期和大小进行拆分生成。
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.5.0</version > <relativePath /> </parent > <groupId > com.halo</groupId > <artifactId > LogBack</artifactId > <version > 0.0.1-SNAPSHOT</version > <name > LogBack</name > <description > Demo project for Spring Boot</description > <properties > <java.version > 11</java.version > </properties > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <optional > true</optional > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > </plugins > </build > </project >
LogBackApplication.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @SpringBootApplication @Slf4j public class LogBackApplication { public static void main (String[] args) { ConfigurableApplicationContext context = SpringApplication.run(LogBackApplication.class, args); int length = context.getBeanDefinitionNames().length; log.trace("Spring boot启动初始化了 {} 个 Bean" , length); log.debug("Spring boot启动初始化了 {} 个 Bean" , length); log.info("Spring boot启动初始化了 {} 个 Bean" , length); log.warn("Spring boot启动初始化了 {} 个 Bean" , length); log.error("Spring boot启动初始化了 {} 个 Bean" , length); try { int i = 0 ; int j = 1 / i; } catch (Exception e) { log.error("【SpringBootDemoLogbackApplication】启动异常:" , e); } } }
logback-spring.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 <?xml version="1.0" encoding="UTF-8"?> <configuration > <include resource ="org/springframework/boot/logging/logback/defaults.xml" /> <appender name ="CONSOLE" class ="ch.qos.logback.core.ConsoleAppender" > <filter class ="ch.qos.logback.classic.filter.LevelFilter" > <level > INFO</level > </filter > <encoder > <pattern > %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern > <charset > UTF-8</charset > </encoder > </appender > <appender name ="FILE_INFO" class ="ch.qos.logback.core.rolling.RollingFileAppender" > <filter class ="ch.qos.logback.classic.filter.LevelFilter" > <level > ERROR</level > <onMatch > DENY</onMatch > <onMismatch > ACCEPT</onMismatch > </filter > <rollingPolicy class ="ch.qos.logback.core.rolling.TimeBasedRollingPolicy" > <FileNamePattern > logs/spring-boot-demo-logback/info.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern > <maxHistory > 90</maxHistory > <timeBasedFileNamingAndTriggeringPolicy class ="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" > <maxFileSize > 2MB</maxFileSize > </timeBasedFileNamingAndTriggeringPolicy > </rollingPolicy > <encoder > <pattern > %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern > <charset > UTF-8</charset > </encoder > </appender > <appender name ="FILE_ERROR" class ="ch.qos.logback.core.rolling.RollingFileAppender" > <filter class ="ch.qos.logback.classic.filter.ThresholdFilter" > <level > Error</level > </filter > <rollingPolicy class ="ch.qos.logback.core.rolling.TimeBasedRollingPolicy" > <FileNamePattern > logs/spring-boot-demo-logback/error.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern > <maxHistory > 90</maxHistory > <timeBasedFileNamingAndTriggeringPolicy class ="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP" > <maxFileSize > 2MB</maxFileSize > </timeBasedFileNamingAndTriggeringPolicy > </rollingPolicy > <encoder > <pattern > %date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern > <charset > UTF-8</charset > </encoder > </appender > <root level ="info" > <appender-ref ref ="CONSOLE" /> <appender-ref ref ="FILE_INFO" /> <appender-ref ref ="FILE_ERROR" /> </root > </configuration >
集成 Freemarker 模板引擎
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.3.10.RELEASE</version > <relativePath /> </parent > <groupId > com.halo</groupId > <artifactId > Freemarker</artifactId > <version > 0.0.1-SNAPSHOT</version > <name > Freemarker</name > <description > Demo project for Spring Boot</description > <properties > <java.version > 11</java.version > </properties > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-freemarker</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <optional > true</optional > </dependency > <dependency > <groupId > cn.hutool</groupId > <artifactId > hutool-all</artifactId > <version > 5.6.5</version > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > </plugins > </build > </project >
resources
1 2 3 4 5 6 7 8 resources ├── application.yml └── templates ├── common │ └── head.ftl └── page ├── index.ftl └── login.ftl
head.ftl
1 2 3 4 5 6 7 <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" > <meta http-equiv ="X-UA-Compatible" content ="ie=edge" > <title > spring-boot-template-freemarker</title > </head >
index.ftl
1 2 3 4 5 6 7 8 9 <!doctype html > <html lang ="en" > <#include "../common/head.ftl"> <body > <div id ="app" style ="margin: 20px 20%" > 欢迎登录,${person.name}! </div > </body > </html >
login.ftl
1 2 3 4 5 6 7 8 9 10 11 12 13 <!doctype html > <html lang ="en" > <#include "../common/head.ftl"> <body > <div id ="app" style ="margin: 20px 20%" > <form action ="/demo/user/login" method ="post" > 用户名<input type ="text" name ="name" placeholder ="用户名" /> 密码<input type ="password" name ="password" placeholder ="密码" /> <input type ="submit" value ="登录" > </form > </div > </body > </html >
application.yml
1 2 3 4 5 6 7 8 9 server: port: 8080 servlet: context-path: /demo spring: freemarker: suffix: .ftl cache: false charset: UTF-8
java
1 2 3 4 5 6 7 com.halo.freemarker ├── controller │ ├── IndexController.java │ └── UserController.java ├── model │ └── Person.java └── FreemarkerApplication.java
IndexController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Controller @Slf4j public class IndexController { @GetMapping(value = {"", "/"}) public ModelAndView index (HttpServletRequest request) { ModelAndView mv = new ModelAndView(); Person person = (Person) request.getSession().getAttribute("person" ); if (ObjectUtil.isNull(person)) { mv.setViewName("redirect:/user/login" ); } else { mv.setViewName("page/index" ); mv.addObject(person); } return mv; } }
UserController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Controller @RequestMapping("/user") @Slf4j public class UserController { @PostMapping("/login") public ModelAndView login (Person person, HttpServletRequest request) { ModelAndView mv = new ModelAndView(); mv.addObject(person); mv.setViewName("redirect:/" ); request.getSession().setAttribute("person" , person); return mv; } @GetMapping("/login") public ModelAndView login () { return new ModelAndView("page/login" ); } }
Person.java
1 2 3 4 5 @Data public class Person { private String name; private String password; }
集成 Thymeleaf 模板引擎
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd" > <modelVersion > 4.0.0</modelVersion > <parent > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-parent</artifactId > <version > 2.5.0</version > <relativePath /> </parent > <groupId > com.halo</groupId > <artifactId > Thymeleaf</artifactId > <version > 0.0.1-SNAPSHOT</version > <name > Thymeleaf</name > <description > Demo project for Spring Boot</description > <properties > <java.version > 11</java.version > </properties > <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-thymeleaf</artifactId > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > <optional > true</optional > </dependency > <dependency > <groupId > cn.hutool</groupId > <artifactId > hutool-all</artifactId > <version > 5.6.5</version > </dependency > </dependencies > <build > <plugins > <plugin > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-maven-plugin</artifactId > </plugin > </plugins > </build > </project >
resources
1 2 3 4 5 6 7 8 resources ├── application.yml └── templates ├── common │ └── head.html └── page ├── index.html └── login.html
application.yml
1 2 3 4 5 6 7 8 9 10 11 server: port: 8080 servlet: context-path: /demo spring: thymeleaf: mode: HTML encoding: UTF-8 servlet: content-type: text/html cache: false
head.html
1 2 3 4 5 6 7 8 9 10 11 12 <!DOCTYPE html > <html xmlns:th ="http://www.thymeleaf.org" > <head th:fragment ="header" > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" > <meta http-equiv ="X-UA-Compatible" content ="ie=edge" > <title > spring-boot-demo-template-thymeleaf</title > </head > <body > </body > </html >
index.html
1 2 3 4 5 6 7 8 9 <!doctype html > <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <header th:replace ="~{common/head :: header}" > </header > <body > <div id ="app" style ="margin: 20px 20%" > 欢迎登录,<span th:text ="${user.name}" > </span > ! </div > </body > </html >
login.html
1 2 3 4 5 6 7 8 9 10 11 12 13 <!doctype html > <html lang ="en" xmlns:th ="http://www.thymeleaf.org" > <header th:replace ="~{common/head :: header}" > </header > <body > <div id ="app" style ="margin: 20px 20%" > <form action ="/demo/user/login" method ="post" > 用户名<input type ="text" name ="name" placeholder ="用户名" /> 密码<input type ="password" name ="password" placeholder ="密码" /> <input type ="submit" value ="登录" > </form > </div > </body > </html >
java
1 2 3 4 5 6 7 com.halo.thymeleaf ├── controller │ ├── IndexController.java │ └── UserController.java ├── model │ └── User.java └── FreemarkerApplication.java
IndexController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Controller @Slf4j public class IndexController { @GetMapping(value = {"", "/"}) public ModelAndView index (HttpServletRequest request) { ModelAndView mv = new ModelAndView(); User user = (User) request.getSession().getAttribute("user" ); if (ObjectUtil.isNull(user)) { mv.setViewName("redirect:/user/login" ); } else { mv.setViewName("page/index" ); mv.addObject(user); } return mv; } }
UserController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @Controller @RequestMapping("/user") @Slf4j public class UserController { @PostMapping("/login") public ModelAndView login (User user, HttpServletRequest request) { ModelAndView mv = new ModelAndView(); mv.addObject(user); mv.setViewName("redirect:/" ); request.getSession().setAttribute("user" , user); return mv; } @GetMapping("/login") public ModelAndView login () { return new ModelAndView("page/login" ); } }
User.java
1 2 3 4 5 6 @Data public class User { private String name; private String password; }
整合原生的 Mybatis
使用了 mybatis 官方提供的脚手架 mybatis-spring-boot-starter 可以很容易的和 Spring Boot 整合。