0. 项目架构一览
分布式系统,主要用到几个东西:注册中心、配置中心、网关
1. 新添加一个微服务的步骤
- pom文件中引入公共依赖包common
- 将这个微服务放到注册中心和配置中心。注册中心做服务发现。配置中心做各种offline的配置文件,冷启动。
加入注册中心的步骤
- 启动nacos服务。(运行cmd文件),默认运行在8848端口。eg: http://192.168.31.23:8848
- 微服务要引入nacos的依赖。这里我们放在了common包中。
- 在微服务的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址
- 在微服务的应用类中,使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
- 给微服务配置上注册中心的地址:也就是nacos.discovery.server-addr
spring:
application:
name: renren-fast
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos
加入配置中心的步骤(待写)
2. MyBatis-Plus的使用
- dao层的mapper接口: 在包下定义一个dao目录,放置对应的数据库操作的接口。这个接口用@Mapper修饰
- 启动类上写@MapperScan,告诉启动类去哪找mapper接口。
- mapper接口可能会有对应的xml文件,xml文件中有丰富的sql写法
2.1 xml中丰富的sql写法
- 下面这个是涉及到foreach的写法。即sql为:select attr_id from pms where id in(x1,x2,..xn) and type=1. 这个里面的变量是in后面的集合,在xml中用foreach写出来。
2.2 分页插件的使用
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
@EnableTransactionManagement 开启事务
这样我们的方法,标记了事务注解,就可以开启事务了
2.3 乐观锁
2.4 写一个接口的步骤和注意
例如写一个save接口;
-
- 看接口文档,定义的参数。对参数,可以使用@RequestParam或@RequestBody解析成我们封装好的某个对象
-
- 处理好参数后,看需要操作哪个数据表,注入对应的dao层接口,调用方法,如果没有现成的方法,就需要自定义,直接在controller中写自定义方法名,然后alt+enter会进入dao层接口中定义,然后继续进接口实现类中实现。
-
- 这其中会涉及一些参数对象 和 我们定义的实体类对象,属性是否对应的情况。不对应的话,应该怎么处理?
-
- 具体实现方法的时候,调用dao层的一些查询方法,mybatis-plus这里结合renren的逆向生成,可以直接用eq()和new wrapper来定义查询的where条件,不用写xml,直接用QueryWrapper或者UpdateWrapper。
-
- 也可以直接写mapper层的接口方法,在xml中自定义sql语句,利用@Param来给参数指定名字,方便xml中给sql利用。
-
- 如果一个方法,连续做了好几步骤的修改,这些修改之间的数据需要一致性同步,那么这个方法就需要开启事务@Transactional,来保证一致性。
2.5 mybatis声明的mapper接口如果有两个以上参数,一定建议用mapper接口参数多了用@Param来指定一个名字。
3. 配置网关路由与路径重写gateway
- 前台先把所有请求都发给网关,即88端口。
- 把每个微服务都注册到nacos。让网关88端口,去解析请求,根据路由规则,转发给不同的微服务处理
- 在网关服务中,编写路由规则。
- 下面这个是重写url中某些字段的规则范例。把/api/xxx 变成 /renren-fast/xxx
spring:
cloud:
sentinel:
transport:
#配置sentinel dashboard地址
dashboard: localhost:8080
gateway:
routes:
- id: test_route
uri: https://www.baidu.com
predicates:
- Query=uri,baidu
- id: admin_route
uri: lb://renren-fast # 路由给renren-fast,lb代表负载均衡
predicates: # 什么情况下路由给它
- Path=/api/** # 默认前端项目都带上api前缀,
filters:
- RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}
4. JSR303数据校验
5. 枚举类的写法
表示异常的状态枚举类
6. 按接口文档开发的相关问题和梳理
1. 接口处设置路径变量和获取:@RequestMapping("/list/{cId}")和@PathVariable("cId")、@RequestParam
- 路径变量用{}包起来
- 在方法上用@PathVariable 修饰一个参数,来获取上面设置的路径变量。
2. 重载吗?
3. 多字段模糊匹配
- select xx where (catelog_id=?) and (attr_group_id=? or attr_group_name like ?)
@Override // AttrGroupServiceImpl.java
public PageUtils queryPage(Map<String, Object> params, Long catelogId) {
String key = (String) params.get("key");
QueryWrapper<AttrGroupEntity> wrapper = new QueryWrapper<>();
// key不为空
if (!StringUtils.isEmpty(key)) {
wrapper.and((obj) ->
obj.eq("attr_group_id", key).or().like("attr_group_name", key)
);
}
if (catelogId == 0) {
// Query可以把map封装为IPage
IPage<AttrGroupEntity> page =
this.page(new Query<AttrGroupEntity>().getPage(params),
wrapper);
return new PageUtils(page);
} else {
// 增加id信息
wrapper.eq("catelog_id", catelogId);
IPage<AttrGroupEntity> page =
this.page(new Query<AttrGroupEntity>().getPage(params),
wrapper);
return new PageUtils(page);
}
}
4. 配置文件中,数据库和日志级别的配置
logging.level设置为debug后,会打印dao层的sql语句。
5. 实体类entity和数据表字段映射,如其中有不存在的字段,用@TableField处理;@JsonInclude处理空值
实体类常常会在后边以json的形式给写出去。如果某个字段为空,我们希望他就不传,这个时候可以用@JsonInclude解决。
6. 冗余字段的数据一致性
电商系统中不做联表设计,所以常用中间表来做冗余设计,当原表修改时冗余表的信息也应该修改。也就是冗余数据表的数据一致性,这部分需要Java业务代码中做修改。
- 保证冗余字段的数据一致
7. 事务:修改数据的同时,还要修改冗余字段,这里用事务来保证
事务开启@Transactional,保证一致性
8. 编写接口获取分页参数
8. 为什么不建议数据库联表,和做联合索引
如果做联表的话,比如有100w数据,分组就算只有1000个分组,那极端情况下,进行笛卡儿积的话,就是100w * 1000,会生成10亿的中间表数据。
- 所以一般有这种需要联动查的话,我们不会联表查询,而是Java在业务层分开查询。
9. 日志级别
```yml
logging: level: com.atguigu.gulimall: debug
# 7. 分页查询的使用!!!!!!!!
- queryWarpper是啥玩意,很多crud语句封装都是这个?
- Mybatis plus中实现查询的对象封装操作类。条件构造器。他的泛型是查哪个表,就传该表对应的实体类。

- 分页查询相关:IPage<>和 new PageUtils()

# 8. 在对象上标记过的注解
- 标注在实体类上的注解(很麻烦,而且看起来很乱)
- 比如一些校验的注解 @NotBlank。

- json注解@JsonInclude(JsonInclude.Include.NON_EMPTY)。将空字段不返回

- @TableId:表示数据库中的某个id字段
- 以上这些非常不规范,所以我们引入VO的视图对象来管理

## PO/VO/BO/DAO
PO:persistant object。就是持久化对象,一般对应数据库中的一张表,也就是常用的数据表实体类。
BO:业务对象。例如简历中,有三个PO(教育经历po,社会关系po,工作经历po),那么这三个合起来就是一个简历BO对象。
DAO:DAO中包含了各种数据库的操作方法,通过这些方法,结合PO对数据库进行相关操作。配合VO,提供数据库的CRUD操作。

## Q:为什么会引入PO、VO等对象
因为我们常常发现数据表对应一个bean对象,然后业务需要和返回的和这个bean对象有出入,有的多些字段,有的少一些字段。原来我们为了处理这种情况,会在数据表对应的bean对象上直接添加字段,加上一些注解来标记就好,但是这种写法很不规范,所以我们引入了VO、PO等对象。
## PO和VO对象存在重合的属性,用BeanUtils.copyProperties()来复制

# docker相关排查错误
- docker ps -a 查看容器的启动情况
- docker log nginx 查看nginx的日志,找到错误
- vim xx.conf 后输入“ :set number ”,文件会显示行号
# nginx代理转发到网关的一些坑
## nginx接受gulimall.com后转发给网关的时候,会丢掉hostname

- 所以需要配置,让nginx不要丢掉这些东西。

- 设置生效

从v
# 7. ES梳理