文章目录
- SpringBoot学习笔记
- 自己对SpringBoot的理解
- 1.父依赖
- 1.1启动器 spring-boot-starter
- 1.2默认的主启动类
- 1.3@SpringBootApplication
- 1.4@ComponentScan
- 1.5@SpringBootConfiguration
- 1.6@EnableAutoConfiguration
- 1.7spring.factories
- 1.8不简单的方法
- 1.9SpringApplication
- 1.2.0run方法流程分析
- 1.2.1SpringBoot理解
- 2.yaml配置
- 2.1配置文件
- 2.2yaml概述
- 2.3yaml基础语法
- 2.4yaml注入配置文件
- 2.5加载指定的配置文件
- 2.6配置文件占位符
- 2.7回顾properties配置
- 对比小结
- 3.JSR303数据校验及多环境切换
- 3.1先看看如何使用
- 3.2常见参数
- 3.3多配置文件
- 3.4yaml的多文档块
- 3.5配置文件加载位置
- 3.6拓展,运维小技巧
- 4.SpringBoot Web开发
- 4.1.jar:webapp!
- 4. 2.模板引擎
- 4.3引入Thymeleaf
- 5.MVC配置原理
- 5.1扩展SpringMvc
- 6.员工管理系统
- 6.1准备工作
- 准备工作
- 配置文件编写
- 配置文件生效探究
- 配置页面国际化值
- 配置国际化解析
- 7.Data
- 创建测试项目测试数据源
- JDBCTemplate
- 测试
- 8.Myabtis整合
- 整合测试
- 我们增加一个员工类再测试下,为之后做准备
- 9.SpringSecurity(安全)
- 安全简介
- 实战测试
- 实验环境搭建
- 认识SpringSecurity
- 认证和授权
- 权限控制和注销
- 记住我
- 定制登录页
- 完整配置代码
- 10.Shiro
- 1、Shiro简介
- 【1】什么是Shiro?
- 【2】Shiro 的特点
- 2、核心组件
- Shiro报错
- 11.Shirio大整合
- 12.Swagger
- 1.导入依赖:
- 2.配置Config 开启Swagger
- 配置Swagger
- Swagger配置扫描接口
自己对SpringBoot的理解
1.首先SpringBoot的@Configuration是让我们知道他是一个配置类,然后SpringBoot会有一个自动匹配注解,去识别我们现在的环境是什么,是普通java还是javaweb,随即去激活所相应的要使用的配置文件,以及配置类,再进行自动加载,在properties中,我们用什么,他就会去匹配什么并且进行自动加载,我们进行yaml配置文件进行配置的时候,其实都是在SpringBoot封装的文件里面,在AutoConfiguration和properties进行配置绑定,这样我们就可以使用自定义了。
我们之前写的HelloSpringBoot,到底是怎么运行的呢,Maven项目,我们一般从pom.xml文件探究起;
笔记基本上是复刻和原本的狂神笔记
1.父依赖其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!
<parent> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-parentartifactId> <version>2.2.5.RELEASEversion> <relativePath/> parent>
点进去,发现还有一个父依赖
<parent> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-dependenciesartifactId> <version>2.2.5.RELEASEversion> <relativePath>../../spring-boot-dependenciesrelativePath>parent>
这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;
以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了;
1.1启动器 spring-boot-starter<dependency> <groupId>org.springframework.bootgroupId> <artifactId>spring-boot-starter-webartifactId>dependency>
springboot-boot-starter-xxx:就是spring-boot的场景启动器
spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;
SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;
主启动类
分析完了 pom.xml 来看看这个启动类
1.2默认的主启动类//@SpringBootApplication 来标注一个主程序类//说明这是一个Spring Boot应用@SpringBootApplicationpublic class SpringbootApplication {
public static void main(String[] args) { //以为是启动了一个方法,没想到启动了一个服务 SpringApplication.run(SpringbootApplication.class, args); }
}
但是**一个简单的启动类并不简单!**我们来分析一下这些注解都干了什么
1.3@SpringBootApplication作用:标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
进入这个注解:可以看到上面还有很多其他注解!
@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan( excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class}), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class})})public @interface SpringBootApplication { // ......}
1.4@ComponentScan
这个注解在Spring中很重要 ,它对应XML配置中的元素。
作用:自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中
1.5@SpringBootConfiguration作用:SpringBoot的配置类 ,标注在某个类上 , 表示这是一个SpringBoot的配置类;
我们继续进去这个注解查看
// 点进去得到下面的 @Component@Configurationpublic @interface SpringBootConfiguration {}
@Componentpublic @interface Configuration {}
这里的 @Configuration,说明这是一个配置类 ,配置类就是对应Spring的xml 配置文件;
里面的 @Component 这就说明,启动类本身也是Spring中的一个组件而已,负责启动应用!
我们回到 SpringBootApplication 注解中继续看。
1.6@EnableAutoConfiguration@EnableAutoConfiguration :开启自动配置功能
以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效;
点进注解接续查看:
@AutoConfigurationPackage :自动配置包
@Import({Registrar.class})public @interface AutoConfigurationPackage {}
@import :Spring底层注解@import , 给容器中导入一个组件
Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;
这个分析完了,退到上一步,继续看
@Import({AutoConfigurationImportSelector.class}) :给容器导入组件 ;
AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
1、这个类中有一个这样的方法
// 获得候选的配置protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //这里的getSpringFactoriesLoaderFactoryClass()方法 //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration List configurations = javaSpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct."); return configurations;}
2、这个方法又调用了 SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { String factoryClassName = factoryClass.getName(); //这里它又调用了 loadSpringFactories 方法 return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());}
3、我们继续点击查看 loadSpringFactories 方法
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { //获得classLoader , 我们返回可以看到这里得到的就是EnableAutoConfiguration标注的类本身 MultiValueMap result = (MultiValueMap)cache.get(classLoader); if (result != null) { return result; } else { try { //去获取一个资源 "META-INF/spring.factories" Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap();
//将读取到的资源遍历,封装成为一个Properties while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) { Entry<?, ?> entry = (Entry)var6.next(); String factoryClassName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) { String factoryName = var9[var11]; result.add(factoryClassName, factoryName.trim()); } } }
cache.put(classLoader, result); return result; } catch (IOException var13) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); } }}
4、发现一个多次出现的文件:spring.factories,全局搜索它
1.7spring.factories我们根据源头打开spring.factories , 看到了很多自动配置的文件;这就是自动配置根源所在!
WebMvcAutoConfiguration
我们在上面的自动配置类随便找一个打开看看,比如 :WebMvcAutoConfiguration
可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。
结论:
- SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
- 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
- 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
- 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
- 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
现在大家应该大概的了解了下,SpringBoot的运行原理,后面我们还会深化一次!
1.8不简单的方法SpringApplication
我最初以为就是运行了一个main方法,没想到却开启了一个服务;
@SpringBootApplicationpublic class SpringbootApplication { public static void main(String[] args) { SpringApplication.run(SpringbootApplication.class, args); }}
SpringApplication.run分析
分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;
1.9SpringApplication这个类主要做了以下四件事情:
1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类
查看构造器:
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) { // ...... this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.setInitializers(this.getSpringFactoriesInstances(); this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass();}
1.2.0run方法流程分析
跟着源码和这幅图就可以一探究竟了!
1.2.1SpringBoot理解- 自动装配
- run()
全面接管SpringMVC的配置!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q5HrVyEC-1652436064033)(C:\Users\一字先生\AppData\Roaming\Typora\typora-user-images\image-20220328202504692.png)]
如果不配置使用了这个注解就会爆红,去官网拿个dependency
org.springframework.boot
spring-boot-configuration-processor
true
或者使用javaconfig绑定配置文件的值
//加载指定的配置文件
@PropertySource(value="classpath:xxx.properties")
//SPEL表达式取出配置文件的值
@Value("${xx}")
2.yaml配置
2.1配置文件
SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的
-
application.properties
-
- 语法结构 :key=value
-
application.yml
-
- 语法结构 :key:空格 value
**配置文件的作用 :**修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;
比如我们可以在配置文件中修改Tomcat 默认启动的端口号!测试一下!
server.port=8081
2.2yaml概述
YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)
这种语言以数据作为中心,而不是以标记语言为重点!
以前的配置文件,大多数都是使用xml来配置;比如一个简单的端口配置,我们来对比下yaml和xml
传统xml配置:
8081
yaml配置:
server: prot: 8080
2.3yaml基础语法
说明:语法要求严格!
1、空格不能省略
2、以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。
3、属性和值的大小写都是十分敏感的。
字面量:普通的值 [ 数字,布尔值,字符串 ]
字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号;
k: v
注意:
-
“ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;
比如 :name: “kuang \n shen” 输出 :kuang 换行 shen
-
‘’ 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出
比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen
对象、Map(键值对)
#对象、Map格式k: v1: v2:
在下一行来写对象的属性和值得关系,注意缩进;比如:
student: name: qinjiang age: 3
行内写法
student: {name: qinjiang,age: 3}
数组( List、set )
用 - 值表示数组中的一个元素,比如:
pets: - cat - dog - pig
行内写法
pets: [cat,dog,pig]
修改SpringBoot的默认端口号
配置文件中添加,端口号的参数,就可以切换端口;
server: port: 8082
注入配置文件
yaml文件更强大的地方在于,他可以给我们的实体类直接注入匹配值!
2.4yaml注入配置文件1、在springboot项目中的resources目录下新建一个文件 application.yml
2、编写一个实体类 Dog;
package com.kuang.springboot.pojo;
@Component //注册bean到容器中public class Dog { private String name; private Integer age; //有参无参构造、get、set方法、toString()方法 }
3、思考,我们原来是如何给bean注入属性值的!@Value,给狗狗类测试一下:
@Component //注册beanpublic class Dog { @Value("阿黄") private String name; @Value("18") private Integer age;}
4、在SpringBoot的测试类下注入狗狗输出一下;
@SpringBootTestclass DemoApplicationTests {
@Autowired //将狗狗自动注入进来 Dog dog;
@Test public void contextLoads() { System.out.println(dog); //打印看下狗狗对象 }
}
结果成功输出,@Value注入成功,这是我们原来的办法对吧。
5、我们在编写一个复杂一点的实体类:Person 类
@Component //注册bean到容器中public class Person { private String name; private Integer age; private Boolean happy; private Date birth; private Map maps; private List
6、我们来使用yaml配置的方式进行注入,大家写的时候注意区别和优势,我们编写一个yaml配置!
person: name: qinjiang age: 3 happy: false birth: 2000/01/01 maps: {k1: v1,k2: v2} lists: - code - girl - music dog: name: 旺财 age: 1
7、我们刚才已经把person这个对象的所有值都写好了,我们现在来注入到我们的类中!
/*@ConfigurationProperties作用:将配置文件中配置的每一个属性的值,映射到这个组件中;告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应*/@Component //注册bean@ConfigurationProperties(prefix = "person")public class Person { private String name; private Integer age; private Boolean happy; private Date birth; private Map maps; private List
8、IDEA 提示,springboot配置注解处理器没有找到,让我们看文档,我们可以查看文档,找到一个依赖!
org.springframework.boot spring-boot-configuration-processor true
9、确认以上配置都OK之后,我们去测试类中测试一下:
@SpringBootTestclass DemoApplicationTests {
@Autowired Person person; //将person自动注入进来
@Test public void contextLoads() { System.out.println(person); //打印person信息 }
}
结果:所有值全部注入成功!
yaml配置注入到实体类完全OK!
课堂测试:
1、将配置文件的key 值 和 属性的值设置为不一样,则结果输出为null,注入失败
2、在配置一个person2,然后将 @ConfigurationProperties(prefix = “person2”) 指向我们的person2;
2.5加载指定的配置文件**@PropertySource :**加载指定的配置文件;
@configurationProperties:默认从全局配置文件中获取值;
1、我们去在resources目录下新建一个person.properties文件
name=kuangshen
2、然后在我们的代码中指定加载person.properties文件
@PropertySource(value = "classpath:person.properties")@Component //注册beanpublic class Person {
@Value("${name}") private String name;
...... }
3、再次输出测试一下:指定配置文件绑定成功!
2.6配置文件占位符配置文件还可以编写占位符生成随机数
person: name: qinjiang${random.uuid} # 随机uuid age: ${random.int} # 随机int happy: false birth: 2000/01/01 maps: {k1: v1,k2: v2} lists: - code - girl - music dog: name: ${person.hello:other}_旺财 age: 1
2.7回顾properties配置
我们上面采用的yaml方法都是最简单的方式,开发中最常用的;也是springboot所推荐的!那我们来唠唠其他的实现方式,道理都是相同的;写还是那样写;配置文件除了yml还有我们之前常用的properties , 我们没有讲,我们来唠唠!
【注意】properties配置文件在写中文的时候,会有乱码 , 我们需要去IDEA中设置编码格式为UTF-8;
settings–>FileEncodings 中配置;
测试步骤:
1、新建一个实体类User
@Component //注册beanpublic class User { private String name; private int age; private String sex;}
2、编辑配置文件 user.properties
user1.name=kuangshenuser1.age=18user1.sex=男
3、我们在User类上使用@Value来进行注入!
@Component //注册bean@PropertySource(value = "classpath:user.properties")public class User { //直接使用@value @Value("${user.name}") //从配置文件中取值 private String name; @Value("#{9*2}") // #{SPEL} Spring表达式 private int age; @Value("男") // 字面量 private String sex;}
4、Springboot测试
@SpringBootTestclass DemoApplicationTests {
@Autowired User user;
@Test public void contextLoads() { System.out.println(user); }
}
结果正常输出:
对比小结@Value这个使用起来并不友好!我们需要为每个属性单独注解赋值,比较麻烦;我们来看个功能对比图
1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加
2、松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下
3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性
4、复杂类型封装,yml中可以封装对象 , 使用value就不支持
结论:
配置yml和配置properties都可以获取到值 , 强烈推荐 yml;
如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value;
如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties,不要犹豫!
jsr303校验
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WSrPj9uI-1652436064036)(C:\Users\一字先生\AppData\Roaming\Typora\typora-user-images\image-20220328205806802.png)]
3.JSR303数据校验及多环境切换 3.1先看看如何使用Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的name只能支持Email格式;
@Component //注册bean@ConfigurationProperties(prefix = "person")@Validated //数据校验public class Person {
@Email(message="邮箱格式错误") //name必须是邮箱格式 private String name;}
运行结果 :default message [不是一个合法的电子邮件地址];
使用数据校验,可以保证数据的正确性;
3.2常见参数@NotNull(message="名字不能为空")private String userName;@Max(value=120,message="年龄最大不能查过120")private int age;@Email(message="邮箱格式错误")private String email;
空检查@Null 验证对象是否为null@NotNull 验证对象是否不为null, 无法查检长度为0的字符串@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.@NotEmpty 检查约束元素是否为NULL或者是EMPTY. Booelan检查@AssertTrue 验证 Boolean 对象是否为 true @AssertFalse 验证 Boolean 对象是否为 false 长度检查@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内 @Length(min=, max=) string is between min and max included.
日期检查@Past 验证 Date 和 Calendar 对象是否在当前时间之前 @Future 验证 Date 和 Calendar 对象是否在当前时间之后 @Pattern 验证 String 对象是否符合正则表达式的规则
.......等等除此以外,我们还可以自定义一些数据校验规则
多环境切换
profile是Spring对不同环境提供不同配置功能的支持,可以通过激活不同的环境版本,实现快速切换环境;
3.3多配置文件我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;
例如:
application-test.properties 代表测试环境配置
application-dev.properties 代表开发环境配置
但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件;
我们需要通过一个配置来选择需要激活的环境:
#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;spring.profiles.active=dev
3.4yaml的多文档块
和properties配置文件中一样,但是使用yml去实现不需要创建多个配置文件,更加方便了 !
server: port: 8081#选择要激活那个环境块spring: profiles: active: prod
---server: port: 8083spring: profiles: dev #配置环境的名称
---
server: port: 8084spring: profiles: prod #配置环境的名称
注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!
3.5配置文件加载位置外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置!
官方外部配置文件说明参考文档
springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:
优先级1:项目路径下的config文件夹配置文件优先级2:项目路径下配置文件优先级3:资源路径下的config文件夹配置文件优先级4:资源路径下配置文件
优先级由高到底,高优先级的配置会覆盖低优先级的配置;
SpringBoot会从这四个位置全部加载主配置文件;互补配置;
我们在最低级的配置文件中设置一个项目访问路径的配置来测试互补问题;
#配置项目的访问路径server.servlet.context-path=/kuang
3.6拓展,运维小技巧
指定位置加载配置文件
我们还可以通过spring.config.location来改变默认的配置文件位置
项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;这种情况,一般是后期运维做的多,相同配置,外部指定的配置文件优先级最高
java -jar spring-boot-config.jar --spring.config.location=F:/application.properties
4.SpringBoot Web开发
4.1.jar:webapp!
自动装配
springboot到底帮我们配置了什么?我们能不能修改?
能修改那些东西?能不能扩展
- xxxxAutoConfiguration…向容器中自动配置组件
- xxxxProperties:自动配置类,装配配置文件中自定义的一些内容!
要解决的问题:
- 导入静态资源:
- 首页
- jsp,模板引擎Thymeleaf
- 装配扩展SpringMVC
- 增删改查
- 拦截器
- 国际化!
什么webjars?
webjars/github-com-jquery-jquery/3.4.1/jquery.js
总结:
- 在SpringBoot中,我们可以使用以下方式处理静态资源
- webjars http://localhost:8080/webjars/github-com-jquery-jquery/3.4.1/jquery.js
- public,static,/**,resources
- 优先级: resource>static(默认)>public
前端交给我们的页面,是html页面。如果是我们以前开发,我们需要把他们转成jsp页面,jsp好处就是当我们查出一些数据转发到JSP页面以后,我们可以用jsp轻松实现数据的显示,及交互等。
jsp支持非常强大的功能,包括能写Java代码,但是呢,我们现在的这种情况,SpringBoot这个项目首先是以jar的方式,不是war,像第二,我们用的还是嵌入式的Tomcat,所以呢,他现在默认是不支持jsp的。
那不支持jsp,如果我们直接用纯静态页面的方式,那给我们开发会带来非常大的麻烦,那怎么办呢?
SpringBoot推荐你可以来使用模板引擎:
模板引擎,我们其实大家听到很多,其实jsp就是一个模板引擎,还有用的比较多的freemarker,包括SpringBoot给我们推荐的Thymeleaf,模板引擎有非常多,但再多的模板引擎,他们的思想都是一样的,什么样一个思想呢我们来看一下这张图:
模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。只不过呢,就是说不同模板引擎之间,他们可能这个语法有点不一样。其他的我就不介绍了,我主要来介绍一下SpringBoot给我们推荐的Thymeleaf模板引擎,这模板引擎呢,是一个高级语言的模板引擎,他的这个语法更简单。而且呢,功能更强大。
我们呢,就来看一下这个模板引擎,那既然要看这个模板引擎。首先,我们来看SpringBoot里边怎么用。
4.3引入Thymeleaf怎么引入呢,对于springboot来说,什么事情不都是一个start的事情嘛,我们去在项目中引入一下。给大家三个网址:
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
根据SpringBoot的内容
properties的优先级别是最高的,其次我们要将我们的主页放在静态资源主页classspath下,但是templates下的资源需要通过controller来进行,并且需要Thymeleaf模板引擎
thymeleaf用:
org.thymeleaf
thymeleaf-spring5
org.thymeleaf.extras
thymeleaf-extras-java8time
所有的html元素都可以被thymeleaf替换接管
th:元素名
Simple expressions:(表达式语法)Variable Expressions: ${...}:获取变量值;OGNL; 1)、获取对象的属性、调用方法 2)、使用内置的基本对象:#18 #ctx : the context object. #vars: the context variables. #locale : the context locale. #request : (only in Web Contexts) the HttpServletRequest object. #response : (only in Web Contexts) the HttpServletResponse object. #session : (only in Web Contexts) the HttpSession object. #servletContext : (only in Web Contexts) the ServletContext object.
3)、内置的一些工具对象: #execInfo : information about the template being processed. #uris : methods for escaping parts of URLs/URIs #conversions : methods for executing the configured conversion service (if any). #dates : methods for java.util.Date objects: formatting, component extraction, etc. #calendars : analogous to #dates , but for java.util.Calendar objects. #numbers : methods for formatting numeric objects. #strings : methods for String objects: contains, startsWith, prepending/appending, etc. #objects : methods for objects in general. #bools : methods for boolean evaluation. #arrays : methods for arrays. #lists : methods for lists. #sets : methods for sets. #maps : methods for maps. #aggregates : methods for creating aggregates on arrays or collections.==================================================================================
Selection Variable Expressions: *{...}:选择表达式:和${}在功能上是一样; Message Expressions: #{...}:获取国际化内容 Link URL Expressions: @{...}:定义URL; Fragment Expressions: ~{...}:片段引用表达式
Literals(字面量) Text literals: 'one text' , 'Another one!' ,… Number literals: 0 , 34 , 3.0 , 12.3 ,… Boolean literals: true , false Null literal: null Literal tokens: one , sometext , main ,… Text operations:(文本 *** 作) String concatenation: + Literal substitutions: |The name is ${name}| Arithmetic operations:(数学运算) Binary operators: + , - , * , / , % Minus sign (unary operator): - Boolean operations:(布尔运算) Binary operators: and , or Boolean negation (unary operator): ! , not Comparisons and equality:(比较运算) Comparators: > , < , >= , <= ( gt , lt , ge , le ) Equality operators: == , != ( eq , ne ) Conditional operators:条件运算(三元运算符) If-then: (if) ? (then) If-then-else: (if) ? (then) : (else) Default: (value) ?: (defaultvalue) Special tokens: No-Operation: _
练习测试:
1、 我们编写一个Controller,放一些数据
@RequestMapping("/t2")public String test2(Map<String,Object> map)
{ //存入数据 map.put("msg","Hello");
map.put("users", Arrays.asList("qinjiang","kuangshen"));
//classpath:/templates/test.html
return "test";}
2、测试页面取出数据
狂神说 测试页面
[[${user}]]
3、启动项目测试!
我们看完语法,很多样式,我们即使现在学习了,也会忘记,所以我们在学习过程中,需要使用什么,根据官方文档来查询,才是最重要的,要熟练使用官方文档!
5.MVC配置原理如果想div一些定制化的功能,只要写这个组件,然后将它交给springboot 他会帮我们自动装配
@Bean
public ViewResolver MyViewResolver(){
return new MyViewResolver();
}
//自定义一个视图解析器
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
5.1扩展SpringMvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//视图跳转
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/study").setViewName("hello");
}
}
@EnableWebMvc //他就是导入了一个类DelegatingWebMvcConfiguration.class
如果导入了@EnableWebMvc,源码里面的自动装配就会全部崩盘
在SpringBoot中,有非常多的XXX Configuraion,会帮助我们进行扩展配置,只要看见了这个东西,我们就要注意了!
6.员工管理系统 6.1准备工作1.首页配置:
- 注意点:所有页面的静态资源都需要使用thymeleaf接管
- url:@{}
2.页面国际化:
- 我们需要配置i18n文件
- 我们如果需要在项目中进行按钮自动切换,我们需要自定义一个组件
LoaclResolver
- 记得将自己写的组件配置到spring容器
@Bean
- #{}
先在IDEA中统一设置properties的编码问题!
编写国际化配置文件,抽取页面需要显示的国际化页面消息。我们可以去登录页面查看一下,哪些内容我们需要编写国际化的配置!
配置文件编写1、我们在resources资源文件下新建一个i18n目录,存放国际化配置文件
2、建立一个login.properties文件,还有一个login_zh_CN.properties;发现IDEA自动识别了我们要做国际化 *** 作;文件夹变了!
3、我们可以在这上面去新建一个文件;
d出如下页面:我们再添加一个英文的;
这样就快捷多了!
4、接下来,我们就来编写配置,我们可以看到idea下面有另外一个视图;
这个视图我们点击 + 号就可以直接添加属性了;我们新建一个login.tip,可以看到边上有三个文件框可以输入
我们添加一下首页的内容!
然后依次添加其他页面内容即可!
然后去查看我们的配置文件;
login.properties :默认
login.btn=登录login.password=密码login.remember=记住我login.tip=请登录login.username=用户名
英文:
login.btn=Sign inlogin.password=Passwordlogin.remember=Remember melogin.tip=Please sign inlogin.username=Username
中文:
login.btn=登录login.password=密码login.remember=记住我login.tip=请登录login.username=用户名
OK,配置文件步骤搞定!
配置文件生效探究我们去看一下SpringBoot对国际化的自动配置!这里又涉及到一个类:MessageSourceAutoConfiguration
里面有一个方法,这里发现SpringBoot已经自动配置好了管理我们国际化资源文件的组件 ResourceBundleMessageSource
// 获取 properties 传递过来的值进行判断@Beanpublic MessageSource messageSource(MessageSourceProperties properties) { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); if (StringUtils.hasText(properties.getBasename())) { // 设置国际化文件的基础名(去掉语言国家代码的) messageSource.setBasenames( StringUtils.commaDelimitedListToStringArray( StringUtils.trimAllWhitespace(properties.getBasename()))); } if (properties.getEncoding() != null) { messageSource.setDefaultEncoding(properties.getEncoding().name()); } messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale()); Duration cacheDuration = properties.getCacheDuration(); if (cacheDuration != null) { messageSource.setCacheMillis(cacheDuration.toMillis()); } messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat()); messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage()); return messageSource;}
我们真实 的情况是放在了i18n目录下,所以我们要去配置这个messages的路径;
spring.messages.basename=i18n.login
配置页面国际化值
去页面获取国际化的值,查看Thymeleaf的文档,找到message取值 *** 作为:#{…}。我们去页面测试下:
IDEA还有提示,非常智能的!
我们可以去启动项目,访问一下,发现已经自动识别为中文的了!
但是我们想要更好!可以根据按钮自动切换中文英文!
配置国际化解析在Spring中有一个国际化的Locale (区域信息对象);里面有一个叫做LocaleResolver (获取区域信息对象)的解析器!
我们去我们webmvc自动配置文件,寻找一下!看到SpringBoot默认配置
@Bean@ConditionalOnMissingBean@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")public LocaleResolver localeResolver() { // 容器中没有就自己配,有的话就用用户配置的 if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) { return new FixedLocaleResolver(this.mvcProperties.getLocale()); } // 接收头国际化分解 AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); localeResolver.setDefaultLocale(this.mvcProperties.getLocale()); return localeResolver;}
AcceptHeaderLocaleResolver 这个类中有一个方法
public Locale resolveLocale(HttpServletRequest request) { Locale defaultLocale = this.getDefaultLocale(); // 默认的就是根据请求头带来的区域信息获取Locale进行国际化 if (defaultLocale != null && request.getHeader("Accept-Language") == null) { return defaultLocale; } else { Locale requestLocale = request.getLocale(); List supportedLocales = this.getSupportedLocales(); if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) { Locale supportedLocale = this.findSupportedLocale(request, supportedLocales); if (supportedLocale != null) { return supportedLocale; } else { return defaultLocale != null ? defaultLocale : requestLocale; } } else { return requestLocale; } }}
那假如我们现在想点击链接让我们的国际化资源生效,就需要让我们自己的Locale生效!
我们去自己写一个自己的LocaleResolver,可以在链接上携带区域信息!
修改一下前端页面的跳转连接:
中文English
我们去写一个处理的组件类!
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) {
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;
@Beanpublic LocaleResolver localeResolver(){ return new MyLocaleResolver();}
3.登录+拦截器
4.员工列表展示
- 提取公共页面
th:fragment="sidebar"
th:replace="~{commons/commons::topbar}"
- 如果要传递参数,可以直接使用()传参,接受判断即可!
- 列表循环展示
5.添加员工
- 按钮提交
- 跳转到添加页面
- 添加员工成功
- 返回首页
前端:
- 模板:别人写好的,我们拿来改
- 框架:组件:自己手动进行拼接! BootStrap Layui
- 栅格系统
1.前端搞定:页面长什么样子:数据
2.设计数据库(数据库设计难点!)
3.前端让他能够自动运行,独立化工程
4.数据接口如何对接:json,对象 all in one!
5.前后端联调测试!
- 有一套自己熟悉的后台模板,工作必要! x-admin
- 前端界面:至少自己能够通过前端框架,组合出来一个网站页面
- index
- about
- blog
- post
- user
- 让这个网站能够独立运行!
一个月!
7.Data对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。
Spring Boot 底层都是采用 Spring Data 的方式进行统一处理各种数据库,Spring Data 也是 Spring 中与 Spring Boot、Spring Cloud 等齐名的知名项目。
Sping Data 官网:https://spring.io/projects/spring-data
数据库相关的启动器 :可以参考官方文档:
https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter
整合JDBC
创建测试项目测试数据源1、我去新建一个项目测试:springboot-data-jdbc ; 引入相应的模块!基础模块
2、项目建好之后,发现自动帮我们导入了如下的启动器:
org.springframework.boot spring-boot-starter-jdbc mysql mysql-connector-java runtime
3、编写yaml配置文件连接数据库;
spring: datasource: username: root password: 123456 #?serverTimezone=UTC解决时区的报错 url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver
4、配置完这一些东西后,我们就可以直接去使用了,因为SpringBoot已经默认帮我们进行了自动配置;去测试类测试一下
@SpringBootTestclass SpringbootDataJdbcApplicationTests {
//DI注入数据源 @Autowired DataSource dataSource;
@Test public void contextLoads() throws SQLException { //看一下默认数据源 System.out.println(dataSource.getClass()); //获得连接 Connection connection = dataSource.getConnection(); System.out.println(connection); //关闭连接 connection.close(); }}
结果:我们可以看到他默认给我们配置的数据源为 : class com.zaxxer.hikari.HikariDataSource , 我们并没有手动配置
我们来全局搜索一下,找到数据源的所有自动配置都在 :DataSourceAutoConfiguration文件:
@Import( {Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class})protected static class PooledDataSourceConfiguration { protected PooledDataSourceConfiguration() { }}
这里导入的类都在 DataSourceConfiguration 配置类下,可以看出 Spring Boot 2.2.5 默认使用HikariDataSource 数据源,而以前版本,如 Spring Boot 1.5 默认使用 org.apache.tomcat.jdbc.pool.DataSource 作为数据源;
HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀;
可以使用 spring.datasource.type 指定自定义的数据源类型,值为 要使用的连接池实现的完全限定名。
关于数据源我们并不做介绍,有了数据库连接,显然就可以 CRUD *** 作数据库了。但是我们需要先了解一个对象 JdbcTemplate
JDBCTemplate1、有了数据源(com.zaxxer.hikari.HikariDataSource),然后可以拿到数据库连接(java.sql.Connection),有了连接,就可以使用原生的 JDBC 语句来 *** 作数据库;
2、即使不使用第三方第数据库 *** 作框架,如 MyBatis等,Spring 本身也对原生的JDBC 做了轻量级的封装,即JdbcTemplate。
3、数据库 *** 作的所有 CRUD 方法都在 JdbcTemplate 中。
4、Spring Boot 不仅提供了默认的数据源,同时默认已经配置好了 JdbcTemplate 放在了容器中,程序员只需自己注入即可使用
5、JdbcTemplate 的自动配置是依赖 org.springframework.boot.autoconfigure.jdbc 包下的 JdbcTemplateConfiguration 类
JdbcTemplate主要提供以下几类方法:
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
- update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
- query方法及queryForXXX方法:用于执行查询相关语句;
- call方法:用于执行存储过程、函数相关语句。
编写一个Controller,注入 jdbcTemplate,编写测试方法进行访问测试;
package com.kuang.controller;
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;
import java.util.Date;import java.util.List;import java.util.Map;
@RestController@RequestMapping("/jdbc")public class JdbcController {
/** * Spring Boot 默认提供了数据源,默认提供了 org.springframework.jdbc.core.JdbcTemplate * JdbcTemplate 中会自己注入数据源,用于简化 JDBC *** 作 * 还能避免一些常见的错误,使用起来也不用再自己来关闭数据库连接 */ @Autowired JdbcTemplate jdbcTemplate;
//查询employee表中所有数据 //List 中的1个 Map 对应数据库的 1行数据 //Map 中的 key 对应数据库的字段名,value 对应数据库的字段值
@GetMapping("/list") public List<Map<String, Object>> userList(){ String sql = "select * from employee"; List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql); return maps; } //新增一个用户
@GetMapping("/add") public String addUser(){ //插入语句,注意时间问题
String sql = "insert into employee(last_name, email,gender,department,birth)" +" values ('狂神说','24736743@qq.com',1,101,'"+ new Date().toLocaleString() +"')"; jdbcTemplate.update(sql); //查询 return "addOk"; }
//修改用户信息
@GetMapping("/update/{id}") public String updateUser(@PathVariable("id") int id){ //插入语句
String sql = "update employee set last_name=?,email=? where id="+id; //数据
Object[] objects = new Object[2]; objects[0] = "秦疆"; objects[1] = "24736743@sina.com"; jdbcTemplate.update(sql,objects); //查询
return "updateOk"; }
//删除用户
@GetMapping("/delete/{id}") public String delUser(@PathVariable("id") int id){ //插入语句
String sql = "delete from employee where id=?"; jdbcTemplate.update(sql,id); //查询
return "deleteOk"; }
8.Myabtis整合
M:数据和业务
C:交接
V:HTML
- 导入包
- 配置文件
- mybatis配置
- 编写sql
- 业务层(service)调用dao层
- controller调用service层
官方文档:http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
Maven仓库地址:https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter/2.1.1
整合测试1、导入 MyBatis 所需要的依赖
org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.1
2、配置数据库连接信息(不变)
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?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
3、测试数据库是否连接成功!
4、创建实体类,导入 Lombok!
Department.java
package com.kuang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;import lombok.NoArgsConstructor;
@Data@NoArgsConstructor@AllArgsConstructorpublic class Department {
private Integer id;
private String departmentName;
}
5、创建mapper目录以及对应的 Mapper 接口
DepartmentMapper.java
//@Mapper : 表示本类是一个 MyBatis 的 Mapper@Mapper@Repositorypublic interface DepartmentMapper {
// 获取所有部门信息 List getDepartments();
// 通过id获得部门 Department getDepartment(Integer id);
}
6、对应的Mapper映射文件
DepartmentMapper.xml
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.mapper.DepartmentMapper">
<select id="getDepartments" resultType="Department"> select * from department; select>
<select id="getDepartment" resultType="Department" parameterType="int"> select * from department where id = #{id}; select>
mapper>
7、maven配置资源过滤问题
<resources>
<resource> <directory>src/main/javadirectory> <includes>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
8、编写部门的 DepartmentController 进行测试!
@RestController
public class DepartmentController { @Autowired
DepartmentMapper departmentMapper;
// 查询全部部门
@GetMapping("/getDepartments")
public List<Department> getDepartments(){
return departmentMapper.getDepartments();
}
// 查询全部部门 @GetMapping("/getDepartment/{id}")
public Department getDepartment(@PathVariable("id") Integer id){
return departmentMapper.getDepartment(id);}
}
启动项目访问进行测试!
我们增加一个员工类再测试下,为之后做准备1、新建一个pojo类 Employee ;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private Integer id;
private String lastName;
private String email;
//1 male, 0 female
private Integer gender;
private Integer department;
private Date birth;
private Department eDepartment; // 冗余设计
}
2、新建一个 EmployeeMapper 接口
//@Mapper : 表示本类是一个 MyBatis 的 Mapper
@Mapper
@Repositorypublic interface EmployeeMapper {
// 获取所有员工信息
List<Employee> getEmployees();
// 新增一个员工
int save(Employee employee);
// 通过id获得员工信息
Employee get(Integer id);
// 通过id删除员工
int delete(Integer id);
}
3、编写 EmployeeMapper.xml 配置文件
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.mapper.EmployeeMapper">
<resultMap id="EmployeeMap" type="Employee"> <id property="id" column="eid"/> <result property="lastName" column="last_name"/> <result property="email" column="email"/> <result property="gender" column="gender"/> <result property="birth" column="birth"/> <association property="eDepartment" javaType="Department"> <id property="id" column="did"/> <result property="departmentName" column="dname"/> association> resultMap>
<select id="getEmployees" resultMap="EmployeeMap"> select e.id as eid,last_name,email,gender,birth,d.id as did,d.department_name as dname from department d,employee e where d.id = e.department select>
<insert id="save" parameterType="Employee"> insert into employee (last_name,email,gender,department,birth) values (#{lastName},#{email},#{gender},#{department},#{birth}); insert>
<select id="get" resultType="Employee"> select * from employee where id = #{id} select>
<delete id="delete" parameterType="int"> delete from employee where id = #{id} delete>
mapper>
4、编写EmployeeController类进行测试
@RestController
public class EmployeeController {
@Autowired
EmployeeMapper employeeMapper;
// 获取所有员工信息 @GetMapping("/getEmployees") public List getEmployees(){ return employeeMapper.getEmployees(); }
@GetMapping("/save") public int save(){ Employee employee = new Employee(); employee.setLastName("kuangshen"); employee.setEmail("qinjiang@qq.com"); employee.setGender(1); employee.setDepartment(101); employee.setBirth(new Date());
return employeeMapper.save(employee);
}
// 通过id获得员工信息 @GetMapping("/get/{id}") public Employee get(@PathVariable("id") Integer id){ return employeeMapper.get(id); }
// 通过id删除员工 @GetMapping("/delete/{id}") public int delete(@PathVariable("id") Integer id){ return employeeMapper.delete(id); }
}
9.SpringSecurity(安全)
在web开发中,安全第一位!过滤器,拦截器~
功能性需求:否
做网站:安全应该在什么时候考虑?
-
漏洞:隐私泄露~
-
架构一旦确定~
shiro,SpringSecurity:很像~除了类不一样,名字不一样;
认证,授权(vip,vip2,vip3)
- 功能权限
- 访问权限
- 菜单权限
- 拦截器 过滤器:大量的原生代码~ 冗余
AOP横切-配置类
安全简介在 Web 开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的初期就考虑进来。如果在应用开发的后期才考虑安全的问题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一方面,应用的基本架构已经确定,要修复安全漏洞,可能需要对系统的架构做出比较重大的调整,因而需要更多的开发时间,影响应用的发布进程。因此,从应用开发的第一天就应该把安全相关的因素考虑进来,并在整个应用的开发过程中。
市面上存在比较有名的:Shiro,Spring Security !
这里需要阐述一下的是,每一个框架的出现都是为了解决某一问题而产生了,那么Spring Security框架的出现是为了解决什么问题呢?
首先我们看下它的官网介绍:Spring Security官网地址
Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements
Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它实际上是保护基于spring的应用程序的标准。
Spring Security是一个框架,侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring安全性的真正强大之处在于它可以轻松地扩展以满足定制需求
从官网的介绍中可以知道这是一个权限框架。想我们之前做项目是没有使用框架是怎么控制权限的?对于权限 一般会细分为功能权限,访问权限,和菜单权限。代码会写的非常的繁琐,冗余。
怎么解决之前写权限代码繁琐,冗余的问题,一些主流框架就应运而生而Spring Scecurity就是其中的一种。
Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个 *** 作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
对于上面提到的两种应用情景,Spring Security 框架都有很好的支持。在用户认证方面,Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等。在用户授权方面,Spring Security 提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制。
实战测试 实验环境搭建1、新建一个初始的springboot项目web模块,thymeleaf模块
2、导入静态资源
welcome.html
|views
|level1
1.html
2.html
3.html
|level2
1.html
2.html
3.html
|level3
1.html
2.html
3.html
Login.html
3、controller跳转!
package com.kuang.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RouterController {
@RequestMapping({"/","/index"})
public String index(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}
@RequestMapping("/level1/{id}")
public String level1(@PathVariable("id") int id){
return "views/level1/"+id;
}
@RequestMapping("/level2/{id}")
public String level2(@PathVariable("id") int id){
return "views/level2/"+id;
}
@RequestMapping("/level3/{id}")
public String level3(@PathVariable("id") int id){
return "views/level3/"+id;
}
}
4、测试实验环境是否OK!
认识SpringSecuritySpring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
- WebSecurityConfigurerAdapter:自定义Security策略
- AuthenticationManagerBuilder:自定义认证策略
- @EnableWebSecurity:开启WebSecurity模式
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
“认证”(Authentication)
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
这个概念是通用的,而不是只在Spring Security 中存在。
认证和授权目前,我们的测试环境,是谁都可以访问的,我们使用 Spring Security 增加上认证和授权的功能
1、引入 Spring Security 模块
org.springframework.boot
spring-boot-starter-security
2、编写 Spring Security 配置类
参考官网:https://spring.io/projects/spring-security
查看我们自己项目中的版本,找到对应的帮助文档:
https://docs.spring.io/spring-security/site/docs/5.3.0.RELEASE/reference/html5 #servlet-applications 8.16.4
3、编写基础配置类
package com.kuang.config;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity // 开启WebSecurity模式
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
}
4、定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
// 定制请求的授权规则
// 首页所有人可以访问
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
}
5、测试一下:发现除了首页都进不去了!因为我们目前没有登录的角色,因为请求需要登录的角色拥有对应的权限才可以!
6、在configure()方法中加入以下配置,开启自动配置的登录功能!
// 开启自动配置的登录功能
// /login 请求来到登录页
// /login?error 重定向到这里表示登录失败
http.formLogin();
7、测试一下:发现,没有权限的时候,会跳转到登录的页面!
8、查看刚才登录页的注释信息;
我们可以定义认证规则,重写configure(AuthenticationManagerBuilder auth)方法
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
auth.inMemoryAuthentication()
.withUser("kuangshen").password("123456").roles("vip2","vip3")
.and()
.withUser("root").password("123456").roles("vip1","vip2","vip3")
.and()
.withUser("guest").password("123456").roles("vip1","vip2");
}
9、测试,我们可以使用这些账号登录进行测试!发现会报错!
There is no PasswordEncoder mapped for the id “null”
10、原因,我们要将前端传过来的密码进行某种方式加密,否则就无法登录,修改代码
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
//Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
//要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
//spring security 官方推荐的是使用bcrypt加密方式。
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
}
11、测试,发现,登录成功,并且每个角色只能访问自己认证下的规则!搞定
权限控制和注销1、开启自动配置的注销的功能
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
//....
//开启自动配置的注销的功能
// /logout 注销请求
http.logout();
}
2、我们在前端,增加一个注销的按钮,index.html 导航栏中
注销
3、我们可以去测试一下,登录成功后点击注销,发现注销完毕会跳转到登录页面!
4、但是,我们想让他注销成功后,依旧可以跳转到首页,该怎么处理呢?
// .logoutSuccessUrl("/"); 注销成功来到首页
http.logout().logoutSuccessUrl("/");
5、测试,注销完毕后,发现跳转到首页OK
6、我们现在又来一个需求:用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮!还有就是,比如kuangshen这个用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能,而vip1的功能菜单不显示!这个就是真实的网站情况了!该如何做呢?
我们需要结合thymeleaf中的一些功能
sec:authorize=“isAuthenticated()”:是否认证登录!来显示不同的页面
Maven依赖:
org.thymeleaf.extras
thymeleaf-extras-springsecurity5
3.0.4.RELEASE
7、修改我们的 前端页面
-
导入命名空间
-
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
-
修改导航栏,增加认证判断
-
<div class="right menu"> <div sec:authorize="!isAuthenticated()"> <a class="item" th:href="@{/login}"> <i class="address card icon">i> 登录 a> div> <div sec:authorize="isAuthenticated()"> <a class="item"> <i class="address card icon">i> 用户名:<span sec:authentication="principal.username">span> 角色:<span sec:authentication="principal.authorities">span> a> div> <div sec:authorize="isAuthenticated()"> <a class="item" th:href="@{/logout}"> <i class="address card icon">i> 注销 a> div> div>
8、重启测试,我们可以登录试试看,登录成功后确实,显示了我们想要的页面;
9、如果注销404了,就是因为它默认防止csrf跨站请求伪造,因为会产生安全问题,我们可以将请求改为post表单提交,或者在spring security中关闭csrf功能;我们试试:在 配置中增加 http.csrf().disable();
http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
http.logout().logoutSuccessUrl("/");
10、我们继续将下面的角色功能块认证完成!
<div class="column" sec:authorize="hasRole('vip1')">
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 1h5>
<hr>
<div><a th:href="@{/level1/1}"><i class="bullhorn icon">i> Level-1-1a>div>
<div><a th:href="@{/level1/2}"><i class="bullhorn icon">i> Level-1-2a>div>
<div><a th:href="@{/level1/3}"><i class="bullhorn icon">i> Level-1-3a>div>
div>
div>
div>
div>
<div class="column" sec:authorize="hasRole('vip2')">
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 2h5>
<hr>
<div><a th:href="@{/level2/1}"><i class="bullhorn icon">i> Level-2-1a>div>
<div><a th:href="@{/level2/2}"><i class="bullhorn icon">i> Level-2-2a>div>
<div><a th:href="@{/level2/3}"><i class="bullhorn icon">i> Level-2-3a>div>
div>
div>
div>
div>
<div class="column" sec:authorize="hasRole('vip3')">
<div class="ui raised segment">
<div class="ui">
<div class="content">
<h5 class="content">Level 3h5>
<hr>
<div><a th:href="@{/level3/1}"><i class="bullhorn icon">i> Level-3-1a>div>
<div><a th:href="@{/level3/2}"><i class="bullhorn icon">i> Level-3-2a>div>
<div><a th:href="@{/level3/3}"><i class="bullhorn icon">i> Level-3-3a>div>
div>
div>
div>
div>
11、测试一下!
12、权限控制和注销搞定!
记住我现在的情况,我们只要登录之后,关闭浏览器,再登录,就会让我们重新登录,但是很多网站的情况,就是有一个记住密码的功能,这个该如何实现呢?很简单
1、开启记住我功能
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
//。。。。。。。。。。。
//记住我
http.rememberMe();
}
2、我们再次启动项目测试一下,发现登录页多了一个记住我功能,我们登录之后关闭 浏览器,然后重新打开浏览器访问,发现用户依旧存在!
思考:如何实现的呢?其实非常简单
我们可以查看浏览器的cookie
3、我们点击注销的时候,可以发现,spring security 帮我们自动删除了这个 cookie
4、结论:登录成功后,将cookie发送给浏览器保存,以后登录带上这个cookie,只要通过检查就可以免登录了。如果点击注销,则会删除这个cookie,具体的原理我们在JavaWeb阶段都讲过了,这里就不在多说了!
定制登录页现在这个登录页面都是spring security 默认的,怎么样可以使用我们自己写的Login界面呢?
1、在刚才的登录页配置后面指定 loginpage
http.formLogin().loginPage("/toLogin");
2、然后前端也需要指向我们自己定义的 login请求
登录
3、我们登录,需要将这些信息发送到哪里,我们也需要配置,login.html 配置提交请求及方式,方式必须为post:
在 loginPage()源码中的注释上有写明:
<form th:action="@{/login}" method="post">
<div class="field">
<label>Usernamelabel>
<div class="ui left icon input">
<input type="text" placeholder="Username" name="username">
<i class="user icon">i>
div>
div>
<div class="field">
<label>Passwordlabel>
<div class="ui left icon input">
<input type="password" name="password">
<i class="lock icon">i>
div>
div>
<input type="submit" class="ui blue submit button"/>
form>
4、这个请求提交上来,我们还需要验证处理,怎么做呢?我们可以查看formLogin()方法的源码!我们配置接收登录的用户名和密码的参数!
http.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.loginPage("/toLogin")
.loginProcessingUrl("/login"); // 登陆表单提交请求
5、在登录页增加记住我的多选框
记住我
6、后端验证处理!
//定制记住我的参数!
http.rememberMe().rememberMeParameter("remember");
7、测试,OK
完整配置代码package com.kuang.config;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//定制请求的授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3");
//开启自动配置的登录功能:如果没有权限,就会跳转到登录页面!
// /login 请求来到登录页
// /login?error 重定向到这里表示登录失败
http.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.loginPage("/toLogin")
.loginProcessingUrl("/login"); // 登陆表单提交请求
//开启自动配置的注销的功能
// /logout 注销请求
// .logoutSuccessUrl("/"); 注销成功来到首页
http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
http.logout().logoutSuccessUrl("/");
//记住我
http.rememberMe().rememberMeParameter("remember");
}
//定义认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在内存中定义,也可以在jdbc中去拿....
//Spring security 5.0中新增了多种加密方式,也改变了密码的格式。
//要想我们的项目还能够正常登陆,需要修改一下configure中的代码。我们要将前端传过来的密码进行某种方式加密
//spring security 官方推荐的是使用bcrypt加密方式。
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
}
}
10.Shiro
1、Shiro简介
【1】什么是Shiro?
Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架。
【2】Shiro 的特点Shiro 是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。如下是它所具有的特点:
· 易于理解的 Java Security API;
· 简单的身份认证(登录),支持多种数据源(LDAP,JDBC 等);
· 对角色的简单的签权(访问控制),也支持细粒度的鉴权;
· 支持一级缓存,以提升应用程序的性能;
· 内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;
· 异构客户端会话访问;
· 非常简单的加密 API;
· 不跟任何的框架或者容器捆绑,可以独立运行。
2、核心组件Shiro架构图
·Subject
Subject主体,外部应用与subject进行交互,subject将用户作为当前 *** 作的主体,这个主体:可以是一个通过浏览器请求的用户,也可能是一个运行的程序。Subject在shiro中是一个接口,接口中定义了很多认证授相关的方法,外部程序通过subject进行认证授,而subject是通过SecurityManager安全管理器进行认证授权。
·SecurityManager
SecurityManager权限管理器,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。SecurityManager是一个接口,继承了Authenticator, Authorizer, SessionManager这三个接口。
·Authenticator
Authenticator即认证器,对用户登录时进行身份认证
·Authorizer
Authorizer授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的 *** 作权限。
·Realm(数据库读取+认证功能+授权功能实现)
Realm领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据
比如:
如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。
注意:
不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。
·SessionManager
SessionManager会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。
·SessionDAO
SessionDAO即会话dao,是对session会话 *** 作的一套接口
比如:
可以通过jdbc将会话存储到数据库;也可以把session存储到缓存服务器。
·CacheManager
CacheManager缓存管理,将用户权限数据存储在缓存,这样可以提高性能。
·Cryptography
Cryptography密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。
org.apache.shiro
shiro-web
1.9.0
去自己的gitee上面拿下来shiro
然后进入[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tlXIEwkE-1652436064048)(C:\Users\一字先生\AppData\Roaming\Typora\typora-user-images\image-20220330184026380.png)]
找到pom.xml导入maven依赖,也可以去官网看十分钟入门教程,但是官网进的太慢了!
https://shiro.apache.org/10-minute-tutorial.html
org.apache.shiro
shiro-core
1.9.0
org.slf4j
jcl-over-slf4j
1.5.6
org.apache.logging.log4j
log4j-slf4j-impl
2.17.1
org.apache.logging.log4j
log4j-core
2.17.1
1.导入依赖
2.导入配置
log4j.rootLogger=INFo,stdout
log4j.appender.stdout=org.apache.log4j.consoleAppender
log4j.appender.stdout.1ayout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p 【%c 】 - ‰m %n
#General Apache libraries
log4j.logger.org.apache=WARN
#Spring
log4j.logger.org.springframework=WARN
#Default Shiro Logging
log4j.logger.org.apache.shiro=INFO
#Disable verbose Logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
3.hello
Spring-Secutiry都有
//获取当前的用户对象 subject
Subject currentUser = SecurityUtils.getSubject();
//通过当前用户拿到session
Session session = currentUser.getSession();
//判断当前的用户是否被认证
currentUser.isAuthenticated()
//token 令牌
//识别主体为用户名
currentUser.getPrincipal()
//等级
currentUser.hasRole("schwartz"))
//粗粒度
currentUser.isPermitted("winnebago:drive:eagle5")
currentUser.logout()
SpringBoot集成
用户==> 管理所有用户 ==>连接数据
整合导入:二选一
org.apache.shiro
shiro-spring-boot-web-starter
1.9.0
org.apache.shiro
shiro-spring
1.9.0
Shiro报错
1.首先:在建立Shiro三个板块时,每个板块都需要用bean注入名字,不然SpringBoot识别不到,
2.先建立Reaml,因为上面的层次结构都是基于他来建立的
3.在设置权限时,如果是所有人都需要访问的,则不需要进行登记设置,会报错
4.如果配置没有问题,报错了,那么肯定是你的函数里面有内容写错了,可能写的不是跟web相关的
11.Shirio大整合SpringBoot + Spirng + Mybatis +Druid + Log4j + Mysql
mysql
mysql-connector-java
log4j
log4j
1.2.17
com.alibaba
druid
1.2.8
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.2
com.github.theborakompanioni
thymeleaf-extras-shiro
2.1.0
12.Swagger
1.导入依赖:
io.springfox
springfox-boot-starter
3.0.0
此依赖不会导致SpirngBoot2.6以上版本不兼容Springfox 及Swagger
2.配置Config 开启Swagger@Configuration
@EnableWebMvc
//@EnableSwagger2
public class SwaggerConfig {
//开启swagger
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-utcEct1w-1652436064049)(C:\Users\一字先生\AppData\Roaming\Typora\typora-user-images\image-20220331105722029.png)]
配置Swagger //配置了Swagger Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
//配置Swagger信息=apInfo
private ApiInfo apiInfo(){
//作者信息
Contact contact = new Contact("一字先生","http://www.baidu.com","11355084@qq.com");
return new ApiInfo("一字先生",
"Mr.One",
"1.0", "点勾勾点",
contact, "Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
Swagger配置扫描接口
Docket.select()
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//配置要扫描接口的方式
//basePackage:扫描指定的包
//any():扫描全部
//none():都不扫描
//withClassAnnotation():扫描类上的注解 参数是一个注解的反射对象
//withMethodAnnotation():扫描方法上的注解
.apis(RequestHandlerSelectors.basePackage("com.study.controller"))
//.paths()过滤什么路劲
.paths(PathSelectors.ant("/study/**"))
.build();
}
配置是否启动Docket .enable(boolean) 但是不能再select下面去,因为是启动
我只希望我的Swagger在生产环境下使用,在发布的时候不使用
- 判断是不是生产环境 flag=false
- 注入enable(flag)
public Docket docket(Environment environment){
//设置要显示的Swagger环境
Profiles profiles = Profiles.of("dev","test");
//获取项目的环境:
//通过environment.acceptsProfiles判断自己是否处在设定的环境中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(flag)
.select()
.apis(RequestHandlerSelectors.basePackage("com.study.controller"))
// .paths(PathSelectors.ant("/study/**"))
.build();
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)