【今日成果】:



 //使用阿里云OSS服务:
 



 //使用v-if如果地址没有就不显示 , 如果地址错误图片就显示不出来;
 
【快速回顾】:
任何数据的删除都不要使用物理上的删除,应当使用逻辑上的删除!!!
 《显示状态控制》——可以通过《el-swtich》控件来完成。
 logo图片需要保存到服务器上,数据库中只是存储了图片的地址。——vsftpd 、 FastDFS ; 或者使用阿里云对象存储。
【details】:
【阿里云OSS】:

 我们在学习的时候,没有那么高的访问频率 , 所以可以选择《低频访问存储》;
【依赖】:
         <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
 
【YML配置】
spring:
  cloud:
    alicloud:
      oss:
        endpoint: oss-cn-hangzhou.aliyuncs.com
      access-key: LTAI5~~~~~~~~~~~~~~~~~~~
      secret-key: otlPc-------------------
 
[ 文件上传方式 ]:
【单体】:
浏览器 -》 商品服务 -》 服务器
//如果上传的文件比较大 , 对正常的业务是有影响的。这个时候就需要进行拆分。
【分布1】:
浏览器 : (1)–商品服务
 (2)–服务器 //在新增品牌的时候,立即就上传到云服务器上,然后会返回一个图片地址,再把这个地址返回给后端系统。
 //这种方式的缺点是在客户端需要获取AccessKey和SecuretKey,这样将相关的核心数据暴露在前端不安全。
【分布2】:
先去后端请求防伪签名 , 拿着签名去文件存储服务器请求。
【新模块】:

【Oss后端代码】:
package com.msb.mall.third.controller;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.msb.common.utils.R;
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;
import java.util.logging.SimpleFormatter;
@RestController
public class OSSController {
    @Autowired
    private 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 getOssPolicy(){
        String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
        // callbackUrl为上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = format+"/"; // 用户上传文件时指定的前缀。
        // 创建OSSClient实例。
        //OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
        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 R.ok().put("data",respMap);
    }
}
 
【前端表单校验】:
        dataRule: {
          name: [
            { required: true, message: '品牌名不能为空', trigger: 'blur' }
          ],
          logo: [
            { required: true, message: '品牌logo地址不能为空', trigger: 'blur' }
          ],
          descript: [
            { required: true, message: '介绍不能为空', trigger: 'blur' }
          ],
          showStatus: [
            { required: true, message: '显示状态[0-不显示;1-显示]不能为空', 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 == "" && value != 0){
                  callback(new Error("检索字母不能为空"))
                }else if(!Number.isInteger(value) || value < 0){
                  callback(new Error("排序必须是数字且不能小于0"))
                }else{
                  callback()
                }
            }, trigger: 'blur' }
          ]
        }
 
[ 诡异BUG ]:
明明校验规则数组写的没有问题,但还是出BUG ————原因是 v-model.number 没有加 , 明明是学过的知识,但是第一时间就是没有反应过来;


















