IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 项目Test01 -> 正文阅读

[人工智能]项目Test01

如何使用Fengn

加依赖,引入open-feign,假设我"会员"服务要去调用"优惠券"服务,那会员服务就可以创建一个包-feign,包里创建接口,在接口上添加注解@FeignClint,表示我要调用远程服务,接口的参数就是另一服务的服务名称,接口中的函数跟被调用的函数一样,要去掉方法体,被调用函数的完整路径要写全。紧接着要在调用者上添加注解@EnbleFeignClients,表示开启远程调用功能,在本注解中设置baskPackages属性为feign包的全路径。---------------完成。

使用Nacos配置中心动态获取配置:

加依赖nacos-config,创建bootstrap.properties配置文件,配置好注册中心的名字和地址端口号,同理,要在Nacos上创建配置,默认是服务名称加.properties,但是仅完成这操作还不行,要在需要获取配置的类上添加注解@RefreshScope注解才算完成、

实现三级分类

导入数据完成后,在CategoryController中创建方法------>查出所有分类以及子分类,以树形结构组装起来,发现并没有这个函数,那就自己造一个,将CategoryService注入进来并创建listWithTree(),并加以实现。

调用Dao层筛选出所有的分类数据,返回一个List集合,这里用的是

baseMapper.selectList(null);

接下来就是组装成父子的树形结构,怎么组装?

1、找出所有一级分类,一级分类的特征就是ParentCid==0,那么既然有ParentCid,那么就有ChildrenCid,下面要用到这个属性,发现实现类并没有这个属性,那么就自己定义一个

@TableField(exist = false)
private List<CategoryEntity> children; 

一个children树形代表着一个List集合(分类对象),上面注解表示数据库里面并没有这个属性,我自己定义的。

接下来通过JDK8新特性的strem流过滤出想要的属性,以下是完整代码。

public List<CategoryEntity> listWithTree() {
    //1、查出所有的分类数据
    List<CategoryEntity> entities = baseMapper.selectList(null);

    //2、组装成父子的树形结构
    //2.1   找到所有的一级分类,一级分类的特征是ParentCid==0
    List<CategoryEntity> entities1 = entities.stream().filter(categoryEntity -> 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 entities1;
}

如何找出children?通过递归。

private List<CategoryEntity> getChildrens(CategoryEntity root,List<CategoryEntity> all){
    List<CategoryEntity> children = all.stream().filter((categoryEntity) -> {
        return categoryEntity.getParentCid().equals(root.getCatId());
????????//找到子菜单了,但是子菜单还是有子菜单,要继续排
    }).map((categoryEntity) -> {
        //1、找到子菜单
        categoryEntity.setChildren(getChildrens(categoryEntity, all));
        return categoryEntity;
    }).sorted((menu1, menu2) -> {
        //2、菜单排序
        return (menu1.getSort() ==null ? 0 :menu1.getSort()) - (menu2.getSort() ==null ? 0 :menu2.getSort());
    }).collect(Collectors.toList());

    return children;
}

第一个参数表示当前菜单,第二个参数表示所有菜单

return 当前菜单的父ID跟传进来的菜单ID相等

完成业务逻辑!!!

前端部分

前端是基于人人快速开发平台的代码上添加需求的

添加了一个菜单---->分类维护,通过访问浏览器得知请求地址为:product-categomy

三级分类显示的效果,使用的是ElementUI,地址:https://element.eleme.cn/#/zh-CN/component/installation

三级分类使用的是Data中的Tree树形控件

创建getMenus()方法,地址就是对应的控制器请求地址,

getMenus()?{

??????this.$http({

????????url:?this.$http.adornUrl("/product/category/list/tree"),

????????method:?"get",

??????}).then(({?data?})?=>?{

????????console.log("成功获取到菜单数据",?data.data);

????????this.menus?=?data.data;

??????});

------------------------

?//生命周期?-?创建完成(可以访问当前this实例)

??created()?{

????this.getMenus();

??},

表示创建组件的时候调用获取菜单方法,这样初始的状态就有了

将以上的代码完成后报错,因为访问的路径不是我想要的路径,怎么解决?通过网关!

将static/config/index.js中的地址改为网关地址!!!!又发现问题,登陆界面的时候验证码被拦截了,怎么解决?将验证码转给人人-fast,将人人fast注册到注册中心,接着轮到网关

- id: admin_route
  uri: lb://renren-fast
  predicates:
    - Path=/api/**
  filters:
    - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}

lb表示负载均衡到某个服务,看清楚是服务。??????? 只要是前端项目,都要带上/api的前缀,上述表示只要有api前缀,都要先路由到我们的renren-fast这个服务中。??????? 接下来又遇到问题,获取验证码的请求地址并不是真正的地址,需要我们再讲/api转换为renren-fast,所以就有上面的filters,讲api直接转换为renren-fast

遇到问题,登陆失败,请求由于跨域被拦截(CORS),浏览器默认是拒绝跨域请求的,如何解决?

解决跨域:配置当前请求允许跨域,在网关服务里配置过滤器,添加返回值类型为CorsWebFilter

要注意:renren-fast本身也配置了跨域,要注释掉,否则会报错

@Configuration
public class GulimallCorsConfiguration {

    @Bean
    public CorsWebFilter corsWebFilter(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        //跨域配置
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);
        //registerCorsConfiguration注册跨域的配置  /**任意路径都要进行跨域配置
        source.registerCorsConfiguration("/**",corsConfiguration);
        //参数是跨域的配置信息
        return new CorsWebFilter(source);
        /*
        new CorsWebFilter需要跨域的配置信息,所以需要source,source注册跨域配置需要跨域配置信息,所以有了以上的代码
         */
    }
}

