SpringBoot

启动方式

Spring boot项目启动方式
|启动方式|命令|
|-|-|
|主类启动|Run 类|
|以spring-boot的maven插件spring-boot-maven-plugin启动|mvn spring-boot:run|
|jar/war启动| mvn clean package && java -jar xxx.jar |

带前端静态资源一键打包

配置文件

application.properties

1
2
3
4
spring.mvc.static-path-pattern=/static/**
spring.mvc.view.suffix=.html
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/

或者application.yml

1
2
3
4
5
6
7
8
9
spring:
mvc:
static-path-pattern: /static/**
view:
suffix: .html
throw-exception-if-no-handler-found: true

resources:
static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/

controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package *******;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SystemController {
private static final transient Logger LOG = LoggerFactory.getLogger(SystemController.class);

/**
* Return to the index page.
*
* @return the index page
*/
@RequestMapping("/")
public String index() {
LOG.debug("return to the system index page.");
// the 'static' prefix MUST BE the same as the value of 'spring.mvc.static-path-pattern' field defined in 'application.properties'
return "/static/index";
}

}

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
60
61
62
63
64
65
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*</include>
</includes>
<excludes>
<exclude>app/**/*</exclude>
<exclude>node/**/*</exclude>
</excludes>
</resource>
</resources>
</build>
<profiles>
<profile>
<id>node</id>
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.5</version>
<configuration>
<installDirectory>src/main/resources</installDirectory>
<workingDirectory>src/main/resources/app</workingDirectory>
</configuration>
<executions>
<execution>
<id>install node and npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<nodeVersion>v6.11.2</nodeVersion>
<downloadRoot>https://npm.taobao.org/mirrors/node/</downloadRoot>
</configuration>
</execution>
<execution>
<id>npm install</id>
<goals>
<goal>npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>npm build</id>
<goals>
<goal>npm</goal>
</goals>
<phase>generate-resources</phase>
<configuration>
<arguments>run build</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

打包

mvn clean package -Dmaven.test.skip=true -PdisableFindBug,node

mvn clean package -DskipTests -Pnode

跨域

全局

implements Filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.springframework.context.annotation.Configuration;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
}

单个接口

@CrossOrigin注解

1
2
3
4
5
6
public class GoodsController {

@CrossOrigin(origins = "http://localhost:4000")
@GetMapping("goods-url")
public Response queryGoodsWithGoodsUrl(@RequestParam String goodsUrl) throws Exception {}
}

mysql

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
1
2
3
4
spring.datasource.url=jdbc:mysql://localhost:3306/grid?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mybatis

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>

让mapper类能够被Spring管理(引入Mybatis)

graph LR
A(注解) --> B{全局}
B -->|YES|B1(MapperScan)
B -->|NO|B2(Mapper)
  1. @Mapper
    • 单个注解
    • 要对每一个mapper类都注解@Mapper
    • 在每一个mapper接口前指定
1
2
3
4
@Mapper
public interface UserMapper {
Long getCreditLevelById(@Param("id") String id);
}
  1. @MapperScan(“com.sample.ch1.persistence”)
    • 全局注解
    • 全局指定要扫描的Mapper类的包路径
    • 在项目入口文件处指定
1
2
3
4
5
6
7
@SpringBootApplication
@MapperScan("com.sample.ch1.persistence")
public class Ch1Application {
public static void main(String[] args) {
SpringApplication.run(Ch1Application.class, args);
}
}

mapper两种写法

graph LR
A{SQL独立写入xml文件} --> |YES|B(两个文件)
A-->|NO|C(一个文件)

C --> C1(interface)

B --> B1(interface)
B --> B2(.xml)
B1 -.文件名相同+sql的Id与接口方法名相同.- B2
  1. SQL直接与接口写在同一文件
1
2
3
4
public interface UserMapper {
@Select("select credit_level from `user` where `id` = #{id}")
Long getCreditLevelById(@Param("id") String id);
}
  1. SQL单独写在xml文件中

接口文件

1
2
3
public interface UserMapper {
Long getCreditLevelById(@Param("id") String id);
}

xml文件

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sample.ch1.persistence.UserMapper">

<select id="getCreditLevelById" resultType="java.lang.Long" parameterType="java.lang.String">
select credit_level from `user` where `id` = #{id}
</select>

