一、使用逆向工程快速完成增删改查对应的前后端代码
逆向工程生成的页面效果如下:

已经具备了品牌模块的增删改查功能!
二、效果优化与快速显示开关
1、查看 element-ui 组件库的 table 表格组件 —— 自定义列模板(使用插槽)

2、这个 scop 中拥有整个这一列的所有数据;
<el-table-column prop="showStatus" header-align="center" align="center" label="显示状态"> <template slot-scope="scope"> <el-switch v-model="scope.row.showStatus" active-color="#13ce66" inactive-color="#ff4949" :active-value="1" :inactive-value="0" @change="updateBrandStatus(scope.row)" ></el-switch> </template> </el-table-column>
这里面的显示状态,我们使用了 el-switch 开关显示;

3、新增中的显示状态也修改为el-switch开关;
三、使用阿里云OSS服务实现logo文件的上传
1、将品牌logo地址,修改为文件上传框,使用 el-upload 组件:
因为我们的文件上传将使用“阿里云的OSS文件存储服务”,所以我们需要先去开通一下;
整个Aliyun OSS服务的开通和后端核心代码的编写,已经在另一篇文章中,有详细说明:
http://www.jiguiquan.com/archives/1199
2、前端实现:
首先封装了单文件上传singleUpload.vue和多文件上传multiUpload.vue的文件,其中引用的policy.js就是用来获取服务端的上传签名的接口调用:

3、然后再逆向工程生成的“新增品牌”的“brand-add-or-update.vue”中引出使用:

4、使用效果如下:

显然,OSS文件上传功能已经可用,到阿里云的OSS控制台查看文件:

至此,文件上传的任务就已经完成了,具体的代码可见于github地址: https://github.com/jiguiquan/zidanmall-vue
四、新增品牌—表单校验&自定义校验器
1、我们将使用 element-ui 的表单组件的校验功能

2、主要使用 el-form 的 :rules="rules" 属性来完成校验规则的设定:在rules中使用validator: ()=>{}箭头函数的方式自定义校验规则;

五、JSR303后端数据校验:
关于 Bean Validation
在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情。应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的。在通常的情况下,应用程序是分层的,不同的层由不同的开发人员来完成。很多时候同样的数据验证逻辑会出现在不同的层,这样就会导致代码冗余和一些管理的问题,比如说语义的一致性等。为了避免这样的情况发生,最好是将验证逻辑与相应的域模型进行绑定。
Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。缺省的元数据是 Java Annotations,通过使用 XML 可以对原有的元数据信息进行覆盖和扩展。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint,例如 @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。
JSR 303 – Bean Validation 规范 http://jcp.org/en/jsr/detail?id=303
Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。如果想了解更多有关 Hibernate Validator 的信息,请查看 http://www.hibernate.org/subprojects/validator.html
1、使用很简单,在实体类上增加注解:

2、同时,我们我们想统一格式化校验错误时候的Error返回格式,我们可以在接口中如下处理:

3、测试,查看结果,错误信息按预期返回:

六、使用 @ControllerAdvice 实现统一异常处理
但是实际业务中,我们不能把所有的这类代码,都在接口中写一遍,太麻烦了,也不优雅:
使用Spring为我们提供的 @ControllerAdvice 注解进行统一的异常处理:
1、创建我们自己的错误码的枚举类:
package com.jiguiquan.common.exception;
/***
* 错误码和错误信息定义类
* 1. 错误码定义规则为5为数字
* 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
* 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
* 错误码列表:
* 10: 通用
* 001:参数格式校验
* 11: 商品
* 12: 订单
* 13: 购物车
* 14: 物流
*/
public enum BizCodeEnum {
UNKNOW_EXCEPTION(10000,"系统未知异常"),
VALID_EXCEPTION(10001, "参数格式校验失败");
private int code;
private String msg;
BizCodeEnum(int code, String msg){
this.code = code;
this.msg = msg;
}
public int getCode(){return code;}
public String getMsg(){return msg;}
}
2、创建 ZidanmallExceptionControllerAdvice 类定义为哪些包捕获异常统一处理;
/**
* 负责处理“com.jiguiquan.zidanmall.product.controller”包下的所有异常
*/
@RestControllerAdvice(basePackages = "com.jiguiquan.zidanmall.product.controller")
public class ZidanmallExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handlerValidException(MethodArgumentNotValidException e){
BindingResult bindingResult = e.getBindingResult();
Map<String, String> map = new HashMap<>();
bindingResult.getFieldErrors().forEach(fe -> map.put(fe.getField(), fe.getDefaultMessage()));
return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg()).put("data", map);
}
@ExceptionHandler(value = Throwable.class)
public R handlerException(Throwable throwable){
return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
}
}
3、测试结果,同上:

七、数据校验——分组校验
有如下场景:
同一个实体类:BrandEntity,在新增的时候和修改的时候,校验的字段是不一样的;
这样的场景,我们就需要用到JSR303为我们提供的“分组校验”功能——将以brandId字段为例:
1、自定义两个分组 AddGroup和UpdateGroup接口:

2、然后再实体类中作如下区分:

3、重要一点,需要将接口上的@Valid修改为Spring提供的:@Validated({AddGroup.class})
4、分别测试新增和修改接口:
新增:

修改:

这样JSR303提供的校验分组功能就完成了;
八、自定义校验注解
我们将以BrandEntity中的showStatus字段进行测试,测试要求:
@ListValue(vals = {0,1}) 此自定义注解意思:只能使用列举出来的0和1两个值;
1、编写一个自定义的校验注解:
package com.jiguiquan.common.exception;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* 1、JSR303规范中明确,校验注解必须拥有3个属性字段:message, groups,payload
* 2、必须标注以下原信息数据注解:
* @Documented
* @Constraint(validatedBy = { ListValueConstraintValidator.class }),此处关联校验器,且可以关联多个校验器
* @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
* @Retention(RetentionPolicy.RUNTIME)
*
*/
@Documented
@Constraint(
validatedBy = {ListValueConstraintValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
//此massage的定义我们放在了 classpath:/ValidationMessages.properties 中:
String message() default "{com.jiguiquan.common.exception.ListValue.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] vals() default {};
}
2、编写一个自定义的校验器:
package com.jiguiquan.common.exception;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
Set<Integer> set = new HashSet<>();
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val : vals) {
set.add(val);
}
}
/**
*
* @param value 需要校验的前端提交过来的值
* @param constraintValidatorContext
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(value);
}
}
3、使用自定义的校验器校验自定义的校验注解(关联):
@Constraint(validatedBy = { ListValueConstraintValidator.class }),此处关联校验器,且可以关联多个校验器
4、在BrandEntity中使用:
//显示状态[0-不显示;1-显示]
@NotNull
@ListValue(vals = {0,1})
private Integer showStatus;
5、测试结果:

至此,我们一个自定义的一对 “校验注解”和“校验器”就完成了;
同时,整个“品牌管理”模块也完成了;



