九、商品服务&品牌管理
2023年7月30日大约 5 分钟
上一级页面:index-la
九、商品服务&品牌管理
9.1、效果显示优化与快速显示开关
vue代码
<el-switch
v-model="scope.row.showStatus"
active-color="#13ce66"
inactive-color="#ff4949"
:active-value="1"
:inactive-value="0"
@change="updateBrandStatus(scope.row)"
>
<!--
scope.row 拿到整行的数据
active-color switch 打开时的背景色
inactive-color switch 关闭时的背景色
active-value switch 打开时的值
inactive-value switch 关闭时的值
-->
组件地址:https://element.eleme.cn/#/zh-CN/component/switch
用户点击 switch 开关就会调用后台的接口更改对应数据库的字段 ( 决定是否显示),定义了 @change 事件 只要修后就会触发对应方法
updateBrandStatus(data) {
console.log("整行数据",data);
// 单独就封装两个字段
let {brandId,showStatus} = data
this.$http({
url: this.$http.adornUrl('/product/brand/update'),
method: 'post',
data: this.$http.adornData({brandId,showStatus}, false)
}).then(({ data }) => {
this.$message({
type:"success",
message:"状态更新成功"
})
});
},
9.2、表单效验&自定义效验规则
Form 组件提供了表单验证的功能,只需要通过 rules
属性传入约定的验证规则,并将 Form-Item 的 prop
属性设置为需校验的字段名即可
<el-form
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="140px"
>
data中
自定义的规则 ,用来对数据进行判断
dataRule: {
name: [{ required: true, message: "品牌名不能为空", trigger: "blur" }],
// 自定义的规则
firstLetter: [
{ validator: (rule, value, callback) => {
if(value == '') {
callback(new Error("首字母必须填写"))
} else if(! /^[a-zA-Z]$/.test(value)) {
callback(new Error("首字母必须a-z或者A-Z之间"))
} else {
callback()
}
},trigger:'blur'}
],
sort: [{ validator: (rule, value, callback) => {
if(value == '') {
callback(new Error("排序字段必须填写"));
} else if(!Number.isInteger(value) || value < 0) {
callback(new Error("排序必须是一个大于等于0的整数"));
} else {
callback();
}
}, trigger: "blur" }]
}
9.3、JSR303 数据效验 & 统一异常处理
前端数据效验成功了,就会把json数据传递到后端,但是有人利用接口 比如 postman 乱发送请求 那会怎么办,于是后端也会利用 JSR303进行数据效验
9.3.1、给Bean添加效验注解 javax.validation.constraints包下 并定义自己的的message提示
@NotEmpty(messsage = "logo不能为空")
@URL(message = "logo必须是一个合法的url地址")
private String logo;
9.3.2、开启效验功能 @Valid
效果:效验错误以后有默认的响应
Controller代码:
@RequestMapping("/save") public R save(@Valid@RequestBody BrandEntity brand){ brandService.save(brand); return R.ok(); }
9.3.3、给效验的bean后紧跟一个BindingResult 就可以获取到效验的结果
public R save(@Valid @RequestBody BrandEntity brand,BindingResult result){
if(result.hasErrors()){
Map<String,String> map = new HashMap<>();
//1、获取校验的错误结果
result.getFieldErrors().forEach((item)->{
//FieldError 获取到错误提示
String message = item.getDefaultMessage();
//获取错误的属性的名字
String field = item.getField();
map.put(field,message);
});
return R.error(400,"提交的数据不合法").put("data",map);
}else {
}
9.3.4、分组效验 (多场景复杂效验)
添加一个组 & 修改一个组
1、@NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})
- 给效验注解标注什么情况需要进行效验
- @Validated({AddGroup.class}) 在对应方法上进行标注
- 默认没有指定分组的效验注解 @NotBlank 在分组效验情况@Validated({AddGroup.class})不生效,只会在@Validated生效
// 标记使用修改分组
public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand){
brandService.updateById(brand);
return R.ok();
}
Entity
/**
* 品牌id
*/
@Null(message = "新增不能指定Id",groups = {AddGroup.class})
@NotNull(message = "修改必须指定品牌id",groups = {UpdateGroup.class})
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空",groups = {AddGroup.class,UpdateGroup.class})
private String name;
/**
* 品牌logo地址
*/
@NotEmpty(groups = {AddGroup.class})
@URL(message = "logo必须是一个合法的url地址",groups = {AddGroup.class,UpdateGroup.class})
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull(groups = {AddGroup.class, UpdateStatusGroup.class})
@ListValue(vals={0,1},groups = {AddGroup.class,UpdateStatusGroup.class})
private Integer showStatus;
/**
* 检索首字母
*/
@NotEmpty(groups = {AddGroup.class})
@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是一个字母",groups = {AddGroup.class,UpdateGroup.class})
private String firstLetter;
/**
* 排序
*/
@NotNull(groups = {AddGroup.class})
@Min(value=0,message = "排序必须大于等于0",groups = {AddGroup.class,UpdateGroup.class})
private Integer sort;
9.3.5、自定义效验
编写一个自定义的效验注解
编写一个自定义的效验器何自定义的效验注解
@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class})//【可以指定多个不同的效验器,适配不同类型的效验】
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
// 三要素不能丢
String message() default "{com.atguigu.gulimall.product.valid.ListValue.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] vals() default { };
}
实现约束
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private Set<Integer> set = new HashSet<>();
// 初始化方法
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for(int val : vals) {
// 将结果添加到set集合
set.add(val);
}
}
/**
* 判断效验是否成功
* @param value 需要效验的值
* @param context
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
// 判断是包含该值
return set.contains(value);
}
}
9.3.6、异常处理
这里使用到了 SpringMVC 的注解 @ControllerAdvice
1、编写异常处理类使用SpringMvc的@ControllerAdvice
2、使用@ExceptionHandler标记方法可以处理异常
@Slf4j
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
/**
* 捕获定义的异常
* @param e
* @return
*/
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleVaildException(MethodArgumentNotValidException e) {
log.error("数据效验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
Map<String,String> errorMap = new HashMap<>();
BindingResult bindingResult = e.getBindingResult();
bindingResult.getFieldErrors().forEach(fieldError -> {
errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
});
return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap);
}
/**
* 兜底异常
* @param throwable
* @return
*/
@ExceptionHandler(value = Throwable.class)
public R handleException(Throwable throwable) {
return R.error();
}
}
异常错误码定义 (重点)
后端将定义的错误码写入到开发手册,前端出现对于的错误,就可以通过手册查询到对应的异常
/***
* 错误码和错误信息定义类
* 1. 错误码定义规则为5为数字
* 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
* 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
* 错误码列表:
* 10: 通用
* 001:参数格式校验
* 11: 商品
* 12: 订单
* 13: 购物车
* 14: 物流
*
*
*/
public enum BizCodeEnume {
UNKNOW_EXCEPTION(10000,"系统未知异常"),
VAILD_EXCEPTION(10001,"参数格式校验失败");
private int code;
private String msg;
BizCodeEnume(int code,String msg){
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}