注解:
//获取所有配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes);
12
获取候选配置:
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;
}
12345
配置文件加载位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5Nr27xHV-1594913883189)(D:\我\MyBlog\狂神说Java SpringBoot.assets\image-20200709213144157.png)]
file : 文件路径,就是项目路径
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MmY445bN-![1594913883192)(D:\我\MyBlog\狂神说Java SpringBoot.assets\image-20200709213352422.png)]
自动装配:
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>
123456
配置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
1234567891011121314
mybatis配置
User
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String password;
}
12345678
UserMapper接口
@Repository
@Mapper
public interface UserMapper {
public User queryUserByName(String name);
}
12345
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>
123456
编写sql
service层调用dao层
UserService 接口
public interface UserService {
public User queryUserByName(String name);
}
123
UserServiceImpl实现类
@Service
public class UserServiceImpl implements UserService{
@Autowired
UserMapper mapper;
public User queryUserByName(String name) {
User user = mapper.queryUserByName(name);
return user;
}
}
123456789
controller调用service层
@Autowired
UserServiceImpl userService;
public void mian(String args[]){
User user = userService.queryUserByName("dog");
}
12345
引入 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");
}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
导入依赖
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-springartifactId>
<version>1.5.3version>
dependency>
12345
编写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();
}
}
1234567891011121314151617181920212223242526
自定义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;
}
}
123456789101112131415
一个小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>
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
整合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();
}
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
自定义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(),"");
}
}
123456789101112131415161718192021222324252627282930313233343536373839404142434445
学习目标:
前后端分离时代:
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>
12345678910111213
编写一个Hello工程
配置Swagger ==> Config
@Configuration
@EnableSwagger2 //开启Swagger
public class SwaggerConfig {
}
12345
测试运行: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());
}
}
12345678910111213141516171819202122
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();
}
123456789101112
题目:我只希望我的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);
...
}
12345678910
配置API文档的分组
.groupName("狂神")
1
如何配置多个分组;多个Docket实例即可
总结:
Swagger是一个优秀的工具,几乎所有的大公司都有使用它
【注意点】在正式发布的时候,关闭Swagger!!出于安全考虑,而且节省运行的内存。
给要实现异步任务加上注解 @Async
@Service
public class AsyncService {
@Async
public void hello(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("数据正在处理...");
}
}
123456789101112
在main方法开启异步功能 @EnableAsync
@EnableAsync // 开启异步注解功能
@SpringBootApplication
public class Springboot09TaskApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot09TaskApplication.class, args);
}
}
1234567
导入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
dependency>
1234
配置邮箱和密码
[email protected]
spring.mail.password=xxyyzzhhll
spring.mail.host=smtp.qq.com
# 开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true
12345
测试发送邮件(组合邮件,带附件)
@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);
}
123456789101112131415161718192021222324
- 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,被执行了!");
}
}
12345678910111213141516171819
在启动类开启定时功能
@EnableAsync // 开启异步注解功能
@EnableScheduling //开启定时功能的注解
@SpringBootApplication
public class Springboot09TaskApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot09TaskApplication.class, args);
}
}
12345678
单独整理
zookeeper :注册中心
dubbo-admin : 监控管理后台,查我们注册了哪些服务,哪些服务被消费了
Dubbo:jar包
步骤:
前提:zookeeper服务已启动
提供者提供服务
导入依赖
配置注册中心的地址,以及服务发现名,和要扫描的包
在想要被注册的服务上面,再增加一个注解**@Service**(dubbo包下的)
消费者如何消费
微服务架构存在的问题:
分布式架构会遇到的四个核心问题
==》 解决方案:
SpringCloud,是一套生态,就是用来解决以上分布式架构的4个问题。
想使用SpringCloud,必须掌握SpringBoot,因为SpringCloud是基于SpringBoot的
1. API网关,服务路由
2. HTTP,RPC框架,异步调用
3. 服务注册与发现,高可用
4. 熔断机制,服务降级