什么是SpringBoot?
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
简单来说,springboot就是会我们自动配置spring框架,从而简化开发流程。
所以约定大于配置变得尤为重要。
构建SpringBoot程序
方式一、从官网构建
在以下网站中初始化配置后,下载到本地使用idea导入即可。
1
|
https://start.spring.io/
|
方式二、使用idea自带方式构建
在new project窗口中选择Spring initializr,然后初始化配置即可。
tips:在resources目录下修改或新建banner.txt可以修改spring启动时欢迎语
模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
_ooOoo_
o8888888o
88" . "88
(| -_- |)
O\ = /O
____/`---'\____
.' \\| |// `.
/ \\||| : |||// \
/ _||||| -:- |||||- \
| | \\\ - /// | |
| \_| ''\---/'' | |
\ .-\__ `-` ___/-. /
___`. .' /--.--\ `. . __
."" '< `.___\_<|>_/___.' >'"".
| | : `- \`.;`\ _ /`;.`/ - ` : | |
\ \ `-. \_ __\ /__ _/ .-` / /
======`-.____`-.___\_____/___.-`____.-'======
`=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
佛祖保佑 永无BUG
|
效果:
SpringBoot原理初探
1、启动器 spring-boot-starter
1
2
3
4
|
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
|
springboot-boot-starter-xxx:就是spring-boot的场景启动器
spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;
2、主启动类
默认的主动启动类
1
2
3
4
5
|
//@SpringBootApplication 来标注一个主程序类//说明这是一个Spring Boot应用@SpringBootApplicationpublic class SpringbootApplication {
public static void main(String[] args) { //以为是启动了一个方法,没想到启动了一个服务
SpringApplication.run(SpringbootApplication.class, args);
}
}
|
@SpringBootApplication注解
作用:标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
spring.factories
我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!
SpringApplication
这个类主要做了以下四件事情:
1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类
YAML
YAML 是 “YAML Ain’t a Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)。
YAML 的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。
YAML 的配置文件后缀为 .yml,如:application.yml 。
基本语法
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- ‘#‘表示注释
数据类型
YAML 支持以下几种数据类型:
- 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
- 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
- 纯量(scalars):单个的、不可再分的值
YAML对象
对象键值对使用冒号结构表示 key: value,冒号后面要加一个空格。
也可以使用 key:{key1: value1, key2: value2, …}。
还可以使用缩进表示层级关系;
1
2
3
|
key:
child-key: value
child-key2: value2
|
YAML数组
YAML 支持多维数组,可以使用行内表示:
1
|
key: [value1, value2, ...]
|
数据结构的子成员是一个数组,则可以在该项下面缩进一个空格。
例子
1
2
3
4
5
6
7
8
9
|
companies:
-
id: 1
name: company1
price: 200W
-
id: 2
name: company2
price: 500W
|
复合结构
数组和对象可以构成复合结构,例:
1
2
3
4
5
6
7
8
9
|
languages:
- Ruby
- Perl
- Python
websites:
YAML: yaml.org
Ruby: ruby-lang.org
Python: python.org
Perl: use.perl.org
|
转换为 json 为:
1
2
3
4
5
6
7
8
9
|
{
languages: [ 'Ruby', 'Perl', 'Python'],
websites: {
YAML: 'yaml.org',
Ruby: 'ruby-lang.org',
Python: 'python.org',
Perl: 'use.perl.org'
}
}
|
配置文件切换
1、多环境切换
profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境;
我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;
例如:
application-test.properties 代表测试环境配置
application-dev.properties 代表开发环境配置
但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件;
我们需要通过一个配置来选择需要激活的环境:
1
2
3
|
#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev
|
yaml的多文档块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
server:
port: 8081
#选择要激活那个环境块
spring:
profiles:
active: prod
---
server:
port: 8083
spring:
profiles: dev #配置环境的名称
---
server:
port: 8084
spring:
profiles: prod #配置环境的名称
|
注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!
2、配置文件加载位置
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:
1
2
3
4
|
优先级1:项目路径下的config文件夹配置文件
优先级2:项目路径下配置文件
优先级3:资源路径下的config文件夹配置文件
优先级4:资源路径下配置文件
|
使用SpringBoot进行Web开发
1、静态资源处理
在springboot中,我们可以使用以下方式处理今天资源。
- webjars
localhost:8080/webjars/
- public,static,/**,resources
localhost:8080
优先级 :resources>static>public
2、模板引擎Thymeleaf
模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。只不过呢,就是说不同模板引擎之间,他们可能这个语法有点不一样。其他的我就不介绍了,我主要来介绍一下SpringBoot给我们推荐的Thymeleaf模板引擎,这模板引擎呢,是一个高级语言的模板引擎,他的这个语法更简单。而且呢,功能更强大。
Thymeleaf 官网:https://www.thymeleaf.org/
Thymeleaf 在Github 的主页:https://github.com/thymeleaf/thymeleaf
Spring官方文档:找到我们对应的版本
https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter
pom依赖:
1
2
3
4
5
|
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
|
3、页面国际化
国际化的作用就是使页面支持多种语言切换,从而使页面国际化!
编写配置文件
-
我们在resources资源文件下新建一个i18n目录,存放国际化配置文件
-
建立一个login.properties文件,还有一个login_zh_CN.properties;发现IDEA自动识别了我们要做国际化操作;文件夹变了!
-
然后就行翻译处理,将所需要翻译的文本翻译后填入对应的文本框中
-
配置目录:在application.properties中配置
1
|
spring.messages.basename=i18n.login
|
配置页面国际化值
去页面获取国际化的值,查看Thymeleaf的文档,找到message取值操作为:#{…}
配置国际化解析
假如我们现在想点击链接让我们的国际化资源生效,就需要让我们自己的Locale生效!我们去自己写一个自己的LocaleResolver,可以在链接上携带区域信息!修改一下前端页面的跳转连接:
我们去写一个处理的组件类!
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
|
package com.kuang.component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
//可以在链接上携带区域信息
public class MyLocaleResolver implements LocaleResolver {
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest request)hailagn {
String language = request.getParameter("l");
Locale locale = Locale.getDefault(); // 如果没有获取到就使用系统默认的
//如果请求链接不为空
if (!StringUtils.isEmpty(language)){
//分割请求参数
String[] split = language.split("_");
//国家,地区
locale = new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
|
为了让我们的区域化信息能够生效,我们需要再配置一下这个组件!在我们自己的MvcConofig下添加bean;
1
2
3
4
|
@Bean
public LocaleResolver localeResolver(){
return new MyLocaleResolver();
}
|
配置登录拦截器
-
编写拦截器类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object loginUser = request.getSession().getAttribute("loginUser");
if(loginUser==null){
request.setAttribute("msg","没有权限,请先登录");
//转发至主页
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{
return true;
}
}
}
|
-
实例化拦截器并注入
1
2
3
4
|
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index.html","/","/user/login","/css/**","/img/**");
}
|
拦截请求时注意过滤静态资源,拦截静态资源会导致css样式不可用,无法访问请求等状况。
SpringBoot整合Mybatis
在绝大多数开发场景中,我们都需要通过数据库进行数据的存储,就目前来说,Mybatis是一个比较常用的持久层框架,他能很好的帮助我们的开发,在下面的例子将会说明如何在springboot中整合mybatis。
官方文档:http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
Maven仓库地址:https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter
整合案例:
- 导Mybatis依赖:
1
2
3
4
5
|
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
|
- 配置数据源:
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
|
spring:
datasource:
username: root
password: root
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#Spring Boot 默认是不注入这些属性值的,需要自己绑定
#druid 数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
|
- 创建测试表:
- 创建实体类:
1
2
3
4
5
6
7
8
9
|
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int number;
private String name;
private int age;
private String sex;
}
|
5.在application.yml中配置mybatis实体类映射:
1
2
3
|
mybatis:
type-aliases-package: com.seawave.pojo
mapper-locations: classpath:mybatis/mapper/*.xml
|
6.编写UserMapper
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
|
<?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.seawave.mapper.UserMapper">
<!-- 查询所有用户-->
<select id="queryUserList" resultType="com.seawave.pojo.User">
select *
from student
</select>
<!-- 根据id查询用户-->
<select id="queryUserById" resultType="User">
select *
from student
where id = #{id}
</select>
<!--添加一个用户-->
<insert id="addUser" parameterType="User">
insert into student (name, age, sex)
values (#{name}, #{age}, #{sex})
</insert>
<!-- 更新一个用户-->
<update id="updateUser" parameterType="User">
update student
set name=#{name},
age=#{age},
sex=#{sex}where id =#{id}
</update>
<!--删除一个用户-->
<delete id="deleteUser" parameterType="int">
delete
from student
where id = #{id}
</delete>
</mapper>
|
- 在测试类中测试是否正常连接数据库
1
2
3
4
5
6
7
8
9
10
11
12
|
@SpringBootTest
class Springboot05MybatisApplicationTests {
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
for (User user : userMapper.queryUserList()) {
System.out.println(user);
}
}
}
|
成功即可读取到数据库表内容:
拦截器配置模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截路径
String[] addPathPatterns = {
"/page/**","/student/**"
};
//排除路径
String[] excludePathPatterns = {
"/student/login","/student/register"
};
registry.addInterceptor(new HandlerController()).addPathPatterns(addPathPatterns).excludePathPatterns(excludePathPatterns);
}
}
|