</mapper>

mapper.xml的位置

graph LR
B2(.xml) --> D{xml位置}

D --> E(resources静态文件夹)
D --> F(与interface同目录)

E --> E1(配置application.properties)
F --> F1(配置pom.xml)
  1. resources
    maven项目的mapper.xml默认放resources中,项目构建时会自动加载到target。
    此方案需配置application.properties。
1
2
3
4
5
6
7
8
9
#application.properties

#mybatis

#Mapper.xml存放位置。当Mapper.xml与对应Mapper接口同一位置时,不用指定该属性的值。
mybatis.mapper-locations=classpath:mapping/*.xml

#实体类所在包。多个package用逗号或者分号分隔。
mybatis.type-aliases-package=com.sample.ch1.model
  1. 非resources
    非resources的.xml(比如,和Mapper接口置于同一文件夹),默认不会编译到target。
    需要在pom.xml文件的build添加resource资源列表。
1
2
3
4
5
6
7
8
9
10
11
12
<build>
<resources>
<resource>
<directory>src/main/java/com/sample/ch1/persistence</directory>
<targetPath>com/sample/ch1/persistence</targetPath>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>

mybatis-generator

mybatis自动代码生成工具,自动生成如下内容:

  1. 实体
  2. mapper接口
  3. xml配置文件
使用

官网下载
https://github.com/mybatis/generator/releases

引入方式有两种:

  1. 直接下载mybatis-generator-core-1.3.7.jar,以命令行方式运行
  2. 添加maven依赖,以maven方式执行

参考

  1. MyBatis
  2. MyBatis generator

日志

SpringBoot支持多种日志框架,如 log4j2 \ logback \ java util logging 等。其中logback是SpringBoot内置的日志框架。

由于log4j2 性能 和配置的灵活性,SpringBoot1.4以上版本建议使用log4j2。

配置log4j2

去掉内置框架(pom.xml)
1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--去掉内置-->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
引入log4j2 (pom.xml)
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
配置log4j2
graph TB
A(配置log4j2) --> B(log4j2-spring.xml)
A --> C(application.properties)
B --- D{所处位置}
D --- D1(resources静态资源)
D --- D2(config配置文件夹)

D1 -.application.properties.- E(logging.config= classpath:log4j2.xml)
D2 -.application.properties.- F(logging.config=./config/log4j2-spring.xml)

D1 -.- E1(命名为log4j2-spring.xml也可省配置)
C -.- G(直接命令行配置)

配置log4j2有两种方式:

  1. 单独创建xml, 在application.properties引入

  2. 在application.properties通过命令行配置

无论上述哪种方式,当①位置在resources中,且②命名符合spring标准,则可省去在application.properties引入。命名规则如下:

  • Logback: logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
  • Log4j: log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
  • Log4j2: log4j2-spring.xml, log4j2.xml
  • JDK (Java Util Logging): logging.properties

否则,需要做如下引入:

1
2
3
4
5
6
7
#application.properties

#若放置于config
logging.config=./config/log4j2-spring.xml

#若放置于resources
#logging.config= classpath:log4j2.xml

语法说明

日志配置结构
graph TB

A(Configuration) --> B(Properties)
A --> C(Appenders)
A --> D(Loggers)

B --> B1(Property)

C --> C1(Console)
C --> C2(RollingFile)

D --> D1(Root必须)
D --> D2(Logger)

C1 -.- E(PatternLayout)
C2 -.- E

E --- E1(格式输出规则)

D1 -.- F(AppenderRef)
D2 -.- F
格式输出规则
格式 说明
%d{HH: mm:ss.SSS} / %date 日志输出时间
%thread 输出日志的进程名字,这在Web应用以及异步任务处理中很有用
%-5level 日志级别,并且使用5个字符靠左对齐
%level 级别
%- 左对齐
%5 5个固定字符,不足用空格补齐
%logger{36} / %c 包名+类名,{36}限制长度,长度不够则尽可能显示雷鸣,压缩报名
%msg / %m 日志消息
%n 平台的换行符
%M 方法名字
%L 日志调用所在代码行,线上不建议
级别level

Log4j建议只使用四个级别,优先级从高到低分别是error、warn、info、debug。如果将日志设置在某个等级,则只能打印>=等级的日志。

graph TB

A(日志级别) --- B(aLL)
A --- C(trace)
A--- D(debug)
A --> E[info]
A --> F[warn]
A --> G[error]
A --> H(fatal)
A --> I(off)

D --- D1[常用]
E --- E1[常用]
F --- F1[常用]
G --- G1[常用]
级别 描述
all 最低等级,打开所有日志记录
trace 一般不会使用
debug 细粒度信息,有助于调试,用于开发过程中打印一些运行信息
info 粗粒度信息,突出应用程序的运行过程。可在生产环境中输出程序运行的重要信息,但是不能滥用,避免打印过多的日志。
warn 会出现潜在错误的场景,有些信息不是错误信息,但是也要给程序员提示。
error 虽然发生错误,但不影响系统继续运行。打印错误和异常信息。如果不想输出太多的日志,可以使用这个级别。
fatal 严重错误,将导致应用程序退出。这种级别可以直接停止程序。
off 最高等级,用于关闭所有日志记录

参考

  1. log4j官网
  2. 日志管理之整合篇
  3. Spring Boot 日志配置(超详细)

Swagger2

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
pom.xml      
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>

创建配置类 Swagger2Config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
@EnableSwagger2
public class Swagger2Config implements WebMvcConfigurer {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(aipInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.sample.ch1.controller"))
.paths(PathSelectors.any())
.build();
}

private ApiInfo aipInfo() {
return new ApiInfoBuilder()
.title("demo rest api")
.description("Spring BOOT 2基础示例")
.license("@2019")
.version("1.0.0")
.build();
}
}

在controller使用

1
2
3
4
5
6
@Api(value = "用户管理", tags = "用户管理接口")
public class UserController {
@ApiOperation(value = "查看用户列表") // 注意指定method
@RequestMapping(value = "/list", method = RequestMethod.GET)
public List<UserDto> getUserList() {}
}

访问 http://localhost:8080/swagger-ui.html

启用场景

Swagger文档在开发环境可查看,在生产环境不可查看。

1
2
3
#application.properties

swagger.enable=false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Swagger2Config

@Value("${swagger.enable}")
private boolean swaggerEnable;

@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(swaggerEnable) // 启用
.apiInfo(aipInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.sample.ch1.controller"))
.paths(PathSelectors.any())
.build();
}

参考

  1. Spring Boot中使用Swagger2构建强大的RESTful API文档

Spring Boot Actuator

监控和管理Spring Boot应用,比如健康检查、审计、统计和HTTP追踪等。

使用

安装依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

启动项目

1
mvn spring-boot:run

访问地址,展示所有通过HTTP暴露的endpoints

1
http://localhost:8080/actuator

访问具体endpoints,查看状态,如果UP则健康,DOWN不健康

1
http://localhost:8080/actuator/health

参考

Spring Boot Actuator:健康检查、审计、统计和监控

REST API

Version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
public class StudentVersioningController {

@GetMapping("v1/student")
// @GetMapping(value = "/student/param", params = "version=1")
// @GetMapping(value = "/student/header", headers = "X-API-VERSION=1")

public StudentV1 studentV1() {
return new StudentV1("Bob Charlie");
}

@GetMapping("v2/student")
public StudentV2 studentV2() {
return new StudentV2(new Name("Bob", "Charlie"));
}

名词

POJO

  1. Plain Ordinary Java Object,简单Java对象。
  2. 只有一些属性及getter/setter的实体类,没有业务逻辑。
  3. 常用于model或dto。

JavaBean

  1. 提供一个默认的无参构造函数。
  2. 需要被序列化并且实现了Serializable接口。
  3. 可能有一系列可读写属性。
  4. 可能有一系列的”getter”或”setter”方法。

JavaBean与POJO

  1. POJO是比Javabean更纯净的简单类或接口。POJO严格地遵守简单对象的概念,而一些JavaBean中往往会封装一些简单逻辑。
  2. POJO主要用于数据的临时传递,它只能装载数据, 作为数据存储的载体,而不具有业务逻辑处理的能力。
  3. Javabean虽然数据的获取与POJO一样,但是javabean当中可以有其它的方法。
-------------Keep It Simple Stupid-------------
0%