接下来通过获取数据库的数据将数据展示为树形三级分类

首先,我现在发送请求发出的地址是发送到renren-fast这里的,因为上面配置了网关的问题,如何解决?再配置一个网关到product服务

- id: product_route
  uri: lb://gulimall-product
  predicates:
    - Path=/api/product/**
  filters:
    - RewritePath=/api/(?<segment>.*),/$\{segment}

注意:要把精确高的路由放在前面??????

后端的数据已经准备好了,接下来写前端

拿到数据按道理来说应该要展示出来,但是并没有,这关乎到一个属性,看<el-tree 标签中的:props="defaultProps" ??????? props表示可视对象

defaultProps:?{

????????children:?"children",

????????label:?"name",

??????},

表示将name数据显示出来,完成!??????? 简单展示功能完成

删除功能

使用ElementUi的自定义节点内容中的?scoped slot

在<el-tree 上加上以下:

<span?class="custom-tree-node"?slot-scope="{?node,?data?}">

????????<span>{{?node.label?}}</span>

????????<span>

??????????<el-button?v-if="node.level?<=?2"?type="text"?size="mini"?@click="()?=>?append(data)">Append</el-button>

??????????<el-button?type="text"?size="mini"?@click="edit(data)">edit</el-button>

??????????<el-button?v-if="node.childNodes.length?==?0"?type="text"?size="mini"?@click="()?=>?remove(node,?data)">Delete

??????????</el-button>

????????</span>

??????</span>

?编写appen和remove方法,具体自己看代码,src/view/module/product/categomy,vue

发现问题:点击节点的时候同时会收缩和展开,怎么解决?

在<el tree 上添加属性::expand-on-click-node="false"

Append和Delete的细节处理:只有是一级或二级分类才可以有append按钮,只有第三级分类才能有delete按钮

<el-button?v-if="node.level?<=?2" ---append ?? <el-button?v-if="node.childNodes.length?==?0" delete ? level表示几级节点

为节点添加可以被选择功能,在eltree上添加show-checkbox属性

添加node-key属性,值为树节点的唯一标识,一般为id????????node-key="catId"

????????p50的逻辑删除

@RequestBody:获取请求体,必须发送POST请求,POST请求才有请求体

SPringMVC自动将请求体的数据(json),转为对应的对象

在java代码中自定义删除节点方法,删除之前需要检查被删除的菜单有没有被引用,现在做不了,将这个需求设置为待办事项,怎么设置?

//TODO 1、检查当前删除的菜单有没有被引用

在IDEA中6:TODO有显示待办事项

开发中常用的是逻辑删除。什么事逻辑删除?使用某一个字段作为标志位,来表示数据是否被删除。在Mybatis如何使用逻辑删除?在配置文件中添加

mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1????????//1表示删除
      logic-not-delete-value: 0????????//0表示不删除

2、 配置组件bean,3.1之后不用,这里直接跳过

3、在实体类上加上逻辑删除注解@TableLogic

/**
 * 是否显示[0-不显示,1显示]
 */
