笔记
文档
- 官方笔记-基础篇:blog.csdn.net/hancoder/ar…
- 官方笔记-高级篇:blog.csdn.net/hancoder/ar…
- 官方笔记-集群篇:blog.csdn.net/hancoder/ar…
- 官方笔记下载地址:download.csdn.net/download/ha…
项目介绍
1.项目架构
2.项目划分
环境搭建
1、docker安装
#卸载系统之前的docker
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
sudo yum install -y yum-utils
# 配置镜像
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
# 设置开机自启动
sudo systemctl enable docker
docker -v
sudo docker images
# 配置镜像加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xdub84vk.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
2、docker安装mysql
# --name指定容器名字 -v目录挂载 -p指定端口映射 -e设置mysql参数 -d后台运行
sudo docker run -p 3306:3306 --name mysql \
-v /root/app/mysql/log:/var/log/mysql \
-v /root/app/mysql/data:/var/lib/mysql \
-v /root/app/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
# 进入容器内部
docker exec -it 471 bash
whereis mysql
#mysql: /usr/bin/mysql /usr/lib/mysql /etc/mysql /usr/share/mysql
# 修改配置文件
vim /root/app/mysql/conf/my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
# 重启
docker restart mysql
# 查看配置文件是否生效
docker exec -it 471 bash
root@471b51c04bd0:/# cat /etc/mysql/my.cnf
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
3、docker安装redis
# 创建挂载目录
mkdir -p /root/app/redis/conf
touch /root/app/redis/conf/redis.conf
# 启动
docker run -p 6379:6379 --name redis \
-v /root/app/redis/data:/data \
-v /root/app/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
# 进入容器内
docker exec -it redis redis-cli
#设置持久化 设置aof类型的持久化方式
vim /root/app/redis/conf/redis.conf
appendonly yes
配置自动重启
[root@like conf]# docker update redis --restart=always
redis
[root@like conf]# docker update mysql --restart=always
mysql
4、创建后端项目
1.共同点
jar包:web,openfeign
包名:com.lk.mall.xxx
2.父项目
<?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>com.like.mall</groupId>
<artifactId>mall</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mall</name>
<description>商城父项目</description>
<packaging>pom</packaging>
<modules>
<module>mall-coupon</module>
<module>mall-member</module>
<module>mall-order</module>
<module>mall-product</module>
<module>mall-ware</module>
</modules>
</project>
5、创建数据库
6、人人开源项目
后端
前端
下载完成后启动
7、生成代码
生成各个库的代码
分布式-微服务
在common中添加依赖
<!-- spring cloud alibaba-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
1、服务发现-nacos
添加依赖
<!--nacos服务发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
添加配置
spring:
# 微服务
cloud:
nacos:
# 注册地址
discovery:
server-addr: 47.112.150.204:8848
application:
name: mall-ware
启动nacos
cd /root/app/nacos/bin
sh startup.sh -m standalone
2、服务远程调用-openfeign
==测试:member 远程调用coupon中的方法==
jar 包
<!--服务调用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
步骤:
- 编写==被调用服务的方法==
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
/**
* 测试 member 远程调用方法
* @return r
*/
public R memberCoupons() {
return R.ok().put("coupons","这里是coupons");
}
- 在调用端新建feign包
package com.like.mall.member.feign;
import com.like.mall.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @author like
* @since 2020-10-25 14:54
* 远程调用 Coupon 服务中的方法
*/
@FeignClient("mall-coupon") // 要调用远程服务
public interface CouponFeignService {
/**
* 远程调用coupon 中的方法,调用地址为coupon服务中的完整调用地址
*/
@GetMapping("coupon/coupon/member/list")
public R memberCoupons();
}
- 在调用端的启动类上添加注解
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现
@EnableFeignClients(basePackages = "com.like.mall.member.feign") // 开启远程调用功能
public class MallMemberApplication {
public static void main(String[] args) {
SpringApplication.run(MallMemberApplication.class, args);
}
}
4.调用远程服务
@RestController
@RequestMapping("member/member")
public class MemberController {
@Autowired
private MemberService memberService;
// 远程调用服务
@Autowired
private CouponFeignService couponFeignService;
// 调运远程方法
@RequestMapping("/coupon")
public R testCoupon() {
R r = couponFeignService.memberCoupons();
return r;
}
}
5.测试
3、配置中心-nacos
添加依赖
<!--nacos配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
- 新建bootstrap.properties文件
# 改名字,对应nacos里的配置文件名
spring.application.name=mall-coupon
# nacos配置中心地址
spring.cloud.nacos.config.server-addr=47.112.150.204:8848
my.name=like
- 新建测试方法
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
// 从配置文件中获取
@Value("${my.name}")
private String myName;
@GetMapping("/test/config")
public R testConfigToNacos() {
return R
.ok()
.put("user", myName);
}
}
3.测试
4.在nacos中新建配置
mall-coupon.properties
- 在controller中添加注解
@RestController
@RequestMapping("coupon/coupon")
@RefreshScope // 动态刷新config
public class CouponController {
6、修改
指定多个配置文件
- 新建一个命名空间
- 新建3个配置文件
- 注释掉application.yml中的配置信息
- 查看coupro中是否加载了相关内容
4、网关- gateway
所有的请求先经过网关,比如常用的路转发,权限校验,限流控制等。==现在用gateway取代了zuul==
新建项目
1.依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.like</groupId>
<artifactId>mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.启动类
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
public class MallGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(MallGatewayApplication.class, args);
}
}
3.配置类
server:
port: 88
spring:
# 微服务
cloud:
# nacos
nacos:
# 服务发现
discovery:
server-addr: 47.112.150.204:8848
# 网关
gateway:
routes:
- id: test_go_baidu
uri: https://www.baidu.com
predicates: # 断言规则
- Query=url,baidu # 携带参数url且值为baidu
- id: test_go_qq
uri: https://www.qq.com
predicates: # 断言规则
- Query=url,qq # 携带参数url且值为qq
application:
name: mall-gateway
# 改名字,对应nacos里的配置文件名
spring.application.name=mall-gateway
# nacos配置中心地址
spring.cloud.nacos.config.server-addr=47.112.150.204:8848
spring.cloud.nacos.config.namespace=8a868529-4b9e-4a77-833f-151532298809
商品服务
a.分类维护
1.查询分类,组装层tree
查询数据库中的所有分类信息,组装成如图下列效果
思路:
- 查找一标签:parentId = 0
- 递归查找该标签的子标签:需要查找子标签的id = parentId
代码实现:
// 添加属性 CategoryEntity
/**
* 在表中不存在,专门用来存放子节点
*/
@TableField(exist = false)
private List<CategoryEntity> children;
// controller 方法
@RestController
@RequestMapping("product/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
/**
* 查询分类中的所有信息,并组成的tree
*/
@RequestMapping("/list/tree")
public R list(@RequestParam Map<String, Object> params){
List<CategoryEntity> entities = categoryService.listWithTree();
return R.ok().put("data", entities);
}
}
// service 方法
@Override
public List<CategoryEntity> listWithTree() {
// 1.查出所有分类
List<CategoryEntity> entities = baseMapper.selectList(null);
// 2.组装成父子结构
return entities
.stream()
.filter(c -> c.getParentCid() == 0) // 查询到所有的一级分类,parent id = 0
.map(c -> {
c.setChildren(getChildren(c, entities)); // 查找当前标签的子标签
return c;
})
.sorted((c1, c2) -> (c1.getSort() == null ? 0 : c1.getSort()) - (c2.getSort() == null ? 0 : c2.getSort())) // 排序
.collect(Collectors.toList()); // 收集
}
/**
* 查找当前标签的子标签
*
* @param root 需要查找的标签
* @param all 所有标签
* @return 返回root的子标签集合
*/
private List<CategoryEntity> getChildren(CategoryEntity root, List<CategoryEntity> all) {
return all
.stream()
.filter(categoryEntity -> categoryEntity.getParentCid() == root.getCatId()) // 条件:当all中的标签的父id是root的id
.map(c -> {
c.setChildren(getChildren(c, all)); // 递归查找,当前标签的子标签,比如说当前是2级标签,就查找他的子标签->3级标签
return c;
})
.sorted((c1, c2) -> (c1.getSort() == null ? 0 : c1.getSort()) - (c2.getSort() == null ? 0 : c2.getSort())) // 排序
.collect(Collectors.toList()); // 收集
}
2.把服务注册到gateway上
修改gateway服务的配置文件
server:
port: 88
spring:
# 微服务
cloud:
# nacos
nacos:
# 服务发现
discovery:
server-addr: 47.112.150.204:8848
# 网关
gateway:
routes:
- id: product_route
uri: lb://mall-product
predicates:
- Path=/api/product/**
filters:
- RewritePath=/api/(?<segment>.*),/$\{segment}
- id: third_party_route
uri: lb://mall-coupon
predicates:
- Path=/api/coupon/**
filters:
- RewritePath=/api/(?<segment>.*),/$\{segment}
- id: member_route
uri: lb://mall-member
predicates:
- Path=/api/member/**
filters:
- RewritePath=/api/(?<segment>.*),/$\{segment}
- id: ware_route
uri: lb://mall-ware
predicates:
- Path=/api/ware/**
filters:
- RewritePath=/api/(?<segment>.*),/$\{segment}
- id: admin_route
uri: lb://renren-fast
predicates:
- Path=/api/**
filters:
- RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}
application:
name: mall-gateway
修改前端项目的请求地址
这样直接访问88端口,通过特定域名访问特定服务
3.解决跨域
- gateway中添加配置类
- 注释掉renren-fast中关于跨域的配置
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsWebFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 1.配置跨域
corsConfiguration.addAllowedHeader("*"); // 请求头
corsConfiguration.addAllowedMethod("*"); // 请求方法
corsConfiguration.addAllowedOrigin("*"); // 请求来源
corsConfiguration.setAllowCredentials(true); // 是否允许携带cookie
// 允许所有请求
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsWebFilter(source);
}
}
4.前端页面搭建
人人开发平台配置页面:
页面具体内容:
mall\mall-sys-vue\src\views\modules\product\category.vue
提交信息:
前端页面-商品系统-分页维护:页面搭建,添加添加和删除按钮逻辑(如果是一级标签就不显示删除只显示添加,如果还有子标签就不显示删除只显示添加)
5.后端删除和添加功能
删除
逻辑删除,使用mybatsi的逻辑删除功能
- product服务添加配置信息
-
给CategoryEntity实体类上的属性添加注解
可以定义删除逻辑,和全局配置是反的
- 方法
// controller
/**
* 删除
*/
@PostMapping("/delete")
public R delete(@RequestBody Long[] catIds) {
// 1.删除标签:检查是否被引用
categoryService.removeMenu(Arrays.asList(catIds));
return R.ok();
}
// service
@Override
public void removeMenu(List<Long> asList) {
// TODO: 2020/10/26 1.删除标签:检查是否被引用
// 现在使用逻辑删除
baseMapper.deleteBatchIds(asList);
}
添加
使用默认的save方法
编辑
使用默认的update方法
6.tree拖拽功能后端数据收集
目标节点的catLevel + deep小于3
需要考虑两种类型节点的catLevel,一种关系是:
如果是==同一个节点==下的==子节点的前后移动==,则不需要修改catLevel。
如果拖动到==与父节点平级的节点关系中==,则要将该拖动的节点的catLevel,设置为兄弟节点的Level,先考虑parentCid还是catLevel?
另外还有一种是前后拖动的情况,哪个范围最大?
肯定是拖动类型关系最大,
如果是前后拖动,则拖动后需要看待拖动节点的层级和设置拖动节点的parentId,
如果拖动节点和目标节点的层级相同,则任务是同级拖动,只需要修改节点的先后顺序,否则任务是跨级拖动,需要修改层级和重新设置parentId
同级拖动:
- 判断节点和目标节点的catLevel是否相同相同则认为是同级拖动,
- 如果此时==移动后目标节点的parentId和待移动节点的相同==,移动类型是前后移动,只需要==修改sort==
- 否则需要修改catLevel和parentId和sort
前后移动:
- 同级移动的标准是catLevel是否相同
- ==同级别==的前后移动分为parentId是否相同
- parentId相同只需要修改sort即可
- 不同则需要修改parentId和sort
- ==不同级别==的前后移动
- 需要修改parentId,catLevel,sort
inner类型的移动:
- 无论是同级inner,跨级inner,都需要修改parentId,catLevel,sort
哪种情况需要更新子节点
- 拖拽的节点是否含有子节点
- 如果有子节点则需要更新子节点的catLevel,
- 如果待移动节点和目标节点额catLevel不同,则是跨级移动。如果是移动到父节点中,则需要设置catLevel,parentId和sort。
- 如果是移动到父节点中,则需要设置catLevel,parentId,sort
b.品牌管理
使用逆向工程生成的代码
c.文件存储-阿里云OSS
服务端签名后直传
- 用户发送上传policy请求到服务器
- 服务器返回上传policy和签名给用户
- 用户直接上传数据给oss
新建模块:
- 导入依赖
<dependencies>
<!-- 公共包-->
<dependency>
<groupId>com.like</groupId>
<artifactId>mall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<!-- mybatis-->
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- oss sdk-->
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alicloud-oss -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 定义配置文件
spring:
# 微服务
cloud:
# oss 上传文件信息
alicloud:
access-key:
secret-key:
oss:
endpoint: oss-cn-shenzhen.aliyuncs.com
bucket: mall-like
nacos:
server-addr:
application:
name: mall-party
server:
port: 13000
- 编写控制层方法
@RestController
public class OssController {
@Autowired
OSS ossClient;
@Value("${spring.cloud.alicloud.oss.endpoint}")
String endpoint;
@Value("${spring.cloud.alicloud.oss.bucket}")
String bucket;
@Value("${spring.cloud.alicloud.access-key}")
String accessId;
@Value("${spring.cloud.alicloud.secret-key}")
String accessKey;
/**
* 服务器签名
*
* @return 签名信息
* @throws Exception 异常
*/
@RequestMapping("/oss/policy")
public Map<String, String> policy() throws Exception {
//https://mall-like.oss-cn-shenzhen.aliyuncs.com/QQ%E6%88%AA%E5%9B%BE20201014092430.png
String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
// callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
String callbackUrl = "http://88.88.88.88:8888";
String nowDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = nowDate + "/"; // 用户上传文件时指定的前缀。
Map<String, String> respMap = null;
try {
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
// PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
respMap = new LinkedHashMap<String, String>();
respMap.put("accessid", accessId);
respMap.put("policy", encodedPolicy);
respMap.put("signature", postSignature);
respMap.put("dir", dir);
respMap.put("host", host);
respMap.put("expire", String.valueOf(expireEndTime / 1000)); // 过期时间
// respMap.put("expire", formatISO8601Date(expiration));
} catch (Exception e) {
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
} finally {
ossClient.shutdown();
}
return respMap;
}
}
- 启动类加服务发现注解
- 测试
d.品牌管理添加图片上传功能
1.图片上传组件
// singleUpload
<template>
<div>
<el-upload
action="http://mall-like.oss-cn-shenzhen.aliyuncs.com"
:data="dataObj"
list-type="picture"
:multiple="false" :show-file-list="showFileList"
:file-list="fileList"
:before-upload="beforeUpload"
:on-remove="handleRemove"
:on-success="handleUploadSuccess"
:on-preview="handlePreview">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过10MB</div>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="fileList[0].url" alt="">
</el-dialog>
</div>
</template>
<script>
import {policy} from './policy'
import { getUUID } from '@/utils'
export default {
name: 'singleUpload',
// 用于父组件传入信息
props: {
value: String
},
computed: {
imageUrl() {
return this.value;
},
imageName() {
if (this.value != null && this.value !== '') {
return this.value.substr(this.value.lastIndexOf("/") + 1);
} else {
return null;
}
},
fileList() {
return [{
name: this.imageName,
url: this.imageUrl
}]
},
showFileList: {
get: function () {
return this.value !== null && this.value !== ''&& this.value!==undefined;
},
set: function (newValue) {
}
}
},
data() {
return {
dataObj: {
policy: '',
signature: '',
key: '',
ossaccessKeyId: '',
dir: '',
host: '',
// callback:'',
},
dialogVisible: false
};
},
methods: {
emitInput(val) {
this.$emit('input', val)
},
handleRemove(file, fileList) {
this.emitInput('');
},
handlePreview(file) {
this.dialogVisible = true;
},
beforeUpload(file) {
let _self = this;
return new Promise((resolve, reject) => {
policy().then(response => {
_self.dataObj.policy = response.data.policy;
_self.dataObj.signature = response.data.signature;
_self.dataObj.ossaccessKeyId = response.data.accessid;
_self.dataObj.key = response.data.dir +getUUID()+'_${filename}';
_self.dataObj.dir = response.data.dir;
_self.dataObj.host = response.data.host;
resolve(true)
}).catch(err => {
reject(false)
})
})
},
handleUploadSuccess(res, file) {
console.log("上传成功...")
this.showFileList = true;
this.fileList.pop();
this.fileList.push({name: file.name, url: this.dataObj.host + '/' + this.dataObj.key.replace("${filename}",file.name) });
this.emitInput(this.fileList[0].url);
}
}
}
</script>
<style>
</style>
2.发送请求脚本
import http from '@/utils/httpRequest.js'
export function policy() {
return new Promise((resolve,reject)=>{
// 获取oss服务器签署信息
http({
url: http.adornUrl("/party/oss/policy"),
method: "get",
params: http.adornParams({})
}).then(({ data }) => {
resolve(data);
})
});
}
3.brand-add-or-update
添加上传组件
4.brand
显示图片
5.添加前端表单校验
e.添加统一个异常处理(数据校验)
定义一个异常处理类==@RestControllerAdvice==
package com.like.mall.product.exception;
@Slf4j
@RestControllerAdvice(basePackages = "com.like.mall")
public class MallException {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleValidationError(MethodArgumentNotValidException e) {
log.error("数据校验出现问题:", e.getMessage(), e.getClass());
Map<String, String> map = new HashMap<>();
e
.getBindingResult()
.getFieldErrors()
.forEach(fieldError -> {
map.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return R.error(400,"数据校验出现问题").put("data",map);
}
@ExceptionHandler
public R handleException(Throwable e) {
return R.error();
}
}
在需要校验的实体类的==添加需要的注解==(使用jsr303规范)
在controller的接口上添加注解==@Valid==
f.分组校验(数据校验)
1.定义几个空实现的接口
- // 数据校验 - 添加public interface Add {}
-// 数据校验 - 修改public interface Update {}
2.在实体类上的校验注解中添加分组信息
- @NotNull(message = "修改必须指定品牌id",groups = {Update.class})
@Null(message = "添加不能指定品牌id",groups = {Add.class})
private Long brandId;
- @NotBlank(message = "品牌名必须提交",groups = {Add.class,Update.class})
private String name;
3.修改接口中的注解为@Valid->@Validated({Add.class})