Forráskód Böngészése

springboot学习完毕

seamew 3 éve
szülő
commit
d3e40f802a
95 módosított fájl, 4453 hozzáadás és 3 törlés
  1. 1 1
      云原生/docker/3.docker基本使用.md
  2. 816 0
      后端/Spring/SpringBoot/JDBC.md
  3. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412223600851-874349014.png
  4. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412223942091-598892546.png
  5. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412224035706-1280927557.png
  6. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412224112471-646829041.png
  7. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412224131010-12963631.png
  8. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412224922244-774346297.png
  9. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412224940354-738491944.png
  10. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412224955594-693958833.png
  11. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225016479-244888602.png
  12. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225034989-1426302926.png
  13. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225051724-1570792880.png
  14. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225103839-1070501209.png
  15. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225128194-996554004.png
  16. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225141876-1307608137.png
  17. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225154889-1524653449.png
  18. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225207604-1238451568.png
  19. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225221065-887398655.png
  20. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225234441-258590952.png
  21. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225247649-1746815344.png
  22. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225259474-1140791172.png
  23. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225311999-716532013.png
  24. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225332289-780138786.png
  25. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225346425-1869149052.png
  26. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225407880-1259118410.png
  27. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225423594-1396861605.png
  28. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225444394-644044214.png
  29. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225500625-350010165.png
  30. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225514634-1503893280.png
  31. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225529234-1972244754.png
  32. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225545785-2143727145.png
  33. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225558425-1483910.png
  34. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225610315-997693293.png
  35. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225623225-1419329566.png
  36. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225641164-1934062088.png
  37. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225651289-251704533.png
  38. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225708744-252995174.png
  39. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225721465-1009548816.png
  40. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225736355-1251829128.png
  41. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225836241-1744130417.png
  42. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225848354-475809714.png
  43. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225901199-858224740.png
  44. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225913839-69515130.png
  45. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225925894-2054203963.png
  46. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225942424-634751471.png
  47. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412225954994-2069522644.png
  48. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230011744-1175379704.png
  49. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230026479-947348663.png
  50. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230037329-740930228.png
  51. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230050035-1907960449.png
  52. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230103589-1318102017.png
  53. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230116159-2103649071.png
  54. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230133804-1513007496.png
  55. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230149119-363508332.png
  56. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230202910-800109291.png
  57. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230223249-22793107.png
  58. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230239279-1442230316.png
  59. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230254269-261185375.png
  60. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230317849-1998269068.png
  61. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230333154-1538491155.png
  62. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230347555-1367252514.png
  63. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230410090-275194565.png
  64. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230424964-1382261300.png
  65. BIN
      后端/Spring/SpringBoot/assets/1905053-20200412230440929-230804638.png
  66. BIN
      后端/Spring/SpringBoot/assets/image-20200729114647110.png
  67. BIN
      后端/Spring/SpringBoot/assets/image-20200729114702566.png
  68. BIN
      后端/Spring/SpringBoot/assets/image-20200729114720578.png
  69. BIN
      后端/Spring/SpringBoot/assets/image-20200729115148574.png
  70. BIN
      后端/Spring/SpringBoot/assets/image-20200729120114648.png
  71. BIN
      后端/Spring/SpringBoot/assets/image-20200729120207730.png
  72. BIN
      后端/Spring/SpringBoot/assets/image-20200729130649625.png
  73. BIN
      后端/Spring/SpringBoot/assets/image-20200729174715011.png
  74. BIN
      后端/Spring/SpringBoot/assets/image-20200729190325307.png
  75. BIN
      后端/Spring/SpringBoot/assets/image-20200729190548307.png
  76. BIN
      后端/Spring/SpringBoot/assets/image-20200729191619576.png
  77. BIN
      后端/Spring/SpringBoot/assets/image-20200729192409085.png
  78. BIN
      后端/Spring/SpringBoot/assets/image-20200729220647520.png
  79. BIN
      后端/Spring/SpringBoot/assets/image-20200729220926500.png
  80. BIN
      后端/Spring/SpringBoot/assets/image-20200730121720922.png
  81. BIN
      后端/Spring/SpringBoot/assets/image-20200730180019861.png
  82. BIN
      后端/Spring/SpringBoot/assets/image-20200730181814293.png
  83. BIN
      后端/Spring/SpringBoot/assets/image-20200730181944253.png
  84. BIN
      后端/Spring/SpringBoot/assets/image-20200730182621912.png
  85. BIN
      后端/Spring/SpringBoot/assets/image-20200730195133631.png
  86. BIN
      后端/Spring/SpringBoot/assets/image-20200730195807437.png
  87. BIN
      后端/Spring/SpringBoot/assets/image-20200730195946692.png
  88. BIN
      后端/Spring/SpringBoot/assets/image-20200730202810034.png
  89. BIN
      后端/Spring/SpringBoot/assets/image-20200730205736153.png
  90. 583 0
      后端/Spring/SpringBoot/springboot.md
  91. 376 0
      后端/Spring/SpringBoot/swagger.md
  92. 288 0
      后端/Spring/SpringBoot/任务.md
  93. 471 0
      后端/Spring/SpringBoot/分布式RPC.md
  94. 1883 0
      后端/Spring/SpringBoot/权限认证.md
  95. 35 2
      部署文档/大数据平台/大数据平台环境搭建.md

+ 1 - 1
云原生/docker/3.docker基本使用.md

@@ -1,4 +1,4 @@
-# 1.docker基本命令
+#  1.docker基本命令
 
 ## 1.docker images
 

+ 816 - 0
后端/Spring/SpringBoot/JDBC.md

