• 谷粒商城-基础篇-Day02


    实现三级分类

    后端实现:

    在controller中

        @RequestMapping("/list/tree")
        public R list(){
    
    List entities=categoryService.listWithTree();
            return R.ok().put("data",entities);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    创建一个istWithTree()方法

    查出所有的父子关系

     //查出所有分类,组装成父子的树形结构
        @Override
        public List listWithTree() {
    
            //查询所有分类
            List entities = categoryDao.selectList(null);
    
            //分类
              //查询所有一级分类
            List level1Menus = entities.stream().filter((categoryEntity -> {
                return categoryEntity.getParentCid() == 0;
            })).map((menu)->{
                menu.setChildren(getChildrens(menu,entities));
                return menu;
                    }).sorted((menu1,menu2)->{
                        return (menu1.getSort()==null?0:menu1.getSort())-(menu2.getSort()==null?0:menu2.getSort());//通过表中的排序字段进行排序
                    })
    
                    .collect(Collectors.toList());
    
            return level1Menus;
        }
    
    
        //递归查找所有的子菜单
        private  List getChildrens(CategoryEntity root,List all ){
    
            List collect = all.stream().filter((categoryEntity -> {
                return categoryEntity.getParentCid() == root.getCatId();
    
            })).map((childrenEntity) -> {
                childrenEntity.setChildren(getChildrens(childrenEntity, all));
                return childrenEntity;
            }).sorted((child1, child2) -> {
                return (child1.getSort()==null?0:child1.getSort())-(child2.getSort()==null?0:child2.getSort());//通过表中的排序字段进行排序
            }).collect(Collectors.toList());
    
            return collect;
        }
    
    
    • 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

    前端实现:

    1、使用人人开发平台创建出来一个目录(商品系统),然后在商品系统的目录下创建一个分类维护(路径为propduct/catory)

    2、在renren-fast-vue中的models中创建product文件夹,在该文件夹下创建category.vue

    
    
    
    
    
    • 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
    • 58

    此时打开分类维护的目录,页面会发送请求,但是请求的地址是http://localhost:8080/product/category/list/tree

    因为在static下的config中的index.js中指定了请求地址是8080端口

    所以我们将前端的请求转发给gateway网关,由网关做转发

    修改前端中的 window.SITE_CONFIG[‘baseUrl’] = ‘http://localhost:88’

    测试:发现我们的验证码没了,这是由于验证码是来源于renren-fast这个项目中的,所以我们要将renren-fast也注册到nacos中

    直接导入gulimall-common的依赖

    		
    			com.atguigu.gulimall
    			gulimall-common
    			0.0.1-SNAPSHOT
    		
    
    • 1
    • 2
    • 3
    • 4
    • 5

    配置nacos的地址

    在启动类上使用注解开启服务

    为了使前端发送的请求都交给renren-fast去处理

    给前端的请求路径上加一个api

     window.SITE_CONFIG['baseUrl'] = 'http://localhost:88/api';//修改为给网关发请求
    
    • 1

    在gateway中

    当遇到由api的路径时交给renren-fast去处理

    修改配置文件

    - id: admin_root
      uri: lb://renren-fast
      predicates:
        - Path=/api/**
    
    • 1
    • 2
    • 3
    • 4

    但是这时候发送的验证码请求变为了http://renren-fast/api/captcha.jpg,路径中带由了api

    所以需要将请求的路径修改为http://renren-fast/captcha.jpg

    需要设置The RewritePath GatewayFilter Factory

            - id: admin_root
              uri: lb://renren-fast
              predicates:
                - Path=/api/**
              ## http://localhost:88/api/captcha.jpg   http://renren-fast/api/captcha.jpg
              filters:
               - RewritePath=/api/(?/?.*), /renren-fast/$\{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时就不会出现验证码的问题了

    解决跨域问题

    此时点击登录,出现跨域问题

    在gate网关配置解决跨域问题

    @Configuration
    public class GulimallCorsConfiguration {
    
        @Bean
        public CorsWebFilter corsWebFilter(){
    
            UrlBasedCorsConfigurationSource urlsorce = new UrlBasedCorsConfigurationSource();
    
            CorsConfiguration corsConfiguration=new CorsConfiguration();
            //配置跨域
            corsConfiguration.addAllowedHeader("*");//允许的请求头
            corsConfiguration.addAllowedMethod("*");//允许的请求方法
            corsConfiguration.addAllowedOrigin("*");//允许的请求来源
            corsConfiguration.setAllowCredentials(true);//是否允许携带cookie
    
    
            urlsorce.registerCorsConfiguration("/**",corsConfiguration);
    
           return new CorsWebFilter(urlsorce);
    
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    并且将renrnen-fast中的跨域问题的配置注释了

    登录页面成功进入后台

    当组件加载完成会发送一个请求获取三级分类数据

    我们使用gateway进行转发

    1、配置gulimall-product模块到nacos中

      cloud:
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848
      application:
        name: gulimall-product
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2、创建product的命名空间,将prodcut的配置拆分(暂时不做)

    3、新建bootstarp.yml文件,配置地址和配置文件

    spring:
      cloud:
        nacos:
          config:
            server-addr: 127.0.0.1:8848
            namespace: 765a7765-9d98-47ca-9050-95b2450d4457
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    4、使用注解*@EnableDiscoveryClient*开启服务发现

    启动测试是否被注册到注册中心

    5、完成gateway的转发

    修改gateway的配置文件

    配置新的路由

            - id: product
              uri: lb://gulimall-product
              predicates:
                - Path=/api/product/**
              filters:
                - RewritePath=/api/(?/?.*), /$\{segment}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    重新启动网关测试

    成功返回到数据

    将数据添加到页面上

    下一步就是将这些数据添加到页面上

    
    
    
    
    
    • 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
    • 58
    • 59
    • 60
    • 61

    给页面添加按钮(添加和删除节点的按钮)并且节点前面添加复选框,规定只有1级和2级节点可以使用append按钮,没有子节点的才能使用delete按钮

    实现

    
    
    
    
    
    
    • 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
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182

    编辑功能实现

    具体效果:

    1、新增编辑按钮

    2、点击编辑,弹出对话框,使用新增的对话框,进行数据回显,且对话框的title根据业务的不同有所变化

    3、进行数据回显时,需要发送get请求查询数据

    4、当打开的对话框是endit时,点击确定发送的updata请求,打开的对话框的save时发送save请求

    5、点击append按钮时,清空表单中回显的数据

    注意:发送修改请求时,只需要修改form中的三个属性即可

    前端代码:

    
    
    
    
    
    
    • 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
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286

    拖拽效果的实现

    给树形控件添加参数:allow-drag=“allowDrag”

    :allow-drop=“allowDrop”

    绑定一个方法allowDrop用来判断是否能被拖动

     //判断是否能被拖拽
        allowDrop(draggingNode, dropNode, type) {
          console.log("draggingNode", draggingNode, dropNode, type);
          //查找最深的level
          this.selectMaxLeven(draggingNode.data);
          let deep = this.MaxLevel - draggingNode.data.catLevel + 1;
    
          console.log("深度", this.MaxLevel);
          if (type == "inner") {
            //如果是拖动到里面
    
            return deep + dropNode.level <= 3;
          } else {
            //  console.log(false);
            return deep + dropNode.parent.level <= 3;
          }
        },
        selectMaxLeven(node) {
          //判断是否有子节点
          if (node.children != null && node.children.length > 0) {
            //有子节点,存放在一个Array的数组里面,遍历子节点
            for (let i = 0; i < node.children.length; i++) {
              if (node.children[i].catLevel > this.MaxLevel) {
                this.MaxLevel = node.children[i].catLevel;
              }
              //递归查找
              this.selectMaxLeven(node.children[i]);
            }
          }
        },
    
    • 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

    拖拽后进行数据更新

    使用事件@node-drag-end=“handleDragEnd” 拖拽结束时(可能未成功)触发的事件

    1、更新他的父节点

    2、对移动后的兄弟节点进行排序

    3、更新他的level

    4、更新他的子节点的level

     handleDrop(draggingNode, dropNode, dropType, ev) {
     
     //先初始化
           this.updateNodes=[];
          this.MaxLevel= 0;
          console.log("draggingNode ", draggingNode, dropNode, dropType, ev);
    
          let pCid = 0; //父节点
          let sibling = null; //拖动后的兄弟节点
          //1、获取拖拽后的节点的父节点
          //判断当前的拖动type
          if (dropType == "before" || dropType == "after") {
            
            pCid=dropNode.parent.data.catId==undefined?0:dropNode.parent.data.catId;
             sibling = dropNode.parent.childNodes;
          } else {
            //如果是inner,则父节点为
            pCid = dropNode.data.catId;
            sibling = dropNode.childNodes;
          }
    
          //2、拿到拖拽后的兄弟节点,并且完成新排序
    
          for (let i = 0; i < sibling.length; i++) {
            if (sibling[i].data.catId == draggingNode.data.catId) {
              //遍历到当前节点是拖拽的节点,还需要更新parentCid,和当前层级,还有它子节点的层级
              let catLevel = draggingNode.data.catLevel; //层级
    // console.log("当前层级为",catLevel)
              if (sibling[i].level !=catLevel) {
                //  console.log("层级发生变化")
                //当前节点层级发生变化
                //层级发生变化
         catLevel=sibling[i].level;
                //修改他的子节点
                this.updateChildNodeLevel(sibling[i])
              }
              this.updateNodes.push({
                catId: sibling[i].data.catId,
                sort: i,
                parentCid: pCid,
                catLevel: catLevel
              });
            }
             else {
              //遍历的是其他子节点
              this.updateNodes.push({
                catId: sibling[i].data.catId,
                sort: i
              });
            }
          }
          //当前拖拽节点的最新层级
          console.log("updateNodes", this.updateNodes);
        },
    
        updateChildNodeLevel(node) {
          if (node.childNodes.length > 0)
            for (let i = 0; i < node.childNodes.length; i++) {
              var cNode = node.childNodes[i].data;
              this.updateNodes.push({
                catId: cNode.catId,
                catLevel: node.childNodes[i].level
              });
              //递归
              this.updateChildNodeLevel(node.childNodes[i]);
            }
        },
    
    • 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
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    后端处理

    /*
     批量修改
     */
    @RequestMapping("/update/sort")
    public R updateByList(@RequestBody CategoryEntity[] categorys){
        categoryService.updateBatchById(Arrays.asList(categorys));
    
        return R.ok();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    前端发送请求

          //当前拖拽节点的最新层级
          console.log("updateNodes", this.updateNodes);
    
          this.$http({
          url: this.$http.adornUrl('/product/category/update/sort'),
          method: 'post',
          data: this.$http.adornData(this.updateNodes, false)
          }).then(({ data }) => { 
    
             this.$message({
              message: '移动节点成功',
              type: 'success'
            });
      //重新刷新界面
            this.getMenus();
            //打开选中节点
            this.isCheckArrays = [pCid];
    
          });
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    拖拽功能优化

    添加一个按钮,点击后开启拖拽,并且显示批量保存的按钮

    点击批量保存实现保存所有拖动过的节点

    由于之前判断是否能拖拽的方法中调用的是数据库中的属性,我们修改为当前节点下的属性

    前端代码实现:

      
    
    
    批量保存
    
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    saveAll(){
      
          this.$http({
          url: this.$http.adornUrl('/product/category/update/sort'),
          method: 'post',
          data: this.$http.adornData(this.updateNodes, false)
          }).then(({ data }) => { 
    
             this.$message({
              message: '移动节点成功',
              type: 'success'
            });
      //重新刷新界面
            this.getMenus();
            //打开选中节点
            this.isCheckArrays =this.pCid;//这里的pCid为一个数组
    //初始化
           this.updateNodes=[];
          this.MaxLevel= 0;
          });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    修改判断是否能被拖拽的方法的修改

        //判断是否能被拖拽
        allowDrop(draggingNode, dropNode, type) {
          console.log("draggingNode", draggingNode, dropNode, type);
          //查找最深的level
          this.selectMaxLeven(draggingNode);
          let deep = Math.abs(this.MaxLevel - draggingNode.level) + 1;
    
          console.log("深度", this.MaxLevel);
          if (type == "inner") {
            //如果是拖动到里面
            return deep + dropNode.level <= 3;
          } else {
            //  console.log(false);
            return deep + dropNode.parent.level <= 3;
          }
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    批量删除实现

    使用下面这个方法获取选中的 cateId

    getCheckedNodes若节点可被选择(即 show-checkboxtrue),则返回目前被选中的节点所组成的数组

    ref 被用来给元素或子组件注册引用信息, 引用信息将会注册在父组件的 $refs 对象上

    给树形控件加上ref

    deleteAll(){
          let nums=[];
    //批量删除
    nums=this.$refs.menuTree.getCheckedNodes();//使用$refs指向这个控件
    
    //遍历这个数组
    for(var i=0;i {
    
    this.$http({
    url: this.$http.adornUrl('/product/category/delete'),
    method: 'post',
    data: this.$http.adornData(this.catIds, false)
    }).then(({ data }) => {
              this.$message({
                type: 'success',
                message: '删除成功!'
              });
              //刷新界面
              this.getMenus();
     });
    
     }).catch(() => {
              this.$message({
                type: 'info',
                message: '已取消删除'
              });          
            });
    
        },
    
    
    • 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

    category.vue的全部代码

    
    
    
    
    
    
    • 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
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
  • 相关阅读:
    企业电子招投标采购系统源码之电子招投标的组成
    java与netty的类对应关系
    动态增删kdtree(ikdtree)主要思路
    成都东部新区文化旅游体育局莅临国际数字影像产业园参观入驻企业,共促政产交流“零距离”
    ads131a04 ADC verilog实现及仿真
    从boot引导到loader引导完整运行
    Spring Boot 中使用 Redis + Aop 进行限流
    maven构建项目报错:Failure to find com.microsoft.sqlserver:sqljdbc4:jar:4.0 in
    selenium 自动化测试——环境搭建
    佩戴最舒适的蓝牙耳机推荐,不入耳佩戴的骨传导蓝牙耳机
  • 原文地址:https://blog.csdn.net/qq_57907966/article/details/126789393