• Vue2:状态管理 Vuex 3.x


    Vuex官网:https://vuex.vuejs.org/zh

    Vuex是实现组件全局状态(数据)管理的一种机制,方便实现组件之间的数据共享。

    • 集中管理共享的数据,易于开发和后期维护。
    • 能够搞笑试下组件之间数据的共享,提高开发效率。
    • 存储在 vuex 中的数据都是响应式的,能够实时保持数据与页面的同步。

    一般只有组件之间共享的数据,才有必要存储到vuex中,对于组件的私有数据,依旧存储在组件自身的data中。


    小范围内数据共享

    父传子v-bind 属性绑定

    字传父:v-on 事件绑定

    兄弟组件之间共享数据:EventBus

    • $on 接收方
    • $emit 发送方

    Vuex基本使用

    1. 安装vuex依赖包

      yarn add vuex --save
      
      • 1
    2. 导入vuex包

      vue2 搭配的是 vuex@3版本,vue3 搭配的是 vuex@4版本。

      import vuex from 'vuex'
      Vue.use(vuex)
      
      • 1
      • 2
    3. 创建 store 对象(共享数据对象)

      const store = new Vuex.store({
        // state中存放的是全局共享的数据
        state: { count: 0 }
      })
      
      • 1
      • 2
      • 3
      • 4
    4. 将 store 对象挂载到 vue 实例中

      new Vue({
        // 所有的组件,可以直接从store中获取全局的数据
        store
      })
      
      • 1
      • 2
      • 3
      • 4

    封装Store.js

    1. 在 src 下新建 stores 文件夹,并新建 index.js 文件。

      import Vue from "vue"
      import Vuex from 'vuex'
      Vue.use(Vuex);
      
      export default new Vuex.Store({
        state: {
          // 源数据
        },
        mutations: {
          // 修改state
        },
        actions: {
          // 异步mutations
        },
        getters: {
          // 更新state
        }
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    2. 引入到 main.js

      import Store from '@/Stores'
      
      new Vue({
          Store
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5

    格式化代码

    在项目根目录新建 .prettierrc 配置文件。

    {   
        "semi": false,		// 不使用分号
        "singleQuote": true	  // 使用单引号
    }
    
    • 1
    • 2
    • 3
    • 4

    State

    State 提供唯一的公共数据源,所有的共享数据都要统一放到 Store 的 State 中进行存储。

    访问 state 的方式

    1. 直接访问

      {{ $store.state.属性名 }}
      
      • 1
    2. 导入 mapState 函数访问

      导入 mapState 函数,将当前组件需要的全局数据,映射为当前组件的 computed 计算属性。

      <template>
      	<div> {{ count }} div>
      template>
      
      <script>
      // 按需导入 mapState 函数
      import { mapState } from 'vuex'
      
      export default {
          // 将全局数据,映射为当前组件的计算属性
          computed: {
              ...mapState(['count'])
          }
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

    …mapState 原理

    1. 创建一个空对象,循环遍历存储有要访问的变量数组。
    2. 在空对象内存储 this.$store.state[item] 挂载的每一项。
    3. 返回这个对象。
    4. 调用即可。
    function myMap (arr) {
        const obj = {};
        arr.forEach((item) => {
            obj[item] = function () {
                return this.$store.state[item];
            };
        });
        return obj;
    }
    
    export default {
        computed: {
            ...myMap(['name', 'age'])
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Mutation

    Mutation 本质是一个 javascript 函数,用于修改 Store 中的数据。可以集中监控所有数据的变化。

    • 只能通过 Mutation 变更 Store 数据,不可以直接操作 Store 中的数据。

    Mutation 无参

    在store.js中定义方法

    const store = new Vuex.store({
        // state中存放的是全局共享的数据
        state: {
            count: 0
        },
        // 变更State数据
        mutations: {
            // 加法函数:state 代表 state对象
            add (state, num) {
                state.count+=num
            },
            // 减法函数
            Sub(state) {
                state.count--
            }
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    调用 mutations 中的方法

    1. 方式一:直接调用

      // 语法格式:
      this.$store.commit('方法名')
      
      • 1
      • 2
      <script>
      export default {
        methods: {
          add() {
             this.$store.commit('add')
          }
        }
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    2. 方式二:按需导入

      通过 mapMutations 函数 调用 mutations 中的方法。

      // 语法格式:
      import { mapMutations } from 'vuex'
      ...mapMutations(['方法名'])
      
      • 1
      • 2
      • 3
      <script>
      // 导入 mapMutations函数
      import { mapState, mapMutations } from 'vuex'
      
      export default {
        // 将全局数据映射为计算属性
        computed: {
            ...mapMutations(['add'])
        },
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    Mutation 传参

    在store.js中定义方法

    const store = new Vuex.store({
        state: {
            count: 0,
        },
        mutations: {
            // 参数二是自定义传参
            add (state, step) {
                state.count += step;
            }
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    调用 mutations 中的方法

    1. 方式一:直接调用

      <script>
      export default {
          methods: {
              add () {
                 this.$store.commit('add', 1);
              }
          }
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    2. 方式二:按需导入

      通过 mapMutations 函数 调用 mutations 中的方法。

      <script>
      // 导入 mapMutations函数
      import { mapState, mapMutations } from 'vuex'
      
      export default {
        // 将全局数据映射为计算属性
        computed: {
            ...mapMutations(['add'])
        }
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    案例:计数器

    App.vue

    <template>
    	<div>
            
    		<button @click="Sub(1)">-1button>
    		{{ $store.state.count }}
    		<button @click="Add">+1button>
    	div>
    template>
    
    <script>
    import { mapState, mapMutations } from 'vuex'
    
    export default {
    	methods: {
            // 方法一:调用时传参
    		Add() {
    			this.$store.commit('Add', 2)
    		},
    
    		...mapMutations(['Sub'])
    	},
        // 方法二:需要把用到的属性传过来
    	computed: {
    		...mapState(['count'])
    	},
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Store.js

    import Vue from "vue"
    import Vuex from 'vuex'
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        Add (state, num) {
          state.count += num;
        },
        Sub(state, num) {
          state.count -= num;
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Action

    Action 本质是一个 javascript 函数,用于处理异步任务。

    如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutation,但在 Action 中还是要通过触发 Mutation 的方式简介变更数据。

    • 一般在网络请求和做延迟的时候使用。

    在 actions 中,不能直接修改 state 中的数据。

    必须通过 context.comit() 触发某个 mutations 才行。

    • 只有 mutations 中定义的函数,才有权利修改state中的数据。

    Action 无参

    const store = new Vuex.store({
        state: { count: 0 },
        // 定义方法
        mutations: {
            add (state) { state.count++ }
        },
        // 异步操作
        actions: {
            // 调用mutations中的方法,重新定义异步方法
            addAsync (context) {
                setTimeout( () => {
                    context.commit('add');
                }, 1000)
            }
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    调用 mutations 中的异步方法

    1. 方式一:直接调用

      // 语法格式:
      this.$store.dispatch('异步方法名')
      
      • 1
      • 2
      <template>
      	<div>
              <button @click="add">直接使用button>
          div>
      template>
      
      <script>
      export default {
          methods: {
              add () {
                  // dispatch 函数用来触发某个actions
                  this.$store.dispatch('addAsync');
              }
          }
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    2. 方式二:按需导入

      通过 mapActions 函数 调用 mutations 中的方法。

      // 语法格式:
      import { mapState, mapActions } from 'vuex'
      
      export default {
          computed: {
              ...mapState(['数据变量名']),
          },
          methods: {
              ...mapActions(['异步方法名']),
          },
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      <template>
      	<div>
              <button @click="addAsync">直接使用button>
          div>
      template>
      
      <script>
      import { mapState, mapMutations, mapActions } from 'vuex'
      
      export default {
          // 将全局数据映射为计算属性
          computed: {
              ...mapState(['count']),
          },
          methods: {
              // 通过 mapActions 函数 调用 mutations 中的方法
              ...mapActions(['addAsync']),
          },
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

    Action 传参

    在store.js中定义方法

    const store = new Vuex.store({
        state: { count: 0 },
        // 定义方法
        mutations: {
            add (state, step) { state.count += step }
        },
        // 异步操作
        actions: {
            // 调用mutations中的方法,重新定义异步方法
            addAsync (context, step) {
                setTimeout( () => {
                    context.commit('add', step);
                }, 1000)
            }
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    调用 mutations 中的异步方法

    1. 方式一:直接调用

      // 语法格式:
      $store.dispatch('异步方法名', 实参)
      
      • 1
      • 2
      <script>
      export default {
          methods: {
              add () {
                  // dispatch 函数用来触发某个actions
                  this.$store.dispatch('addAsync', 1);
              }
          }
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    2. 方式二:按需导入

      通过 mapActions 函数 调用 mutations 中的方法。

      <template>
      	<div>
              <button @click="add(1)">直接使用button>
              <button @click="addN">重新定义使用button>
          div>
      template>
      
      <script>
      import { mapState, mapMutations, mapActions } from 'vuex'
      
      export default {
          // 将全局数据映射为计算属性
          computed: {
              ...mapState(['count']),
          },
          methods: {
              // 通过 mapActions 函数 调用 mutations 中的方法
              ...mapActions(['add']),
              addN () {
                  this.add(1);
              }
          },
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24

    案例:延迟打印

    App.vue

    <template>
    	<div>
    		<button @click="strAsync">点击输出一句话button>
    		<p>{{ $store.state.msg }}p>
    	div>
    template>
    
    <script>
    import { mapState, mapActions } from 'vuex'
    
    export default {
    	computed: {
    		...mapState(['msg'])
    	},
    	methods: {
            // 方法一:
    		str () {
    			this.$store.dispatch('strAsync')
    		},
            // 方法二:
    		...mapActions(['strAsync'])
    	},
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    Store.js

    import Vue from "vue"
    import Vuex from 'vuex'
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        msg: ''
      },
      mutations: {
        Str (state) {
          state.msg = 'Hello World'
        }
      },
      actions: {
        strAsync (context) {
          setInterval(() => {
            context.commit('Str')
          }, 1000)
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    Getter

    Getter 本质是一个 javascript 函数,用于对 Store 中的数据进行加工处理形成新数据。类似于 Vue 的计算属性。

    • Store 中的数据发生变化,Getter 的数据也会跟着发生变化。
    const store = new Vuex.store({
        state: { count: 0 },
        // 定义方法
        mutations: {
            add (state) { state.count++ }
        },
        // 异步操作
        actions: {
            // 调用mutations中的方法,重新定义异步方法
            addAsync (context) {
                setTimeout( () => {
                    context.commit('add');
                }, 1000)
            }
        },
        // 更新数据
        getters: {
            showNum (state) {
                return state.count
            }
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    调用 mutations 中的方法

    1. 方式一:直接调用

      // 语法格式:
      this.$store.getters.方法名
      
      • 1
      • 2
      <script>
      export default {
          methods: {
              showNums () {
                  $store.getter.showNum();
              }
          }
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    2. 方式二:按需导入

      // 语法格式:
      import { mapState, mapMutations, mapGetters } from 'vuex'
      ...mapGetters(['getters中的方法名'])
      
      • 1
      • 2
      • 3
      <template>
      	<div>
              <button @click="add">直接使用button>
              <button @click="addN">重新定义使用button>
          div>
      template>
      
      <script>
      import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
      
      export default {
          // 将全局数据映射为计算属性
          computed: {
              ...mapState(['count']),
              ...mapGetters(['showNum'])
          },
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18

    modules

    按照模块化的思想开发,把不同的数据和方法,按照彼此的关联进行封装。

    1. 定义模块

      在 stores 文件夹下新建 userStore.js 文件

      export default {
          state: {
              name: '法外狂徒 张三',
              time: 18,
              navList: [
                  '首页',
                  '作品展示',
                  '商务合作',
              ]
          },
          mutations: {
              changeTime (state, num) {
                  state.time += num
              }
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    2. 注册模块

      在 stores 文件夹下的 index.js 中导入分类后的模块。

      import Vue from 'vue'
      import Vuex from 'vuex'
      Vue.use(Vuex)
      
      // 导入不同的module模块
      import userStore from './userStore'
      
      export default nw Vuex.Store({
          // 把 store 分离出去
          modules: {
              user: userStore
          }
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
    3. 通过模块的注册名称访问模块下的成员

      <template>
      	<div>
              
          div>
      template>
      
      <script>
      export default {
      	// 不能随便访问,只能在访问空间访问
          namespaced: true,
          
          computed: {
      		...mapState('user', ["name", "time", "navList"]),
      	},
      	methods: {
      		...mapMutations('user', ['changeTime'])
      	}
      }
      script>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • // 不开启命名空间访问方法:
        this.$store.state.命名空间名.变量名
        
        // 开启空间语法格式:
        ...mapState('命名空间名', ["变量名/方法名"]),
        
        • 1
        • 2
        • 3
        • 4
        • 5

    案例:Todos

    准备工作

    1. 下载组件库

      Ant-design-vue 组件库官网:https://1x.antdv.com/docs/vue/introduce-cn/

      yarn add ant-design-vue
      
      • 1
    2. 引入组件库

      在 src/main.js 中全局引入

      // 引入 Button 样式
      import Button from 'ant-design-vue/lib/button';
      import 'ant-design-vue/dist/antd.css';
      
      Vue.component(Button.name, Button);
      
      • 1
      • 2
      • 3
      • 4
      • 5
    3. 样式模板

      <template>
      	<div id="app">
      		<a-input placeholder="请输入任务" class="my_ipt" />
      		<a-button primary>添加事项a-button>
      		<a-list bordered class="dt_list">
      			<a-list-item slot="renderItem">
      				
      				<a-checkbox>a-checkbox>
      				
      				<a slot="actions">删除a>
      			a-list-item>
      			
      			<div slot="footer" class="footer">
      				
      				<span>0条剩余span>
      				
      				<a-button-group>
      					<a-button>全部a-button>
      					<a-button>未完成a-button>
      					<a-button>已完成a-button>
      				a-button-group>
      				
      				<a>清除完成a>
      			div>
      		a-list>
      	div>
      template>
      
      <script>
      export default {};
      script>
      
      <style scoped>
      #app {
      	padding: 10px;
      }
      .my_ipt {
      	width: 500px;
      	margin-right: 10px;
      }
      .dt_list {
      	width: 500px;
      	margin-top: 10px;
      }
      .footer {
      	display: flex;
      	justify-content: space-between;
      	align-items: center;
      }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50

    App.vue

    <template>
    	<div>
    		<header class="header">
    			<h1>todosh1>
    			<input id="toggle-all" class="toggle-all" type="checkbox" />
    			<label for="toggle-all">label>
    			<input class="new-todo"
                       placeholder="输入任务名称-回车确认"
                       autofocus
                        />
    		header>
    
    		<ul class="todo-list">
    			
    			<li class="completed">
    				<div class="view">
    					<input class="toggle" type="checkbox" />
    					<label>任务名label>
    					<button class="destroy">button>
    				div>
    			li>
    		ul>
    
    		<footer class="footer">
    			<span class="todo-count">剩余<strong>数量值strong>span>
    			<ul class="filters">
    				<li>
    					<a href="javascript:;"
                           class="selected" >
                            全部
        				a>
    				li>
    				<li>
    					<a href="javascript:;">
                            未完成
        				a>
    				li>
    				<li>
    					<a href="javascript:;">
                            已完成
        				a>
    				li>
    			ul>
    			<button class="clear-completed">清除已完成button>
    		footer>
    	div>
    template>
    
    <script>
    export default {
        data () {
            return {
                list: []
            }
        }
    };
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    store.js

    import Vue from 'vue'
    import Vuex from 'vuex'
    Vue.use(Vuex);
    
    import axios from 'axios'
    
    export default new Vuex.store({
        // 源数据
        state: {
            
        },
        // 方法
        mutations: {
            
        },
        // 异步
        actions: {
            getList (context) {
                axios({
                    
                })
            }
        },
        // 更新
        getters: {
            
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    created 与 mounted 的区别

    • created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
    • mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

    mounted 与 methods 的区别

    • mounted 是生命周期方法之一,会在对应生命周期时执行。
    • methods 是Vue实例对象上绑定的方法,供当前Vue组件作用域内使用,未调用不会执行,只执行逻辑,返回值可有可无。

    computed 与 watched 的区别

    • computed 是计算属性,也可以理解为一个方法。其中计算的结果如果不发生改变就不会触发,且必须返回一个值并在DOM中绑定的才能取得值。他可以自动获取数据的改变。
    • watched 属性是手动定义的所需监听的值,不同的数据可以在其中多次定义监听值,这时会消耗一定性能,他并不能像computed那样自动改变。
  • 相关阅读:
    一个tomcat中部署的多个war,相当于几个jvm
    flutter系列之:用来管理复杂状态的State详解
    三、W5100S/W5500+RP2040树莓派Pico<TCP Client数据回环测试>
    【Hack The Box】windows练习-- Silo
    Docker下载Elasticsearch镜像并运行Elasticsearch容器
    Java如何使用实时流式计算处理?
    LeetCode - 743 网络延迟时间
    java计算机毕业设计基于springboot 医院急诊挂号系统
    C语言300行代码实现扫雷(可展开+可标记+可更改困难级别+内附图形界面版本)
    过滤器Filter和拦截器Interceptor实现登录校验
  • 原文地址:https://blog.csdn.net/qq_41952539/article/details/127896804