启动renren-fast如果出现如下错误
-Djps.track.ap.dependencies=false
添加相关配置即可
JDK8特性:https://blog.csdn.net/qq_38526573/category_11113126.html
在后端服务中我们需要查询出所有的三级分类信息,并将这些信息组合为有父子关系的数据,所以首先我们需要在对应的entity中添加关联字段 childrens
/**
* 当前类别所拥有的所有的子类
*/
@TableField(exist = false)
private List<CategoryEntity> childrens;
然后我们在service中完成对应的数据处理的逻辑,具体实现逻辑参考注释
/**
* 查询所有的类别数据,然后将数据封装为树形结构,便于前端使用
*
* @param params
* @return
*/
@Override
public List<CategoryEntity> queryPageWithTree(Map<String, Object> params) {
// 1.查询所有的商品分类信息
List<CategoryEntity> categoryEntities = baseMapper.selectList(null);
// 2.将商品分类信息拆解为树形结构【父子关系】
// 第一步遍历出所有的大类 parent_cid = 0
List<CategoryEntity> list = categoryEntities.stream().filter(categoryEntity -> categoryEntity.getParentCid() == 0)
.map(categoryEntity -> {
// 根据大类找到多有的小类 递归的方式实现
categoryEntity.setChildrens(getCategoryChildrens(categoryEntity,categoryEntities));
return categoryEntity;
}).sorted((entity1, entity2) -> {
return (entity1.getSort() == null ? 0 : entity1.getSort()) - (entity2.getSort() == null ? 0 : entity2.getSort());
}).collect(Collectors.toList());
// 第二步根据大类找到对应的所有的小类
return list;
}
/**
* 查找该大类下的所有的小类 递归查找
* @param categoryEntity 某个大类
* @param categoryEntities 所有的类别数据
* @return
*/
private List<CategoryEntity> getCategoryChildrens(CategoryEntity categoryEntity
, List<CategoryEntity> categoryEntities) {
List<CategoryEntity> collect = categoryEntities.stream().filter(entity -> {
// 根据大类找到他的直属的小类
return entity.getParentCid().equals(categoryEntity.getCatId());
}).map(entity -> {
// 根据这个小类递归找到对应的小小类
entity.setChildrens(getCategoryChildrens(entity, categoryEntities));
return entity;
}).sorted((entity1, entity2) -> {
return (entity1.getSort() == null ? 0 : entity1.getSort()) - (entity2.getSort() == null ? 0 : entity2.getSort());
}).collect(Collectors.toList());
return collect;
}
CategoryService中同步定义对应的接口方法
public interface CategoryService extends IService<CategoryEntity> {
PageUtils queryPage(Map<String, Object> params);
List<CategoryEntity> queryPageWithTree(Map<String, Object> params);
}
然后在CategoryController中新增对应处理的方法
@GetMapping("/listTree")
public R listTree(@RequestParam Map<String, Object> params){
List<CategoryEntity> list = categoryService.queryPageWithTree(params);
return R.ok().put("data", list);
}
启动服务访问测试
首先我们新增一个 商品系统
的目录
按照上图的操作完成即可
然后在商品系统下添加 类别管理
的菜单
对应的三级分类的页面 product/catagory–> src/views/modules/product/category.vue
ElementUI官网:https://element.eleme.cn/#/zh-CN
第一步:展示静态的数据,直接从ElementUI官网拷贝Tree相关案例代码
<template>
<div>
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick">el-tree>
div>
template>
<script>
/* eslint-disable */
export default {
data() {
return {
data: [{
label: '一级 1',
children: [{
label: '二级 1-1',
children: [{
label: '三级 1-1-1'
}]
}]
}, {
label: '一级 2',
children: [{
label: '二级 2-1',
children: [{
label: '三级 2-1-1'
}]
}, {
label: '二级 2-2',
children: [{
label: '三级 2-2-1'
}]
}]
}, {
label: '一级 3',
children: [{
label: '二级 3-1',
children: [{
label: '三级 3-1-1'
}]
}, {
label: '二级 3-2',
children: [{
label: '三级 3-2-1'
}]
}]
}],
defaultProps: {
children: 'children',
label: 'label'
}
};
},
methods: {
handleNodeClick(data) {
console.log(data);
}
}
};
script>
<style>
style>
页面效果
第二步:动态获取后台服务的数据
<template>
<div>
<el-tree :data="data" :props="defaultProps" @node-click="handleNodeClick">el-tree>
div>
template>
<script>
/* eslint-disable */
export default {
data() {
return {
data: [],
defaultProps: {
children: 'children',
label: 'label'
}
};
},
methods: {
getCategory(){
this.$http({
url: this.$http.adornUrl('/product/category/listTree'),
method: 'get'
}).then(({data}) => {
console.log("成功获取的类别数据:",data.data)
this.data = data.data
})
},
handleNodeClick(data) {
console.log(data);
}
},created(){
this.getCategory();
}
};
script>
<style>
style>
访问三级分类数据并没有得到我们期望的结果。出现了404错误:http://localhost:8080/renren-fast/product/category/listTree
针对这个错误提示我们需要通过网关服务来实现统一的路由处理
修改了前端统一的后端服务地址为路由服务后
访问后这个验证码出不来了
验证码出不来的原因是请求的地址:http://localhost:8070/captcha.jpg?uuid=a496be9e-d916-4f3e-813d-d396c13a8b87
跑到网关服务获取验证码了,这里网关服务就应该要将这个请求路由到renren-fast服务中。
首先renren-fast服务没有在注册中心中注册,网关发现不了,先注册renren-fast服务
在renren-fast中依赖commons
<dependency>
<groupId>com.msb.mallgroupId>
<artifactId>mall-commonsartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
添加注册中心和配置中心相关的信息
然后放开注册中心
最后启动服务提示如下错误
原因是因为SpringBoot我们把版本升级到了2.4.12那么validation默认被移除了,我们需要收到的添加依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
<version>2.4.12version>
dependency>
启动服务,注册成功
解决验证码图片不显示的问题,我们需要在网关服务中添加对renren-fast服务访问的路由
# 注册中心的信息
spring:
application:
name: mall-gateway
cloud:
nacos:
discovery:
server-addr: 192.168.56.100:8848
gateway:
routes:
- id: route1
uri: http://www.baidu.com
predicates:
- Query=url,baidu
- id: route2
uri: http://www.jd.com
predicates:
- Query=url,jd
- id: app_route
uri: lb://renren-fast
predicates:
- Path=/app/**
filters:
- RewritePath=/app/(?>/?.*), /renren-fast/$\{segment}
# localhost:8070/app/captcha.jpg -->
# localhost:8080/app/captcha.jpg localhost:8080/renren-fast/captcha.jpg
# 指定注册中心的服务端口
server:
port: 8070
然后测试访问验证码出现了503的错误
出现503错误的原因是Gateway网关服务中会根据loadbanlance负载均衡路由到renren-fast但是缺少了对应的依赖,在Gateway服务中添加即可
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>
同源策略
由于浏览器的同源策略,即属于不同域的页面之间不能相互访问各自的页面内容
注
:同源策略,单说来就是同协议,同域名,同端口
URL 说明 是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js 同一域名下 允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js 同一域名下不同文件夹 允许
http://www.a.com:8000/a.js
http://www.a.com/b.js 同一域名,不同端口 不允许
http://www.a.com/a.js
https://www.a.com/b.js 同一域名,不同协议 不允许
http://www.a.com/a.js
http://70.32.92.74/b.js 域名和域名对应ip 不允许
http://www.a.com/a.js
http://script.a.com/b.js 主域相同,子域不同 不允许
http://www.a.com/a.js
http://a.com/b.js 同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js 不同域名 不允许
跨域网站介绍:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
对于跨域问题的解决我们统一在Gateway中设定。注意删除掉在renren-fast中配置的跨域问题
package com.msb.mall.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
@Configuration
public class MallCorsConfiguration {
@Bean
public CorsWebFilter corsWebFilter(){
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration configuration = new CorsConfiguration();
// 配置跨域的信息
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");
// SpringBoot升级到2.4.0 之后需要使用该配置
configuration.addAllowedOriginPattern("*");
configuration.setAllowCredentials(true);
source.registerCorsConfiguration("/**",configuration);
return new CorsWebFilter(source);
}
}
然后登录操作即可
首先需要在Gateway中配置商品服务的路由信息,同时要注意配置规则的先后顺序
然后服务端响应的数据的字段要在Vue文件中显示的对应,才能正确的显示
访问测试
2> 实现后台服务逻辑删除的操作
在实际开发中针对数据删除这块我们一般都会采用逻辑删除的方法来操作。在本项目中我们可以通过mybatis-Puls中提供的逻辑删除方式来实现
mybatis-plus:https://mp.baomidou.com/guide/
首先配置全局的逻辑删除逻辑
然后在entity的字段中显示的标明:
然后我们就可以在service中继续使用delete相关的方法来操作了
/**
* 逻辑批量删除操作
* @param ids
*/
@Override
public void removeCategoryByIds(List<Long> ids) {
// TODO 1.检查类别数据是否在其他业务中使用
// 2.批量逻辑删除操作
baseMapper.deleteBatchIds(ids);
}
然后通过postman测试
然后在数据库中反应的效果
3> 串联前后端的逻辑
要实现该效果,首先需要通过ajax异步的来提交请求到后端服务
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(ids, false),
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "操作成功",
type: "success",
});
// 重新加载所有的菜单数据
this.getCategory();
// 设置默认展开的父节点信息
this.expandKeys=[node.parent.data.catId]
} else {
this.$message.error(data.msg);
}
然后删除需要必要的提示信息
this.$confirm(`是否确认删除【${data.name}】记录?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
// 传递的数据
let ids = [data.catId];
// 把删除的请求提交到后台服务
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(ids, false),
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "操作成功",
type: "success",
});
// 重新加载所有的菜单数据
this.getCategory();
// 设置默认展开的父节点信息
this.expandKeys=[node.parent.data.catId]
} else {
this.$message.error(data.msg);
}
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
console.log("删除", data, node);
最后删除成功数据后Tree数据刷新及对应的Tree的默认展示父节点信息
到此,三级分类数据的删除操作搞定