59.使用逆向工程的前后端代码
1.首先在‘系统管理’-‘菜单管理’里面进行新增‘品牌管理’
2.将自动生成的brand.vue和brand-add-or-update.vue新增到前端product目录下
3.修改权限,以用来展示‘新增’‘删除’按钮,将index.js export funcation isAuth(){}
全部返回true;
60.效果优化与快速显示开关
1.修改webpack.base.conf.js里的const createLintingRule{}全部注释掉;为了消除控制台代码校验总是报错;
2.加入开关
3.修改弹窗显示状态开关组件;brand-add-or-updaye.vue
首先:做好以上的所有准备工作后,我们首先来修改‘显示状态’
1.为我们的开关来绑定change事件
后台Controller还有renren默认生成的代码
61.云存储开通与使用
由于系统架构分为 单体应用 与 分布式应用 两种风格
1.单体架构:文件上传到服务器,获取文件,也是从该服务器获取的
2.分布式:首次文件上传,由于负载均衡到B服务器,而获取文件,有可能从A服务器获取;会
出现文件找不到的现象;
解决方法
不同服务之间来获取文件,都来单独的文件存储服务里获取;
分类:
1.自建服务器:FastDFS vsftpd 搭建复杂、维护成本高、前期费用高;
2.云存储:阿里云存储对象、七牛云存储 即开即用、无需维护、按量收费;
1.注册阿里云账号
SpringCloud Alibaba-OSS
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,
适合存放任意类型的文件。容量和处理能力弹性扩展,多种云存储类型供选择,全面优化存储成本。
2.首次,需要开通OSS,开通过以后,进入自己的控制台
1.创建Bucket,也就是创建一个桶;建议一个项目创建一个Bucket;
a.输入名称
b.选择区域
c.存储类型选择‘低频访问’
d.同城冗余存储 ‘关闭’
e.读写权限 ‘公共读’
f.服务器端加密:无
g.实时日志查询:不开通
3.阿里云对象存储-服务端签名后直传
62.OSS整合测试
第一种:先测试
1.安装SDK,gulimall-product pom.xml
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.5.0</version>
</dependency>
2.写测试类
@Test
public void testUpload() throws FileNotFoundException {
// Endpoint以杭州为例,其它Region请按照实际情况填写
String endpoint = "oss-cn-beijing.aliyuncs.com";
// 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问活日常运维
String accessKeyId = "";
String accessKeySecret = "";
//创建OSSClient示例
OSS ossClient = new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);
//上传文件流
InputStream inputStream = new FileInputStream();
ossClient.putObject(,,inputStream);
//关闭OSSClient
ossClient.shutdown();
}
1.获取endpoint 在概览里
2.获取各种key 选择使用‘子用户’的key
3.修改权限
第二种:用SpringCloud Alibaba OSS
<dependency>
<groupId>com.alibaba.cloud</grouId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
</dependency>
63.OSS获取服务端签名
1.创建gulimall-thired-party(选择web、openfeign,依赖gulimall-common)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.atguigu.gulimall</groupId>
<artifactId>gulimall-third-party</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gulimall-third-party</name>
<description>第三方服务</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>com.atguigu.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 阿里云上传图片-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.将third-party配置到注册中心、发现
修改application.yml
修改main 新增注册发现
3.新建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 com.atguigu.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 org.springframework.web.bind.annotation.RestController;
@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() {
//https://gulimall-hello.oss-cn-beijing.aliyuncs.com/hahaha.jpg
String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
// callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
// String callbackUrl = "http://88.88.88.88:8888";
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format + "/"; // 用户上传文件时指定的前缀。
Map<String, String> respMap = null;
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);
}
}
4.以上就成功的获取到签名;修改网关
- id: third_party_route
uri: lb://gulimall-third-party
predicates:
- Path=/api/thirdparty/**
filters:
- RewritePath=/api/thirdparty/(?<segment>.*),/$\{segment}
64.OSS前后端调试上传
1.新增upload
2.引入但文件上传组件
在components:{ SingleUpload }
3.修改OSS的跨域问题
65.表单校验&自定义校验器
自定义校验
66.JSR303数据校验
使用步骤
1.给Bean添加校验注解:javax.validation.constraints,并定义自己的message提示
2.开启校验功能@Valid 效果:校验错误以后会有默认的响应
3.给校验的bean后紧跟一个BindingResult,就可以获取到校验的结果
@NotEmpty与@NotBlank区别:
@NotEmpty:必须不是null或者empty
@NotBlank:必须不是null并且包含至少一个非空字符
package com.atguigu.gulimall.product.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
/**
* 品牌
*
* @author niuniu
* @email 13303835433@163.com
* @date 2020-07-03 09:59:53
*/
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名必须添加")
private String name;
/**
* 品牌logo地址
*/
@URL(message="logo必须是一个合法的url地址")
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
private Integer showStatus;
/**
* 检索首字母
*/
@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母")
private String firstLetter;
/**
* 排序
*/
@Min(value = 0,message = "排序必须大于等于0")
private Integer sort;
}
67.统一异常处理
统一异常处理
1.@ControllerAdvice
集中处理所有异常
GulimallExceptionControllerAdvice
package com.atguigu.gulimall.product.exception;
import com.atguigu.common.exception.BizCodeEnume;
import com.atguigu.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.Map;
/**
* 集中处理所有异常
*/
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
@ExceptionHandler(value= MethodArgumentNotValidException.class)
public R handleVaildException(MethodArgumentNotValidException e){
log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
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);
}
@ExceptionHandler(value = Throwable.class)
public R handleException(Throwable throwable){
log.error("错误:",throwable);
return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
}
}
gulimall-common
package com.atguigu.common.exception;
/***
* 错误码和错误信息定义类
* 1. 错误码定义规则为5为数字
* 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
* 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
* 错误码列表:
* 10: 通用
* 001:参数格式校验
* 11: 商品
* 12: 订单
* 13: 购物车
* 14: 物流
*
*
*/
public enum BizCodeEnume {
UNKNOW_EXCEPTION(10000,"系统未知异常"),
VAILD_EXCEPTION(10001,"参数格式校验失败"),
PRODUCT_UP_EXCEPTION(11000,"商品上架异常");
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;
}
}
68.JSR303分组校验
说明:例如BrandEntity的brandId字段,在新增的时候,id是自增,不用校验;在修改的时候,id必须指定;
/**
*品牌id
*/
@NotNull(message = "修改必须指定品牌id",groups = {UpdateGroup.class})
@Null(message="新增不能指定id",groups = {AddGroup.class})
@TableId
private Long brandId
在valid/gulimall-common声明两个接口
在gulimall-product/brandController的save方法上加上注解
69.JSR303自定义校验注解
1.编写一个自定义的校验注解
2.编写一个自定义的校验器
3.关联自定义的校验器和自定义的校验注解
1.在gulimall-common的pom.xml文件引入依赖
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
2.在gulimall-common的valid包下创建ListValue接口