SpringBoot

目前最流行的Spring框架

简介

简单介绍

springBoot按照开发习惯对原来的xml配置提供了预配置,开发人员使用springBoot框架,不用再手工配置xml

springBoot按包依赖习惯,提供了各个常用模块的依赖启动器starter

  • 官方提供的启动器如:spring-boot-starter-*
  • 第三方的启动器如:*-spring-boot-starter
  • 比如web模块,test模块,mybaits模块,redis模板

项目结构说明

src/main/java/*Application启动类,主类

src/main/resources/static静态资源路径(css/js/图片/视频。。。纯静态资源)

src/main/resources/templates视图模板文件。(html加thymeleaf模板引擎)

src/main/resources/application.properties项目核心配置文件。改默认配置的地方

pom.xml

父工程:项目有两个父工程,管理了jdk版本,管理了maven的resources配置,管理了常用依赖的版本.

jdk版本:重写父工程的java.version.重新制定jdk版本

dependency依赖:配置启动器依赖。

spring-boot-maven-plugin打包插件:打jar包的插件,配置启动类位置

项目运行方式

jar包运行:java -jar jar包名称

war包运行:为了tomcat调优,或者不用tomcat,需要打war包

  • pom中加入
1
2
3
4
<packaging>war</packaging>
<build>
<finalName>war包名称</finalName>
</build>
  • 默认tomcat启动器,设置scope为provided,避免与本地tomcat冲突
1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
  • 要有入口配置类,等价于web.xml,配置类从SpringBootServletInitializer抽象类派生,重写configure方法,把配置类加到环境中
1
2
3
4
5
6
7
8
9
10
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
// 等价于web.xml
public class WebServletInit extends SpringBootServletInitializer {

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Boot1Application.class);
}
}

配置文件

  • application**.yml:这个更常用**
  • application**.properties:这个的优先级更高**,重复配置以properties为主
  • 存放位置:
    1. /
    2. /config
    3. src/main/resources/.yml或者.properties
    4. src/main/resources/config/.yml或者.properties,优先级最高

启动类

  • @SpringBootApplicaiotn
    • @SpringBootConfiguration:表示当前类是一个配置类
      • @Configuration
    • @EnableAutoConfiguration:开启自动配置
      • @AutoConfigurationPackage:设置包扫描范围。获取启动类所在的包作为扫描包范围。
      • @Import({AutoConfigurationImportSelector.class}):
        • 选择到META-INF/spring.factories文件,找到keyorg.springframework.boot.autoconfigure.EnableAutoConfiguration的值,选择到117个配置类。通过Import注解导入到总配置类。
    • @ComponentScan:包扫描
      • @Controller,@Service,@Repository,@Bean,@Value,@Component,@AutoWired,@Resource,@Configuration
1
2
3
4
5
public static void main(String[] args) {
SpringApplication.run(WebcrmApplication.class, args);
}

"启动tomcat,filter,listener,启动标志,启动日志"

获取配置类中的自定义注解

@Value注解

  • @Value注解获取properties配置文件中的数据,例:@Value(“${key}”)
  • @PropertySource(“classpath:自定义properties文件的名称”),写到配置类上。

@ConfigurationProperties(prefix=””)

  • 集合注值
1
2
3
4
5
jdbc:
url: jdbc:mysql://localhost:3306/jtxyh
driverClassName: com.javasm.Driver
userName: root
password: root
1
2
3
4
5
6
@ConfigurationProperties(prefix = "jdbc")
public class MyDataSourceProperties {
private String url;
private String driverClassName;
private String userName;
private String password;

自定义banner

resources下添加banner.txt,自动加载

自定义欢迎页

resources/resources或resources/static或resources/public或/下自定义一个index.html文件,优先级由高到低

替换ico图标

静态资源路径下放favicon.ico图标

tomcat下的root下放favicon.ico

在页面的link标签引入favicon.ico

使用

自定义拦截器,消息转换器

使用核心接口WebMvcConfigurer 来自定义扩展

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
@Configuration  // 启动类自动加载这个类
public class MyWebMvcConfigurer implements WebMvcConfigurer {

// 做统一视图解析器
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/uinfo").setViewName("uinfo");
registry.addViewController("/cinfo").setViewName("cinfo");
registry.addViewController("/minfo").setViewName("minfo");
}

// 设置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// new MyInterceptor()是自己写一个继承HandlerInterceptor接口的拦截器
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/login","/");
}

//数据格式工具
@Override
public void addFormatters(FormatterRegistry registry) {
// new MyDateFormater()是自定义的一个格式化日期的类,继承Converter<String,Date>接口
registry.addConverter(new MyDateFormater());
}

// 静态资源
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 静态资源下的文件会放行,但文件夹中的文件不会,所以如果有文件夹就这样设置
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
}

异常处理

  • 在SpringBoot中,自动配置机制会加载ErrorMvcAutoConfiguration类,在该类中由basicErrorController主要负责发生错误后的页面跳转,而basicErrorController中的errorHtml()和error()方法就分别是返回html和json的两个控制器。
  • 当用浏览器访问时,出错,返回错误页面,页面包含
    • timestamp,status,message,error,path
  • 非浏览器客户端访问时,返回的json字符串,
1
2
3
4
5
{
"timestamp": "2019-12-20T02:27:45.856+0000",
"status": 404, "error": "Not Found",
"message": "No message available",
"path": "/page"}

springboot异常处理1.png
springboot异常处理3.png
springboot异常处理4.png
springboot异常处理2.png

自定义异常处理

  1. 自定义错误信息:从DefaultErrorAttributes派生子类
  2. 自定义错误页面
    • 创建error.html,得到自定义错误信息
    • 或者创建error目录,下加4xx.html,5xx.html
1
2
3
4
5
6
7
8
public class MyErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(webRequest, includeStackTrace);
// 在map中添加自定义要显示的异常信息
return map;
}
}

日志集成

SpringBoot默认集成有日志功能,使用的是Apache的commons-logging做日志的输出功能,且使用的logback的日志机制

替换默认使用的日志:

排除默认的logging依赖

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<!-- 排除默认的依赖 -->
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>

加入log4j2依赖

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

自定义log4j2模板

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appenders>
<!-- 控制台输出 -->
<console name="Console" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %class %L %M -- %msg%n" />
</console>

<!-- fileName:输出路径 filePattern:命名规则 -->
<RollingFile name="RollingFileDebug"
fileName="E:/logs/debug.log"
filePattern="E:/logs/$${date:yyyy-MM-dd}/debug-%d{yyyy-MM-dd}-%i.log">
<Filters>
<ThresholdFilter level="DEBUG" />
<ThresholdFilter level="INFO" onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
<!-- 输出格式 -->
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %class{36} %L %M - %msg%n" />
<Policies>
<!-- 单个日志文件的大小限制 -->
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
<!-- 最多保留20个日志文件 -->
<DefaultRolloverStrategy max="20" />
</RollingFile>

<RollingFile name="RollingFileInfo"
fileName="E:/logs/info.log"
filePattern="E:/logs/$${date:yyyy-MM-dd}/info-%d{yyyy-MM-dd}-%i.log">
<Filters>
<ThresholdFilter level="INFO" />
<ThresholdFilter level="WARN" onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
<!-- 输出格式 -->
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n" />
<Policies>
<!-- SizeBasedTriggeringPolicy单个文件的大小限制 -->
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
<!-- DefaultRolloverStrategy同一个文件下的最大文件数 -->
<DefaultRolloverStrategy max="20" />
</RollingFile>

<RollingFile name="RollingFileWarn"
fileName="E:/logs/warn.log"
filePattern="E:/logs/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log">
<Filters>
<ThresholdFilter level="WARN" />
<ThresholdFilter level="ERROR" onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
<PatternLayout
pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
<Policies>
<!--<TimeBasedTriggeringPolicy modulate="true" interval="1"/> -->
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
<!--最多保留20个日志文件 -->
<DefaultRolloverStrategy max="20" min="0" />
</RollingFile>

<RollingFile name="RollingFileError"
fileName="E:/logs/error.log"
filePattern="E:/logs/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log">
<Filters>
<ThresholdFilter level="ERROR" />
<ThresholdFilter level="FATAL" onMatch="DENY"
onMismatch="NEUTRAL" />
</Filters>
<PatternLayout
pattern="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n" />
<Policies>
<!--<TimeBasedTriggeringPolicy modulate="true" interval="1"/> -->
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
<!--最多保留20个日志文件 -->
<DefaultRolloverStrategy max="20" min="0" />
</RollingFile>
</appenders>

<loggers>
<root level="debug">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileDebug"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
</root>

<logger name="org.springframework" level="error"></logger>
<logger name="org.mybatis.spring" level="error"></logger>
<logger name="org.apache.ibatis" level="error"></logger>

<!-- 下面是实现异步日志 -->
<!--过滤掉spring和mybatis的一些无用的debug信息 -->
<!-- <AsyncLogger name="org.springframework" level="error" includeLocation="true">
<AppenderRef ref="RollingFileError"></AppenderRef>
</AsyncLogger>
<AsyncLogger name="org.mybatis" level="error" includeLocation="true">
<AppenderRef ref="RollingFileError"></AppenderRef>
</AsyncLogger>
<AsyncLogger name="com.alibaba.druid" level="error" includeLocation="true">
<AppenderRef ref="RollingFileError"></AppenderRef>
</AsyncLogger>
<AsyncLogger name="org.apache.ibatis" level="error" includeLocation="true">
<AppenderRef ref="RollingFileError"></AppenderRef>
</AsyncLogger>

<AsyncRoot level="debug" includeLocation="true">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileDebug"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
<appender-ref ref="RollingFileFatal"/>
</AsyncRoot> -->

</loggers>
</configuration>

使用

1
2
3
4
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// 日志记录,在需要做日志记录的类上添加就可以了
private Logger l = LoggerFactory.getLogger(UinfoHandler.class);

Mybatis集成

  • 在SpringBoot中默认采用DataSourceAutoConfiguration来配置数据源(DataSource)。官方默认只需要在application配置文件中使用简单的配置就可以连接数据库。
  • 当加入了Druid-starter之后,它的DruidDataSourceAutoConfigure默认初始化了一个创建DataSource的方法。而这个DataSource默认就是读取当前application配置文件中的spring.datasource.druid的值,由此创建了基于Druid的数据源

SpringBoot配置DataSource.png

  • 在pom.xml添加依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <!-- mybatis依赖,mybatis与spring整合-->
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
    </dependency>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    </dependency>
    <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
    </dependency>
    <!--分页启动器-->
    <dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.2.12</version>
    </dependency>
  • 配置java目录下的配置资源扫描和逆向工程插件

    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
    <build>
    <resources>
    <resource>
    <directory>src/main/java</directory>
    <includes>
    <include>**/*.xml</include>
    </includes>
    </resource>
    </resources>
    <!--逆向工程插件-->
    <plugins>
    <plugin>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <version>1.3.2</version>
    <dependencies>
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.34</version>
    </dependency>
    </dependencies>
    <configuration>
    <overwrite>true</overwrite>
    <configurationFile>src/main/resources/generator.xml</configurationFile>
    </configuration>
    </plugin>
    </plugins>
    </build>
  • 配置数据库连接信息

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
spring:
datasource:
name: mysql_test
type: com.alibaba.druid.pool.DruidDataSource
#druid相关配置
druid:
#监控统计拦截的filters
filters: stat
driver-class-name: com.mysql.cj.jdbc.Driver
#基本属性
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=GMT%2B8&useSSL=false
username: root
password: jiang110
#配置初始化大小/最小/最大
initial-size: 1
min-idle: 1
max-active: 20
#获取连接等待超时时间
max-wait: 60000
#间隔多久进行一次检测,检测需要关闭的空闲连接
time-between-eviction-runs-millis: 60000
#一个连接在池中最小生存的时间
min-evictable-idle-time-millis: 300000
validation-query: SELECT 'x'
#空闲连接是否被回收
test-while-idle: true
#申请连接时是否检测有效性
test-on-borrow: false
#归还连接时是否检测有效性
test-on-return: false

