狂神视频连接:和原文笔记https://www.cnblogs.com/th11/p/15208081.html
第一个SpringBoot程序
到底多么简单:
- jdk 1.8
- maven 3.6.1
- SpringBoot 最新版
- IDEA
官方:提供了一个快速生成的网站!IDEA集成了这个网站!(建议IDEA创建)
原理初探
自动配置
pom.xml
- spring-boot-description:核心依赖在父工程中!
- 我们在写或者引入一些SpringBoot依赖的时候,不需要指定版本,就因为有这些版本仓库
启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
- spring-boot-starter-web,他就会帮我们自动导入web环境所有依赖!
- springboot会将所有的功能场景,都变成一个个的启动器
- 我们要使用什么功能,就只需要找到对应的启动器就可以了
starter
主程序
//SpringBootApplication:标注这个类是一个springboot的应用 :启动类下的所有资源被导入
@SpringBootApplication
public class HelloworldApplication {
public static void main(String[] args) {
//将springboot应用启动
SpringApplication.run(HelloworldApplication.class, args);
}
}
注解
@SpringBootConfiguration //springboot的配置
@Configuration //spring配置类
@Component //说明这也是一个spring的组件
@EnableAutoConfiguration //自动配置
@AutoConfigurationPackage //自动配置包
@Import({AutoConfigurationPackages.Registrar.class}) //自动配置`包注册`
@Import({AutoConfigurationImportSelector.class})
//获取所有的配置
List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//这里的getSpringFactoriesLoaderFactoryClass()方法
//返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
List<String> configurations = SpringFactoriesLoader.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;
}
META-INF/spring.factories:自动配置的核心文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
所有资源加载到配置中!
**结论:**springboot所有自动配置都是在启动的时候扫描并加载:spring.factories
所有的自动配置类都在这里面,但不一定生效,要判断条件是否成立,只要成立,只要导入了对应的 start,就有对应的启动器,有了启动器,我们自动装配就会生效,然后就配置成功!
- springboot在启动的时候,从类路径下
META-INF/spring.factories
获取指定的值; - 将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置!
- 以前我们需要自动配置的东西,现在springboot帮我们做了!
- 整合javaEE,解决方案和自动配置的东西都在
spring-boot-autoconfigure-2.6.5jar
这个包下 - 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器;
- 容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration,JavaConfig!
- 有了自动配置类,免去了我们的手动编写配置文件的工作!
SpringApplication
这个类主要做了以下四件事情:
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();
}
run方法流程分析
SpringBoot配置
yaml可以直接给实体类赋值!
# k=v properties 只能保存键值对!
# 对空格的要求十分严格!
# 普通的key-value
# 注入到我们的配置类中!
name: qinjiang
# 对象
student:
name: qinjiang
age: 3
# 行内写法
student: {name: qinjiang,age: 3}
# 数组
pets:
- cat
- dog
- pig
pets: [cat,dog,pig]
配置文件占位符
这里有微调,否则旺财输出为乱码
person:
name: qinjiang${random.uuid} # 随机uuid
age: ${random.int} # 随机int
happy: false
birth: 2023/13/14
maps: {k1: v1,k2: v2}
hello: LOVE
lists:
- code
- music
- girl
dog:
name: "${person.hello:hello}_旺财"
age: 3
server:
port: 8081
spring:
profiles:
active: dev
---
server:
port: 8082
spring:
profiles: dev
---
server:
port: 8083
spring:
profiles: test
//表示这是一个配置类
@Configuration(
proxyBeanMethods = false
)
//自动配置属性:ServerProperties
@EnableConfigurationProperties({ServerProperties.class})
//Spring的底层注解:根据不同的条件,来判断当前配置或者类是否生效!
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
prefix = "server.servlet.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {........
精髓
1、SpringBoot启动会加载大量的自动配置类
2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
# 配置文件到底能写什么 -----联系---spring.factories;
# 在我们这配置文件中能配置的东西,都存在一个规律
# xxxAutoConfiguration:默认值 xxxProperties 和 配置文件绑定,我们就可以使用自动义的配置了!
# 可以通过 debug: true 来查看,哪些自动配置类生效,哪些没有生效!
debug: true
Positive matches:(自动配置类启用的:正匹配)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Unconditional classes: (没有条件的类)
SpringBoot Web开发
jar : webapp
自动装配
springboot到底帮我们配置了什么?我们能不能进行修改?能修改哪些东西?能不能扩展?
- xxxxAutoConfiguraion… 向容器中自动配置组件
- xxxxproperties:自动配置类,装配配置文件中自定义的一些内容!
要解决的问题:
- 导入静态资源…
- 首页
- jsp,模板引擎Thymeleaf
- 装配扩展SpringMVC
- 增删改查
- 拦截器
- 国际化!
静态资源
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
总结:
- 在springboot,我们可以使用以下方式处理静态资源
- webjars
localhost:8080/webjars/
- public, static, /**, resources
localhost:8080/
- webjars
- 优先级:resources > static(默认) > public
模板引擎
结论:只要西药使用thymeleaf,只需要导入对应的依赖就可以了!我们将html放在我们的templates目录下即可!
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
MVC配置原理
package com.kuang.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Locale;
//如果你想diy一些定制化的功能,只要写这个组件,然后将它交给springboot,springboot就会帮我们自动装配!
//扩展 springmvc dispatchservlet
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//ViewResolver 实现了视图解析器接口的类,我们就可以把它看做视图解析器
@Bean
public ViewResolver myViewResolver(){
return new MyViewResolver();
}
//自定义了一个自己的视图解析器 MyViewResolver
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return null;
}
}
}
在springboot中,有很多的xxx 帮助我们进行扩展配置,只要看见了这个东西,我们就要注意了!
**<font color='red'>狂神视频连接:和原文笔记</font>**[https://www.cnblogs.com/th11/p/15208081.html](https://www.cnblogs.com/th11/p/15208081.html)
## 第一个SpringBoot程序
到底多么简单:
- jdk 1.8
- maven 3.6.1
- SpringBoot 最新版
- IDEA
官方:提供了一个快速生成的网站!IDEA集成了这个网站!(建议IDEA创建)
## 原理初探
<font color='red'>自动配置</font>
> **pom.xml**
- spring-boot-description:核心依赖在父工程中!
- 我们在写或者引入一些SpringBoot依赖的时候,不需要指定版本,就因为有这些版本仓库
> **启动器**
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
- spring-boot-starter-web,他就会帮我们自动导入web环境所有依赖!
- springboot会将所有的功能场景,都变成一个个的启动器
- 我们要使用什么功能,就只需要找到对应的启动器就可以了
starter
主程序
//SpringBootApplication:标注这个类是一个springboot的应用 :启动类下的所有资源被导入
@SpringBootApplication
public class HelloworldApplication {
public static void main(String[] args) {
//将springboot应用启动
SpringApplication.run(HelloworldApplication.class, args);
}
}
注解
@SpringBootConfiguration //springboot的配置
@Configuration //spring配置类
@Component //说明这也是一个spring的组件
@EnableAutoConfiguration //自动配置
@AutoConfigurationPackage //自动配置包
@Import({AutoConfigurationPackages.Registrar.class}) //自动配置`包注册`
@Import({AutoConfigurationImportSelector.class})
//获取所有的配置
List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
获得候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//这里的getSpringFactoriesLoaderFactoryClass()方法
//返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
List<String> configurations = SpringFactoriesLoader.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;
}
META-INF/spring.factories:自动配置的核心文件
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
所有资源加载到配置中!
**结论:**springboot所有自动配置都是在启动的时候扫描并加载:spring.factories
所有的自动配置类都在这里面,但不一定生效,要判断条件是否成立,只要成立,只要导入了对应的 start,就有对应的启动器,有了启动器,我们自动装配就会生效,然后就配置成功!
- springboot在启动的时候,从类路径下
META-INF/spring.factories
获取指定的值; - 将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置!
- 以前我们需要自动配置的东西,现在springboot帮我们做了!
- 整合javaEE,解决方案和自动配置的东西都在
spring-boot-autoconfigure-2.6.5jar
这个包下 - 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器;
- 容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这些类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration,JavaConfig!
- 有了自动配置类,免去了我们的手动编写配置文件的工作!
SpringApplication
这个类主要做了以下四件事情:
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();
}
run方法流程分析
SpringBoot配置
yaml可以直接给实体类赋值!
# k=v properties 只能保存键值对!
# 对空格的要求十分严格!
# 普通的key-value
# 注入到我们的配置类中!
name: qinjiang
# 对象
student:
name: qinjiang
age: 3
# 行内写法
student: {name: qinjiang,age: 3}
# 数组
pets:
- cat
- dog
- pig
pets: [cat,dog,pig]
配置文件占位符
这里有微调,否则旺财输出为乱码
person:
name: qinjiang${random.uuid} # 随机uuid
age: ${random.int} # 随机int
happy: false
birth: 2023/13/14
maps: {k1: v1,k2: v2}
hello: LOVE
lists:
- code
- music
- girl
dog:
name: "${person.hello:hello}_旺财"
age: 3
server:
port: 8081
spring:
profiles:
active: dev
---
server:
port: 8082
spring:
profiles: dev
---
server:
port: 8083
spring:
profiles: test
//表示这是一个配置类
@Configuration(
proxyBeanMethods = false
)
//自动配置属性:ServerProperties
@EnableConfigurationProperties({ServerProperties.class})
//Spring的底层注解:根据不同的条件,来判断当前配置或者类是否生效!
@ConditionalOnWebApplication(
type = Type.SERVLET
)
@ConditionalOnClass({CharacterEncodingFilter.class})
@ConditionalOnProperty(
prefix = "server.servlet.encoding",
value = {"enabled"},
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {........
精髓
1、SpringBoot启动会加载大量的自动配置类
2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
# 配置文件到底能写什么 -----联系---spring.factories;
# 在我们这配置文件中能配置的东西,都存在一个规律
# xxxAutoConfiguration:默认值 xxxProperties 和 配置文件绑定,我们就可以使用自动义的配置了!
# 可以通过 debug: true 来查看,哪些自动配置类生效,哪些没有生效!
debug: true
Positive matches:(自动配置类启用的:正匹配)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Unconditional classes: (没有条件的类)
SpringBoot Web开发
jar : webapp
自动装配
springboot到底帮我们配置了什么?我们能不能进行修改?能修改哪些东西?能不能扩展?
- xxxxAutoConfiguraion… 向容器中自动配置组件
- xxxxproperties:自动配置类,装配配置文件中自定义的一些内容!
要解决的问题:
- 导入静态资源…
- 首页
- jsp,模板引擎Thymeleaf
- 装配扩展SpringMVC
- 增删改查
- 拦截器
- 国际化!
静态资源
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
总结:
- 在springboot,我们可以使用以下方式处理静态资源
- webjars
localhost:8080/webjars/
- public, static, /**, resources
localhost:8080/
- webjars
- 优先级:resources > static(默认) > public
模板引擎
结论:只要西药使用thymeleaf,只需要导入对应的依赖就可以了!我们将html放在我们的templates目录下即可!
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
MVC配置原理
package com.kuang.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Locale;
//如果你想diy一些定制化的功能,只要写这个组件,然后将它交给springboot,springboot就会帮我们自动装配!
//扩展 springmvc dispatchservlet
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//ViewResolver 实现了视图解析器接口的类,我们就可以把它看做视图解析器
@Bean
public ViewResolver myViewResolver(){
return new MyViewResolver();
}
//自定义了一个自己的视图解析器 MyViewResolver
public static class MyViewResolver implements ViewResolver{
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return null;
}
}
}
在springboot中,有很多的xxx 帮助我们进行扩展配置,只要看见了这个东西,我们就要注意了!
package com.kuang.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//如果我们要扩展springmvc,官方建议我们这样去做!
@Configuration
@EnableWebMvc //这玩意就是导入一个类:DelegatingWebMvcConfiguration:从容器中获取所以的webmvcconfig
public class MyMvcConfig implements WebMvcConfigurer {
//视图跳转
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/kuang").setViewName("test");
}
}
员工管理系统
参考源码:https://blog.csdn.net/weixin_44517301/article/details/121050452
1、首页配置:
- 注意点,所有页面的静态资源都需要使用thymeleaf接管;
- url:@{}
2、页面国际化:
- 我们需要配置
i18n
文件 - 我们如果需要在项目中进行按钮自动切换,我们需要自定义一个组件
localeResolver
- 记得将自己写的组件配置到spring容器
@Bean
#{}
3、登录 + 拦截器
4、员工列表展示
- 提取公共页面
th:fragment="sidebar"
th:replace="~{dashboard::topbar}"
- 如果要传递参数,可以直接使用 () 传参,接受判断即可!
- 列表循环展示5.添加员工
4.返回首页
6.CRUD 搞定
7.404
上周回顾
- SpringBoot是什?
- 微服务
- HelloWorld~
- 探究源码~ 自动装配原理~
- 配置 yaml
- 多文档环境切换
- 静态资源映射
- Thymeleaf th:xxx
- SpringBoot 如何扩展MVC javaconfig~
- 如何修改SpringBoot的默认配置~
- CRUD
- 国际化
- 拦截器
- 定制首页,错误页~
这周:
- JDBC
- Mybatis:重点
- Shiro:安全:重点
- Spring Security:安全:重点
- 异步任务~,邮件发送,定时任务()
- Swagger
- Dubbo + Zookeeper
Data
mybatis
整合包
mybatis-spring-boot-starter
- 导入包
- 配置文件
- mybatis配置
- 编写SQL
- service层调用dao层
- controller调用service层
SpringSecurity(安全)
在web开发中,安全第一位!过滤器,拦截器 ~
功能性需求:否
做网站:安全用在什么时候考虑? 设计之初!
- 漏洞,隐私泄露 ~
- 架构一旦确定 ~
shiro、SpringSecurity:很像~除了类不一样,名字不一样;
认证,授权(VIP1,VIP2,VIP3)
- 功能权限
- 访问权限
- 菜单权限
- … 拦截器,过滤器:大量的原生代码~ 冗余
MVC—SPEING—SPRINGBOOT——框架思想
静态源码: https://gitee.com/ENNRIAAA/spring-security-material/repository/archive/master.zip
shiro
1.导入依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.配置文件
log4j.properties
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=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
shiro.ini
[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz
3.HelloWorld
Quickstart源码
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.ini.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.lang.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple Quickstart application showing how to use Shiro's API.
*
* @since 0.9 RC2
*/
public class Quickstart {
/*通过LoggerFactory 工厂类,创建log4j对象,
加上transient就不会被序列化,不会被持久化生命周期仅为内存中
*/
private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
public static void main(String[] args) {
// The easiest way to create a Shiro SecurityManager with configured
// realms, users, roles and permissions is to use the simple INI config.
// We'll do that by using a factory that can ingest a .ini file and
// return a SecurityManager instance:
// Use the shiro.ini file at the root of the classpath
// (file: and url: prefixes load from files and urls respectively):
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
// for this simple example quickstart, make the SecurityManager
// accessible as a JVM singleton. Most applications wouldn't do this
// and instead rely on their container configuration or web.xml for
// webapps. That is outside the scope of this simple quickstart, so
// we'll just do the bare minimum so you can continue to get a feel
// for things.
SecurityUtils.setSecurityManager(securityManager);
// Now that a simple Shiro environment is set up, let's see what you can do:
// get the currently executing user:
//1 获取当前执行的用户 (也不能叫用户,就是个Subject,类似于用户)
//2 会自动获取与当前线程所匹配的相关基于用户的数据参数
// -----获取原因详解-----
/*
*通过SebjectUtils类调用getSubject()方法
*
* 通过ThreadContext直接获取到当前的Subject 有三种情况
* 1 如果能获取,则return Subject对象
* 2 如果没能获取到,调用buildSubject 创建Subject
* 再进行尝试绑定,如果subject仍未空,则清空
* 3 如果操作失败则抛出UnavaiLableSecurityManagerException异常
* 这时候就需要检查配置或者Realm里出问题了
*/
Subject currentUser = SecurityUtils.getSubject();
// Do some stuff with a Session (no need for a web or EJB container!!!)
//3 可以在其中插入获取session的事务,获取当前的会话
// 此session是Shiro的特有的,提供了常规HttpSession的大部分功能
Session session = currentUser.getSession();
session.setAttribute("someKey", "aValue");
//4 获取<K,V>的Value值,通过session.getAttribute,这就是角色 我们的用户(Subject)
String value = (String) session.getAttribute("someKey");
if (value.equals("aValue")) {
log.info("Retrieved the correct value! [" + value + "]");
}
//5 OK.现在获取成功了,我们有一个角色了
// let's login the current user so we can check against roles and permissions:
/*6 接下来,就可以添加用Subject Session 做角色和权限检查之类的功能
但是,现在只能对Shiro已知用户进行操作,虽然Subject是我们当前的用户,
但是,一个很严重的问题,这个用户对于我们来说是一个匿名用户
什么是匿名用户,我们知道有这么一个角色,但是我们不知道他是谁,他有什么权限
直到他至少登录一次进行操作,我们才能得到用户具体对象权限
isAuthenticated 收集Subject和凭证/令牌 并进行一个认证机制
这里只是进行判断是否为第一次登陆或者没有设置RememberMe=true,即RememberMe=false
如果为true则跳过login ,这里isAuthenticated原值为false
在处理的时候会由login进行角色验证,并赋予authenticated true值*/
if (!currentUser.isAuthenticated()) {
/*实际上就是一个普通的字符串没有特殊意义,只是为了将令牌变成char[]数组来存储
以及其他信息也赋予进去变成一个token*/
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
/*设置,RememberMe缓存,后面直接可以通过subject.getPrincipal来获取用户信息,
但是,仅仅针对于非匿名用户且非敏感网页(如会员管理,后台和个人信息等),由我们来设置*/
token.setRememberMe(true);
//7 第一个分叉,尝试去登录
try {
currentUser.login(token);
//会发生多种异常,从小往大排序,这期间,我们可以在login里加一些其他信息
//为Subject异常,不对应等问题
} catch (UnknownAccountException uae) {
log.info("There is no user with username of " + token.getPrincipal());
//令牌不对应等问题
} catch (IncorrectCredentialsException ice) {
log.info("Password for account " + token.getPrincipal() + " was incorrect!");
//账号被锁定问题,登陆次数过多等
} catch (LockedAccountException lae) {
log.info("The account for username " + token.getPrincipal() + " is locked. " +
"Please contact your administrator to unlock it.");
}
// ... catch more exceptions here (maybe custom ones specific to your application?
//其他异常或者大的异常,也可设置自己想处理的异常机制
catch (AuthenticationException ae) {
//unexpected condition? error?
}
}//输出Subject信息
//say who they are:
//print their identifying principal (in this case, a username):
log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
//如果角色拥有权限,则输出权限信息
//test a role:
if (currentUser.hasRole("schwartz")) {
log.info("May the Schwartz be with you!");
//很有意思的翻译:愿施瓦茨和你在一起
} else {
log.info("Hello, mere mortal.");
//很有意思的翻译:你好,凡人(意思,你是个凡人,普通人)
}
/*isPermitted查看是否有权限,是否有其他特定的相关权限
即判断已登陆用户是否具有某权限
查看普通实例用户,这里不查看强大的用户(功能强大的实例级权限管理)
翻译: 权限名:光剑使用权
*/
//test a typed permission (not instance-level)
if (currentUser.isPermitted("lightsaber:wield")) {
log.info("You may use a lightsaber ring. Use it wisely.");
//很有意思的翻译:你可以使用光剑。明智地使用它
} else {
log.info("Sorry, lightsaber rings are for schwartz masters only.");
//很有意思的翻译:抱歉,光剑只供施瓦兹大师使用
}
//权限再判断,判断是否有更细粒度的权限
//a (very powerful) Instance Level permission:
if (currentUser.isPermitted("winnebago:drive:eagle5")) {
log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " +
"Here are the keys - have fun!");
} else {
log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
}
//all done - log out!
/*获取currentUser.login(),登出
//查看源码分析,
// 登出的底层实际上是清除session
//最后再将
this.session = null;
this.principals = null;
//将authenticated初始化即赋值false
this.authenticated = false*/
currentUser.logout();
System.exit(0);
}
}
Spring Secutiry~都有!
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Simple Quickstart application showing how to use Shiro's API.
*
* @since 0.9 RC2
*/
public class Quickstart {
private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
public static void main(String[] args) {
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
// Now that a simple Shiro environment is set up, let's see what you can do:
// get the currently executing user:
//获取当前的用户对象 Subject
Subject currentUser = SecurityUtils.getSubject();
//通过当前用户拿到 session
Session session = currentUser.getSession();
session.setAttribute("someKey", "aValue");
String value = (String) session.getAttribute("someKey");
if (value.equals("aValue")) {
log.info("Subject>>>session[" + value + "]");
}
//判断当前用户是否被认证
//Token:没有获取,直接设置令牌
if (!currentUser.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken("haojiahuo123", "vespa");
token.setRememberMe(true);//设置记住我
try {
currentUser.login(token);//执行登录操作
} catch (UnknownAccountException uae) {
log.info("There is no user with username of " + token.getPrincipal());
} catch (IncorrectCredentialsException ice) {
log.info("Password for account " + token.getPrincipal() + " was incorrect!");
} catch (LockedAccountException lae) {
log.info("The account for username " + token.getPrincipal() + " is locked. " +
"Please contact your administrator to unlock it.");
}
// ... catch more exceptions here (maybe custom ones specific to your application?
catch (AuthenticationException ae) {
//unexpected condition? error?
}
}
//say who they are:
//print their identifying principal (in this case, a username):
log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
//test a role:
if (currentUser.hasRole("schwartz")) {
log.info("May the Schwartz be with you!");
} else {
log.info("Hello, mere mortal.");
}
//粗粒度
//test a typed permission (not instance-level)
//
if (currentUser.isPermitted("lightsaber:wield")) {
log.info("You may use a lightsaber ring. Use it wisely.");
} else {
log.info("Sorry, lightsaber rings are for schwartz masters only.");
}
//细粒度
//a (very powerful) Instance Level permission:
if (currentUser.isPermitted("winnebago:drive:eagle5")) {
log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " +
"Here are the keys - have fun!");
} else {
log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
}
//注销
//all done - log out!
currentUser.logout();
//结束
System.exit(0);
}
}
具体的看这个博主:https://www.cnblogs.com/feng-zhi/p/14761954.html
Swagger
学习目标:
- 了解swagger的作用和概念
- 了解前后端分离
- 在springboot中集成swagger
Swagger简介
前后端分离
Vue + SpringBoot
后端时代:前端只用管理静态页面;html =>后端。模板引擎 JSP =>后端是主力
前后端分离式时代
- 后端:后端控制层,服务层,数据访问层【后端团队】
- 前端:前端控制层,视图层【前端团队】
- 伪造后端数据,json。已经存在了,不需要后端,前端工程依旧能跑起来
- 前端如何交互? ===> API
- 前后端相对独立,松耦合;
- 前后端甚至可以部署在不同的服务器上;
产生了一个问题:
- 前后端集成联调,前端人员和后端人员无法做到“即时协商,尽早解决”,最终导致问题集中爆发!
解决方案:
- 首先指定schema[计划的提纲],实时更新最新的API,降低集成风险 ;
- 早些年:指定word计划文档;
- 前端测试后端接口:postman
- 后端提供接口,后端提供接口需要实时更新的消息的改动!
Swagger
- 号称世界上最流行的Api框架;
- RestFul Api 文档在线自动生成工具 => Api文档与API定义同步更新
- 直接运行,可以在线测试API接口;
- 支持多种语言:(Java,Php…)
官网:https://swagger.io/
在项目使用swagger需要水平springbox;
- swagger2
- ui
SpringBoot集成 Swagger
1、新建一个SpringBoot == web项目
2、导入相关依赖
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<!--启动包-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
application.properties
# 更改规则
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
3.编写一个hello工程
4.配置Swagger ==> Config
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
}
5.测试运行!**3.0之后的访问地址:**http://localhost:8080/swagger-ui/index.html
swagger配置扫描接口
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//RequestHandlerSelectors,配置要扫描接口的方式
//basePackage:指定要扫描的包
//any():扫描全部
//none():不扫描
//withClassAnnotation:扫描类上的注解,参数是一个注解的反射对象
//withMethodAnnotation:扫描方法上的注解
.apis(RequestHandlerSelectors.basePackage("com.kuang.controller"))
//paths() 过滤什么路径
.paths(PathSelectors.ant("/kuang/**"))
.build();
}
配置是否启动swagger
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(false)//enable是否启动swagger,如果为false,则swagger不能在浏览器
.select()
.apis(RequestHandlerSelectors.basePackage("com.kuang.controller"))
//.paths(PathSelectors.ant("/kuang/**"))
.build();
}
swagger在生产环境中使用,在发布的时候不使用?
- 判断是不是生产环境 falg = false
- 注入enable(flag)
//配置了swagger的docket的bean实例
@Bean
public Docket docket(Environment environment){
//设置要显示的swagger环境
Profiles profiles = Profiles.of("dev");
//通过 environment.acceptsProfiles 判断是否处于自己设定的环境当中
boolean flag = environment.acceptsProfiles(profiles);
System.out.println(flag);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(flag)//enable是否启动swagger,如果为false,则swagger不能在浏览器
.select()
.apis(RequestHandlerSelectors.basePackage("com.kuang.controller"))
//.paths(PathSelectors.ant("/kuang/**"))
.build();
}
配置API文档的分组
.groupName("浪潮")
如何配置多个分组;多个Docket实例即可
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("B");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("C");
}
实体类配置: 得加get和set方法
@ApiModel("用户实体类")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private String password;
controller
package com.kuang.controller;
import com.kuang.pojo.User;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.Mapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping(value = "/hello")
public String hello(){
return "hello";
}
//只要我们的接口中,返回值中存在实体类,他就会被扫描到swagger中
@GetMapping(value = "/user")
public User user(){
return new User();
}
//Operation接口,不是放在类上的,是方法
@ApiOperation("hello控制类")
@GetMapping(value = "hello2")
public String hello2(String username){
return "hello" + username;
}
@ApiOperation("post测试类")
@PostMapping(value = "postt")
public User postt(User user){
int i = 5/0;
return user;
}
}
总结:
- 我们可以通过swagger给一些比较难理解的属性或者接口,增加注释信息
- 接口文档实时更新
- 可以在线测试
seagger是一个优秀的工具,几乎所有的大公司都有在使用它
【注意点】在正式发布的时候,关闭swagger!!!处于安全考虑。而节省运行的内存!
任务
异步任务~
邮件发送~
<!--javax.mail-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
@Autowired
JavaMailSenderImpl javaMailSender;
@Test
void contextLoads() {
//一个简单的邮箱
SimpleMailMessage MailMessage = new SimpleMailMessage();
MailMessage.setSubject("刘志伟爸爸");
MailMessage.setText("你站在这别动,我去买点橘子,我就吃两个,剩下的都给你。");
MailMessage.setFrom("2465665899@qq.com");//发件人,更改发件人,要改properties配置文件
MailMessage.setTo("2465665899@qq.com");//收件人
javaMailSender.send(MailMessage);
}
@Test
void contextLoads2() throws MessagingException {
//一个复杂的邮箱
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
//组装~
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
//正文
helper.setSubject("父爱无声~~~");
helper.setText("<p style='color:red'>你室友弄的酒真喝了?</p>",true);
//附件
helper.addAttachment("1.jpg",new File("C:\\Users\\Administrator\\Desktop\\1.png"));
helper.addAttachment("2.jpg",new File("C:\\Users\\Administrator\\Desktop\\2.png"));
helper.setFrom("2465665899@qq.com");
helper.setTo("3540428468@qq.com");
javaMailSender.send(mimeMessage);
}
定时任务表达式
TaskScheduler //任务调度者
TaskExecutor //任务执行者
@EnableScheduling//开启定时功能的注解
@Scheduled//什么时候执行~
cron表达式
@Service
public class ScheduledService {
//在一个特定的时间执行这个方法~ Timer
//cron 表达式~
// 秒 分 时 日 月 星期~
/*
30 15 10 * * ? 每天10点15分30 执行一次
30 0/5 10,18 * * ? 每天10点和18点,每隔五分钟执行一次
0 15 10 ? * 1-6 每个月的周一到周六
*/
@Scheduled(cron = "0/2 * * * * ?")
public void hello(){
System.out.println("BUG可以离我远点~~~");
}
}
springboot整合redisTemplate
这里一级在Redis课程,讲过一次,具体笔记可以去那里看!
Redis笔记:https://blog.csdn.net/qq_54726480/article/details/123089747
分布式 Dubbo + Zookeeper + springboot
RPC
RPC 两个核心模块:通讯和序列化。
序列化:数据传输需要转换
Dubbo ~ 18年重启! Dubbo 3.x RPC Error Exception
专业的事,交给专业的人来做~ 不靠谱! 阿里巴巴!
zookeeper:注册中心!
dubbo-admin:是一个监控管理后台查看我们注册了哪些服务,哪些服务被消费了
Dubbo:jar包~
步骤:
前提:zookeeper服务已开启!
1、提供者提供服务
- 导入依赖
- 配置注册中心的地址,以及服务发现名,和要扫描的包~
- 在想要被注册的服务上面~增加一个注解@Service
2、消费者如何消费
- 导入依赖
- 配置注册中心的地址,配置自己的服务名
- 从远程注入服务~@Reference
具体可以代码可以看:https://blog.csdn.net/qq_41819988/article/details/109606328