@@ -0,0 +1,816 @@
+
+
+> [TOC]
+
+# 1、SpringBoot整合JDBC
+
+## 1.1、SpringData简介
+
+对于数据访问层,无论是 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.2、创建测试项目测试数据源
+
+1、我去新建一个项目测试:springboot-data-jdbc ; 引入相应的模块!基础模块
+
+![img](assets/1905053-20200412223600851-874349014.png)
+
+2、项目建好之后,发现自动帮我们导入了如下的启动器
+
+```xml
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-jdbc</artifactId>
+</dependency>
+<dependency>
+    <groupId>mysql</groupId>
+    <artifactId>mysql-connector-java</artifactId>
+    <scope>runtime</scope>
+</dependency>
+```
+
+3、编写yaml配置文件连接数据库;
+
+```yml
+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已经默认帮我们进行了自动配置;去测试类测试一下
+
+```java
+@SpringBootTest
+class 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文件:
+
+```java
+@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
+
+## 1.3、JDBCTemplate
+
+1、有了数据源(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方法:用于执行存储过程、函数相关语句。
+
+## 1.4、测试
+
+编写一个Controller,注入 jdbcTemplate,编写测试方法进行访问测试;
+
+```java
+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";
+    }
+    
+}
+```
+
+测试请求,结果正常;
+
+到此,CURD的基本操作,使用 JDBC 就搞定了。https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/htmlsingle/#using-boot-starter)
+
+## 
+
+## 1.5、原理探究 
+
+org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration 数据源配置类作用 :根据逻辑判断之后,添加数据源;
+
+**SpringBoot默认支持以下数据源:**
+
+**com.zaxxer.hikari.HikariDataSource (Spring Boot 2.0 以上,默认使用此数据源)**
+
+org.apache.tomcat.jdbc.pool.DataSource
+
+org.apache.commons.dbcp2.BasicDataSource
+
+**可以使用 spring.datasource.type 指定自定义的数据源类型,值为 要使用的连接池实现的完全限定名。默认情况下,它是从类路径自动检测的。**
+
+```less
+    @Configuration
+    @ConditionalOnMissingBean({DataSource.class})
+    @ConditionalOnProperty(
+        name = {"spring.datasource.type"}
+    )
+    static class Generic {
+        Generic() {
+        }
+
+        @Bean
+        public DataSource dataSource(DataSourceProperties properties) {
+            return properties.initializeDataSourceBuilder().build();
+        }
+    }
+```
+
+
+
+# 2、SpringBoot整合Druid
+
+## 2.1、Druid简介
+
+Java程序很大一部分要操作数据库,为了提高性能操作数据库的时候,又不得不使用数据库连接池。
+
+Druid 是阿里巴巴开源平台上一个数据库连接池实现,结合了 C3P0、DBCP 等 DB 池的优点,同时加入了日志监控。
+
+Druid 可以很好的监控 DB 池连接和 SQL 的执行情况,天生就是针对监控而生的 DB 连接池。
+
+Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
+
+Spring Boot 2.0 以上默认使用 Hikari 数据源,可以说 Hikari 与 Driud 都是当前 Java Web 上最优秀的数据源,我们来重点介绍 Spring Boot 如何集成 Druid 数据源,如何实现数据库监控。
+
+Github地址:https://github.com/alibaba/druid/
+
+**com.alibaba.druid.pool.DruidDataSource 基本配置参数如下:**
+
+| 配置                          | 缺省值             | 说明                                                         |
+| ----------------------------- | ------------------ | ------------------------------------------------------------ |
+| name                          |                    | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:"DataSource-" + System.identityHashCode(this). 另外配置此属性至少在1.0.5版本中是不起作用的,强行设置name会出错 [详情-点此处](http://blog.csdn.net/lanmo555/article/details/41248763)。 |
+| url                           |                    | 连接数据库的url,不同数据库不一样。例如: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto |
+| username                      |                    | 连接数据库的用户名                                           |
+| password                      |                    | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/使用ConfigFilter |
+| driverClassName               | 根据url自动识别    | 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName |
+| initialSize                   | 0                  | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
+| maxActive                     | 8                  | 最大连接池数量                                               |
+| maxIdle                       | 8                  | 已经不再使用,配置了也没效果                                 |
+| minIdle                       |                    | 最小连接池数量                                               |
+| maxWait                       |                    | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 |
+| poolPreparedStatements        | false              | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
+| maxOpenPreparedStatements     | -1                 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
+| validationQuery               |                    | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。 |
+| validationQueryTimeout        |                    | 单位:秒,检测连接是否有效的超时时间。底层调用jdbc Statement对象的void setQueryTimeout(int seconds)方法 |
+| testOnBorrow                  | true               | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
+| testOnReturn                  | false              | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
+| testWhileIdle                 | false              | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
+| timeBetweenEvictionRunsMillis | 1分钟(1.0.14)    | 有两个含义: 1) Destroy线程会检测连接的间隔时间,如果连接空闲时间大于等于minEvictableIdleTimeMillis则关闭物理连接 2) testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
+| numTestsPerEvictionRun        |                    | 不再使用,一个DruidDataSource只支持一个EvictionRun           |
+| minEvictableIdleTimeMillis    | 30分钟(1.0.14)   | 连接保持空闲而不被驱逐的最长时间                             |
+| connectionInitSqls            |                    | 物理连接初始化的时候执行的sql                                |
+| exceptionSorter               | 根据dbType自动识别 | 当数据库抛出一些不可恢复的异常时,抛弃连接                   |
+| filters                       |                    | 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat 日志用的filter:log4j 防御sql注入的filter:wall |
+| proxyFilters                  |                    | 类型是List<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系 |
+
+## 2.2、配置数据源
+
+1、添加上 Druid 数据源依赖。
+
+```xml
+<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
+<dependency>
+    <groupId>com.alibaba</groupId>
+    <artifactId>druid</artifactId>
+    <version>1.1.12</version>
+</dependency>
+```
+
+2、切换数据源;之前已经说过 Spring Boot 2.0 以上默认使用 com.zaxxer.hikari.HikariDataSource 数据源,但可以 通过 spring.datasource.type 指定数据源。
+
+```yml
+spring:
+  datasource:
+    username: root
+    password: 123456
+    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    type: com.alibaba.druid.pool.DruidDataSource # 自定义数据源
+```
+
+3、数据源切换之后,在测试类中注入 DataSource,然后获取到它,输出一看便知是否成功切换;
+
+![img](assets/1905053-20200412223942091-598892546.png)
+
+4、切换成功!既然切换成功,就可以设置数据源连接初始化大小、最大连接数、等待时间、最小连接数 等设置项;可以查看源码
+
+```yml
+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
+    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
+```
+
+5、导入Log4j 的依赖
+
+```xml
+        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+        </dependency>
+```
+
+6、现在需要程序员自己为 DruidDataSource 绑定全局配置文件中的参数,再添加到容器中,而不再使用 Spring Boot 的自动生成了;我们需要 自己添加 DruidDataSource 组件到容器中,并绑定属性;
+
+```java
+package com.kuang.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+@Configuration
+public class DruidConfig {
+
+    /*
+       将自定义的 Druid数据源添加到容器中,不再让 Spring Boot 自动创建
+       绑定全局配置文件中的 druid 数据源属性到 com.alibaba.druid.pool.DruidDataSource从而让它们生效
+       @ConfigurationProperties(prefix = "spring.datasource"):作用就是将 全局配置文件中
+       前缀为 spring.datasource的属性值注入到 com.alibaba.druid.pool.DruidDataSource 的同名参数中
+     */
+    @ConfigurationProperties(prefix = "spring.datasource")
+    @Bean
+    public DataSource druidDataSource() {
+        return new DruidDataSource();
+    }
+
+}
+```
+
+7、去测试类中测试一下;看是否成功!
+
+```java
+@SpringBootTest
+class SpringbootDataJdbcApplicationTests {
+
+    //DI注入数据源
+    @Autowired
+    DataSource dataSource;
+
+    @Test
+    public void contextLoads() throws SQLException {
+        //看一下默认数据源
+        System.out.println(dataSource.getClass());
+        //获得连接
+        Connection connection =   dataSource.getConnection();
+        System.out.println(connection);
+
+        DruidDataSource druidDataSource = (DruidDataSource) dataSource;
+        System.out.println("druidDataSource 数据源最大连接数:" + druidDataSource.getMaxActive());
+        System.out.println("druidDataSource 数据源初始化连接数:" + druidDataSource.getInitialSize());
+
+        //关闭连接
+        connection.close();
+    }
+}
+```
+
+输出结果 :可见配置参数已经生效!
+
+![img](assets/1905053-20200412224035706-1280927557.png)
+
+## 2.3、配置Druid数据源监控
+
+Druid 数据源具有监控的功能,并提供了一个 web 界面方便用户查看,类似安装 路由器 时,人家也提供了一个默认的 web 页面。
+
+所以第一步需要设置 Druid 的后台管理页面,比如 登录账号、密码 等;配置后台管理;
+
+```java
+//配置 Druid 监控管理后台的Servlet;
+//内置 Servlet 容器时没有web.xml文件,所以使用 Spring Boot 的注册 Servlet 方式
+@Bean
+public ServletRegistrationBean statViewServlet() {
+    ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
+
+    // 这些参数可以在 com.alibaba.druid.support.http.StatViewServlet 
+    // 的父类 com.alibaba.druid.support.http.ResourceServlet 中找到
+    Map<String, String> initParams = new HashMap<>();
+    initParams.put("loginUsername", "admin"); //后台管理界面的登录账号
+    initParams.put("loginPassword", "123456"); //后台管理界面的登录密码
+
+    //后台允许谁可以访问
+    //initParams.put("allow", "localhost"):表示只有本机可以访问
+    //initParams.put("allow", ""):为空或者为null时,表示允许所有访问
+    initParams.put("allow", "");
+    //deny:Druid 后台拒绝谁访问
+    //initParams.put("kuangshen", "192.168.1.20");表示禁止此ip访问
+
+    //设置初始化参数
+    bean.setInitParameters(initParams);
+    return bean;
+}
+```
+
+配置完毕后,我们可以选择访问 :http://localhost:8080/druid/login.html
+
+![img](assets/1905053-20200412224112471-646829041.png)
+
+进入之后
+
+![img](assets/1905053-20200412224131010-12963631.png)
+
+**配置 Druid web 监控 filter 过滤器**
+
+```java
+//配置 Druid 监控 之  web 监控的 filter
+//WebStatFilter:用于配置Web和Druid数据源之间的管理关联监控统计
+@Bean
+public FilterRegistrationBean webStatFilter() {
+    FilterRegistrationBean bean = new FilterRegistrationBean();
+    bean.setFilter(new WebStatFilter());
+
+    //exclusions:设置哪些请求进行过滤排除掉,从而不进行统计
+    Map<String, String> initParams = new HashMap<>();
+    initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");
+    bean.setInitParameters(initParams);
+
+    //"/*" 表示过滤所有请求
+    bean.setUrlPatterns(Arrays.asList("/*"));
+    return bean;
+}
+```
+
+平时在工作中,按需求进行配置即可,主要用作监
+
+# 3、SpringBoot 整合mybatis
+
+## **3.1、导入mybatis所需要的依赖**
+
+```xml
+        <!-- 引入 myBatis,这是 MyBatis官方提供的适配 Spring Boot 的,而不是Spring Boot自己的-->
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.0</version>
+        </dependency>
+```
+
+## **3.2、配置数据库连接信息**
+
+```properties
+spring.datasource.username=root
+spring.datasource.password=123456
+spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
+spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+```
+
+## 3.3、我们这里就是用默认的数据源了;先去测试一下连接是否成功!
+
+```java
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class SpringbootDemoMybatisApplicationTests {
+
+    @Autowired
+    DataSource dataSource;
+
+    @Test
+    public void contextLoads() throws SQLException {
+
+        System.out.println("数据源>>>>>>" + dataSource.getClass());
+        Connection connection = dataSource.getConnection();
+        System.out.println("连接>>>>>>>>>" + connection);
+        System.out.println("连接地址>>>>>" + connection.getMetaData().getURL());
+        connection.close();
+
+    }
+
+}
+```
+
+**查看输出结果,数据库配置OK!**
+
+## **3.4、创建实体类**
+
+```java
+package com.kuang.mybatis.pojo;
+
+public class User {
+
+    private int id;
+    private String name;
+    private String pwd;
+
+    public User() {
+    }
+
+    public User(int id, String name, String pwd) {
+        this.id = id;
+        this.name = name;
+        this.pwd = pwd;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getPwd() {
+        return pwd;
+    }
+
+    public void setPwd(String pwd) {
+        this.pwd = pwd;
+    }
+
+    @Override
+    public String toString() {
+        return "User{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ", pwd='" + pwd + '\'' +
+                '}';
+    }
+
+}
+```
+
+## 3.5、配置Mapper接口类
+
+```java
+package com.kuang.mybatis.pojo.mapper;
+
+import com.kuang.mybatis.pojo.User;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+//@Mapper : 表示本类是一个 MyBatis 的 Mapper,等价于以前 Spring 整合 MyBatis 时的 Mapper 接口
+@Mapper
+@Repository
+public interface UserMapper {
+
+    //选择全部用户
+    List<User> selectUser();
+    //根据id选择用户
+    User selectUserById(int id);
+    //添加一个用户
+    int addUser(User user);
+    //修改一个用户
+    int updateUser(User user);
+    //根据id删除用户
+    int deleteUser(int id);
+
+}
+```
+
+## 3.6、对应Mapper映射文件
+
+```xml
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="com.kuang.mybatis.pojo.mapper.UserMapper">
+
+    <select id="selectUser" resultType="User">
+    select * from user
+  </select>
+
+    <select id="selectUserById" resultType="User">
+    select * from user where id = #{id}
+</select>
+
+    <insert id="addUser" parameterType="User">
+    insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
+</insert>
+
+    <update id="updateUser" parameterType="User">
+    update user set name=#{name},pwd=#{pwd} where id = #{id}
+</update>
+
+    <delete id="deleteUser" parameterType="int">
+    delete from user where id = #{id}
+</delete>
+</mapper>
+```
+
+## 3.7、maven配置资源过滤问题
+
+```xml
+<resources>
+    <resource>
+        <directory>src/main/java</directory>
+        <includes>
+            <include>**/*.xml</include>
+        </includes>
+        <filtering>true</filtering>
+    </resource>
+</resources>
+```
+
+## 3.8、SpringBoot 整合!
+
+以前 MyBatis 未与 spring 整合时,配置数据源、事务、连接数据库的账号、密码等都是在 myBatis 核心配置文件中进行的myBatis 与 spring 整合后,配置数据源、事务、连接数据库的账号、密码等就交由 spring 管理。因此,在这里我们即使不使用mybatis配置文件也完全ok!
+**既然已经提供了 myBatis 的映射配置文件,自然要告诉 spring boot 这些文件的位置**
+
+```properties
+spring.datasource.username=root
+spring.datasource.password=123456
+spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
+spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+
+#指定myBatis的核心配置文件与Mapper映射文件
+mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
+# 注意:对应实体类的路径
+mybatis.type-aliases-package=com.kuang.mybatis.pojo
+```
+
+已经说过 spring boot 官方并没有提供 myBaits 的启动器,是 myBatis 官方提供的开发包来适配的 spring boot,从 pom.xml 文件中的依赖包名也能看出来,并非是以 spring-boot 开头的;
+
+同理上面全局配置文件中的这两行配置也是以 mybatis 开头 而非 spring 开头也充分说明这些都是 myBatis 官方提供的
+
+可以从 org.mybatis.spring.boot.autoconfigure.MybatisProperties 中查看所有配置项
+
+```java
+@ConfigurationProperties(
+    prefix = "mybatis"
+)
+public class MybatisProperties {
+    public static final String MYBATIS_PREFIX = "mybatis";
+    private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
+    private String configLocation;
+    private String[] mapperLocations;
+    private String typeAliasesPackage;
+    private Class<?> typeAliasesSuperType;
+    private String typeHandlersPackage;
+    private boolean checkConfigLocation = false;
+    private ExecutorType executorType;
+    private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;
+    private Properties configurationProperties;
+    @NestedConfigurationProperty
+    private Configuration configuration;
+```
+
+也可以直接去查看 [官方文档](http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/)
+
+## 3.9、编写controller
+
+```java
+package com.kuang.mybatis.controller;
+
+import com.kuang.mybatis.pojo.User;
+import com.kuang.mybatis.pojo.mapper.UserMapper;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class UserController {
+
+    @Autowired
+    private UserMapper userMapper;
+
+    //选择全部用户
+    @GetMapping("/selectUser")
+    public String selectUser(){
+        List<User> users = userMapper.selectUser();
+        for (User user : users) {
+            System.out.println(user);
+        }
+
+        return "ok";
+    }
+    //根据id选择用户
+    @GetMapping("/selectUserById")
+    public String selectUserById(){
+        User user = userMapper.selectUserById(1);
+        System.out.println(user);
+        return "ok";
+    }
+    //添加一个用户
+    @GetMapping("/addUser")
+    public String addUser(){
+        userMapper.addUser(new User(5,"阿毛","456789"));
+        return "ok";
+    }
+    //修改一个用户
+    @GetMapping("/updateUser")
+    public String updateUser(){
+        userMapper.updateUser(new User(5,"阿毛","421319"));
+        return "ok";
+    }
+    //根据id删除用户
+    @GetMapping("/deleteUser")
+    public String deleteUser(){
+        userMapper.deleteUser(5);
+        return "ok";
+    }
+
+}
+```
+
+## **3.10、启动项目访问进行测试!**
+
+**步骤:**
+
+Mybatis整合包
+
+mybatis-spring-boot-starter
+
+1.导入包
+
+2.配置文件
+
+3.mybatis配置
+
+4.编写sql
+
+5.service层调用dao层
+
+6.controller调用service层
+
+## **注:配置数据库连接信息(不变)**
+
+```yml
+spring:
+  datasource:
+    username: root
+    password: MKcloud123
+    url: jdbc:mysql://180.76.231.231:6033/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
+    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
+```
+

BIN
后端/Spring/SpringBoot/assets/1905053-20200412223600851-874349014.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412223942091-598892546.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412224035706-1280927557.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412224112471-646829041.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412224131010-12963631.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412224922244-774346297.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412224940354-738491944.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412224955594-693958833.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225016479-244888602.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225034989-1426302926.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225051724-1570792880.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225103839-1070501209.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225128194-996554004.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225141876-1307608137.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225154889-1524653449.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225207604-1238451568.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225221065-887398655.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225234441-258590952.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225247649-1746815344.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225259474-1140791172.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225311999-716532013.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225332289-780138786.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225346425-1869149052.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225407880-1259118410.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225423594-1396861605.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225444394-644044214.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225500625-350010165.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225514634-1503893280.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225529234-1972244754.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225545785-2143727145.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225558425-1483910.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225610315-997693293.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225623225-1419329566.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225641164-1934062088.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225651289-251704533.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225708744-252995174.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225721465-1009548816.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225736355-1251829128.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225836241-1744130417.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225848354-475809714.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225901199-858224740.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225913839-69515130.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225925894-2054203963.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225942424-634751471.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412225954994-2069522644.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230011744-1175379704.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230026479-947348663.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230037329-740930228.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230050035-1907960449.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230103589-1318102017.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230116159-2103649071.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230133804-1513007496.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230149119-363508332.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230202910-800109291.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230223249-22793107.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230239279-1442230316.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230254269-261185375.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230317849-1998269068.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230333154-1538491155.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230347555-1367252514.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230410090-275194565.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230424964-1382261300.png


BIN
后端/Spring/SpringBoot/assets/1905053-20200412230440929-230804638.png


BIN
后端/Spring/SpringBoot/assets/image-20200729114647110.png


BIN
后端/Spring/SpringBoot/assets/image-20200729114702566.png


BIN
后端/Spring/SpringBoot/assets/image-20200729114720578.png


BIN
后端/Spring/SpringBoot/assets/image-20200729115148574.png


BIN
后端/Spring/SpringBoot/assets/image-20200729120114648.png


BIN
后端/Spring/SpringBoot/assets/image-20200729120207730.png


BIN
后端/Spring/SpringBoot/assets/image-20200729130649625.png


BIN
后端/Spring/SpringBoot/assets/image-20200729174715011.png


BIN
后端/Spring/SpringBoot/assets/image-20200729190325307.png


BIN
后端/Spring/SpringBoot/assets/image-20200729190548307.png


BIN
后端/Spring/SpringBoot/assets/image-20200729191619576.png


BIN
后端/Spring/SpringBoot/assets/image-20200729192409085.png


BIN
后端/Spring/SpringBoot/assets/image-20200729220647520.png


BIN
后端/Spring/SpringBoot/assets/image-20200729220926500.png


BIN
后端/Spring/SpringBoot/assets/image-20200730121720922.png


BIN
后端/Spring/SpringBoot/assets/image-20200730180019861.png


BIN
后端/Spring/SpringBoot/assets/image-20200730181814293.png


BIN
后端/Spring/SpringBoot/assets/image-20200730181944253.png


BIN
后端/Spring/SpringBoot/assets/image-20200730182621912.png


BIN
后端/Spring/SpringBoot/assets/image-20200730195133631.png


BIN
后端/Spring/SpringBoot/assets/image-20200730195807437.png


BIN
后端/Spring/SpringBoot/assets/image-20200730195946692.png


BIN
后端/Spring/SpringBoot/assets/image-20200730202810034.png


BIN
后端/Spring/SpringBoot/assets/image-20200730205736153.png


+ 583 - 0
后端/Spring/SpringBoot/springboot.md

@@ -1387,3 +1387,586 @@ private Resource getIndexHtml(String location) {
 
 ![img](assets/1905053-20200412224343431-2144081992.png)
 
+# 7、SpringBoot:MVC自动配置原理
+
+## 7.1、官网阅读
+
+在进行项目编写前,我们还需要知道一个东西,就是SpringBoot对我们的SpringMVC还做了哪些配置,包括如何扩展,如何定制。
+
+只有把这些都搞清楚了,我们在之后使用才会更加得心应手。途径一:源码分析,途径二:官方文档!
+
+地址 :https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration
+
+```java
+Spring MVC Auto-configuration
+// Spring Boot为Spring MVC提供了自动配置,它可以很好地与大多数应用程序一起工作。
+Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
+// 自动配置在Spring默认设置的基础上添加了以下功能:
+The auto-configuration adds the following features on top of Spring’s defaults:
+// 包含视图解析器
+Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
+// 支持静态资源文件夹的路径,以及webjars
+Support for serving static resources, including support for WebJars 
+// 自动注册了Converter:
+// 转换器,这就是我们网页提交数据到后台自动封装成为对象的东西,比如把"1"字符串自动转换为int类型
+// Formatter:【格式化器,比如页面给我们了一个2019-8-10,它会给我们自动格式化为Date对象】
+Automatic registration of Converter, GenericConverter, and Formatter beans.
+// HttpMessageConverters
+// SpringMVC用来转换Http请求和响应的的,比如我们要把一个User对象转换为JSON字符串,可以去看官网文档解释;
+Support for HttpMessageConverters (covered later in this document).
+// 定义错误代码生成规则的
+Automatic registration of MessageCodesResolver (covered later in this document).
+// 首页定制
+Static index.html support.
+// 图标定制
+Custom Favicon support (covered later in this document).
+// 初始化数据绑定器:帮我们把请求数据绑定到JavaBean中!
+Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).
+
+/*
+如果您希望保留Spring Boot MVC功能,并且希望添加其他MVC配置(拦截器、格式化程序、视图控制器和其他功能),则可以添加自己
+的@configuration类,类型为webmvcconfiguer,但不添加@EnableWebMvc。如果希望提供
+RequestMappingHandlerMapping、RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定义
+实例,则可以声明WebMVCregistrationAdapter实例来提供此类组件。
+*/
+If you want to keep Spring Boot MVC features and you want to add additional MVC configuration 
+(interceptors, formatters, view controllers, and other features), you can add your own 
+@Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide 
+custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or 
+ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.
+
+// 如果您想完全控制Spring MVC,可以添加自己的@Configuration,并用@EnableWebMvc进行注释。
+If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc.
+```
+
+我们来仔细对照,看一下它怎么实现的,它告诉我们SpringBoot已经帮我们自动配置好了SpringMVC,然后自动配置了哪些东西呢?
+
+## 7.2、ContentNegotiatingViewResolver 内容协商视图解析器**
+
+自动配置了ViewResolver,就是我们之前学习的SpringMVC的视图解析器;
+
+即根据方法的返回值取得视图对象(View),然后由视图对象决定如何渲染(转发,重定向)。
+
+我们去看看这里的源码:我们找到 WebMvcAutoConfiguration , 然后搜索ContentNegotiatingViewResolver。找到如下方法!
+
+```java
+@Bean
+@ConditionalOnBean(ViewResolver.class)
+@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
+public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
+    ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
+    resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
+    // ContentNegotiatingViewResolver使用所有其他视图解析器来定位视图,因此它应该具有较高的优先级
+    resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
+    return resolver;
+}
+```
+
+我们可以点进这类看看!找到对应的解析视图的代码;
+
+```java
+@Nullable // 注解说明:@Nullable 即参数可为null
+public View resolveViewName(String viewName, Locale locale) throws Exception {
+    RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
+    Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
+    List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
+    if (requestedMediaTypes != null) {
+        // 获取候选的视图对象
+        List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
+        // 选择一个最适合的视图对象,然后把这个对象返回
+        View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
+        if (bestView != null) {
+            return bestView;
+        }
+    }
+    // .....
+}
+```
+
+我们继续点进去看,他是怎么获得候选的视图的呢?
+
+getCandidateViews中看到他是把所有的视图解析器拿来,进行while循环,挨个解析!
+
+```java
+Iterator var5 = this.viewResolvers.iterator();
+```
+
+所以得出结论:**ContentNegotiatingViewResolver 这个视图解析器就是用来组合所有的视图解析器的**
+
+我们再去研究下他的组合逻辑,看到有个属性viewResolvers,看看它是在哪里进行赋值的!
+
+```java
+protected void initServletContext(ServletContext servletContext) {
+    // 这里它是从beanFactory工具中获取容器中的所有视图解析器
+    // ViewRescolver.class 把所有的视图解析器来组合的
+    Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
+    ViewResolver viewResolver;
+    if (this.viewResolvers == null) {
+        this.viewResolvers = new ArrayList(matchingBeans.size());
+    }
+    // ...............
+}
+```
+
+既然它是在容器中去找视图解析器,我们是否可以猜想,我们就可以去实现一个视图解析器了呢?
+
+我们可以自己给容器中去添加一个视图解析器;这个类就会帮我们自动的将它组合进来;**我们去实现一下**
+
+1、我们在我们的主程序中去写一个视图解析器来试试;
+
+```java
+@Bean //放到bean中
+public ViewResolver myViewResolver(){
+    return new MyViewResolver();
+}
+
+//我们写一个静态内部类,视图解析器就需要实现ViewResolver接口
+private static class MyViewResolver implements ViewResolver{
+    @Override
+    public View resolveViewName(String s, Locale locale) throws Exception {
+        return null;
+    }
+}
+```
+
+2、怎么看我们自己写的视图解析器有没有起作用呢?
+
+我们给 DispatcherServlet 中的 doDispatch方法 加个断点进行调试一下,因为所有的请求都会走到这个方法中
+
+![img](assets/1905053-20200412224922244-774346297.png)
+
+3、我们启动我们的项目,然后随便访问一个页面,看一下Debug信息;
+
+找到this
+
+![img](assets/1905053-20200412224940354-738491944.png)
+
+找到视图解析器,我们看到我们自己定义的就在这里了;
+
+![img](assets/1905053-20200412224955594-693958833.png)
+
+所以说,我们如果想要使用自己定制化的东西,我们只需要给容器中添加这个组件就好了!剩下的事情SpringBoot就会帮我们做了!
+
+## 7.3、转换器和格式化器
+
+找到格式化转换器:
+
+```java
+@Bean
+@Override
+public FormattingConversionService mvcConversionService() {
+    // 拿到配置文件中的格式化规则
+    WebConversionService conversionService = 
+        new WebConversionService(this.mvcProperties.getDateFormat());
+    addFormatters(conversionService);
+    return conversionService;
+}
+```
+
+点击去:
+
+```java
+public String getDateFormat() {
+    return this.dateFormat;
+}
+
+/**
+* Date format to use. For instance, `dd/MM/yyyy`. 默认的
+ */
+private String dateFormat;
+```
+
+可以看到在我们的Properties文件中,我们可以进行自动配置它!
+
+如果配置了自己的格式化方式,就会注册到Bean中生效,我们可以在配置文件中配置日期格式化的规则:
+
+![img](assets/1905053-20200412225016479-244888602.png)
+
+其余的就不一一举例了,大家可以下去多研究探讨即可!
+
+## 7.4、修改SpringBoot的默认配置
+
+这么多的自动配置,原理都是一样的,通过这个WebMVC的自动配置原理分析,我们要学会一种学习方式,通过源码探究,得出结论;这个结论一定是属于自己的,而且一通百通。
+
+SpringBoot的底层,大量用到了这些设计细节思想,所以,没事需要多阅读源码!得出结论;
+
+SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(如果用户自己配置@bean),如果有就用用户配置的,如果没有就用自动配置的;
+
+如果有些组件可以存在多个,比如我们的视图解析器,就将用户配置的和自己默认的组合起来!
+
+**扩展使用SpringMVC** 官方文档如下:
+
+If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.
+
+我们要做的就是编写一个@Configuration注解类,并且类型要为WebMvcConfigurer,还不能标注@EnableWebMvc注解;我们去自己写一个;我们新建一个包叫config,写一个类MyMvcConfig;
+
+```java
+//应为类型要求为WebMvcConfigurer,所以我们实现其接口
+//可以使用自定义类扩展MVC的功能
+@Configuration
+public class MyMvcConfig implements WebMvcConfigurer {
+
+    @Override
+    public void addViewControllers(ViewControllerRegistry registry) {
+        // 浏览器发送/test , 就会跳转到test页面;
+        registry.addViewController("/test").setViewName("test");
+    }
+}
+```
+
+我们去浏览器访问一下:
+
+![img](assets/1905053-20200412225034989-1426302926.png)
+
+**确实也跳转过来了!所以说,我们要扩展SpringMVC,官方就推荐我们这么去使用,既保SpringBoot留所有的自动配置,也能用我们扩展的配置!**
+
+我们可以去分析一下原理:
+
+1、WebMvcAutoConfiguration 是 SpringMVC的自动配置类,里面有一个类WebMvcAutoConfigurationAdapter
+
+2、这个类上有一个注解,在做其他自动配置时会导入:@Import(EnableWebMvcConfiguration.class)
+
+3、我们点进EnableWebMvcConfiguration这个类看一下,它继承了一个父类:DelegatingWebMvcConfiguration
+
+这个父类中有这样一段代码:
+
+```java
+public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
+    private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
+    
+  // 从容器中获取所有的webmvcConfigurer
+    @Autowired(required = false)
+    public void setConfigurers(List<WebMvcConfigurer> configurers) {
+        if (!CollectionUtils.isEmpty(configurers)) {
+            this.configurers.addWebMvcConfigurers(configurers);
+        }
+    }
+}
+```
+
+4、我们可以在这个类中去寻找一个我们刚才设置的viewController当做参考,发现它调用了一个
+
+```java
+protected void addViewControllers(ViewControllerRegistry registry) {
+    this.configurers.addViewControllers(registry);
+}
+```
+
+5、我们点进去看一下
+
+```java
+public void addViewControllers(ViewControllerRegistry registry) {
+    Iterator var2 = this.delegates.iterator();
+
+    while(var2.hasNext()) {
+        // 将所有的WebMvcConfigurer相关配置来一起调用!包括我们自己配置的和Spring给我们配置的
+        WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
+        delegate.addViewControllers(registry);
+    }
+
+}
+```
+
+所以得出结论:所有的WebMvcConfiguration都会被作用,不止Spring自己的配置类,我们自己的配置类当然也会被调用;
+
+## 7.5、全面接管SpringMVC
+
+官方文档:
+
+```java
+If you want to take complete control of Spring MVC
+you can add your own @Configuration annotated with @EnableWebMvc.
+```
+
+全面接管即:SpringBoot对SpringMVC的自动配置不需要了,所有都是我们自己去配置!
+
+只需在我们的配置类中要加一个@EnableWebMvc。
+
+我们看下如果我们全面接管了SpringMVC了,我们之前SpringBoot给我们配置的静态资源映射一定会无效,我们可以去测试一下;
+
+不加注解之前,访问首页:
+
+![img](assets/1905053-20200412225051724-1570792880.png)
+
+给配置类加上注解:@EnableWebMvc
+
+![img](assets/1905053-20200412225103839-1070501209.png)
+
+我们发现所有的SpringMVC自动配置都失效了!回归到了最初的样子;
+
+**当然,我们开发中,不推荐使用全面接管SpringMVC**
+
+思考问题?为什么加了一个注解,自动配置就失效了!我们看下源码:
+
+1、这里发现它是导入了一个类,我们可以继续进去看
+
+```java
+@Import({DelegatingWebMvcConfiguration.class})public @interface EnableWebMvc {}
+```
+
+2、它继承了一个父类 WebMvcConfigurationSupport
+
+```java
+public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {  // ......}
+```
+
+3、我们来回顾一下Webmvc自动配置类
+
+```java
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnWebApplication(type = Type.SERVLET)
+@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
+// 这个注解的意思就是:容器中没有这个组件的时候,这个自动配置类才生效
+@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
+@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
+@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
+    ValidationAutoConfiguration.class })
+public class WebMvcAutoConfiguration {
+    
+}
+```
+
+总结一句话:@EnableWebMvc将WebMvcConfigurationSupport组件导入进来了;
+
+而导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能!
+
+**在SpringBoot中会有非常多的扩展配置,只要看见了这个,我们就应该多留心注意~**
+
+# 8、SpringBoot:页面国际化
+
+有的时候,我们的网站会去涉及中英文甚至多语言的切换,这时候我们就需要学习国际化了!
+
+## 8.1、准备工作
+
+先在IDEA中统一设置properties的编码问题!
+
+![img](assets/1905053-20200412225128194-996554004.png)
+
+编写国际化配置文件,抽取页面需要显示的国际化页面消息。我们可以去登录页面查看一下,哪些内容我们需要编写国际化的配置!
+
+## 8.2、配置文件编写
+
+1、我们在resources资源文件下新建一个i18n目录,存放国际化配置文件
+
+2、建立一个login.properties文件,还有一个login_zh_CN.properties;发现IDEA自动识别了我们要做国际化操作;文件夹变了!
+
+![img](assets/1905053-20200412225141876-1307608137.png)
+
+3、我们可以在这上面去新建一个文件;
+
+![img](assets/1905053-20200412225154889-1524653449.png)
+
+弹出如下页面:我们再添加一个英文的;
+
+![img](assets/1905053-20200412225207604-1238451568.png)
+
+这样就快捷多了!
+
+![img](assets/1905053-20200412225221065-887398655.png)
+
+**4、接下来,我们就来编写配置,我们可以看到idea下面有另外一个视图;**
+
+![img](assets/1905053-20200412225234441-258590952.png)
+
+这个视图我们点击 + 号就可以直接添加属性了;我们新建一个login.tip,可以看到边上有三个文件框可以输入
+
+![img](assets/1905053-20200412225247649-1746815344.png)
+
+我们添加一下首页的内容!
+
+![img](assets/1905053-20200412225259474-1140791172.png)
+
+然后依次添加其他页面内容即可!
+
+![img](assets/1905053-20200412225311999-716532013.png)
+
+然后去查看我们的配置文件;
+
+login.properties :默认
+
+```properties
+login.btn=登录
+login.password=密码
+login.remember=记住我
+login.tip=请登录
+login.username=用户名
+```
+
+英文:
+
+```properties
+login.btn=Sign in
+login.password=Password
+login.remember=Remember me
+login.tip=Please sign in
+login.username=Username
+```
+
+中文:
+
+```properties
+login.btn=登录
+login.password=密码
+login.remember=记住我
+login.tip=请登录
+login.username=用户名
+```
+
+OK,配置文件步骤搞定!
+
+## 8.3、配置文件生效探究
+
+我们去看一下SpringBoot对国际化的自动配置!这里又涉及到一个类:MessageSourceAutoConfiguration
+
+里面有一个方法,这里发现SpringBoot已经自动配置好了管理我们国际化资源文件的组件 ResourceBundleMessageSource;
+
+```java
+// 获取 properties 传递过来的值进行判断
+@Bean
+public 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的路径;
+
+```java
+spring.messages.basename=i18n.login
+```
+
+## 8.4、配置页面国际化值
+
+去页面获取国际化的值,查看Thymeleaf的文档,找到message取值操作为:#{...}。我们去页面测试下:
+
+IDEA还有提示,非常智能的!
+
+![img](assets/1905053-20200412225332289-780138786.png)
+
+我们可以去启动项目,访问一下,发现已经自动识别为中文的了!
+
+![img](assets/1905053-20200412225346425-1869149052.png)
+
+**但是我们想要更好!可以根据按钮自动切换中文英文!**
+
+## 8.5、配置国际化解析
+
+在Spring中有一个国际化的Locale (区域信息对象);里面有一个叫做LocaleResolver (获取区域信息对象)的解析器!
+
+我们去我们webmvc自动配置文件,寻找一下!看到SpringBoot默认配置:
+
+```java
+@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 这个类中有一个方法
+
+```java
+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<Locale> 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,可以在链接上携带区域信息!
+
+修改一下前端页面的跳转连接:
+
+```html
+<!-- 这里传入参数不需要使用 ?使用 (key=value)-->
+<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
+<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
+```
+
+我们去写一个处理的组件类!
+
+```java
+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;
+
+```java
+@Beanpublic LocaleResolver localeResolver(){    return new MyLocaleResolver();}
+```
+
+**我们重启项目,来访问一下,发现点击按钮可以实现成功切换!搞定收工!**
+

+ 376 - 0
后端/Spring/SpringBoot/swagger.md

@@ -0,0 +1,376 @@
+>[TOC]
+
+# SpringBoot:集成Swagger终极版
+
+![img](assets/1905053-20200412225407880-1259118410.png)
+
+**学习目标:**
+
+- 了解Swagger的概念及作用
+- 掌握在项目中集成Swagger自动生成API文档
+
+# 1、Swagger简介
+
+**前后端分离**
+
+- 前端 -> 前端控制层、视图层
+- 后端 -> 后端控制层、服务层、数据访问层
+- 前后端通过API进行交互
+- 前后端相对独立且松耦合
+
+**产生的问题**
+
+- 前后端集成,前端或者后端无法做到“及时协商,尽早解决”,最终导致问题集中爆发
+
+**解决方案**
+
+- 首先定义schema [ 计划的提纲 ],并实时跟踪最新的API,降低集成风险
+
+**Swagger**
+
+- 号称世界上最流行的API框架
+- Restful Api 文档在线自动生成器 => **API 文档 与API 定义同步更新**
+- 直接运行,在线测试API
+- 支持多种语言 (如:Java,PHP等)
+- 官网:https://swagger.io/
+
+# 2、SpringBoot集成Swagger
+
+**SpringBoot集成Swagger** => **springfox**,两个jar包
+
+- **Springfox-swagger2**
+- swagger-springmvc
+
+**使用Swagger**
+
+要求:jdk 1.8 + 否则swagger2无法运行
+
+步骤:
+
+1、新建一个SpringBoot-web项目
+
+2、添加Maven依赖
+
+```xml
+<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
+<dependency>
+   <groupId>io.springfox</groupId>
+   <artifactId>springfox-swagger2</artifactId>
+   <version>2.9.2</version>
+</dependency>
+<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
+<dependency>
+   <groupId>io.springfox</groupId>
+   <artifactId>springfox-swagger-ui</artifactId>
+   <version>2.9.2</version>
+</dependency>
+```
+
+3、编写HelloController,测试确保运行成功!
+
+4、要使用Swagger,我们需要编写一个配置类-SwaggerConfig来配置 Swagger
+
+```java
+@Configuration //配置类
+@EnableSwagger2// 开启Swagger2的自动配置
+public class SwaggerConfig {  
+}j
+```
+
+5、访问测试 :http://localhost:8080/swagger-ui.html ,可以看到swagger的界面;
+
+![img](assets/1905053-20200412225423594-1396861605.png)
+
+# 3、配置Swagger
+
+1、Swagger实例Bean是Docket,所以通过配置Docket实例来配置Swaggger。
+
+```java
+@Bean //配置docket以配置Swagger具体参数
+public Docket docket() {
+   return new Docket(DocumentationType.SWAGGER_2);
+}
+```
+
+2、可以通过apiInfo()属性配置文档信息
+
+```java
+//配置文档信息
+private ApiInfo apiInfo() {
+   Contact contact = new Contact("联系人名字", "http://xxx.xxx.com/联系人访问链接", "联系人邮箱");
+   return new ApiInfo(
+           "Swagger学习", // 标题
+           "学习演示如何配置Swagger", // 描述
+           "v1.0", // 版本
+           "http://terms.service.url/组织链接", // 组织链接
+           contact, // 联系人信息
+           "Apach 2.0 许可", // 许可
+           "许可链接", // 许可连接
+           new ArrayList<>()// 扩展
+  );
+}
+```
+
+3、Docket 实例关联上 apiInfo()
+
+```java
+@Bean
+public Docket docket() {
+   return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
+}
+```
+
+4、重启项目,访问测试 http://localhost:8080/swagger-ui.html 看下效果;
+
+# 4、配置扫描接口
+
+1、构建Docket时通过select()方法配置怎么扫描接口。
+
+```java
+any() // 扫描所有,项目中的所有接口都会被扫描到
+none() // 不扫描接口
+// 通过方法上的注解扫描,如withMethodAnnotation(GetMapping.class)只扫描get请求
+withMethodAnnotation(final Class<? extends Annotation> annotation)
+// 通过类上的注解扫描,如.withClassAnnotation(Controller.class)只扫描有controller注解的类中的接口
+withClassAnnotation(final Class<? extends Annotation> annotation)
+basePackage(final String basePackage) // 根据包路径扫描接口
+```
+
+2、重启项目测试,由于我们配置根据包的路径扫描接口,所以我们只能看到一个类
+
+3、除了通过包路径配置扫描接口外,还可以通过配置其他方式扫描接口,这里注释一下所有的配置方式:
+
+```java
+any() // 扫描所有,项目中的所有接口都会被扫描到
+none() // 不扫描接口
+// 通过方法上的注解扫描,如withMethodAnnotation(GetMapping.class)只扫描get请求
+withMethodAnnotation(final Class<? extends Annotation> annotation)
+// 通过类上的注解扫描,如.withClassAnnotation(Controller.class)只扫描有controller注解的类中的接口
+withClassAnnotation(final Class<? extends Annotation> annotation)
+basePackage(final String basePackage) // 根据包路径扫描接口
+```
+
+4、除此之外,我们还可以配置接口扫描过滤:
+
+```java
+@Bean
+public Docket docket() {
+   return new Docket(DocumentationType.SWAGGER_2)
+      .apiInfo(apiInfo())
+      .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
+      .apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
+       // 配置如何通过path过滤,即这里只扫描请求以/kuang开头的接口
+      .paths(PathSelectors.ant("/kuang/**"))
+      .build();
+}
+```
+
+5、这里的可选值还有
+
+```java
+any() // 任何请求都扫描
+none() // 任何请求都不扫描
+regex(final String pathRegex) // 通过正则表达式控制
+ant(final String antPattern) // 通过ant()控制
+```
+
+![img](assets/1905053-20200412225444394-644044214.png)
+
+# 5、配置Swagger开关
+
+1、通过enable()方法配置是否启用swagger,如果是false,swagger将不能在浏览器中访问了
+
+```java
+@Bean
+public Docket docket() {
+   return new Docket(DocumentationType.SWAGGER_2)
+      .apiInfo(apiInfo())
+      .enable(false) //配置是否启用Swagger,如果是false,在浏览器将无法访问
+      .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
+      .apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
+       // 配置如何通过path过滤,即这里只扫描请求以/kuang开头的接口
+      .paths(PathSelectors.ant("/kuang/**"))
+      .build();
+}
+```
+
+2、如何动态配置当项目处于test、dev环境时显示swagger,处于prod时不显示?
+
+```java
+@Bean
+public Docket docket(Environment environment) {
+   // 设置要显示swagger的环境
+   Profiles of = Profiles.of("dev", "test");
+   // 判断当前是否处于该环境
+   // 通过 enable() 接收此参数判断是否要显示
+   boolean b = environment.acceptsProfiles(of);
+   
+   return new Docket(DocumentationType.SWAGGER_2)
+      .apiInfo(apiInfo())
+      .enable(b) //配置是否启用Swagger,如果是false,在浏览器将无法访问
+      .select()// 通过.select()方法,去配置扫描接口,RequestHandlerSelectors配置如何扫描接口
+      .apis(RequestHandlerSelectors.basePackage("com.kuang.swagger.controller"))
+       // 配置如何通过path过滤,即这里只扫描请求以/kuang开头的接口
+      .paths(PathSelectors.ant("/kuang/**"))
+      .build();
+}
+```
+
+3、可以在项目中增加一个dev的配置文件查看效果!
+
+![img](assets/1905053-20200412225500625-350010165.png)
+
+# 6、配置API分组
+
+![img](assets/1905053-20200412225514634-1503893280.png)
+
+1、如果没有配置分组,默认是default。通过groupName()方法即可配置分组:
+
+```java
+@Bean
+public Docket docket(Environment environment) {
+   return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
+      .groupName("hello") // 配置分组
+       // 省略配置....
+}
+```
+
+2、重启项目查看分组
+
+3、如何配置多个分组?配置多个分组只需要配置多个docket即可:
+
+```java
+@Bean
+public Docket docket1(){
+   return new Docket(DocumentationType.SWAGGER_2).groupName("group1");
+}
+@Bean
+public Docket docket2(){
+   return new Docket(DocumentationType.SWAGGER_2).groupName("group2");
+}
+@Bean
+public Docket docket3(){
+   return new Docket(DocumentationType.SWAGGER_2).groupName("group3");
+}
+```
+
+4、重启项目查看即可
+
+# 7、实体配置
+
+1、新建一个实体类
+
+```java
+@ApiModel("用户实体")
+public class User {
+   @ApiModelProperty("用户名")
+   public String username;
+   @ApiModelProperty("密码")
+   public String password;
+}
+```
+
+2、只要这个实体在**请求接口**的返回值上(即使是泛型),都能映射到实体项中:
+
+```java
+@RequestMapping("/getUser")
+public User getUser(){   
+	return new User();
+}
+```
+
+3、重启查看测试
+
+![img](assets/1905053-20200412225529234-1972244754.png)
+
+注:并不是因为@ApiModel这个注解让实体显示在这里了,而是只要出现在接口方法的返回值上的实体都会显示在这里,而@ApiModel和@ApiModelProperty这两个注解只是为实体添加注释的。
+
+@ApiModel为类添加注释
+
+@ApiModelProperty为类属性添加注释
+
+# 8、常用注解
+
+Swagger的所有注解定义在io.swagger.annotations包下
+
+下面列一些经常用到的,未列举出来的可以另行查阅说明:
+
+| Swagger注解                                            | 简单说明                                             |
+| ------------------------------------------------------ | ---------------------------------------------------- |
+| @Api(tags = "xxx模块说明")                             | 作用在模块类上                                       |
+| @ApiOperation("xxx接口说明")                           | 作用在接口方法上                                     |
+| @ApiModel("xxxPOJO说明")                               | 作用在模型类上:如VO、BO                             |
+| @ApiModelProperty(value = "xxx属性说明",hidden = true) | 作用在类方法和属性上,hidden设置为true可以隐藏该属性 |
+| @ApiParam("xxx参数说明")                               | 作用在参数、方法和字段上,类似@ApiModelProperty      |
+
+我们也可以给请求的接口配置一些注释
+
+```java
+@ApiOperation("狂神的接口")
+@PostMapping("/kuang")
+@ResponseBody
+public String kuang(@ApiParam("这个名字会被返回")String username){
+   return username;
+}
+```
+
+这样的话,可以给一些比较难理解的属性或者接口,增加一些配置信息,让人更容易阅读!
+
+相较于传统的Postman或Curl方式测试接口,使用swagger简直就是傻瓜式操作,不需要额外说明文档(写得好本身就是文档)而且更不容易出错,只需要录入数据然后点击Execute,如果再配合自动化框架,可以说基本就不需要人为操作了。
+
+Swagger是个优秀的工具,现在国内已经有很多的中小型互联网公司都在使用它,相较于传统的要先出Word接口文档再测试的方式,显然这样也更符合现在的快速迭代开发行情。当然了,提醒下大家在正式环境要记得关闭Swagger,一来出于安全考虑二来也可以节省运行时内存。
+
+# 9、拓展:其他皮肤
+
+我们可以导入不同的包实现不同的皮肤定义:
+
+1、默认的 **访问 http://localhost:8080/swagger-ui.html**
+
+```xml
+<dependency> 
+   <groupId>io.springfox</groupId>
+   <artifactId>springfox-swagger-ui</artifactId>
+   <version>2.9.2</version>
+</dependency>
+```
+
+![img](assets/1905053-20200412225545785-2143727145.png)
+
+2、bootstrap-ui **访问 http://localhost:8080/doc.html**
+
+```xml
+<!-- 引入swagger-bootstrap-ui包 /doc.html-->
+<dependency>
+   <groupId>com.github.xiaoymin</groupId>
+   <artifactId>swagger-bootstrap-ui</artifactId>
+   <version>1.9.1</version>
+</dependency>
+```
+
+![img](assets/1905053-20200412225558425-1483910.png)
+
+3、Layui-ui **访问 http://localhost:8080/docs.html**
+
+```xml
+<!-- 引入swagger-ui-layer包 /docs.html-->
+<dependency>
+   <groupId>com.github.caspar-chen</groupId>
+   <artifactId>swagger-ui-layer</artifactId>
+   <version>1.1.3</version>
+</dependency>
+```
+
+![img](assets/1905053-20200412225610315-997693293.png)
+
+4、mg-ui **访问 http://localhost:8080/document.html**
+
+```xml
+<!-- 引入swagger-ui-layer包 /document.html-->
+<dependency>
+   <groupId>com.zyplayer</groupId>
+   <artifactId>swagger-mg-ui</artifactId>
+   <version>1.0.6</version>
+</dependency>
+```
+
+![img](assets/1905053-20200412225623225-1419329566.png)

+ 288 - 0
后端/Spring/SpringBoot/任务.md

@@ -0,0 +1,288 @@
+> [TOC]
+
+# 1、SpringBoot:异步、定时、邮件任务
+
+前言
+
+> 在我们的工作中,常常会用到异步处理任务,比如我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,直到邮件发送完毕,响应才会成功,所以我们一般会采用多线程的方式去处理这些任务。还有一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息。还有就是邮件的发送,微信的前身也是邮件服务呢?这些东西都是怎么实现的呢?其实SpringBoot都给我们提供了对应的支持,我们上手使用十分的简单,只需要开启一些注解支持,配置一些配置文件即可!那我们来看看吧~
+>
+> 最后编辑于2020.3.26 作者:狂神说
+
+## 1.1、异步任务
+
+1、创建一个service包
+
+2、创建一个类AsyncService
+
+异步处理还是非常常用的,比如我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,直到邮件发送完毕,响应才会成功,所以我们一般会采用多线程的方式去处理这些任务。
+
+编写方法,假装正在处理数据,使用线程设置一些延时,模拟同步等待的情况;
+
+```java
+@Service
+public class AsyncService {
+
+   public void hello(){
+       try {
+           Thread.sleep(3000);
+      } catch (InterruptedException e) {
+           e.printStackTrace();
+      }
+       System.out.println("业务进行中....");
+  }
+}
+```
+
+3、编写controller包
+
+4、编写AsyncController类
+
+我们去写一个Controller测试一下
+
+```java
+@RestController
+public class AsyncController {
+
+   @Autowired
+   AsyncService asyncService;
+
+   @GetMapping("/hello")
+   public String hello(){
+       asyncService.hello();
+       return "success";
+  }
+
+}
+```
+
+5、访问http://localhost:8080/hello进行测试,3秒后出现success,这是同步等待的情况。
+
+问题:我们如果想让用户直接得到消息,就在后台使用多线程的方式进行处理即可,但是每次都需要自己手动去编写多线程的实现的话,太麻烦了,我们只需要用一个简单的办法,在我们的方法上加一个简单的注解即可,如下:
+
+6、给hello方法添加@Async注解;
+
+```java
+//告诉Spring这是一个异步方法
+@Async
+public void hello(){
+   try {
+       Thread.sleep(3000);
+  } catch (InterruptedException e) {
+       e.printStackTrace();
+  }
+   System.out.println("业务进行中....");
+}
+```
+
+SpringBoot就会自己开一个线程池,进行调用!但是要让这个注解生效,我们还需要在主程序上添加一个注解@EnableAsync ,开启异步注解功能;
+
+```java
+@EnableAsync //开启异步注解功能
+@SpringBootApplication
+public class SpringbootTaskApplication {
+
+   public static void main(String[] args) {
+       SpringApplication.run(SpringbootTaskApplication.class, args);
+  }
+
+}
+```
+
+7、重启测试,网页瞬间响应,后台代码依旧执行!
+
+## 1.2、定时任务
+
+项目开发中经常需要执行一些定时任务,比如需要在每天凌晨的时候,分析一次前一天的日志信息,Spring为我们提供了异步执行任务调度的方式,提供了两个接口。
+
+- TaskExecutor接口
+- TaskScheduler接口
+
+两个注解:
+
+- @EnableScheduling
+- @Scheduled
+
+**cron表达式:**
+
+![img](assets/1905053-20200412225641164-1934062088.png)
+
+![img](assets/1905053-20200412225651289-251704533.png)
+
+**测试步骤:**
+
+1、创建一个ScheduledService
+
+我们里面存在一个hello方法,他需要定时执行,怎么处理呢?
+
+```java
+@Service
+public class ScheduledService {
+   
+   //秒   分   时     日   月   周几
+   //0 * * * * MON-FRI
+   //注意cron表达式的用法;
+   @Scheduled(cron = "0 * * * * 0-7")
+   public void hello(){
+       System.out.println("hello.....");
+  }
+}
+```
+
+2、这里写完定时任务之后,我们需要在主程序上增加@EnableScheduling 开启定时任务功能
+
+```java
+@EnableAsync //开启异步注解功能
+@EnableScheduling //开启基于注解的定时任务
+@SpringBootApplication
+public class SpringbootTaskApplication {
+
+   public static void main(String[] args) {
+       SpringApplication.run(SpringbootTaskApplication.class, args);
+  }
+
+}
+```
+
+3、我们来详细了解下cron表达式;
+
+http://www.bejson.com/othertools/cron/
+
+4、常用的表达式
+
+```markdown
+ (1)0/2 * * * * ?   表示每2秒 执行任务
+(1)0 0/2 * * * ?   表示每2分钟 执行任务
+(1)0 0 2 1 * ?   表示在每月的1日的凌晨2点调整任务
+(2)0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业
+(3)0 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作
+(4)0 0 10,14,16 * * ?   每天上午10点,下午2点,4点
+(5)0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时
+(6)0 0 12 ? * WED   表示每个星期三中午12点
+(7)0 0 12 * * ?   每天中午12点触发
+(8)0 15 10 ? * *   每天上午10:15触发
+(9)0 15 10 * * ?     每天上午10:15触发
+(10)0 15 10 * * ?   每天上午10:15触发
+(11)0 15 10 * * ? 2005   2005年的每天上午10:15触发
+(12)0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发
+(13)0 0/5 14 * * ?   在每天下午2点到下午2:55期间的每5分钟触发
+(14)0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
+(15)0 0-5 14 * * ?   在每天下午2点到下午2:05期间的每1分钟触发
+(16)0 10,44 14 ? 3 WED   每年三月的星期三的下午2:10和2:44触发
+(17)0 15 10 ? * MON-FRI   周一至周五的上午10:15触发
+(18)0 15 10 15 * ?   每月15日上午10:15触发
+(19)0 15 10 L * ?   每月最后一日的上午10:15触发
+(20)0 15 10 ? * 6L   每月的最后一个星期五上午10:15触发
+(21)0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发
+(22)0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发
+```
+
+## 1.3、邮件任务
+
+邮件发送,在我们的日常开发中,也非常的多,Springboot也帮我们做了支持
+
+- 邮件发送需要引入spring-boot-start-mail
+- SpringBoot 自动配置MailSenderAutoConfiguration
+- 定义MailProperties内容,配置在application.yml中
+- 自动装配JavaMailSender
+- 测试邮件发送
+
+**测试:**
+
+1、引入pom依赖
+
+```java
+<<dependency>
+   <groupId>org.springframework.boot</groupId>
+   <artifactId>spring-boot-starter-mail</artifactId>
+</dependency>
+```
+
+看它引入的依赖,可以看到 jakarta.mail
+
+```java
+<dependency>
+   <groupId>com.sun.mail</groupId>
+   <artifactId>jakarta.mail</artifactId>
+   <version>1.6.4</version>
+   <scope>compile</scope>
+</dependency>
+```
+
+2、查看自动配置类:MailSenderAutoConfiguration
+
+![img](assets/1905053-20200412225708744-252995174.png)
+
+这个类中存在bean,JavaMailSenderImpl
+
+![img](assets/1905053-20200412225721465-1009548816.png)
+
+然后我们去看下配置文件
+
+```java
+@ConfigurationProperties(
+   prefix = "spring.mail"
+)
+public class MailProperties {
+   private static final Charset DEFAULT_CHARSET;
+   private String host;
+   private Integer port;
+   private String username;
+   private String password;
+   private String protocol = "smtp";
+   private Charset defaultEncoding;
+   private Map<String, String> properties;
+   private String jndiName;
+}
+```
+
+3、配置文件:
+
+```properties
+spring.mail.username=24736743@qq.comspring.mail.password=你的qq授权码spring.mail.host=smtp.qq.com# qq需要配置sslspring.mail.properties.mail.smtp.ssl.enable=true
+```
+
+获取授权码:在QQ邮箱中的设置->账户->开启pop3和smtp服务
+
+![img](assets/1905053-20200412225736355-1251829128.png)
+
+4、Spring单元测试
+
+```java
+@Autowired
+JavaMailSenderImpl mailSender;
+
+@Test
+public void contextLoads() {
+   //邮件设置1:一个简单的邮件
+   SimpleMailMessage message = new SimpleMailMessage();
+   message.setSubject("通知-明天来狂神这听课");
+   message.setText("今晚7:30开会");
+
+   message.setTo("24736743@qq.com");
+   message.setFrom("24736743@qq.com");
+   mailSender.send(message);
+}
+
+@Test
+public void contextLoads2() throws MessagingException {
+   //邮件设置2:一个复杂的邮件
+   MimeMessage mimeMessage = mailSender.createMimeMessage();
+   MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
+
+   helper.setSubject("通知-明天来狂神这听课");
+   helper.setText("<b style='color:red'>今天 7:30来开会</b>",true);
+
+   //发送附件
+   helper.addAttachment("1.jpg",new File(""));
+   helper.addAttachment("2.jpg",new File(""));
+
+   helper.setTo("24736743@qq.com");
+   helper.setFrom("24736743@qq.com");
+
+   mailSender.send(mimeMessage);
+}
+```
+
+查看邮箱,邮件接收成功!
+
+我们只需要使用Thymeleaf进行前后端结合即可开发自己网站邮件收发功能了!

+ 471 - 0
后端/Spring/SpringBoot/分布式RPC.md

@@ -0,0 +1,471 @@
+
+
+> [toc]
+
+# 1、SpringBoot:Dubbo和Zookeeper集成
+
+分布式理论
+
+## 1.1、什么是分布式系统?
+
+在《分布式系统原理与范型》一书中有如下定义:“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”;
+
+分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是**利用更多的机器,处理更多的数据**。
+
+分布式系统(distributed system)是建立在网络之上的软件系统。
+
+首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统。因为,分布式系统要解决的问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构,会引入很多单机系统没有的问题,为了解决这些问题又会引入更多的机制、协议,带来更多的问题。。。
+
+## 1.2、Dubbo文档
+
+随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,急需**一个治理系统**确保架构有条不紊的演进。
+
+在Dubbo的官网文档有这样一张图
+
+![img](assets/1905053-20200412225836241-1744130417.png)
+
+## 1.3、单一应用架构
+
+当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
+
+![img](assets/1905053-20200412225848354-475809714.png)
+
+适用于小型网站,小型管理系统,将所有功能都部署到一个功能里,简单易用。
+
+**缺点:**
+
+1、性能扩展比较难
+
+2、协同开发问题
+
+3、不利于升级维护
+
+## 1.4、垂直应用架构
+
+当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
+
+![img](assets/1905053-20200412225901199-858224740.png)
+
+通过切分业务来实现各个模块独立部署,降低了维护和部署的难度,团队各司其职更易管理,性能扩展也更方便,更有针对性。
+
+缺点:公用模块无法重复利用,开发性的浪费
+
+## 1.5、分布式服务架构
+
+当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的**分布式服务框架(RPC)**是关键。
+
+![img](assets/1905053-20200412225913839-69515130.png)
+
+## 1.6、流动计算架构
+
+当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于**提高机器利用率的资源调度和治理中心**(SOA)[ Service Oriented Architecture]是关键。
+
+![img](assets/1905053-20200412225925894-2054203963.png)
+
+什么是RPC
+
+RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同。
+
+也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。为什么要用RPC呢?就是无法在一个进程内,甚至一个计算机内通过本地调用的方式完成的需求,比如不同的系统间的通讯,甚至不同的组织间的通讯,由于计算能力需要横向扩展,需要在多台机器组成的集群上部署应用。RPC就是要像调用本地的函数一样去调远程函数;
+
+推荐阅读文章:https://www.jianshu.com/p/2accc2840a1b
+
+**RPC基本原理**
+
+![img](assets/1905053-20200412225942424-634751471.png)
+
+**步骤解析:**
+
+![img](assets/1905053-20200412225954994-2069522644.png)
+
+RPC两个核心模块:通讯,序列化。
+
+测试环境搭建
+
+## 1.7、Dubbo
+
+Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
+
+dubbo官网 http://dubbo.apache.org/zh-cn/index.html
+
+1.了解Dubbo的特性
+
+2.查看官方文档
+
+**dubbo基本概念**
+
+![img](assets/1905053-20200412230011744-1175379704.png)
+
+**服务提供者**(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
+
+**服务消费者**(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
+
+**注册中心**(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
+
+**监控中心**(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
+
+**调用关系说明**
+
+l 服务容器负责启动,加载,运行服务提供者。
+
+l 服务提供者在启动时,向注册中心注册自己提供的服务。
+
+l 服务消费者在启动时,向注册中心订阅自己所需的服务。
+
+l 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
+
+l 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
+
+l 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
+
+### 1.7.1、Dubbo环境搭建
+
+点进dubbo官方文档,推荐我们使用Zookeeper 注册中心
+
+什么是zookeeper呢?可以查看官方文档
+
+### 1.7.2、Window下安装zookeeper
+
+1、下载zookeeper :地址, 我们下载3.4.14 , 最新版!解压zookeeper
+
+2、运行/bin/zkServer.cmd ,初次运行会报错,没有zoo.cfg配置文件;
+
+可能遇到问题:闪退 !
+
+解决方案:编辑zkServer.cmd文件末尾添加pause 。这样运行出错就不会退出,会提示错误信息,方便找到原因。
+
+![img](assets/1905053-20200412230026479-947348663.png)
+
+![img](assets/1905053-20200412230037329-740930228.png)
+
+3、修改zoo.cfg配置文件
+
+将conf文件夹下面的zoo_sample.cfg复制一份改名为zoo.cfg即可。
+
+注意几个重要位置:
+
+dataDir=./ 临时数据存储的目录(可写相对路径)
+
+clientPort=2181 zookeeper的端口号
+
+修改完成后再次启动zookeeper
+
+![img](assets/1905053-20200412230050035-1907960449.png)
+
+4、使用zkCli.cmd测试
+
+ls /:列出zookeeper根下保存的所有节点
+
+```css
+[zk: 127.0.0.1:2181(CONNECTED) 4] ls /[zookeeper]
+```
+
+create –e /kuangshen 123:创建一个kuangshen节点,值为123
+
+![img](assets/1905053-20200412230103589-1318102017.png)
+
+get /kuangshen:获取/kuangshen节点的值
+
+![img](assets/1905053-20200412230116159-2103649071.png)
+
+我们再来查看一下节点
+
+![img](assets/1905053-20200412230133804-1513007496.png)
+
+### 1.7.3、window下安装dubbo-admin
+
+dubbo本身并不是一个服务软件。它其实就是一个jar包,能够帮你的java程序连接到zookeeper,并利用zookeeper消费、提供服务。
+
+但是为了让用户更好的管理监控众多的dubbo服务,官方提供了一个可视化的监控程序dubbo-admin,不过这个监控即使不装也不影响使用。
+
+我们这里来安装一下:
+
+**1、下载dubbo-admin**
+
+地址 :https://github.com/apache/dubbo-admin/tree/master
+
+**2、解压进入目录**
+
+修改 dubbo-admin\src\main\resources \application.properties 指定zookeeper地址
+
+```ini
+server.port=7001spring.velocity.cache=falsespring.velocity.charset=UTF-8spring.velocity.layout-url=/templates/default.vmspring.messages.fallback-to-system-locale=falsespring.messages.basename=i18n/messagespring.root.password=rootspring.guest.password=guestdubbo.registry.address=zookeeper://127.0.0.1:2181
+```
+
+**3、在项目目录下**打包dubbo-admin
+
+```go
+mvn clean package -Dmaven.test.skip=true
+```
+
+**第一次打包的过程有点慢,需要耐心等待!直到成功!**
+
+![img](assets/1905053-20200412230149119-363508332.png)
+
+4、执行 dubbo-admin\target 下的dubbo-admin-0.0.1-SNAPSHOT.jar
+
+```mipsasm
+java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
+```
+
+【注意:zookeeper的服务一定要打开!】
+
+执行完毕,我们去访问一下 http://localhost:7001/ , 这时候我们需要输入登录账户和密码,我们都是默认的root-root;
+
+登录成功后,查看界面
+
+![img](assets/1905053-20200412230202910-800109291.png)
+
+安装完成!
+
+# 2、SpringBoot + Dubbo + zookeeper
+
+## 2.1、框架搭建
+
+**1. 启动zookeeper !**
+
+**2. IDEA创建一个空项目;**
+
+**3.创建一个模块,实现服务提供者:provider-server , 选择web依赖即可**
+
+**4.项目创建完毕,我们写一个服务,比如卖票的服务;**
+
+编写接口
+
+```java
+package com.kuang.provider.service;
+
+public interface TicketService {
+   public String getTicket();
+}
+```
+
+编写实现类
+
+```java
+package com.kuang.provider.service;
+
+public class TicketServiceImpl implements TicketService {
+   @Override
+   public String getTicket() {
+       return "《狂神说Java》";
+  }
+}
+```
+
+**5.创建一个模块,实现服务消费者:consumer-server , 选择web依赖即可**
+
+**6.项目创建完毕,我们写一个服务,比如用户的服务;**
+
+编写service
+
+```java
+package com.kuang.consumer.service;
+
+public class UserService {
+   //我们需要去拿去注册中心的服务
+}
+```
+
+**需求:现在我们的用户想使用买票的服务,这要怎么弄呢 ?**
+
+## 2.2、服务提供者
+
+**1、将服务提供者注册到注册中心,我们需要整合Dubbo和zookeeper,所以需要导包**
+
+**我们从dubbo官网进入github,看下方的帮助文档,找到dubbo-springboot,找到依赖包**
+
+```xml
+<!-- Dubbo Spring Boot Starter -->
+<dependency>
+   <groupId>org.apache.dubbo</groupId>
+   <artifactId>dubbo-spring-boot-starter</artifactId>
+   <version>2.7.3</version>
+</dependency>    
+```
+
+**zookeeper的包我们去maven仓库下载,zkclient;**
+
+```xml
+<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
+<dependency>
+   <groupId>com.github.sgroschupf</groupId>
+   <artifactId>zkclient</artifactId>
+   <version>0.1</version>
+</dependency>
+```
+
+**【新版的坑】zookeeper及其依赖包,解决日志冲突,还需要剔除日志依赖;**
+
+```xml
+<!-- 引入zookeeper -->
+<dependency>
+   <groupId>org.apache.curator</groupId>
+   <artifactId>curator-framework</artifactId>
+   <version>2.12.0</version>
+</dependency>
+<dependency>
+   <groupId>org.apache.curator</groupId>
+   <artifactId>curator-recipes</artifactId>
+   <version>2.12.0</version>
+</dependency>
+<dependency>
+   <groupId>org.apache.zookeeper</groupId>
+   <artifactId>zookeeper</artifactId>
+   <version>3.4.14</version>
+   <!--排除这个slf4j-log4j12-->
+   <exclusions>
+       <exclusion>
+           <groupId>org.slf4j</groupId>
+           <artifactId>slf4j-log4j12</artifactId>
+       </exclusion>
+   </exclusions>
+</dependency>
+```
+
+**2、在springboot配置文件中配置dubbo相关属性!**
+
+```properties
+#当前应用名字
+dubbo.application.name=provider-server
+#注册中心地址
+dubbo.registry.address=zookeeper://127.0.0.1:2181
+#扫描指定包下服务
+dubbo.scan.base-packages=com.kuang.provider.service
+```
+
+**3、在service的实现类中配置服务注解,发布服务!注意导包问题**
+
+```java
+import org.apache.dubbo.config.annotation.Service;
+import org.springframework.stereotype.Component;
+
+@Service //将服务发布出去
+@Component //放在容器中
+public class TicketServiceImpl implements TicketService {
+   @Override
+   public String getTicket() {
+       return "《狂神说Java》";
+  }
+}
+```
+
+**逻辑理解 :应用启动起来,dubbo就会扫描指定的包下带有@component注解的服务,将它发布在指定的注册中心中!**
+
+## 2.3、服务消费者
+
+**1、导入依赖,和之前的依赖一样;**
+
+```xml
+<!--dubbo-->
+<!-- Dubbo Spring Boot Starter -->
+<dependency>
+   <groupId>org.apache.dubbo</groupId>
+   <artifactId>dubbo-spring-boot-starter</artifactId>
+   <version>2.7.3</version>
+</dependency>
+<!--zookeeper-->
+<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
+<dependency>
+   <groupId>com.github.sgroschupf</groupId>
+   <artifactId>zkclient</artifactId>
+   <version>0.1</version>
+</dependency>
+<!-- 引入zookeeper -->
+<dependency>
+   <groupId>org.apache.curator</groupId>
+   <artifactId>curator-framework</artifactId>
+   <version>2.12.0</version>
+</dependency>
+<dependency>
+   <groupId>org.apache.curator</groupId>
+   <artifactId>curator-recipes</artifactId>
+   <version>2.12.0</version>
+</dependency>
+<dependency>
+   <groupId>org.apache.zookeeper</groupId>
+   <artifactId>zookeeper</artifactId>
+   <version>3.4.14</version>
+   <!--排除这个slf4j-log4j12-->
+   <exclusions>
+       <exclusion>
+           <groupId>org.slf4j</groupId>
+           <artifactId>slf4j-log4j12</artifactId>
+       </exclusion>
+   </exclusions>
+</dependency>
+```
+
+2、**配置参数**
+
+```properties
+#当前应用名字
+dubbo.application.name=consumer-server
+#注册中心地址
+dubbo.registry.address=zookeeper://127.0.0.1:2181
+```
+
+**3. 本来正常步骤是需要将服务提供者的接口打包,然后用pom文件导入,我们这里使用简单的方式,直接将服务的接口拿过来,路径必须保证正确,即和服务提供者相同;**
+
+![img](assets/1905053-20200412230223249-22793107.png)
+
+**4. 完善消费者的服务类**
+
+```java
+package com.kuang.consumer.service;
+
+import com.kuang.provider.service.TicketService;
+import org.apache.dubbo.config.annotation.Reference;
+import org.springframework.stereotype.Service;
+
+@Service //注入到容器中
+public class UserService {
+
+   @Reference //远程引用指定的服务,他会按照全类名进行匹配,看谁给注册中心注册了这个全类名
+   TicketService ticketService;
+
+   public void bugTicket(){
+       String ticket = ticketService.getTicket();
+       System.out.println("在注册中心买到"+ticket);
+  }
+
+}
+```
+
+**5. 测试类编写;**
+
+```java
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class ConsumerServerApplicationTests {
+
+   @Autowired
+   UserService userService;
+
+   @Test
+   public void contextLoads() {
+
+       userService.bugTicket();
+
+  }
+
+}
+```
+
+## 2.4、启动测试
+
+**1. 开启zookeeper**
+
+**2. 打开dubbo-admin实现监控【可以不用做】**
+
+**3. 开启服务者**
+
+**4. 消费者消费测试,结果:**
+
+![img](assets/1905053-20200412230239279-1442230316.png)
+
+**监控中心 :**
+
+![img](assets/1905053-20200412230254269-261185375.png)
+
+**ok , 这就是SpingBoot + dubbo + zookeeper实现分布式开发的应用,其实就是一个服务拆分的思想;**

+ 1883 - 0
后端/Spring/SpringBoot/权限认证.md

@@ -0,0 +1,1883 @@
+> [TOC]
+
+# 1、SpringBoot:集成SpringSecurity
+
+## 1.1、安全简介
+
+在 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.2、实战测试
+
+### 1.2.1、实验环境搭建
+
+1、新建一个初始的springboot项目web模块,thymeleaf模块
+
+2、导入静态资源
+
+```undefined
+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跳转!
+
+```java
+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!
+
+### 1.2.2、认识SpringSecurity
+
+Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
+
+记住几个类:
+
+- WebSecurityConfigurerAdapter:自定义Security策略
+- AuthenticationManagerBuilder:自定义认证策略
+- @EnableWebSecurity:开启WebSecurity模式
+
+Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
+
+**“认证”(Authentication)**
+
+身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
+
+身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
+
+**“授权” (Authorization)**
+
+授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
+
+这个概念是通用的,而不是只在Spring Security 中存在。
+
+### 1.2.3、认证和授权
+
+目前,我们的测试环境,是谁都可以访问的,我们使用 Spring Security 增加上认证和授权的功能
+
+1、引入 Spring Security 模块
+
+```java
+<dependency>
+   <groupId>org.springframework.boot</groupId>
+   <artifactId>spring-boot-starter-security</artifactId>
+</dependency>
+```
+
+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
+
+![img](assets/1905053-20200412230317849-1998269068.png)
+
+3、编写基础配置类
+
+```java
+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、定制请求的授权规则
+
+```java
+@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()方法中加入以下配置,开启自动配置的登录功能!
+
+```java
+// 开启自动配置的登录功能
+// /login 请求来到登录页
+// /login?error 重定向到这里表示登录失败
+http.formLogin();
+```
+
+7、测试一下:发现,没有权限的时候,会跳转到登录的页面!
+
+![img](assets/1905053-20200412230333154-1538491155.png)
+
+8、查看刚才登录页的注释信息;
+
+我们可以定义认证规则,重写configure(AuthenticationManagerBuilder auth)方法
+
+```java
+//定义认证规则
+@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”
+
+![img](assets/1905053-20200412230347555-1367252514.png)
+
+10、原因,我们要将前端传过来的密码进行某种方式加密,否则就无法登录,修改代码
+
+```java
+//定义认证规则
+@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.2.4、权限控制和注销
+
+1、开启自动配置的注销的功能
+
+```java
+//定制请求的授权规则
+@Override
+protected void configure(HttpSecurity http) throws Exception {
+   //....
+   //开启自动配置的注销的功能
+      // /logout 注销请求
+   http.logout();
+}
+```
+
+2、我们在前端,增加一个注销的按钮,index.html 导航栏中
+
+```html
+<a class="item" th:href="@{/logout}">
+   <i class="address card icon"></i> 注销
+</a>
+```
+
+3、我们可以去测试一下,登录成功后点击注销,发现注销完毕会跳转到登录页面!
+
+4、但是,我们想让他注销成功后,依旧可以跳转到首页,该怎么处理呢?
+
+```java
+// .logoutSuccessUrl("/"); 注销成功来到首页
+http.logout().logoutSuccessUrl("/");
+```
+
+5、测试,注销完毕后,发现跳转到首页OK
+
+6、我们现在又来一个需求:用户没有登录的时候,导航栏上只显示登录按钮,用户登录之后,导航栏可以显示登录的用户信息及注销按钮!还有就是,比如kuangshen这个用户,它只有 vip2,vip3功能,那么登录则只显示这两个功能,而vip1的功能菜单不显示!这个就是真实的网站情况了!该如何做呢?
+
+**我们需要结合thymeleaf中的一些功能**
+
+sec:authorize="isAuthenticated()":是否认证登录!来显示不同的页面
+
+Maven依赖:
+
+```xml
+<!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
+<dependency>
+   <groupId>org.thymeleaf.extras</groupId>
+   <artifactId>thymeleaf-extras-springsecurity5</artifactId>
+   <version>3.0.4.RELEASE</version>
+</dependency>
+```
+
+7、修改我们的 前端页面
+
+1. 导入命名空间
+
+2. ```html
+   xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
+   ```
+
+3. 修改导航栏,增加认证判断
+
+4. ```html
+   <!--登录注销-->
+   <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();`
+
+```java
+http.csrf().disable();//关闭csrf功能:跨站请求伪造,默认只能通过post方式提交logout请求
+http.logout().logoutSuccessUrl("/");
+```
+
+10、我们继续将下面的角色功能块认证完成!
+
+```html
+<!-- sec:authorize="hasRole('vip1')" -->
+<div class="column" sec:authorize="hasRole('vip1')">
+   <div class="ui raised segment">
+       <div class="ui">
+           <div class="content">
+               <h5 class="content">Level 1</h5>
+               <hr>
+               <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
+               <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
+               <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></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 2</h5>
+               <hr>
+               <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
+               <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
+               <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></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 3</h5>
+               <hr>
+               <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
+               <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
+               <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
+           </div>
+       </div>
+   </div>
+</div>
+```
+
+11、测试一下!
+
+12、权限控制和注销搞定!
+
+### 1.2.5、记住我
+
+现在的情况,我们只要登录之后,关闭浏览器,再登录,就会让我们重新登录,但是很多网站的情况,就是有一个记住密码的功能,这个该如何实现呢?很简单
+
+1、开启记住我功能
+
+```java
+//定制请求的授权规则
+@Override
+protected void configure(HttpSecurity http) throws Exception {
+//。。。。。。。。。。。
+   //记住我
+   http.rememberMe();
+}
+```
+
+2、我们再次启动项目测试一下,发现登录页多了一个记住我功能,我们登录之后关闭 浏览器,然后重新打开浏览器访问,发现用户依旧存在!
+
+思考:如何实现的呢?其实非常简单
+
+我们可以查看浏览器的cookie
+
+![img](assets/1905053-20200412230410090-275194565.png)
+
+3、我们点击注销的时候,可以发现,spring security 帮我们自动删除了这个 cookie
+
+![img](assets/1905053-20200412230424964-1382261300.png)
+4、结论:登录成功后,将cookie发送给浏览器保存,以后登录带上这个cookie,只要通过检查就可以免登录了。如果点击注销,则会删除这个cookie,具体的原理我们在JavaWeb阶段都讲过了,这里就不在多说了!
+
+### 1.2.6、定制登录页
+
+现在这个登录页面都是spring security 默认的,怎么样可以使用我们自己写的Login界面呢?
+
+1、在刚才的登录页配置后面指定 loginpage
+
+```java
+http.formLogin().loginPage("/toLogin");
+```
+
+2、然后前端也需要指向我们自己定义的 login请求
+
+```html
+<a class="item" th:href="@{/toLogin}">
+   <i class="address card icon"></i> 登录
+</a>
+```
+
+3、我们登录,需要将这些信息发送到哪里,我们也需要配置,login.html 配置提交请求及方式,方式必须为post:
+
+在 loginPage()源码中的注释上有写明:
+
+![img](assets/1905053-20200412230440929-230804638.png)
+
+```html
+<form th:action="@{/login}" method="post">
+   <div class="field">
+       <label>Username</label>
+       <div class="ui left icon input">
+           <input type="text" placeholder="Username" name="username">
+           <i class="user icon"></i>
+       </div>
+   </div>
+   <div class="field">
+       <label>Password</label>
+       <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()方法的源码!我们配置接收登录的用户名和密码的参数!
+
+```java
+http.formLogin()
+  .usernameParameter("username")
+  .passwordParameter("password")
+  .loginPage("/toLogin")
+  .loginProcessingUrl("/login"); // 登陆表单提交请求
+```
+
+5、在登录页增加记住我的多选框
+
+```html
+<input type="checkbox" name="remember"> 记住我
+```
+
+6、后端验证处理!
+
+```java
+//定制记住我的参数!
+http.rememberMe().rememberMeParameter("remember");
+```
+
+7、测试,OK
+
+## 1.3、完整配置代码
+
+```java
+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");
+  }
+}
+```
+
+去进行一波源码分析!**
+
+# 2、Shiro简介
+
+## 2.1、Shiro 是什么?
+
+- Apache Shiro 是 Java 的一个安全(权限)框架。
+
+- Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。
+
+- Shiro 可以完成:认证、授权、加密、会话管理、与Web 集成、缓存等。
+- 下载地址
+  - 官网:[http://shiro.apache.org/](http://shiro.apache.org/)
+  - github:[https://github.com/apache/shiro](https://github.com/apache/shiro)
+
+
+
+## 2.2、有哪些功能?
+
+![image-20200729114647110](assets/image-20200729114647110.png)
+
+- Authentication:身份认证/登录,验证用户是不是拥有相应的身份
+
+- Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限
+
+- Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境,也可以是Web 环境的
+
+- Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储
+
+- Web Support:Web 支持,可以非常容易的集成到Web 环境
+
+- Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率
+
+- Concurrency:Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去
+
+- Testing:提供测试支持
+
+- "Run As":允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
+
+- Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
+
+## 2.3、Shiro架构(外部)
+
+从外部来看Shiro,即从应用程序角度的来观察如何使用Shiro完成工作
+
+![image-20200729114702566](assets/image-20200729114702566.png)
+
+- Subject:应用代码直接交互的对象是Subject,也就是说Shiro的对外API 核心就是Subject。Subject 代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;与Subject 的所有交互都会委托给SecurityManager;Subject 其实是一个门面,SecurityManager才是实际的执行者
+
+- SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且其管理着所有Subject;可以看出它是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMVC中DispatcherServlet的角色
+
+- Realm:Shiro从Realm 获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm 得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm 看成DataSource
+
+## 2.4、Shiro架构(内部)
+
+![image-20200729114720578](assets/image-20200729114720578.png)
+
+- Subject:任何可以与应用交互的“用户”;
+- SecurityManager:相当于SpringMVC中的DispatcherServlet;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证、授权、会话及缓存的管理。
+- Authenticator:负责Subject 认证,是一个扩展点,可以自定义实现;可以使用认证策略(Authentication Strategy),即什么情况下算用户认证通过了;
+- Authorizer:授权器、即访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;
+- Realm:可以有1 个或多个Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC 实现,也可以是内存实现等等;由用户提供;所以一般在应用中都需要实现自己的Realm;
+- SessionManager:管理Session 生命周期的组件;而Shiro并不仅仅可以用在Web 环境,也可以用在如普通的JavaSE环境
+  CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能
+- Cryptography:密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密。
+
+# 3、Hello World
+
+## 3.1、快速实践
+
+- 查看官方文档:http://shiro.apache.org/tutorial.html
+
+- 官方的quickstart : https://github.com/apache/shiro/tree/master/samples/quickstart/
+
+  ![image-20200729115148574](assets/image-20200729115148574.png)
+
+1. 创建一个maven父工程,用来学习Shiro,删掉不必要的部分
+
+2. 创建一个普通的Maven子工程:hell-shiro
+
+   ![image-20200729120114648](assets/image-20200729120114648.png)
+
+3. 根据[官方文档](https://github.com/apache/shiro/blob/master/samples/quickstart/pom.xml),我们导入Shiro的依赖
+
+   ![image-20200729120207730](assets/image-20200729120207730.png)
+
+   
+
+   [版本号点击这里](https://mvnrepository.com/artifact/org.apache.shiro/shiro-core)
+
+   ```xml
+       <dependencies>
+           <dependency>
+               <groupId>org.apache.shiro</groupId>
+               <artifactId>shiro-core</artifactId>
+               <version>1.9.0</version>
+           </dependency>
+   
+           <!-- configure logging -->
+           <dependency>
+               <groupId>org.slf4j</groupId>
+               <artifactId>jcl-over-slf4j</artifactId>
+               <version>1.7.36</version>
+           </dependency>
+           <dependency>
+               <groupId>org.slf4j</groupId>
+               <artifactId>slf4j-log4j12</artifactId>
+               <version>1.7.36</version>
+           </dependency>
+           <dependency>
+               <groupId>log4j</groupId>
+               <artifactId>log4j</artifactId>
+               <version>1.2.17</version>
+           </dependency>
+       </dependencies>
+   ```
+
+4. 相关配置文件
+
+   - log4j.properties——[官网](https://github.com/apache/shiro/blob/master/samples/quickstart/src/main/resources/log4j.properties)
+
+     ```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——[官网](https://github.com/apache/shiro/blob/master/samples/quickstart/src/main/resources/shiro.ini)
+
+     ```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
+     
+     # -----------------------------------------------------------------------------
+     # Roles with assigned permissions
+     # 
+     # Each line conforms to the format defined in the
+     # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
+     # -----------------------------------------------------------------------------
+     [roles]
+     # 'admin' role has all permissions, indicated by the wildcard '*'
+     admin = *
+     # The 'schwartz' role can do anything (*) with any lightsaber:
+     schwartz = lightsaber:*
+     # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
+     # license plate 'eagle5' (instance specific id)
+     goodguy = winnebago:drive:eagle5
+     ```
+
+   - 启动类 Quickstart——[官网](https://github.com/apache/shiro/blob/master/samples/quickstart/src/main/java/Quickstart.java)
+
+     ```java
+     public class Quickstart {
+     
+         private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
+     
+     
+         public static void main(String[] args) {
+             // 加载配置文件
+             IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
+             DefaultSecurityManager securityManager = new DefaultSecurityManager();
+             securityManager.setRealm(iniRealm);
+     
+     
+             SecurityUtils.setSecurityManager(securityManager);
+     
+             // 获取当前的用户对象
+             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("Retrieved the correct value! [" + value + "]");
+             }
+     
+             // 判断当前用户是否被认证
+             if (!currentUser.isAuthenticated()) {
+                 // 设置token
+                 UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "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 (Exception e) {
+                     //unexpected condition?  error?
+                 }
+             }
+     
+             //say who they are:
+             //print their identifying principal (in this case, a username):
+             log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
+     
+             // 测试角色
+             if (currentUser.hasRole("schwartz")) {
+                 log.info("May the Schwartz be with you!");
+             } else {
+                 log.info("Hello, mere mortal.");
+             }
+     
+             //  粗粒度
+             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.");
+             }
+     
+             // 细粒度
+             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!");
+             }
+     
+             // 注销
+             currentUser.logout();
+     
+             System.exit(0);
+         }
+     }
+     ```
+     
+     ![image-20200729130649625](assets/image-20200729130649625.png)
+     
+   - Spring Secutrry都有~(只是换了个名字)
+   
+     ```java
+     // 获取当前的用户对象 Subject
+     Subject currentUser = SecurityUtils.getSubject();
+     Session session = currentUser.getSession();
+     currentUser.isAuthenticated()
+         currentUser.getPrincipal()
+         currentUser.hasRole("schwartz")
+         currentUser.isPermitted("lightsaber:wield")
+         currentUser.logout();
+     ```
+
+
+
+# 4、SpringBoot集成
+
+## 4.1、SpringBoot整合Shiro环境搭建
+
+1. 新建一个项目或模块,勾选依赖
+
+   ![image-20200729174715011](assets/image-20200729174715011.png)
+
+   pom.xml
+
+   ```xml
+   <dependencies>
+       <!--thymeleaf-->
+       <dependency>
+           <groupId>org.springframework.boot</groupId>
+           <artifactId>spring-boot-starter-thymeleaf</artifactId>
+       </dependency>
+   
+       <dependency>
+           <groupId>org.springframework.boot</groupId>
+           <artifactId>spring-boot-starter-web</artifactId>
+       </dependency>
+   
+       <dependency>
+           <groupId>org.springframework.boot</groupId>
+           <artifactId>spring-boot-starter-test</artifactId>
+           <scope>test</scope>
+           <exclusions>
+               <exclusion>
+                   <groupId>org.junit.vintage</groupId>
+                   <artifactId>junit-vintage-engine</artifactId>
+               </exclusion>
+           </exclusions>
+       </dependency>
+   </dependencies>
+   ```
+
+2. 测试环境是否正常
+
+   - 新建一个controller页面
+
+     ```java
+     @Controller
+     public class MyController {
+     
+         @RequestMapping({"/","/index"})
+         public String toIndex(Model model) {
+             model.addAttribute("msg","hello,Shiro");
+             return "index";
+         }
+         
+         @RequestMapping("/user/add")
+         public String add() {
+             return "user/add";
+         }
+     
+         @RequestMapping("/user/update")
+         public String update() {
+             return "user/update";
+     	}
+     }
+     ```
+
+   - 新建一个index.html页面
+
+     ```html
+     <!DOCTYPE html>
+     <html lang="en" xmlns:th="http://www.thymeleaf.org">
+     <head>
+         <meta charset="UTF-8">
+         <title>首页</title>
+     </head>
+     <body>
+     <div>
+         <h1>首页</h1>
+         <p th:text="${msg}"></p>
+     
+         <hr>
+         <a th:href="@{/user/add}">add</a>   | <a th:href="@{/user/update}">update</a>
+     </div>
+     </body>
+     </html>
+     ```
+
+   - 新建一个add.html页面
+
+     ```html
+     <!DOCTYPE html>
+     <html lang="en">
+     <head>
+         <meta charset="UTF-8">
+         <title>Title</title>
+     </head>
+     <body>
+         <h1>add</h1>
+     </body>
+     </html>
+     ```
+
+   - 新建一个update.html页面
+
+     ```html
+     <!DOCTYPE html>
+     <html lang="en">
+     <head>
+         <meta charset="UTF-8">
+         <title>Title</title>
+     </head>
+     <body>
+         <h1>update</h1>
+     </body>
+     </html>
+     ```
+
+   - 项目结构
+
+     ![image-20200729190325307](assets/image-20200729190325307.png)
+
+   - 运行截图
+
+     ![image-20200729190548307](assets/image-20200729190548307.png)
+
+3. 导入shiro整合spring的包——[官网](https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring),查看最新版本
+
+   ```xml
+   <!--
+         Subject  用户
+         SecurityManager 管理所有用户
+         Realm 连接数据库
+   -->
+   
+   <!--shiro整合spring的包-->
+   <dependency>
+       <groupId>org.apache.shiro</groupId>
+       <artifactId>shiro-spring</artifactId>
+       <version>1.5.3</version>
+   </dependency>
+   ```
+
+4. 编写导入配置类
+
+   - 编写一个自定义类UserRealm
+
+     ```java
+     //自定义的UserRealm
+     public class UserRealm extends AuthorizingRealm {
+         //授权
+         @Override
+         protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
+             System.out.println("执行了=>授权doGetAuthorizationInfo");
+             return null;
+         }
+     
+         //认证
+         @Override
+         protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
+             System.out.println("执行了=>认证doGetAuthorizationInfo");
+             return null;
+         }
+     }
+     ```
+
+   - 编写配置ShiroConfig
+
+     - 创建realm对象,需要自定义类
+     - DefaultWebSecurityManager
+     - ShiroFilterFactoryBean
+
+     ```java
+     @Configuration
+     public class ShiroConfig {
+     
+         //3. shiroFilterFactoryBean
+     
+         @Bean
+         public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
+             ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
+             // 设置安全管理器
+             bean.setSecurityManager(defaultWebSecurityManager);
+     
+             return bean;
+         }
+     
+         //2. DefaultWebSecurityManager
+     
+         @Bean
+         public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
+             DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+     
+             // 关联userRealm
+             securityManager.setRealm(userRealm);
+             return securityManager;
+         }
+         //1. 创建realm对象,需要自定义类
+     
+         @Bean
+         public UserRealm userRealm() {
+             return new UserRealm();
+         }
+     }
+     ```
+
+## 4.2、Shiro实现登录拦截
+
+- 在`ShiroConfig`中的`getShiroFilterFactoryBean`方法中添加如下配置
+
+    - anon: 无需认证就可以访问
+    - authc: 必须认证了才能访问
+    - user: 必须拥有记住我功能才能用
+    - perms: 拥有对某个资源的权限才能访问
+    - role: 拥有某个角色权限
+
+    ```java
+    Map<String, String> filterMap = new LinkedHashMap<>();
+    filterMap.put("/user/add","authc");
+    filterMap.put("/user/update","authc");
+    bean.setFilterChainDefinitionMap(filterMap);
+    ```
+
+- 点击首页的add或者update之后
+
+  ![image-20200729191619576](assets/image-20200729191619576.png)
+
+- 添加拦截成功页面
+  - 登录页面login.html
+
+    ```html
+    <!DOCTYPE html>
+    <html lang="en">
+    <head>
+        <meta charset="UTF-8">
+        <title>登录页面</title>
+    </head>
+    <body>
+    <h1>登录</h1>
+    <hr>
+
+    <form action="">
+        <p>用户名:<input type="text" name="username"></p>
+        <p>密码:<input type="text" name="password"></p>
+        <p>密码:<input type="submit"></p>
+    </form>
+    </body>
+    </html>
+    ```
+
+  - 在MyConfig中添加
+  
+      ```java
+      @RequestMapping("/toLogin")
+      public String toLogin() {
+          return "login";
+      }
+      ```
+  
+  - 在`ShiroConfig`中的`getShiroFilterFactoryBean`方法中添加如下配置
+  
+      ```java
+      //设置登录的请求
+      bean.setLoginUrl("/toLogin");
+      ```
+  
+- 拦截成功页面
+
+  ![image-20200729192409085](assets/image-20200729192409085.png)
+
+## 4.3、Shiro实现用户认证
+
+1. 在`MyController`中编写用户提交表单之后处理
+
+   ```java
+   @RequestMapping("/login")
+   public String login(String username, String password, Model model) {
+       //获取一个用户
+       Subject subject = SecurityUtils.getSubject();
+       // 封装用户的登录数据
+       UsernamePasswordToken token = new UsernamePasswordToken(username, password);
+   
+       try {
+           subject.login(token);//执行登录的方法,如果没有异常就说明ok了
+           return "index";
+       } catch (UnknownAccountException e) {//用户名不存在
+           model.addAttribute("msg","用户名错误");
+           return "login";
+       } catch (IncorrectCredentialsException e) {//密码不存在
+           model.addAttribute("msg","密码错误");
+           return "login";
+       }
+   
+   }
+   ```
+
+2. login.html的修改
+
+   ```html
+   <!DOCTYPE html>
+   <html lang="en" xmlns:th="http://www.thymeleaf.org">
+   <head>
+       <meta charset="UTF-8">
+       <title>登录页面</title>
+   </head>
+   <body>
+   <h1>登录</h1>
+   <hr>
+   
+   <p th:text="${msg}" style="color: red;"></p>
+   <form th:action="@{/login}">
+       <p>用户名:<input type="text" name="username"></p>
+       <p>密码:<input type="text" name="password"></p>
+       <p>密码:<input type="submit"></p>
+   </form>
+   </body>
+   </html>
+   ```
+
+3. 用户输入登录信息
+
+   - 页面
+
+     ![image-20200729220647520](assets/image-20200729220647520.png)
+
+   - 控制台
+
+     ![image-20200729220926500](assets/image-20200729220926500.png)
+
+4. 用户认证编写`UserRealm`中的认证(doGetAuthenticationInfo)
+
+   ```java
+   //认证
+   @Override
+   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+       System.out.println("执行了=>认证doGetAuthorizationInfo");
+       // 用户名、密码, 数据中取
+       String name = "root";
+       String password = "123456";
+   
+       UsernamePasswordToken userToken = (UsernamePasswordToken) token;
+   
+       if (!userToken.getUsername().equals(name)) {
+           return null;//抛出异常 UnknownAccountException
+       }
+   
+       // 密码认证,shiro做
+       return new SimpleAuthenticationInfo("",password,"");
+   }
+   ```
+
+## 4.4、Shiro整合Mybatis
+
+1. 导入依赖
+
+   ```xml
+   <dependency>
+       <groupId>org.projectlombok</groupId>
+       <artifactId>lombok</artifactId>
+   </dependency>
+   <dependency>
+       <groupId>mysql</groupId>
+       <artifactId>mysql-connector-java</artifactId>
+   </dependency>
+   
+   <dependency>
+       <groupId>log4j</groupId>
+       <artifactId>log4j</artifactId>
+       <version>1.2.17</version>
+   </dependency>
+   
+   <dependency>
+       <groupId>com.alibaba</groupId>
+       <artifactId>druid</artifactId>
+       <version>1.1.23</version>
+   </dependency>
+   
+   <!--引入mybatis,这是MyBatis官方提供的适配spring Boot的,而不是spring Boot自己的-->
+   <dependency>
+       <groupId>org.mybatis.spring.boot</groupId>
+    <artifactId>mybatis-spring-boot-starter</artifactId>
+       <version>2.1.3</version>
+   </dependency>
+   ```
+   
+2. 配置文件application.yml的编写
+
+   ```yml
+   spring:
+     datasource:
+       username: root
+       password: admin
+       #?serverTimezone=UTC解决时区的报错
+       url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
+       driver-class-name: com.mysql.cj.jdbc.Driver
+       type: com.alibaba.druid.pool.DruidDataSource
+   
+       #Spring Boot 默认是不注入这些属性值的,需要自己绑定
+       #druid 数据源专有配置
+       initialSize: 5
+       minIdle: 5
+       maxActive: 20
+       maxWait: 60000
+       timeBetweenEvictionRunsMillis: 60000
+       minEvictableIdleTimeMillis: 300000
+       validationQuery: SELECT 1 FROM DUAL
+       testWhileIdle: true
+       testOnBorrow: false
+       testOnReturn: false
+       poolPreparedStatements: true
+   
+       #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
+       #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
+       #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
+       filters: stat,wall,log4j
+       maxPoolPreparedStatementPerConnectionSize: 20
+       useGlobalDataSourceStat: true
+       connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
+       
+   mybatis:
+     type-aliases-package: nuc.ss.pojo
+     mapper-locations: classpath:mapper/*.xml
+   ```
+
+3. User类的编写
+
+   ```java
+   @Data
+   @AllArgsConstructor
+   @NoArgsConstructor
+   public class User {
+       private int id;
+       private String name;
+       private String pwd;
+   }
+   ```
+
+4. UserMapper.xml映射
+
+   ```xml
+   <?xml version="1.0" encoding="UTF-8" ?>
+   <!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+           "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+   <!--namespace=绑定一个对应的Dao/Mapper接口-->
+   <mapper namespace="nuc.ss.mapper.UserMapper">
+       
+       <select id="queryUserList" resultType="User">
+           select * from mybatis.user;
+       </select>
+   
+       <select id="queryUserById" resultType="User">
+           select * from mybatis.user where id = #{id};
+       </select>
+   
+       <insert id="addUser" parameterType="User">
+           insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
+       </insert>
+   
+       <update id="updateUser" parameterType="User">
+           update mybatis.user set name=#{name},pwd = #{pwd} where id = #{id};
+       </update>
+   
+       <delete id="deleteUser" parameterType="int">
+           delete from mybatis.user where id = #{id}
+       </delete>
+   </mapper>
+   ```
+   
+5. UserService接口实现
+
+   ```java
+   public interface UserService {
+   
+       public User queryUserByName(String name);
+   }
+   ```
+
+6. UserServiceImpl业务逻辑
+
+   ```java
+   @Service
+   public class UserServiceImpl implements UserService {
+   
+       @Autowired
+       UserMapper userMapper;
+       @Override
+       public User queryUserByName(String name) {
+           return userMapper.queryUserByName(name);
+       }
+   }
+   
+   ```
+
+7. 测试环境
+
+   ```java
+   @SpringBootTest
+   class ShiroSpringbootApplicationTests {
+   
+       @Autowired
+       UserService userService;
+       @Test
+       void contextLoads() {
+           System.out.println(userService.queryUserByName("狂神"));
+       }
+   
+   }
+   ```
+
+   ![image-20200730121720922](assets/image-20200730121720922.png)
+
+8. `UserRealm`连接真实数据库
+
+   ```java
+   //认证
+   @Override
+   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+       System.out.println("执行了=>认证doGetAuthorizationInfo");
+   
+       UsernamePasswordToken userToken = (UsernamePasswordToken) token;
+       
+       // 真实数据库 用户名、密码, 数据中取
+       User user = userService.queryUserByName(userToken.getUsername());
+   
+       if (user == null) {//没有这个人
+           return null;
+       }
+   
+       // 密码认证,shiro做
+       return new SimpleAuthenticationInfo("",user.getPwd(),"");
+   }
+   ```
+
+   ![image-20200730180019861](assets/image-20200730180019861.png)
+   
+9. 断点测试密码加密类型
+
+   - 打断点Debug
+
+     ![image-20200730182621912](assets/image-20200730182621912.png)
+
+   - 默认是`SimpleCredentialsMatcher`加密
+
+     ![image-20200730181814293](assets/image-20200730181814293.png)
+
+   - MD5加密——[测试](http://tool.chinaz.com/tools/md5.aspx)
+
+     123456——E10ADC3949BA59ABBE56E057F20F883E
+
+   - MD5盐值加密
+
+   - 所有加密
+
+     ![image-20200730181944253](assets/image-20200730181944253.png)
+
+## 4.5、Shiro实现用户授权
+
+1. `ShiroConfig`中的`getShiroFilterFactoryBean`方法添加认证代码
+
+   ```java
+   //授权,正常情况下,没有授权会跳转到为授权页面
+   filterMap.put("/user/add","perms[user:add]");
+   filterMap.put("/user/update","perms[user:update]");
+   ```
+
+2. 登录之后点击add按钮会弹出如下页面
+
+   ![image-20200730195133631](assets/image-20200730195133631.png)
+
+3. 添加为授权页面
+
+   - MyController
+
+     ```java
+     @RequestMapping("/noauto")
+     @ResponseBody
+     public String unauthorized() {
+         return "未经授权,无法访问此页面";
+     }
+     ```
+
+   - `ShiroConfig`中的`getShiroFilterFactoryBean`方法中添加
+
+     ```java
+     //为授权页面
+     bean.setUnauthorizedUrl("/noauto");
+     ```
+
+4. 再次测试
+
+   ![image-20200730195807437](assets/image-20200730195807437.png)
+
+   ![image-20200730195946692](assets/image-20200730195946692.png)
+
+   所以需要在UserRealm中为用户进行真正授权
+
+5. UserRealm类的修改
+
+   ```java
+   //自定义的UserRealm
+   public class UserRealm extends AuthorizingRealm {
+   
+       @Autowired
+       UserService userService;
+       //授权
+       @Override
+       protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
+           System.out.println("执行了=>授权doGetAuthorizationInfo");
+   
+           SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
+   
+           //拿到当前登录的这个对象
+           Subject subject = SecurityUtils.getSubject();
+           User currentUser = (User)subject.getPrincipal();//拿到user对象
+   
+           //设置当前用户的权限
+           info.addStringPermission(currentUser.getPerms());
+   
+           return info;
+       }
+   
+       //认证
+       @Override
+       protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+           ......
+           // 密码认证,shiro做
+           return new SimpleAuthenticationInfo(user,user.getPwd(),"");
+       }
+   }
+   
+   ```
+
+6. 再次测试
+
+   ![image-20200730202810034](assets/image-20200730202810034.png)
+
+## 4.6、Shiro整合Thymeleaf
+
+1. shiro-thymeleaf整合包导入——[官网](https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro)
+
+   ```xml
+   <!--shiro-thymeleaf整合-->
+   <dependency>
+       <groupId>com.github.theborakompanioni</groupId>
+       <artifactId>thymeleaf-extras-shiro</artifactId>
+       <version>2.0.0</version>
+   </dependency>
+   ```
+
+2. 在ShiroConfig中整合ShiroDialect
+
+   ```java
+   // 整合ShiroDialect: 用来整合 Shiro thymeleaf
+   @Bean
+   public ShiroDialect getShiroDialect() {
+       return new ShiroDialect();
+   }
+   ```
+
+3. index.html页面
+
+   ```html
+   <!DOCTYPE html>
+   <html lang="en" xmlns:th="http://www.thymeleaf.org"
+         xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
+   <head>
+       <meta charset="UTF-8">
+       <title>首页</title>
+   </head>
+   <body>
+   
+   <div>
+       <h1>首页</h1>
+       <p th:text="${msg}"></p>
+   
+       <!--用session实现,配合UserRealm中的session实现-->
+       <!--<div th:if="${session.loginUser==null}">
+           <a th:href="@{/toLogin}">登录</a>
+       </div>-->
+   
+       <div shiro:notAuthenticated>
+           <a th:href="@{/toLogin}">登录</a>
+       </div>
+   
+       <hr>
+   
+       <div shiro:hasPermission="user:add">
+           <a th:href="@{/user/add}">add</a>
+       </div>
+   
+       <div shiro:hasPermission="user:update">
+           <a th:href="@{/user/update}">update</a>
+       </div>
+   
+   </div>
+   </body>
+   </html>
+   ```
+
+4. 页面显示
+
+   ![image-20200730205736153](assets/image-20200730205736153.png)
+
+## 4.7、所有代码
+
+- ShiroConfig
+
+  ```java
+  package nuc.ss.config;
+  
+  import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
+  import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+  import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+  import org.springframework.beans.factory.annotation.Qualifier;
+  import org.springframework.context.annotation.Bean;
+  import org.springframework.context.annotation.Configuration;
+  
+  import java.util.LinkedHashMap;
+  import java.util.Map;
+  
+  @Configuration
+  public class ShiroConfig {
+  
+      //shiroFilterFactoryBean
+  
+      @Bean
+      public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
+          ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
+          // 设置安全管理器
+          bean.setSecurityManager(defaultWebSecurityManager);
+  
+          // 添加shiro的内置过滤器
+          /*
+              anon: 无需认证就可以访问
+              authc: 必须认证了才能访问
+              user: 必须拥有记住我功能才能用
+              perms: 拥有对某个资源的权限才能访问
+              role: 拥有某个角色权限
+           */
+  
+          //拦截
+          Map<String, String> filterMap = new LinkedHashMap<>();
+          //filterMap.put("/user/add","authc");
+          //filterMap.put("/user/update","authc");
+  
+  
+          //授权,正常情况下,没有授权会跳转到为授权页面
+          filterMap.put("/user/add","perms[user:add]");
+          filterMap.put("/user/update","perms[user:update]");
+  
+          filterMap.put("/user/*","authc");
+  
+          bean.setFilterChainDefinitionMap(filterMap);
+  
+          //设置登录的请求
+          bean.setLoginUrl("/toLogin");
+  
+          //为授权页面
+          bean.setUnauthorizedUrl("/noauto");
+  
+        return bean;
+      }
+  
+      //DefaultWebSecurityManager
+  
+      @Bean
+      public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
+          DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
+  
+          // 关联userRealm
+          securityManager.setRealm(userRealm);
+          return securityManager;
+      }
+      //创建realm对象,需要自定义类
+  
+      @Bean
+      public UserRealm userRealm() {
+          return new UserRealm();
+      }
+  
+      // 整合ShiroDialect: 用来整合 Shiro thymeleaf
+      @Bean
+      public ShiroDialect getShiroDialect() {
+          return new ShiroDialect();
+      }
+  }
+  ```
+
+- UserRealm
+
+  ```java
+  package nuc.ss.config;
+  
+  import nuc.ss.pojo.User;
+  import nuc.ss.service.UserService;
+  import org.apache.shiro.SecurityUtils;
+  import org.apache.shiro.authc.*;
+  import org.apache.shiro.authz.AuthorizationInfo;
+  import org.apache.shiro.authz.SimpleAuthorizationInfo;
+  import org.apache.shiro.realm.AuthorizingRealm;
+  import org.apache.shiro.session.Session;
+  import org.apache.shiro.subject.PrincipalCollection;
+  import org.apache.shiro.subject.Subject;
+  import org.springframework.beans.factory.annotation.Autowired;
+  
+  //自定义的UserRealm
+  public class UserRealm extends AuthorizingRealm {
+  
+      @Autowired
+      UserService userService;
+      //授权
+      @Override
+      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
+          System.out.println("执行了=>授权doGetAuthorizationInfo");
+  
+          SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
+  
+          //info.addStringPermission("user:add");
+  
+          //拿到当前登录的这个对象
+          Subject subject = SecurityUtils.getSubject();
+          User currentUser = (User)subject.getPrincipal();//拿到user对象
+  
+          //设置当前用户的权限
+          info.addStringPermission(currentUser.getPerms());
+  
+          return info;
+      }
+  
+      //认证
+      @Override
+      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+          System.out.println("执行了=>认证doGetAuthorizationInfo");
+  
+          UsernamePasswordToken userToken = (UsernamePasswordToken) token;
+  
+          // 虚拟用户
+          //String name = "root";
+          //String password = "123456";
+          //if (!userToken.getUsername().equals(name)) {
+          //    return null;//抛出异常 UnknownAccountException
+          //}
+  
+          // 真实数据库 用户名、密码, 数据中取
+          User user = userService.queryUserByName(userToken.getUsername());
+  
+          if (user == null) {//没有这个人
+              return null;
+          }
+  
+          //首页
+          //Subject currentSubject = SecurityUtils.getSubject();
+          //Session session = currentSubject.getSession();
+          //session.setAttribute("loginUser",user);
+  
+  
+          // 密码认证,shiro做
+          return new SimpleAuthenticationInfo(user,user.getPwd(),"");
+      }
+  }
+  ```
+
+- MyController
+
+  ```java
+  package nuc.ss.controller;
+  
+  import org.apache.shiro.SecurityUtils;
+  import org.apache.shiro.authc.IncorrectCredentialsException;
+  import org.apache.shiro.authc.UnknownAccountException;
+  import org.apache.shiro.authc.UsernamePasswordToken;
+  import org.apache.shiro.subject.Subject;
+  import org.springframework.stereotype.Controller;
+  import org.springframework.ui.Model;
+  import org.springframework.web.bind.annotation.RequestMapping;
+  import org.springframework.web.bind.annotation.ResponseBody;
+  
+  @Controller
+  public class MyController {
+  
+      @RequestMapping({"/","/index"})
+      public String toIndex(Model model) {
+          model.addAttribute("msg","hello,Shiro");
+          return "index";
+      }
+  
+      @RequestMapping("/user/add")
+      public String add() {
+          return "user/add";
+      }
+  
+      @RequestMapping("/user/update")
+      public String update() {
+          return "user/update";
+      }
+  
+      @RequestMapping("/toLogin")
+      public String toLogin() {
+          return "login";
+      }
+  
+      @RequestMapping("/login")
+      public String login(String username, String password, Model model) {
+          //获取一个用户
+          Subject subject = SecurityUtils.getSubject();
+          // 封装用户的登录数据
+          UsernamePasswordToken token = new UsernamePasswordToken(username, password);
+  
+          try {
+              subject.login(token);//执行登录的方法,如果没有异常就说明ok了
+              return "index";
+          } catch (UnknownAccountException e) {//用户名不存在
+              model.addAttribute("msg","用户名错误");
+              return "login";
+          } catch (IncorrectCredentialsException e) {//密码不存在
+              model.addAttribute("msg","密码错误");
+              return "login";
+          }
+      }
+  
+      @RequestMapping("/noauto")
+      @ResponseBody
+      public String unauthorized() {
+          return "未经授权,无法访问此页面";
+      }
+  }
+  
+  ```
+
+- pom依赖
+
+  ```xml
+  <?xml version="1.0" encoding="UTF-8"?>
+  <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.0</modelVersion>
+      <groupId>nuc.ss</groupId>
+      <artifactId>shiro-springboot</artifactId>
+      <version>0.0.1-SNAPSHOT</version>
+      <name>shiro-springboot</name>
+      <description>Demo project for Spring Boot</description>
+  
+      <properties>
+          <java.version>1.8</java.version>
+          <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+          <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+          <spring-boot.version>2.3.0.RELEASE</spring-boot.version>
+      </properties>
+  
+      <dependencies>
+  
+          <!--
+              Subject  用户
+              SecurityManager 管理所有用户
+              Realm 连接数据库
+          -->
+  
+          <!--shiro-thymeleaf整合-->
+          <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
+          <dependency>
+              <groupId>com.github.theborakompanioni</groupId>
+              <artifactId>thymeleaf-extras-shiro</artifactId>
+              <version>2.0.0</version>
+          </dependency>
+  
+          <dependency>
+              <groupId>org.projectlombok</groupId>
+              <artifactId>lombok</artifactId>
+          </dependency>
+          <dependency>
+              <groupId>mysql</groupId>
+              <artifactId>mysql-connector-java</artifactId>
+          </dependency>
+  
+          <dependency>
+              <groupId>log4j</groupId>
+              <artifactId>log4j</artifactId>
+              <version>1.2.17</version>
+          </dependency>
+  
+          <dependency>
+              <groupId>com.alibaba</groupId>
+              <artifactId>druid</artifactId>
+              <version>1.1.23</version>
+          </dependency>
+  
+          <!--引入mybatis,这是MyBatis官方提供的适配spring Boot的,而不是spring Boot自己的-->
+          <dependency>
+              <groupId>org.mybatis.spring.boot</groupId>
+              <artifactId>mybatis-spring-boot-starter</artifactId>
+              <version>2.1.3</version>
+          </dependency>
+  
+          <!--shiro整合spring的包-->
+          <dependency>
+              <groupId>org.apache.shiro</groupId>
+              <artifactId>shiro-spring</artifactId>
+              <version>1.5.3</version>
+          </dependency>
+          <!--thymeleaf-->
+          <dependency>
+              <groupId>org.springframework.boot</groupId>
+              <artifactId>spring-boot-starter-thymeleaf</artifactId>
+          </dependency>
+  
+          <dependency>
+              <groupId>org.springframework.boot</groupId>
+              <artifactId>spring-boot-starter-web</artifactId>
+          </dependency>
+  
+          <dependency>
+              <groupId>org.springframework.boot</groupId>
+              <artifactId>spring-boot-starter-test</artifactId>
+              <scope>test</scope>
+              <exclusions>
+                  <exclusion>
+                      <groupId>org.junit.vintage</groupId>
+                      <artifactId>junit-vintage-engine</artifactId>
+                  </exclusion>
+              </exclusions>
+          </dependency>
+      </dependencies>
+  
+      <dependencyManagement>
+          <dependencies>
+              <dependency>
+                  <groupId>org.springframework.boot</groupId>
+                  <artifactId>spring-boot-dependencies</artifactId>
+                  <version>${spring-boot.version}</version>
+                  <type>pom</type>
+                  <scope>import</scope>
+              </dependency>
+          </dependencies>
+      </dependencyManagement>
+  
+      <build>
+          <plugins>
+              <plugin>
+                  <groupId>org.apache.maven.plugins</groupId>
+                  <artifactId>maven-compiler-plugin</artifactId>
+                  <configuration>
+                      <source>1.8</source>
+                      <target>1.8</target>
+                      <encoding>UTF-8</encoding>
+                  </configuration>
+              </plugin>
+              <plugin>
+                  <groupId>org.springframework.boot</groupId>
+                  <artifactId>spring-boot-maven-plugin</artifactId>
+              </plugin>
+          </plugins>
+      </build>
+  
+  </project>
+  
+  ```
+
+  
+
+# 5、完美的解释
+
+[让 Apache Shiro 保护你的应用](https://www.infoq.cn/article/apache-shiro/?itm_source=infoq_en&itm_medium=link_on_en_item&itm_campaign=item_in_other_langs)

+ 35 - 2
部署文档/大数据平台/大数据平台环境搭建.md

@@ -604,10 +604,43 @@ mv commons-configuration-1.10.jar /opt/modules/hbase-2.2.6/lib/commons-configura
 ## 7.2、atlas集成Hbase
 
 ````shell
+# 修改 hbase-site.xml文件,加入这一行
+<property>
+<name>hbase.coprocessor.master.classes</name>
+<value>org.apache.atlas.hbase.hook.HBaseAtlasCoprocessor</value>
+</property>
 # 拷贝atlas配置文件到hbase的conf中
 cp atlas-application.properties /opt/modules/hbase-2.2.6/conf/
+# 链接atlas钩子到hbase
+ln -s <atlas package>/hook/hbase/* <hbase-home>/lib/
+# 检查atlas-env.sh文件配置是否有hbase路径
+export HBASE_CONF_DIR=/opt/modules/hbase-2.2.6/conf
+
+# 最后执行钩子程序
+./import-hbase.sh
 ````
 
+## 7.3、atlas集成hive
+
+```shell
+# 修改  hive-site.xml 文件,加入这一行
+<property>
+    <name>hive.exec.post.hooks</name>
+      <value>org.apache.atlas.hive.hook.HiveHook</value>
+  </property>
+# 拷贝atlas配置文件到hbase的conf中
+cp atlas-application.properties /opt/modules/hive-3.1.2/conf
+# 检查atlas-env.sh文件配置是否有hbase路径
+export HBASE_CONF_DIR=/opt/modules/hbase-2.2.6/conf
+# Add 'export HIVE_AUX_JARS_PATH=<atlas package>/hook/hive' in hive-env.sh of your hive configuration
+export HIVE_AUX_JARS_PATH=/opt/modules/atlas-2.2.0/hook/hive
+# 最后执行钩子程序
+./import-h.sh
+```
+
+
+
+
 
 # 8、Altas数据恢复
 
@@ -709,8 +742,8 @@ http://lab2:21000
 
 ```shell
 # 猜测可能是申请内存过大导致的
-# 修改py文件无效
-释放内存
+# 修改linux系统配置,让他允许申请大内存
+#释放内存
 echo 3 > /proc/sys/vm/drop_caches
 # 解决方式:
 echo 1 > /proc/sys/vm/overcommit_memory