@TableLogic(value = "1",delval = "0")
private Integer showStatus;????????//1表示逻辑不删除,0表示删除,以这里为准 

?完成,接下来让IDEA在控制台打印出SQL语句,怎么打印?

logging:
  level:
    com.atguigu.gulimall.product: debug

?p52??????? 完成删除功能

代码已经是写好的了,直接抄就行了。

点击Delete弹出提示框,怎么实现?参考????????ElementUi的MessagesBox弹框----确认消息提示框

this.$confirm(`是否删除【${data.name}】菜单?`,?"提示",?{

????????confirmButtonText:?"确定",

????????cancelButtonText:?"取消",

????????type:?"warning",

??????})

点击确认弹框之后应该要有一个消息提示,具体参照ElementUi的Notice----Message消息提示
?

this.$message({

??????????????message:?"恭喜你,删除成功",

??????????????type:?"success",

????????????});

?删除成功后还有展开被删除节点的父节点

在<el tree>加属性:default-expanded-keys="expendedKey"??????? 在data(){}中 设置expendedKey:?[],在remove方法删除成功之后添加this.expendedKey?=?[node.parent.data.catId]; 完成

????????p52 实现添加功能

点击Append,弹出对话框,输入自定义分类的名字,确认之后添加子分类

将<el-dialog>标签添加完之后,看 :visible.sync="dialogVisible" 在data里将dialogVisible设置为默认值false,将model设置为? :model="category" 并在data里面为category对象赋值,默认为空串。

初步完成之后,为确认按钮绑定单击事件,也就是addCategory()方法,代码就不粘了,自己找!

我总算明白了,如果前端需要用到数据库的数据,不能写数据库的字段名,要写的是java实体类相对应的属性。。。

??????? p53基本修改功能

代码已经敲好了,直接去看就行了

??????? p54拖拽效果

在<el tree>上添加属性::draggable="draggable" ,在data上设置好属性

节点能不能进行拖拽,需要进行判断,所有要添加上这个属性::allow-drop="allowDrop" 拖拽时判定目标节点能否被放置??????? allow-drop是一个函数,有三个参数,其中的type有三种情况,prev,inner,next表示插入目标前,目标本身,目标之后。

怎么判断?

1、判断被拖动的节点以及所在的父节点总层数不能大于3

自定义一个函数countNodeLevel(node) 来进行统计 详细看代码

其实最重要的就是要明白3-2+1就行了,这里确实不太懂,记住了到时候再回去看一遍

?p55? 拖拽数据收集

监听拖拽功能事件,拖拽成功后将数据拿来发给数据库,也就是以下这个属性

@node-drop="handleDrop" (拖拽成功完成时触发的事件)

想要完成拖拽功能需要获取以下三个属性:

1、当前节点最新的父节点id??????? 2、当前拖拽节点的最新顺序(便利) 3、当前拖拽节点的最新顺序

????????p57设置开关按钮

<el-switch?v-model="draggable"?active-text="开启拖拽"?inactive-text="关闭拖拽"></el-switch>

优化:每次拖拽节点都会更新,频繁的跟数据库交互,很麻烦,所以要有一个按钮,统一将所有修改提交

<el-button?v-if="draggable"?@click="batchSave">批量保存</el-button>

<el-button?type="danger"?@click="batchDelete">批量删除</el-button>

??????? p58节点删除功能

前后端交互的过程,前端负责收集数据,组装好各种数据,真正增删改查要交给后台,后台将前端收集来的数据拿来转换成自己想要的数据后,再调用service处理真正的功能

????????p59品牌管理功能??????? 使用逆向工程的前后端代码