# 配置mybatis映射
mybatis:
mapper-locations: classpath:io/jtxyh/webcrm/*/mapper/*.xml
type-aliases-package: io.jtxyh.webcrm
  • 启动MapperScan扫描

    1
    2
    // 在主启动类上加
    @MapperScan(basePackages = "io.jtxyh.webcrm.*.mapper") // 扫描mapper文件做映射
  • 开启注解式事务

    1
    2
    3
    // 在主启动类上加
    // 开启事务结合@Transactional注解使用
    @EnableTransactionManagement

Redis集成

  • 添加redis启动器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!--redis整合-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
  • 配置redis
1
2
3
4
5
spring:
redis:
host: 127.0.0.1
port: 6379
password: root
  • redis使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Autowired
private StringRedisTemplate rt;
private String key = "uinfo:";

@GetMapping("select/{uid}")
public Uinfo selectUinfoById(@PathVariable("uid") String uid){
// 存储到redis中
ValueOperations<String, String> ops = rt.opsForValue();
Uinfo uinfo = null;
String redisKey = key+uid;
String ouinfo = ops.get(redisKey);
if(ouinfo == null){
uinfo = us.selectByPrimaryKey(uid);
ops.set(redisKey, JSON.toJSONString(uinfo));
}else {
uinfo = JSON.parseObject(ouinfo,Uinfo.class);
}
return uinfo;
}
  • redis默认使用了StringRedisTemplateRedisTemplate,做序列化存储
    • StringRedisTemplate默认泛型都是String,默认采用string做序列化
    • RedisTemplate默认泛型都是Object,默认采用JDK做序列化
      • 可以重写RedisTemplate方法,改变默认的序列方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 自定义RedisTemplate序列化方式
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
// 设置键的序列化方式为string序列化
template.setKeySerializer(new StringRedisSerializer());
// 设置值的序列化方式为fastJson序列化
template.setKeySerializer(new GenericFastJsonRedisSerializer());
// 设置hash的值的序列化方式为string
template.setHashKeySerializer(new StringRedisSerializer());
// 设置值的序列化方式为fastJson序列化
template.setHashValueSerializer(new GenericFastJsonRedisSerializer());
return template;
}
  • 注解式使用redis

    springboot使用Redis注解.png

    1. 在启动类上加**@EnableCaching**

    2. 在需要使用redis的类上使用注解

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18

      // 先去缓存找,找到返回,找不到查数据加入缓存
      // 在查询方法上加Cacheable注解,先去缓存中找userinfo:23的值,找到则返回,找不到执行方法,把方法返回值加入缓存。
      // condition:方法执行之前的条件判断
      // unless:方法执行完后的条件判断
      @Cacheable(cacheNames = "userinfo",key = "#uid",unless = "#result==null")
      public Uinfo getUserById(@PathVariable("uid") int uid){
      Uinfo sysuser = sm.selectByPrimaryKey(uid);
      return sysuser;
      }

      // 用在删改的方法上。当删除和修改数据时,把缓存中对应数据删除掉。
      @GetMapping("/udel/{uid}")
      @CacheEvict(cacheNames = "userinfo",key = "#uid")
      public int delUserById(@PathVariable("uid") int uid){
      int rows = sm.deleteByPrimaryKey(uid);
      return rows;
      }

定时任务

  • 引入依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>
  • 在启动类上加注解开启定时任务

    1
    @EnableScheduling // 开启定时任务
  • 使用

    1
    2
    3
    4
    5
    6
    7
    8
    @Component
    public class MyQuery {
    // 每5分钟执行一次
    @Scheduled(cron = "0 0/5 * * * ?")
    public void run(){
    System.out.println("定时任务执行了。。。。");
    }
    }

兼容jsp

  • 修改项目为打war包的格式

    1
    2
    3
    4
    <packaging>war</packaging>
    <build>
    <finalName>war包名称</finalName>
    </build>
  • 设置内置tomcat为provided

    1
    2
    3
    4
    5
    6
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <version>2.1.11.RELEASE</version>
    <scope>provided</scope>
    </dependency>
  • 加入jsp引擎,jstl支持

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
    </dependency>
    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    </dependency>
  • 创建webapp目录

  • 创建继承SpringBootServletInitializer类代替web.xml

    1
    2
    3
    4
    5
    6
    7
    //等价于web.xml
    public class MyServletInit extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    return builder.sources(Boot3Application.class);
    }
    }

不抛出404页面

1
2
3
4
5
spring:
mvc:
throw-exception-if-no-handler-found: true
resources:
add-mappings: false

相关文章

数据库连接池

Junit和Spring

Tomcat

Servlet

Request,Response和ServletContext

Cookie和Session

JSP和EL和Jstl

Filter和Listener

Mybatis

SpringCache