尚硅谷的谷粒商城项目,这个项目集成了市面上流行的微服务架构和解决方案。
1、下载vs code,傻瓜式安装
2、插件安装
Auto Close Tag:自动开闭标签
Auto Rename Tag
Chinese (Simplifi..):简体中文包
ESLint:ES语法检查
HTML CSS Support :
HTML Sinppets
JavaScript(ES6) co...
Live Server
Open in browser
Vetur
1、安装node,配置环境变量 2、安装npm 3、安装cnpm 4、cnpm i -g webpack 5、cnpm i -g @vue-cli
npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
注:这么做得原理就是先单独从淘宝镜像吧nod-sass下载下来,然后再进行编译,因为这句命令好像是不成功的,(npm config set registry http://registry.npm.taobao.org/),默认从github下载,导致报错的 如果之前安装失败的。先清理 缓存 清理缓存:npm rebuild node-sass npm uninstall node-sass
官网:https://baomidou.com/guide/logic-delete.html
1、配置全局逻辑删除配置(可以不用配置,直接使用步骤2中的注解来标注逻辑删除的字段和字段值,注解的优先级大于全局配置)
mybatis-plus:
global-config:
db-config:
logic-delete-field: showStatus # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
2、实体类字段上加上@TableLogic
注解
// value表示逻辑未删除的数据,delval表示逻辑删除
@TableLogic(value = "1",delval = "0")
private Integer showStatus;
1、文件 —— 首选项 —— 用户片段 —— 新建全局代码片段文件
2、吧你的代码片段文件名写进去,生成一个新文件,里面填写你的代码片段模板
{
"http-get请求": {
"prefix": "httpget",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'get',",
"params: this.\\$http.adornParams({})",
"}).then(({ data }) => {",
"})"],
"description": "httpGET请求"
},
"http-post请求": {
"prefix": "httppost",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'post',",
"data: this.\\$http.adornData(data, false)",
"}).then(({ data }) => { });" ],
"description": "httpPOST请求"
}
}
1、打开webpack.base.conf.js文件
2、注释掉createLintingRule方法中的语句
3、重新启动前端项目
1、启动访问地址:http://localhost/#generator.html
1、注册阿里云,然后开通OSS(不用钱,按量计费)
2、打开oss使用API手册(选择对应的语言JDK)
https://help.aliyun.com/document_detail/32009.html?spm=a2c4g.11186623.6.934.485514a0fS7JrL
3、开通阿里云的RAM权限控制,然后创建一个子账号,创建的子账号选择的访问方式,选择:编程访问启用 AccessKey ID 和 AccessKey Secret,支持通过 API 或其他开发工具访问
4、给创建的子账号添加oss权限:AliyunOSSFullAccess
5、使用步骤二中的案例添加依赖之后测试(上传文件流)
// Endpoint以杭州为例,其它Region请按实际情况填写。
String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建。
String accessKeyId = "<yourAccessKeyId>";
String accessKeySecret = "<yourAccessKeySecret>";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 上传文件流。
InputStream inputStream = new FileInputStream("<yourlocalFile>");
ossClient.putObject("<yourBucketName>", "<yourObjectName>", inputStream);
// 关闭OSSClient。
ossClient.shutdown();
官方:https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
问题:官方找了半天没找到最新的oss集成文档,只有springboot的集成文档,真心为阿里的开源感到心塞,就这么敷衍的么
1、添加依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alicloud-oss</artifactId>
</dependency>
2、添加配置
spring:
cloud:
alicloud:
access-key: LTAI4G8fDyV7qF9MxaEu7rEr
secret-key: IzAF0didOy8BUsFKaBroeyp4mixRVw
oss:
endpoint: oss-cn-shenzhen.aliyuncs.com
注意:必须放在application.yml或者application.properties配置文件内
3、java代码,跟上面的oss文件上传差不多
@Autowired
private OSSClient ossClient;
@Test
public void testAliossUpload() throws FileNotFoundException {
InputStream inputStream = new FileInputStream("D:\\DevelopSoft\\WorkSpaceJava\\gulimall\\document\\pics\\7ae0120ec27dc3a7.jpg");
ossClient.putObject("gulimall-lijiao", "7ae0120ec27dc3a7.jpg", inputStream);
// 关闭OSSClient。
ossClient.shutdown();
System.out.println("上传成功。。。。");
}
4、使用服务端签名直传方式
https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1739.27cc7d9cbJFMys
@RunWith(SpringRunner.class)
@SpringBootTest
public class Test{
// class必须是public
}
问题:java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
解决:单元测试的测试类一定要和启动类在同一个根目录下
JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。
Bean Validation 中内置的 constraint
Hibernate Validator 附加的 constraint
日期校验
在上面没有日期校验注解,so自己定义注解校验:https://blog.csdn.net/mfkarj/article/details/105228132
@DateTimeFormat(pattern = "yyyy-MM-dd") Date startTime
@JsonFormat 注解,jackson在序列化时间时是按照国际标准时间GMT进行格式化的,而在国内默认时区使用的是CST时区,两者相差8小时, @JsonFormat(timezone = "GMT+8", pattern ="yyyy-MM-dd HH:mm:ss")
使用步骤
在实体类上添加如上图中注解
@NotBlank(message = "品牌名不能为空")
private String name;
开启注解校验@Valid
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result) {
if (result.hasErrors()) {
Map<String, String> errorMap = new HashMap<>();
result.getFieldErrors().forEach((item)->{
// 获取fieldError的错误提示
String message = item.getDefaultMessage();
// 获取错误属性的名字
String fieldName = item.getField();
errorMap.put(fieldName, message);
});
return R.error(400, "提交的数据不合法").put("data", errorMap);
} else {
brandService.save(brand);
}
return R.ok();
}
通过BindingResult result对象接收校验结果,并重写响应结果
result.hasErrors():判断校验是否通过,通过为false
result.getFieldErrors():获取所有的错误校验信息
使用方式跟JSR303数据校验差不多,只不过使用切面将所有响应返回的异常获取统一处理
@RequestMapping("/save")public R save(@Valid @RequestBody BrandEntity brand){
brandService.save(brand);
return R.ok();
}
@ControllerAdvice+@ExceptionHandler+@ResponseBody或者@RestControllerAdvice+@ExceptionHandler
@Slf4j
@RestControllerAdvice(basePackages = "top.dark.product.controller")
public class GlobalException {
@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((item)->{
errorMap.put(item.getField(), item.getDefaultMessage());
});
return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(),BizCodeEnum.VALID_EXCEPTION.getMsg()).put("data", errorMap);
}
@ExceptionHandler(value = Exception.class)
public R handleException(Exception e) {
return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
}
}
系统错误码
/***
* 错误码和错误信息定义类
* 1. 错误码定义规则为 5 为数字
* 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 000:系统未知
异常
* 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
* 错误码列表:
* 10: 通用
* 001:参数格式校验
* 11: 商品
* 12: 订单
* 13: 购物车
* 14: 物流
*/
public enum BizCodeEnum {
UNKNOW_EXCEPTION(10000,"系统未知异常"),
VALID_EXCEPTION(10001,"参数格式校验失败"),
;
private Integer code;
private String msg;
BizCodeEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
背景:更新和新增数据时,部分的数据校验是不相同的,因此需要根据不同的需求分组来进行不同的校验
创建分组接口
public interface AddGroup {
}
public interface UpdateGroup {
}
public interface UpdateStatusGroup {
}
为需要校验的实体字段进行不同分组校验标识
@NotBlank(message = "首字母不能为空",groups = {AddGroup.class})
@Pattern(regexp = "^[a-zA-Z]$",message = "首字母必须是a-z或A-Z字符",groups = {AddGroup.class, UpdateGroup.class})
private String firstLetter;
使用@Validated指定分组校验
@RequestMapping("/save")
public R save(@Validated(value = {AddGroup.class}) @RequestBody BrandEntity brand) {
brandService.save(brand);
return R.ok();
}
注意:如果指定了分组标识进行分组校验,字段上没有分配分组标识的字段则不会被校验
1、自定义校验注解
@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
String message() default "{top.dark.common.exception.ListValue.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] vals() default { };
}
2、自定义校验器
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private Set<Integer> set = new HashSet<>();
// 初始化方法
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
if (vals != null && vals.length > 0) {
Arrays.stream(vals).forEach((item)->{
set.add(item);
});
}
}
// 判断校验是否成功
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}
3、关联自定义校验器和自定义校验注解
@Constraint(validatedBy = {ListValueConstraintValidator.class})
4、message默认信息都是从ValidationMessages.properties文件中获取的,我们也能自定义默认message值。创建一个新的ValidationMessages.properties文件
top.dark.common.exception.ListValue.message=必须提交指定的值
子组件给父组件传递数据,事件机制:子组件给父组件发送一个事件,携带上数据
1、子组件创建一个触发事件,事件里面通过this.$emit()函数将数据传递给父组件
handleNodeClick(data,node,component){
console.log("子组件数据:",data,node,component);
this.$emit('tree-attr-group', data,node,component);
}
this.$emit("事件名",...不定参数数据)
2、父组件在引入子组件标签中使用步骤1中的定义的事件获取传递过来的数据
<Category @tree-attr-group="treeAttrGroup"></Category>
import Category from "../common/category";
components: { Category,AddOrUpdate },
// 树型子组件数据传递给父组件
treeAttrGroup(data,node,component){
console.log("父组件获取到子组件数据:",data,node,component);
console.log("节点id:",data.catId);
},
标注该字段不是数据库表实体字段
@TableField(exist = false)
标注该字段为空时不需要将其转换为json属性传输出去
@JsonInclude(value = JsonInclude.Include.NON_EMPTY)
忽略指定属性
@JSONField(serialize = false)
https://easydoc.xyz/s/78237135/ZUqEdvA4/hKJTcbfd
数据库设计的时候有些中间表(关联表)会设计一些冗余字段,在更新这些主表中的字段时,如果没有同步更新中间表中的冗余字段,则会导致数据的不一致性,因此在进行更新主表中的信息数据时需要将中间表中的冗余字段也同步进行更新
官方:https://baomidou.com/guide/page.html
@Configuration
@EnableTransactionManagement // 开启事务使用
@MapperScan("top.dark.product.dao")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题
*/
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
可以在需要使用事务控制的代码方法上添加@Transactional注解来启动事务
public class Page<T> implements IPage<T> {
private static final long serialVersionUID = 8545996863226528798L;
protected List<T> records;
protected long total;
protected long size;
protected long current;
protected List<OrderItem> orders;
protected boolean optimizeCountSql;
protected boolean isSearchCount;
protected boolean hitCount;
protected String countId;
protected Long maxLimit;
records 查询数据 total 数据总条数 size 每页显示条数,默认 10 current 当前页,默认1 orders 排序字段信息 optimizeCountSql 自动优化 COUNT SQL,默认true isSearchCount 是否进行 count 查询,默认true hitCount 是否命中count缓存,默认false
vue ReferenceError: PubSub is not defined 解决方案
npm install --save pubsub-js
全局使用
import PubSub from 'pubsub-js'
Vue.prototype.PubSub = PubSub //组件发布订阅消息
这个插件总共就两个方法:订阅和发布,其原理等同于:绑定事件和触发事件
发布:第一个参数为自定义事件名(与订阅方法保持一致),第二个参数为你需要传递给订阅者的参数
this.PubSub.publish("catPath",v);
订阅:第一个参数没啥用,第二个参数是发布方法传递过来的参数
this.catPathSub = PubSub.subscribe("catPath", (msg, val) => {
this.spu.catalogId = val[val.length - 1];
});
对于主键自增,mybatis-plus里最直接的有两种方法,一种是INPUT ,一种是AUTO.
如果设置的是在数据库自增,就需要在pojo类中标注。@TableId(type=IdType.AUTO)
还可以直接在配置文件中进行全局配置,但是如果不想要主键自增的时候就需要在主键上添加上面的注解,标注不用主键自增
ribbon调用超时,在配置文件中配置超时时间
http请求报错超时,feign的调用分两层,ribbon的调用和hystrix的调用,高版本的hystrix默认是关闭的,所以设置ribbon即可
#请求处理的超时时间
ribbon.ReadTimeout: 120000
#请求连接的超时时间
ribbon.ConnectTimeout: 30000
#feign.hystrix.enabled: true
#hystrix 熔断机制
#hystrix:
# shareSecurityContext: true
# command:
# default:
# circuitBreaker:
# sleepWindowInMilliseconds: 100000
# forceClosed: true
# execution:
# isolation:
# thread:
# timeoutInMilliseconds: 600000
下载:
docker pull elasticsearch:7.4.2 存储和检索数据
docker pull kibana:7.4.2 可视化检索数据
创建文件与目录:
mkdir -p /mydata/elasticsearch/config
mkdir -p /mydata/elasticsearch/data
mkdir -p /mydata/elasticsearch/plugins
echo "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasticsearch.yml
chmod -R 777 /mydata/elasticsearch/ 保证权限
启动:
docker run --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins -d elasticsearch:7.4.2
问题:docker: invalid reference format: repository name must be lowercase.
启动的过程中有格式不对
kibana
docker run --name kibana -e ELASTICSEARCH_HOSTS=http://192.168.136.138:9200 -p 5601:5601 \
-d kibana:7.4.2
http://192.168.136.138:9200 一定改为自己虚拟机的地址
测试数据:https://github.com/elastic/elasticsearch/blob/master/docs/src/test/resources/accounts.json
官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
索引(index)——对应数据库概念
类型(type)——对应表概念
文档(document)——对应记录概念
springboot中默认是给elasticsearch定义过版本,可能会给es的客户端依赖造成版本不一致性
解决方案:在springboot中的依赖里面找到版本设定的值,然后在自定义的pom文件中自定义版本进行覆盖
背景:压力不间断测试,redis报堆外内存溢出
2021-03-09 22:43:56.228 WARN 16220 --- [ioEventLoop-4-1] io.lettuce.core.protocol.CommandHandler : null Unexpected exception during request: io.netty.util.internal.OutOfDirectMemoryError: failed to allocate 125829120 byte(s) of direct memory (used: 138412032, max: 259522560)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。