??????? p60??????? 效果优化与快速显示开关

<template?slot-scope="scope">

??????????<img?:src="scope.row.logo"?style="width:?100px;?height:?80px"?/>

?</template>

给显示状态添加按钮

监听开关状态,如果改变了,应该要给服务器发送请求修改数据,详情参考

@change="updateBrandStatus(scope.row)"

位置在src/modules/product/brand.vue中

改了Status后刷新页面为什么还是状态还是关闭的状态?关乎到两个属性

:active-value="1"??????? 表示激活的值,默认是true,要跟数据库对应,所以是1

:inactive-value="0"??????? 表示关闭的值,默认是false

??????? p 品牌logo的文件上传功能

微服务环境下,获取文件,不要把文件直接存储在服务中,统一存储在文件系统,可以选择自己搭建,也可以选择云存储,这里使用的是阿里云的对象存储OSS

阿里云对象存储-服务端签名后直传

把账号密码等操作信息存在自己的服务里,浏览器想要给阿里云上传数据,上传之前先找服务器要到一个Policy(上传策略),服务器利用阿里云的账号密码生成一个防伪的签名,签名里面包含访问阿里云这一次的授权令牌以及要上传给阿里云的哪个地址哪个位置等,前端带着签名以及要上传的文件交给阿里云,阿里云可以来验证这防伪签名是否正确,正确就接受。

如何使用对象存储??????? 1、引入oss-starter 依赖 2、配置阿里云子账号的key,endpoint相关信息

3、使用OSSClient,将其注入进来

?????????p65表单校验??????? 自定义校验器

图片添加完成之后显示的是logo地址, 不是图片本身,怎么解决?

在logo标签中添加<img?:src="scope.row.logo"?style="width:?100px;?height:?80px"?/>

完善校验规则:

参考 brand-add-or-update中的dataRule:?{

????????p66 服务端进行校验 使用JSR303数据校验

在需要检验的实体类属性上添加指定的注解,具体要什么注解详情参考

javax.validation.constraints

注解上有message属性,可以自定义错误提示消息,

当已有的注解不能满足业务需求时,可以添加@Pattern在实体类上,这个注解可以自己写正则表达式

??????? p67??????? 统一进行异常处理

?新建exception包以及类,在类上添加上注解

@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")

属性的意思是要处理哪个包下出现的异常,具体代码自己再看自己的,当然还要再配合一个注解

@ExceptionHandler(value= MethodArgumentNotValidException.class)

类中肯定要有方法来处理业务,这个注解就是来告诉springmvc这个方法能处理哪些异常

不同的异常错误应该有不同的状态码以及信息来提示,这个可以自定义一个枚举类型的类放在common里面

??????? p68数据校验的更高级功能,分组校验。---给检验注解标注什么情况需要进行检验

假设有这样的一个业务场景,我已经将品牌的ID定义不能为空,这种情况我对品牌进行修改没问题,但是假设我是要新增品牌,本来就不需要带上ID,但是又被限制了不得不带,所以就有了这个分组校验。

具体应该怎么操作?在实体类属性上标的注解添加上groups属性。属性为数组,并且必须是一个接口,在common中定义一个包valid,接口就写里面就行,接口只起到标识作用

?????? ----------还有一个注解要配置分组校验? @Validated--------

前端处理请求用的是哪个函数,@Validated 注解就加在哪个函数当中,属性就是上面刚定义好的groups属性

注意:没有标志分组的属性,及时添加的检验注解,默认也是不起作用的!!!

默认没有指定分组的校验注解@NotBlank,在分组校验情况@Validated({AddGroup.class})下不生效,只会在@Validated生效;
?

??????? p69自定义校验注解

自定义校验
?*????? 1)、编写一个自定义的校验注解
?*????? 2)、编写一个自定义的校验器 ConstraintValidator
?*????? 3)、关联自定义的校验器和自定义的校验注解
???????? *????? @Documented
???????? * @Constraint(validatedBy = { ListValueConstraintValidator.class【可以指定多个不同的校验器,适配不同类型的校验】 })
???????? * @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
???????? * @Retention(RUNTIME)
???????? * public @interface ListValue {

具体信息再参考common里面的vaild的LIstValue和ListValueController以及配置文件

使用自定义校验注解要记得添加依赖:

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>

??????? 属性分组功能

在接下来的开发中需要经常用到三级分类,所以我在vue的module中新建一个common包,将公共的部分抽取出来放在里面

完成子组件被单机,父组件感知到,并且能够将子组件的东西发送给父组件,怎么做?

使用父子传递事件??????? 详情参考p71

/**
 * 实现逻辑是这样的,先获取查询条件带来的参数key,然后将查询数据库对应的工具类准备好,也就是
 * new QueryWrapper<AttrGroupEntity>();
 * 再判断key是不是空的,如果不是,那么如果id等于key,或名字中有key的数据库数据就是被查询出来,也就是将想要的东西已经存到wrapper当中了
 * 再判断catlogId是不是空的,如果是,返回查询全部
 * 如果不是,那就根据catlogId以及带来的key查询出想要的数据返回给前端处理
 * @param params
 * @param catelogId
 * @return
 */

?详情参考IDEA代码

????????p73 属性分组新增功能 --分类的级联选择

详情参考ElementUI的Cascader 级联选择器????????组件 / Basic / Layout 布局

通过一系列的操作(cv),能够拿到数据,但是显示不出来,怎么解决?

添加props对象,要动态绑定的,完成后遇到问题:三级的分类之后还会弹出一个选择框,原因是???????? 在三级分类下还有一个children,ElementUI以为我们还有数据,所以就再弹出一个窗口,怎么解决???????? 在java实体类中的children属性上添加:

@JsonInclude(JsonInclude.Include.NON_EMPTY)

表示只能返回不为空的children,接着还有一个catelogs数组和catelog的问题,详情再参考视频,这里就不说了

最后遇到问题,想要修改刚刚新增提交上去的品牌属性,但是品牌的id却不能回显,怎么解决?看p74

??????? p74级联选择器回显

因为返回的catId是一个值,并不是一个数组,所以会回显不出来

编写方法,通过传过来的三级分类ID,获取三级分类对象,再拿出里面的父ID,然后再编写一个函数(使用递归),拿出二级分类以及一级分类,返回给AttrGroupController,再返回给前端,其他细节反面再参考视频

??????? p75品牌分类关联和级联更新

完成品牌的分页功能,创建包config,再创建好配置类,直接cv就行了,完成

完善品牌的模糊查询功能

BrandServiceImpl中的new QueryWrapper<BrandEntity>()默认是没有任何条件的,我们给它加上一个key,接着使用SpringUtil的工具类进行模糊查询然后返回结果

开始编写关联分类功能??????? 一个品牌有多个分类,一个分类有多个品牌(小米有电视,手机,家具等,但是电视也有索尼等品牌),所以就是一个多对多的关系

更改catelog-brand-relation的Controller的save方法

我们传进来的是一个relation对象,我可以直接拿到对象的品牌ID和分类ID,通过ID获取整个实体对象(品牌和分类的),然后直接通过对象获取对应ID的name属性,调用set方法直接修改name属性,return this.save(relation对象)

有一个问题,假设我的品牌名修改了,但是我关联的界面上得品牌并没有修改,这是一个BUG,怎么解决?

Brand的update修改的时候,不能只改品牌表,那么代码如何操作呢?

先修改BrandController的update方法成updateDetail()??????? 更新具体的数据

在实现类上,先更新好自己的品牌表 updateByID(brand),然后判断brandID是否为空,不空就调用catelogBrandRelation的updateBrand()--自己写的,通过传过去的Brand对象找到对应ID的对应name属性,调用UpdateWrapper实现更新操作,完成

接着更新关联表中有关分类的数据,更改CategoryController的update方法(自己写),在service实现类中先更新自己本身的数据,调用this.updateById(category),接着调用关系标的updateCategory()--自己写的,在这个函数当中调用this.baseMapper(id,name),接着去完善这个方法对应的sql语句就OK了

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-08-31 15:27:21  更:2021-08-31 15:29:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 16:44:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码