5.28 商城知识梳理

198 阅读7分钟

0. 项目架构一览

分布式系统,主要用到几个东西:注册中心、配置中心、网关

1. 新添加一个微服务的步骤

  1. pom文件中引入公共依赖包common
  2. 将这个微服务放到注册中心和配置中心。注册中心做服务发现。配置中心做各种offline的配置文件,冷启动。

加入注册中心的步骤

  1. 启动nacos服务。(运行cmd文件),默认运行在8848端口。eg: http://192.168.31.23:8848
  2. 微服务要引入nacos的依赖。这里我们放在了common包中。
  3. 在微服务的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址
  4. 在微服务的应用类中,使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
  5. 给微服务配置上注册中心的地址:也就是nacos.discovery.server-addr
spring: 
    application: 
        name: renren-fast 
    cloud: 
        nacos: 
            discovery: 
                server-addr: localhost:8848 # nacos

加入配置中心的步骤(待写)

2. MyBatis-Plus的使用

  1. dao层的mapper接口: 在包下定义一个dao目录,放置对应的数据库操作的接口。这个接口用@Mapper修饰
  2. 启动类上写@MapperScan,告诉启动类去哪找mapper接口。
  3. 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写出来。 image.png

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);
    }
}

image.png

@EnableTransactionManagement 开启事务

这样我们的方法,标记了事务注解,就可以开启事务了

2.3 乐观锁

2.4 写一个接口的步骤和注意

例如写一个save接口;

    1. 看接口文档,定义的参数。对参数,可以使用@RequestParam或@RequestBody解析成我们封装好的某个对象
    1. 处理好参数后,看需要操作哪个数据表,注入对应的dao层接口,调用方法,如果没有现成的方法,就需要自定义,直接在controller中写自定义方法名,然后alt+enter会进入dao层接口中定义,然后继续进接口实现类中实现。
    1. 这其中会涉及一些参数对象 和 我们定义的实体类对象,属性是否对应的情况。不对应的话,应该怎么处理?
    1. 具体实现方法的时候,调用dao层的一些查询方法,mybatis-plus这里结合renren的逆向生成,可以直接用eq()和new wrapper来定义查询的where条件,不用写xml,直接用QueryWrapper或者UpdateWrapper。
    1. 也可以直接写mapper层的接口方法,在xml中自定义sql语句,利用@Param来给参数指定名字,方便xml中给sql利用。
    1. 如果一个方法,连续做了好几步骤的修改,这些修改之间的数据需要一致性同步,那么这个方法就需要开启事务@Transactional,来保证一致性。

2.5 mybatis声明的mapper接口如果有两个以上参数,一定建议用mapper接口参数多了用@Param来指定一个名字。

image.png

image.png

3. 配置网关路由与路径重写gateway

  1. 前台先把所有请求都发给网关,即88端口。
  2. 把每个微服务都注册到nacos。让网关88端口,去解析请求,根据路由规则,转发给不同的微服务处理
  1. 在网关服务中,编写路由规则。
  • 下面这个是重写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. 枚举类的写法

表示异常的状态枚举类

image.png

6. 按接口文档开发的相关问题和梳理

1. 接口处设置路径变量和获取:@RequestMapping("/list/{cId}")和@PathVariable("cId")、@RequestParam

image.png

  • 路径变量用{}包起来
  • 在方法上用@PathVariable 修饰一个参数,来获取上面设置的路径变量。

2. 重载吗?

image.png

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语句。 image.png

5. 实体类entity和数据表字段映射,如其中有不存在的字段,用@TableField处理;@JsonInclude处理空值

实体类常常会在后边以json的形式给写出去。如果某个字段为空,我们希望他就不传,这个时候可以用@JsonInclude解决。

image.png

6. 冗余字段的数据一致性

电商系统中不做联表设计,所以常用中间表来做冗余设计,当原表修改时冗余表的信息也应该修改。也就是冗余数据表的数据一致性,这部分需要Java业务代码中做修改。

  • 保证冗余字段的数据一致

