将逆向生成的前端代码拷贝到category目录下
You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.
前端控制台会一直报错,是由于语法检查过于严格,可以关闭语法检查
通过 Scoped slot
可以获取到 row, column, $index 和 store(table 内部的状态管理)的数据
暂时将权限改成所有可用
@change=“updateBrandStatus(scope.row)”
//更新品牌状态
updateBrandStatus(data) {
console.log("数据", data);
let { brandId, showStatus } = data;
this.$http({
url: this.$http.adornUrl("/product/brand/update/status"),
method: "post",
data: this.$http.adornData({ brandId, showStatus }, false)
}).then(({ data }) => {
//消息提示删除成功
this.$message({
message: "修改状态成功!",
type: "success"
});
});
},
对象存储服务(Object Storage Service,OSS)是一种海量、安全、低成本、高可靠的云存储服务,适合存放任意类型的文件。容量和处理能力弹性扩展,多种存储类型供选择,全面优化存储成本。
https://www.aliyun.com/
导入依赖
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
<version>3.10.2version>
dependency>
@Test
public void upload() throws FileNotFoundException {
// Endpoint以北京为例,其它Region请按实际情况填写。在bucket的概览里
String endpoint = "oss-cn-beijing.aliyuncs.com";
// 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建。
String accessKeyId = "" ;
String accessKeySecret = "" ;
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 上传文件流。
InputStream inputStream = new FileInputStream("" );
ossClient.putObject("" , "" , inputStream);
// 关闭OSSClient。
ossClient.shutdown();
//上传成功
System.out.println("上传成功");
}
修改Pom
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alicloud-ossartifactId>
dependency>
Yml配置账号密码
代码:
@AutoWired
private OSS ossClient;
@Test
public void upload() throws FileNotFoundException {
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 上传文件流。
InputStream inputStream = new FileInputStream("" );
ossClient.putObject("" , "" , inputStream);
// 关闭OSSClient。
ossClient.shutdown();
//上传成功
System.out.println("上传成功");
}
将oss文件存储服务放入一个第三方maven模块中
配置bootstrap
spring:
application:
name: gulimall-third-party
cloud:
nacos:
config:
server-addr: localhost:8848
namespace: df45e354-ebe2-4109-bd34-0a18ba549d43
ext-config:
- dataId: oss.yml
group: DEFAULT_GROUP
refresh: true
配置远程config oss.yml
spring:
config:
name: gulimall-third-party
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
alicloud:
access-key: xxxxxxxxxxxxxxxxxxxx
secret-key: xxxxxxxxxxxxxxxxxxxxxx
oss:
endpoint: oss-cn-beijing.aliyuncs.com
bucket: gulimall-xiaoxiao
server:
port: 30000
配置Controller
@RestController
@RequestMapping("thirdparty/oss")
public class OssController {
@Autowired
private OSS ossClient;
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
@Value("${spring.cloud.alicloud.secret-key}")
private String accessKey;
@Value("${spring.cloud.alicloud.oss.endpoint}")
private String endpoint;
@Value("${spring.cloud.alicloud.oss.bucket}")
private String bucket;
@RequestMapping("/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("yyyy-MM-dd").format(new Date());
String dir = format+"/"; // 用户上传文件时指定的前缀。
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
Map<String, String> respMap = new LinkedHashMap<String, String>();
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.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);
}
}
网关断言
gateway:
routes:
- id: thirdparty_route
uri: lb://gulimall-third-party
predicates:
- Path=/api/thirdparty/**
filters:
- RewritePath=/api/(?>.*), /$\{
segment}
获取外网访问oss域名
/components下新建一个组件upload
multiUpload.vue
policy.js
import http from '@/utils/httpRequest.js'
export function policy() {
return new Promise((resolve,reject)=>{
http({
url: http.adornUrl("/thirdparty/oss/policy"),
method: "get",
params: http.adornParams({
})
}).then(({
data }) => {
resolve(data);
})
});
}
singleUpload.vue
点击上传
只能上传jpg/png文件,且不超过10MB
1.导入singleUpload
<script>
import SingleUpload from "@/components/upload/singleUpload";
export default {
components:{SingleUpload},
2.修改标签体
<el-form-item label="品牌logo地址" prop="logo">
<single-upload v-model="dataForm.logo">single-upload>
el-form-item>
<el-table-column prop="logo" header-align="center" align="center" label="品牌logo地址">
<template slot-scope="scope">
<el-image style="width: 100px; height: 80px" :src="scope.row.logo" fit="fill">el-image>
template>
el-table-column>
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();
}
}
}
],
sort: [
{
validator: (rule, value, callback) => {
if (value == "") {
callback(new Error("排序不能为空"));
} else if (!Number.isInteger(value) || value < 0) {
callback(new Error("必须输入一个大于等于0的数字"));
} else {
callback();
}
}
}
]
}
};
}
给属性添加校验注解,并附上自己的message提示
@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地址
*/
@NotEmpty
private String logo;
/**
* 介绍
*/
@NotEmpty
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull
private Integer showStatus;
/**
* 检索首字母
*/
@NotEmpty
@Pattern(regexp = "^[a-zA-Z]$",message = "首字母必须为a-zA-Z的一个字母")
private String firstLetter;
/**
* 排序
*/
@NotNull
@Min(value = 0,message = "排序数字必须大于等于0")
private Integer sort;
}
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand){
brandService.save(brand);
return R.ok();
}
/**
* 保存
*/
@RequestMapping("/save")
//@RequiresPermissions("product:brand:save")
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {
if (result.hasErrors()) {
Map<String, String> map = new HashMap<>();//保存错误信息
result.getFieldErrors().forEach((error) -> {
String field = error.getField();
String eMessage = error.getDefaultMessage();
map.put(field, eMessage);
});
return R.ok().put("error", map);
} else {
brandService.save(brand);
return R.ok();
}
}
所有后台请求只做正确处理,异常直接抛出
@Slf4j
@RestControllerAdvice(basePackages = "com.xiaoxiao.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handlerValidException(MethodArgumentNotValidException e) {
log.error("错误异常"+e.getMessage().getClass());
return R.error(400,"数据校验异常");
}
@ExceptionHandler(value = Throwable.class)
public R handlerException(Throwable t) {
return R.error(400,"系统未知异常");
}
}
使用枚举列出常用异常
/*错误码和错误信息定义类
*1.错误码定义规则为5为数字
*2.前两位表示业务场景,最后三位表示错误码。例如: 10001. 10:通用001:系统未知异常
*3.维护错误码后需要维护错误描述,将他们定义为枚举形式
* 错误码列表:*10:通用
001:参数格式校验
11:商品
12:订单
13:购物车
14:物流
*/
public enum BizCodeEnum {
UNKNOWN_EXCEPTION(10000,"系统未知异常"),
VALID_EXCEPTION(10001,"参数校验出现错误,校验失败");
private int code;
private String message;
BizCodeEnum(int code,String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
使用枚举异常
@Slf4j
@RestControllerAdvice(basePackages = "com.xiaoxiao.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handlerValidException(MethodArgumentNotValidException e) {
log.error("错误异常"+e.getClass());
Map<String,String> map = new HashMap<>();
e.getBindingResult().getFieldErrors().forEach((error)->{
String field = error.getField();
String defaultMessage = error.getDefaultMessage();
map.put(field,defaultMessage);
});
return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(),BizCodeEnum.VALID_EXCEPTION.getMessage()).put("errors",map);
}
@ExceptionHandler(value = Throwable.class)
public R handlerException(Throwable t) {
return R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(),BizCodeEnum.UNKNOWN_EXCEPTION.getMessage());
}
}
如果标注了分组校验,没有指定分组,则不进行校验
package com.xiaoxiao.gulimall.product.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import com.xiaoxiao.common.valid.AddGroup;
import com.xiaoxiao.common.valid.UpdateGroup;
import com.xiaoxiao.common.valid.UpdateStatusGroup;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import javax.validation.constraints.Pattern;
/**
* 品牌
*
* @author xiaoxiao
* @email [email protected]
* @date 2020-07-07 20:13:06
*/
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
@NotNull(message = "必须指定品牌id",groups = {
UpdateGroup.class,UpdateStatusGroup.class})
@Null(message = "新增不能指定id",groups = {
AddGroup.class})
private Long brandId;
/**
* 品牌名
*/
@NotBlank(groups = {
AddGroup.class, UpdateGroup.class},message = "品牌名不能为空")
private String name;
/**
* 品牌logo地址
*/
@NotEmpty(groups = {
AddGroup.class})
@URL(message = "logo地址必须是一个合法的url地址",groups={
AddGroup.class,UpdateGroup.class})
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
@ListValue(vals={
0,1},groups = {
AddGroup.class, UpdateStatusGroup.class})//自定义校验器
@NotNull(groups = {
AddGroup.class, UpdateStatusGroup.class})
private Integer showStatus;
/**
* 检索首字母
*/
@NotEmpty(groups={
AddGroup.class})
@Pattern(regexp = "^[a-zA-Z]$",message = "首字母必须为a-zA-Z的一个字母",groups={
AddGroup.class,UpdateGroup.class})
private String firstLetter;
/**
* 排序
*/
@NotNull(groups={
AddGroup.class})
@Min(value = 0,message = "排序数字必须大于等于0",groups={
AddGroup.class,UpdateGroup.class})
private Integer sort;
}
/**
* 保存
*/
@RequestMapping("/save")
//@RequiresPermissions("product:brand:save")
public R save(@Validated(value = {
AddGroup.class}) @RequestBody BrandEntity brand/*, BindingResult result*/) {
brandService.save(brand);
return R.ok();
}
/**
* 修改
*/
@RequestMapping("/update")
//@RequiresPermissions("product:brand:update")
public R update(@Validated(value = {
UpdateGroup.class}) @RequestBody BrandEntity brand) {
brandService.updateById(brand);
return R.ok();
}
/**
* 修改状态
*/
@RequestMapping("/update/status")
//@RequiresPermissions("product:brand:update")
public R updateStatus(@Validated(value = {
UpdateStatusGroup.class}) @RequestBody BrandEntity brand) {
brandService.updateById(brand);
return R.ok();
}
<dependency>
<groupId>javax.validationgroupId>
<artifactId>validation-apiartifactId>
<version>2.0.1.Finalversion>
dependency>
package com.xiaoxiao.common.valid;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
/**
* @author xiaoxiao
* @date 2020/7/17 - 14:23
*/
@Documented
@Constraint(validatedBy = {
ListValueConstraintValidator.class })
@Target({
METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
String message() default "{com.xiaoxiao.common.valid.ListValue.message}";
Class<?>[] groups() default {
};
Class<? extends Payload>[] payload() default {
};
int[] vals() default {
};
}
com.xiaoxiao.common.valid.ListValue.message=显示状态必须为0或者1
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private 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 context
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}