059 品牌管理-增删改查
品牌表:pms_brand
1 创建品牌管理菜单
2 前端代码
在之前使用renren-generator生成的代码中,包含了一些.vue文件。
在gulimall-product/src/main/resources/src/views/modules/product/路径下,可以找到品牌管理的相关代码。
将brand.vue和brand-add-or-update.vue两个文件复制到前端项目renren-fast-vue的src/views/modules/product/路径下。
重启renren-fast-vue项目(ctrl c停止运行项目) ,品牌管理页面出现内容。
此时在品牌管理页面上并没有新增和批量删除的接口,实际上代码里是有的,只是因为权限问题没有显示出来。
修改src/utils/index.js文件中的isAuth方法,使权限总是为true。
刷新页面,页面上出现新增和批量删除接口。
简单测试了一下,生成代码的新增、修改、删除功能都没问题。
060 品牌管理-使用开关表示布尔值
品牌的显示状态字段值为0或1,可以使用ElmentUI中的Switch开关组件来表示。
代码见 069 品牌管理-完整前端代码
061-064 品牌管理-云存储的开通与使用
新增或修改品牌时,我们希望将品牌logo地址一栏改为直接上传文件。
上传文件的存储架构为:
本项目使用阿里云对象存储(OSS)来实现。
OSS官网
1 准备工作
OSS服务是一个第三方服务,我们以后可能会用到许多第三方服务,所以可以创建一个微服务gulimall-third-party来整合。
在pom.xml文件中添加对gulimall-common的依赖:
com.atguigu.gulimall gulimall-common0.0.1-SNAPSHOT com.baomidou mybatis-plus-boot-starter
然后添加对OSS服务的依赖:
com.alibaba.cloud spring-cloud-alicloud-oss2.2.0.RELEASE
包括dependencyManagement部分:
com.alibaba.cloud spring-cloud-alibaba-dependencies2021.1 pom import
在gulimall-third-party/src/main/resources/路径下添加配置文件:
bootstrap.properties
spring.application.name=gulimall-third-party spring.cloud.nacos.config.server-addr=127.0.0.1:8848
application.yml
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: gulimall-third-party
server:
port: 30000
在gulimall-third-party/src/main/java/com/atguigu/gulimall/thirdparty/GulimallThirdPartyApplication类上添加注解:
@EnableDiscoveryClient
2 调用OSS服务
开通OSS服务后,创建一个bucket。(bucket名称自拟)
在页面右上角的菜单中选择AccessKey管理,创建一个用户。
给创建的用户添加管理OSS的权限。
然后在gulimall-third-party/src/main/resources/application.yml中添加配置:(其中access-key和secret-key是创建用户时生成的)
我们有许多种方式可以将文件提交给OSS,最终选择的方案是服务端签名后直传。
在gulimall-third-party/src/main/java/com/atguigu/gulimall/thirdparty/路径下创建目录controller/,并在该目录中创建OssController类(参照官方文档)。
package com.atguigu.gulimall.thirdparty.controller;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.linkedHashMap;
import java.util.Map;
@RestController
public class OssController {
@Autowired
OSS ossClient;
@Value("${spring.cloud.alicloud.oss.endpoint}")
private String endpoint;
@Value("${spring.cloud.alicloud.oss.bucket}")
private String bucket;
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
@RequestMapping("/oss/policy")
public R policy() {
String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
// callbackUrl为上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
//String callbackUrl = "http://88.88.88.88:8888";
String format = new SimpleDateFormat("yyyyMMdd").format(new Date());
String dir = format + "/"; // 用户上传文件时指定的前缀。
Map 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();
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 R.ok().put("data", respMap);
}
}
启动gulimall-third-party服务。
访问:http://localhost:30000/oss/policy
- accessid:访问ID
- policy:策略
- signature:签名
- dir:上传到的文件夹
- host:上传到的主机地址
- expire:签名过期时间
配置网关:gulimall-gateway/src/main/resources/application.yml
- id: third_party_route
uri: lb://gulimall-third-party
predicates:
- Path=/api/thirdparty
@Slf4j
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleVaildException(MethodArgumentNotValidException e) {
Map errorMap = new HashMap<>();
BindingResult bindingResult = e.getBindingResult();
bindingResult.getFieldErrors().forEach((fieldError) ->
{
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(), BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data", errorMap);
}
@ExceptionHandler(value = Throwable.class)
public R handleException(Throwable throwable) {
return R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(), BizCodeEnum.UNKNOWN_EXCEPTION.getMsg());
}
}
然后为品牌管理实体类gulimall-product/src/main/java/com/atguigu/gulimall/product/entity/BrandEntity添加校验注解。
最后,给新增/修改的接口方法的入参添加@Valid注解。
使用postman进行测试。
3 分组校验
使用JSR-303实现分组校验,实际上就是group属性的用法,不实现了。
4 自定义校验
我觉得这部分内容对产品质量的提升不大,但是学习写自定义注解是有价值的。
品牌的显示状态字段showStatus的值必须是0或1。我们创建一个@ListValue注解来校验它。
- 编写一个自定义的校验注解
- 编写一个自定义的校验器
- 关联自定义的校验器和自定义的校验注解
在gulimall-common/src/main/java/com/atguigu/common/路径下创建valid/目录,在该目录下创建注解ListValue。
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@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 {
// 指明默认的错误信息
String message() default "{com.atguigu.common.valid.ListValue.message}";
// 支持分组校验功能
Class>[] groups() default {};
// 自定义负载信息
Class extends Payload>[] payload() default {};
int[] values() default {};
}
在valid/目录下创建ListValueConstraintValidator类。
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.HashSet; import java.util.Set; public class ListValueConstraintValidator implements ConstraintValidator{ private Set set = new HashSet<>(); // 初始化方法 @Override public void initialize(ListValue constraintAnnotation) { int[] values = constraintAnnotation.values(); for (int val : values) { set.add(val); } } @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return set.contains(value); } }
在gulimall-common/src/main/resources/路径下创建配置文件ValidationMessages.properties。
com.atguigu.common.valid.ListValue.message=只能提交列举的值
重启gulimall-product服务,使用postman验证通过。
069 品牌管理-完整前端代码
brand.vue
查询
新增
批量删除
修改
删除
brand-add-or-update.vue
取消 确定



