SpringCloud(学习 商品服务-品牌管理的开发)五


前言

本章内容主要记录品牌服务的开发,重点在于阿里云平台oss对象存储、后端数据参数校验JSR303的使用。


一、品牌服务

品牌服务用于管理品牌的添加、修改、删除等操作,可上传logo到图片服务器中,数据库存储的是图片地址,对于品牌的操作主要涉及添加和修改的操作,后端对于数据的校验分为普通校验、分组校验、自定义校验三种方式来校验数据。

品牌服务界面
新增


二、图片服务

1.开通oss对象存储服务

首先,图片存储服务不止阿里云有,还有像七牛云之类的都有类似的服务,前期使用七牛云主要七牛云存储过程与本项目有点出入,所以这里还是选择阿里云平台进行存储。

  • 首先找到oss对象存储并开通服务

阿里云平台oss对象存储

  • 创建Bucket
    创建Bucket
    箭头标注的为比较重要的点,名称在项目中会使用到,而公共读是方便开发,后期可以修改私有

  • 找到AccessKey和SecretKey

  • 添加权限

添加权限

  • 找到外网访问域名

外网访问域名

  • 配置跨域
    跨域
    这里是配置了post的所有请求

  • 找到java的示例

OSS JAVA


至此阿里云平台的配置就完成了,可以进行图片服务的开发了

2.图片储存服务

  • 创建图片服务并在注册中心中注册
  • 添加maven依赖
 <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>

这里的依赖是使用了cloud的依赖,这样可以直接使用ossClient实例,官方依赖如下:

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.15.1</version>
</dependency>
  • 编写接口类
@RequestMapping("/oss/policy")
    public R policy() {
        // 填写Host地址,格式为https://bucketname.endpoint。
        String host = "https://" + bucket + "." + endpoint;
        // 设置上传回调URL,即回调服务器地址,用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后,把文件上传信息通过此回调URL发送给应用服务器。
        // String callbackUrl = "https://192.168.0.0:8888";
        // 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = format + "/";

        Map<String, String> respMap = null;
        // 创建ossClient实例。
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            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());
        }
        return R.ok().put("data", respMap);
    }
  • nacos添加配置
spring:
  cloud:
    alicloud:
      access-key: My access-key
      secret-key: My secret-key
      oss:
        endpoint: oss-cn-hangzhou.aliyuncs.com
        bucket: guli-smz

至此图片服务编写完成


三、后端数据校验

  • 首先加入校验的相关依赖
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>3.1.1</version>
        </dependency>

1、普通校验

  • 给Bean添加注解:javax.validation.constraints,定义自己的message提示
@NotNull(message ="修改必须指定品牌id")
	@Null(message = "新增不能指定id")
	@TableId
	private Long brandId;
  • 开启校验,在controller层添加注解@Valid