image.png

7. 事务:修改数据的同时,还要修改冗余字段,这里用事务来保证

事务开启@Transactional,保证一致性

image.png

8. 编写接口获取分页参数

image.png

image.png

8. 为什么不建议数据库联表,和做联合索引

如果做联表的话,比如有100w数据,分组就算只有1000个分组,那极端情况下,进行笛卡儿积的话,就是100w * 1000,会生成10亿的中间表数据。

  • 所以一般有这种需要联动查的话,我们不会联表查询,而是Java在业务层分开查询。

9. 日志级别

```yml

logging: level: com.atguigu.gulimall: debug



# 7. 分页查询的使用!!!!!!!!
- queryWarpper是啥玩意,很多crud语句封装都是这个?
- Mybatis plus中实现查询的对象封装操作类。条件构造器。他的泛型是查哪个表,就传该表对应的实体类。
![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/507f40c12d814e2daa59f62572e2c256~tplv-k3u1fbpfcp-watermark.image?)

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

![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a360dd98192446c2880a58cc59223a61~tplv-k3u1fbpfcp-watermark.image?)


# 8. 在对象上标记过的注解
- 标注在实体类上的注解(很麻烦,而且看起来很乱)
- 比如一些校验的注解 @NotBlank。
![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dd6e70160a74439c8018fa6367bc973e~tplv-k3u1fbpfcp-watermark.image?)
- json注解@JsonInclude(JsonInclude.Include.NON_EMPTY)。将空字段不返回
![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b2c5e5638d154eab8a0d2ddc213d27e3~tplv-k3u1fbpfcp-watermark.image?)
- @TableId:表示数据库中的某个id字段
- 以上这些非常不规范,所以我们引入VO的视图对象来管理

![image.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5c1e6e38a1e54e53b96ea903bf1cf9ea~tplv-k3u1fbpfcp-watermark.image?)

## PO/VO/BO/DAO
PO:persistant object。就是持久化对象,一般对应数据库中的一张表,也就是常用的数据表实体类。
BO:业务对象。例如简历中,有三个PO(教育经历po,社会关系po,工作经历po),那么这三个合起来就是一个简历BO对象。
DAO:DAO中包含了各种数据库的操作方法,通过这些方法,结合PO对数据库进行相关操作。配合VO,提供数据库的CRUD操作。
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/54e80d9ca1e6474391d0455c627f1ee7~tplv-k3u1fbpfcp-watermark.image?)
## Q:为什么会引入PO、VO等对象
因为我们常常发现数据表对应一个bean对象,然后业务需要和返回的和这个bean对象有出入,有的多些字段,有的少一些字段。原来我们为了处理这种情况,会在数据表对应的bean对象上直接添加字段,加上一些注解来标记就好,但是这种写法很不规范,所以我们引入了VO、PO等对象。

## PO和VO对象存在重合的属性,用BeanUtils.copyProperties()来复制

![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a3946aa7683b4eac94ce411263f8382d~tplv-k3u1fbpfcp-watermark.image?)
 
 
# docker相关排查错误
- docker ps -a 查看容器的启动情况
- docker log nginx 查看nginx的日志,找到错误
- vim xx.conf 后输入“ :set number ”,文件会显示行号

# nginx代理转发到网关的一些坑
## nginx接受gulimall.com后转发给网关的时候,会丢掉hostname
![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dabc32b908fb4230ab7d8a2ac8c2b949~tplv-k3u1fbpfcp-watermark.image?)
- 所以需要配置,让nginx不要丢掉这些东西。
![image.png](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cfa50c97af814a60a2cd46cd50fd5d8a~tplv-k3u1fbpfcp-watermark.image?)
- 设置生效
![image.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fcc6310e09454a29bb8303ce39b8ab5f~tplv-k3u1fbpfcp-watermark.image?)
从v                     
# 7. ES梳理