狂神说SpringBoot01:Hello,World!
狂神说SpringBoot02:运行原理初探
狂神说SpringBoot03:yaml配置注入
狂神说SpringBoot04:JSR303数据校验及多环境切换
狂神说SpringBoot05:自动配置原理
狂神说SpringBoot06:自定义starter
狂神说SpringBoot07:整合JDBC
狂神说SpringBoot08:整合Druid
狂神说SpringBoot09:整合MyBatis
狂神说SpringBoot10:Web开发静态资源处理
狂神说SpringBoot11:Thymeleaf模板引擎
狂神说SpringBoot12:MVC自动配置原理
狂神说SpringBoot13:页面国际化
狂神说SpringBoot14:集成Swagger终极版
狂神说SpringBoot15:异步、定时、邮件任务
狂神说SpringBoot16:富文本编辑器
狂神说SpringBoot17:Dubbo和Zookeeper集成
狂神说SpringBoot18:集成SpringSecurity
注解:
//获取所有配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes);
获取候选配置:
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
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;
}
配置文件加载位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Nr27xHV-1594913883189)(D:\我\MyBlog\狂神说Java SpringBoot.assets\image-20200709213144157.png)]
file : 文件路径,就是项目路径
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MmY445bN-
自动装配:
SpringBoot到底帮我们配置了什么?我们能不能进行修改?能修改哪些东西?能不能扩展?
要解决的问题:
导入静态资源…
首页
jsp, 模板引擎Thymeleaf
thymeleaf依赖
装配扩展SpringMVC
增删改查
拦截器
国际化
LocaleResolver
@Bean
整合包
mybatis-spring-boot-starter
导入包
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.1version>
dependency>
配置yml文件
application.yml
# 配置spring自带的数据源
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
# 整合mybatis
mybatis:
# 别名
type-aliases-package: com.kuang.pojo
# mapper文件位置
mapper-locations: classpath:mybatis/mapper/*.xml
mybatis配置
User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String password;
}
UserMapper接口
@Repository
@Mapper
public interface UserMapper {
public User queryUserByName(String name);
}
UserMapper.xml配置文件
<mapper namespace="com.kuang.mapper.UserMapper">
<select id="getUserList" resultType="com.kuang.pojo.User" parameterType="String">
select * from USER where name = #{name}
select>
mapper>
编写sql
service层调用dao层
UserService 接口
public interface UserService {
public User queryUserByName(String name);
}
UserServiceImpl实现类
@Service
public class UserServiceImpl implements UserService{
@Autowired
UserMapper mapper;
public User queryUserByName(String name) {
User user = mapper.queryUserByName(name);
return user;
}
}
controller调用service层
@Autowired
UserServiceImpl userService;
public void mian(String args[]){
User user = userService.queryUserByName("dog");
}
引入 Spring Security 模块
编写 Spring Security 配置类
参考官网:https://spring.io/projects/spring-security
编写基础配置类
//AOP : 拦截器
@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");
//没有权限默认会到登录页面,需要开启登录的页面
http.formLogin()
.loginPage("/toLogin")
.usernameParameter("username")
.passwordParameter("password")
.loginProcessingUrl("/login");
http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
// 开启注销功能
http.logout().logoutSuccessUrl("/");
//开启记住我功能
http.rememberMe().rememberMeParameter("rememberme");
}
//认证
@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("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
.and()
.withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}
导入依赖
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>1.5.3version>
dependency>
编写Shiro配置类
@Configuration
public class ShrioConfig {
//ShiroFilterFactoryBean : Step3
@Bean
public ShiroFilterFactoryBean getShrioFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
return bean;
}
//DefaultWebSecurityManager : Step2
@Bean("securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建 realm 对象, 需要自定义类:Step1
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
自定义UserRealm
//自定义的 UserRealm
public class UserRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
一个小Demo:
导入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.1.RELEASEversion>
<relativePath/>
parent>
<groupId>com.kuanggroupId>
<artifactId>shiro-springbootartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>shiro-springbootname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>com.github.theborakompanionigroupId>
<artifactId>thymeleaf-extras-shiroartifactId>
<version>2.0.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.20version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.22version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.1version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.12version>
dependency>
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>1.5.3version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
整合MyBatis
编写Shiro配置类
@Configuration
public class ShrioConfig {
//ShiroFilterFactoryBean : Step3
@Bean
public ShiroFilterFactoryBean getShrioFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
anno: 无需认证就可以访问
authc: 必须认证了才可以访问
user: 必须拥有 记住我 功能才能用
perms: 拥有对某个资源的权限才能访问
role: 拥有某个角色权限才能访问
*/
Map<String, String> filterMap = new LinkedHashMap<>();
//用户授权,正常情况下没有授权会跳转到授权页面
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/update","perms[user:update]");
//拦截
//filterMap.put("/user/add","authc");
//filterMap.put("/user/update","authc");
filterMap.put("/user/*","authc");
//设置登录请求
bean.setLoginUrl("/toLogin");
//设置未授权页面
bean.setUnauthorizedUrl("/noauth");
bean.setFilterChainDefinitionMap(filterMap);
return bean;
}
//DefaultWebSecurityManager : Step2
@Bean("securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联userRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建 realm 对象, 需要自定义类:Step1
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
//整合 ShiroDialect:用来整合shiro thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
自定义UserRealm
//自定义的 UserRealm
public class UserRealm extends AuthorizingRealm {
@Autowired
UserServiceImpl userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了 => doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 拿到当前登录的这个对象
Subject subject = SecurityUtils.getSubject();
// 拿到User对象
User currentUser = (User) subject.getPrincipal();
// 设置当前用户的权限
System.out.println(currentUser.getName() + "的权限为 " + currentUser.getPerms());
info.addStringPermission(currentUser.getPerms());
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了 => 认证AuthenticationToken");
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
//连接真实的数据库
User user = userService.queryUserByName(userToken.getUsername());
if(user == null){
//没有这个人
return null; //抛出异常 UnknownAccountException
}
// 登录成功 将用户信息存入session
Subject currentSubject = SecurityUtils.getSubject();
Session session = currentSubject.getSession();
session.setAttribute("loginUser",user.getName());
// 密码认证,shiro做
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
}
学习目标:
前后端分离时代:
Swagger :
在项目中使用Swagger需要Springbox
新建一个SpringBoot - web 工程
导入相关依赖
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
编写一个Hello工程
配置Swagger ==> Config
@Configuration
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
}
测试运行:http://localhost:8080/swagger-ui.html
@Configuration
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
//配置了Swagger 的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
}
//配置Swagger信息=apiInfo
public ApiInfo apiInfo(){
//作者信息
Contact contact = new Contact("Daniel","https://www.baidu.com","[email protected]");
return new ApiInfo("Dainel的SwaggerAPI文档",
"天道酬勤",
"v1.0",
"urn:tos",
contact, "Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList());
}
}
Docket.select()
//配置了Swagger 的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.select()
//RequestHandlerSelectors,配置要扫描接口的方式
//basePackage,指定要扫描的包
//any(): 扫描全部
.apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
.paths(PathSelectors.ant("/kuang/**"))
.build();
}
题目:我只希望我的Swagger在生产环境中使用,在发布的时候不使用
- 判断是不是生产环境 flag = false
- 注入enable (flag)
//配置了Swagger 的Docket的bean实例
@Bean
public Docket docket(Environment environment){
//设置要显示的Swagger环境
Profiles profiles = Profiles.of("dev","test");
//通过 environment.acceptsProfiles 判断是否处在自己设定的环境中
boolean flag = environment.acceptsProfiles(profiles);
...
}
配置API文档的分组
.groupName("狂神")
Swagger是一个优秀的工具,几乎所有的大公司都有使用它
【注意点】在正式发布的时候,关闭Swagger!!出于安全考虑,而且节省运行的内存。
给要实现异步任务加上注解 @Async
@Service
public class AsyncService {
@Async
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据正在处理...");
}
}
在main方法开启异步功能 @EnableAsync
@EnableAsync // 开启异步注解功能
@SpringBootApplication
public class Springboot09TaskApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot09TaskApplication.class, args);
}
}
导入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
dependency>
配置邮箱和密码
[email protected]
spring.mail.password=xxyyzzhhll
spring.mail.host=smtp.qq.com
# 开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true
测试发送邮件(组合邮件,带附件)
@SpringBootTest
class Springboot09TaskApplicationTests {
@Autowired
JavaMailSenderImpl mailSender;
@Test
void contextLoads2() throws MessagingException {
//一个复杂的邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
//组装
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
//正文
helper.setSubject("Test");
helper.setText(" 这是一封测试邮件
",true);
//附件
helper.addAttachment("data1",new File("D:\\testdata\\2017-01-01.xls"));
helper.setTo("[email protected]");
helper.setFrom("[email protected]");
mailSender.send(mimeMessage);
}
- TaskScheduler 任务调度者
- TaskExecutor 任务执行者
- @EnableScheduling 开启定时功能的注解
- @Scheduled 什么时候执行
- Cron表达式
编写定时服务
@Service
public class ScheduledService {
//在一个特定的时间执行这个方法
//cron 表达式
//秒 分 时 日 月 周几
/*
30 17 17 * * ? 每天10点15分30 执行一次
30 0/5 10,18 * * ? 每天10点和18点,每隔五分钟执行一次
*/
@Scheduled(cron = "30 17 17 * * ?")
public void Hello(){
System.out.println("hello,被执行了!");
}
}
在启动类开启定时功能
@EnableAsync // 开启异步注解功能
@EnableScheduling //开启定时功能的注解
@SpringBootApplication
public class Springboot09TaskApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot09TaskApplication.class, args);
}
}
单独整理
zookeeper :注册中心
dubbo-admin : 监控管理后台,查我们注册了哪些服务,哪些服务被消费了
Dubbo:jar包
步骤:
前提:zookeeper服务已启动
提供者提供服务
消费者如何消费
架构 --> 解耦
开发框架:
Spring:
Ioc(控制反转) + Aop(面向切面编程)[本质:动态代理]
Ioc(控制反转)
以前自己是new 对象,现在交给spring ioc容器统一管理,我们需要什么直接去拿 ioc容器就像是一个对象工厂,把对象交给工厂,工程管理对象的创建以及依赖关系,我们需要的时候直接去工厂中获取
[控制反转,依赖注入] 控制反转:是一种思想,原本自己控制的事情,交给ico控制 ,依赖注入是控制反转的实现方式【对象】无需自行创建或者管理依赖关系,依赖关系将被自动注入到需要他们的对象当中
:将对象统一管理 :降低耦合
Aop(面向切面编程)[本质:动态代理]
解决非业务代码抽取的问题,底层是动态代理,在spring内实现依赖是BeanPostProcessor ,在方法前后增加非业务代码
spring是轻量型的java的开源框架,容器
负载均衡
微服务架构存在的问题:
==》 解决方案:
SpringCloud,是一套生态,就是用来解决以上分布式架构的4个问题。
想使用SpringCloud,必须掌握SpringBoot,因为SpringCloud是基于SpringBoot的
1. API网关,服务路由
2. HTTP,RPC框架,异步调用
3. 服务注册与发现,高可用
4. 熔断机制,服务降级