@RequestMapping("/save")
    //@RequiresPermissions("product:brand:save")
    public R save(@Valid @RequestBody BrandEntity brand/*, BindingResult result*/){
  • 由于错误存在于所有服务,所以在common编写一个错误状态码和错误信息定义枚举类
/**
 * 错误状态码和错误信息定义类
 * 1、错误码定义规则为5位数字
 * 2、前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
 * 3、维护错误码后需要维护错误描述,将他们定义为枚举形式
 *
 * 错误码列表:
 * 10:通用
 *     001:参数格式校验
 * 11:商品
 * 12:订单
 * 13:购物车
 * 14:物流
 */
public enum BizCodeEnume {
    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VAILD_EXCEPTION(10001, "参数格式校验失败");

    private final int code;
    private final String msg;
    BizCodeEnume(int code, String msg){
        this.code = code;
        this.msg = msg;
    }

    public int getCode(){
        return code;
    }
    public String getMsg(){
        return msg;
    }
}

  • 编写集中异常处理类
@Slf4j
@RestControllerAdvice(basePackages = "com.smz.guli.product.controller")
public class GuliExceptionControllerAdvice {

    /**
     *
     * @param e 捕获的精确异常
     * @return 返回异常信息集合
     */
    @ExceptionHandler(value = Exception.class)
    public R handleVaildException(MethodArgumentNotValidException e){
        BindingResult bindingResult = e.getBindingResult();
        Map<String,String> errorMap = new HashMap<>();
        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){
        log.error("错误", throwable);
        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(), BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }

}

在规则中regexp为正则校验,message为自定义信息,groups为规则组

	@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须为字母",groups = {AddGroup.class, UpdateGroup.class})

常用注解如下:

注解作用
@Null被注释的元素必须为null
@NotNull被注释的元素不能为null,可以为空字符串
@AssertTrue被注释的元素必须为true
@AssertFalsel被注释的元素必须为false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max,min)被注释的元素的大小必须在指定的范围内
@Digits(integer,fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future被注释的元素必须是一个将来的日期
@Pattern(value)被注释的元素必须符合指定的正则表达式
@Email被注释的元素必须是电子邮件地址
@Length被注释的字符串的大小必须在指定的范围内
@Range被注释的元素必须在合适的范围内
@NotEmpty用在集合类上,不能为null,并且长度必须大于0
@NotBlank只能作用在String上,不能为null,而且调用trim()后,长度必须大于0

2、分组校验

分组校验的场景用于同一接口的不同操作来进行校验,不同操作也适用于其它接口。

  • 在common编写接口用于区分不同的分组
/**
 * 添加分组
 */
public interface AddGroup {
}

/**
 * 修改分组
 */
public interface UpdateGroup {
}

  • 在实体类添加注解用于区分不同操作对应的分组
/**
	 * 品牌id
	 */
	@NotNull(message ="修改必须指定品牌id", groups = {UpdateGroup.class})
	@Null(message = "新增不能指定id", groups = {AddGroup.class})
	@TableId
	private Long brandId;
	/**
	 * 品牌名
	 */
	@NotBlank(message = "品牌名不能为空", groups = {AddGroup.class})
	private String name;
  • 更换controller层注释为@Validated并添加校验分组
 @RequestMapping("/update")
    //@RequiresPermissions("product:brand:update")
    public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand){
		brandService.updateById(brand);

        return R.ok();
    }

@RequestMapping("/save")
    //@RequiresPermissions("product:brand:save")
    public R save(@Validated(AddGroup.class) @RequestBody BrandEntity brand/*, BindingResult result*/){
		brandService.save(brand);

        return R.ok();
    }

3、自定义校验

自定义校验用于复杂的校验逻辑,用于处理内置校验规则处理不了的数据校验。

  • 创建一个配置文件用于存放自定义消息
    文件名必须为 ValidationMessages.properties 会自动从该文件找配置项
com.smz.common.valid.ListValue.message=必须填写该项
  • 创建一个自定义注解类
@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.smz.common.valid.ListValue.message}";

    //实现规则的选取
    Class<?>[] groups() default {};

    //接收的消息体
    Class<? extends Payload>[] payload() default {};

    //自定义接收参数
    int[] vals() default {};

}
  • 创建一个校验器
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
/**
 * @ListValue 校验器
 * ListValue 校验注解
 * Integer 校验类型
 * initialize 初始化方法 (获取详细信息)
 * isValid 判断是否校验成功
 */
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    private final Set<Integer>set = new HashSet<>();

    /**
     *
     * @param constraintAnnotation 初始化方法
     */
    @Override
    public void initialize(ListValue constraintAnnotation) {
       int[] vals = constraintAnnotation.vals();
       for (int val : vals){
           set.add(val);
       }
    }


    /**
     *
     * @param value 需要校验的值
     * @param context 定义是否包含
     * @return 返回是否包含
     */
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        return set.contains(value);
    }
}

  • 使用自定义校验
/**
	 * 显示状态[0-不显示;1-显示]
	 */
	@ListValue(vals={0,1},groups = {AddGroup.class})
	private Integer showStatus;

总结

本文主要讲了阿里OSS对象储存的对接以及后端JSR303数据校验的三种使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天将降大任于我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值