当前位置: 首页 > article >正文

SpringCloud学习(补漏)

学习文档地址

https://b11et3un53m.feishu.cn/wiki/FJAnwOhpIihMkLkOKQocdWZ7nUc

1 MybatisPlus

https://baomidou.com/reference/annotation/

1.1 使用的基本步骤

1.2 常用注解

1.3 常用配置

1.4 核心功能

1.4.1 条件构造器

用法及建议

    QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .select("id", "username", "info", "balance")
                .like("username", "o")
                .ge("balance", 1000);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);

1.4.2 自定义sql

xml

  <update id="updateBalanceByIds">
        update user set balance = balance - #{amount}
        ${ew.customSqlSegment}
    </update>

mapper

void updateBalanceByIds(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper,@Param("amount") int amount);

逻辑

List<Long> ids = List.of(1L, 3L, 4L);
        int amount = 200;
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .in("id", ids);
        // 调用自定义
        userMapper.updateBalanceByIds(wrapper, amount);
基于wrapper的多表关联查询

1.4.3 Service接口

图示

举例:

1、创建IUserService接口并且继承IService接口

2、定义UserServiceImpl实现类,实现IUserService接口,并继承ServiceImpl实现类

3、在UserServiceImpl就可以直接调用MP(MybatisPlus)相关的方法,如getById;

UserServiceImpl中对应的mapper就是baseMapper,这个就等于是注入的userMapper=>这个是ServiceImpl已经有的,可以直接拿来用

关于Autowired注入的调整

1.4.3.1 IService中的Lambda查询
 @Override
    public List<User> queryUsers(String name, Integer status, Integer minBalance, Integer maxBalance) {
       return lambdaQuery()
                .like(name!=null, User::getUsername, name)
                .eq(status!=null, User::getStatus, status)
                .ge(minBalance!=null, User::getBalance, minBalance)
                .le(maxBalance!=null, User::getBalance, maxBalance)
                .list();
    }
1.4.3.2 IService中的Lambda更新
  lambdaUpdate()
                .set(User::getBalance, user.getBalance() - money)
                .set(user.getBalance() - money == 0,User::getStatus, 2)
                .eq(User::getId, id)
                .eq(User::getBalance, user.getBalance()) // 乐观锁:先比较再更新
                .update();
1.4.3.3 批量新增

&rewriteBatchedStatements=true

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

1.5 扩展功能

1.5.1 MyBatisPlus插件使用

jdbc:mysql://127.0.0.1:3306/mp?useSSL=false&serverTimezone=Asia/Shanghai

1.5.2 DB静态工具–高版本的mp才有

stream流的map提取后收集

users.stream().map(User::getId).collect(Collectors.toList());

stream流的根据某个返回值分组收集

addressVOS.stream().collect(Collectors.groupingBy(AddressVO::getUserId));

@Override
    public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
        // 查用户
        List<User> users = listByIds(ids);
        if (CollUtil.isEmpty(users)) {
            return Collections.emptyList();
        }
        // 获取用户id集合
        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        // 根据id集合查所有地址
        List<Address> addressList = Db.lambdaQuery(Address.class)
                .in(Address::getUserId, userIds).list();
        // 将地址转vo
        List<AddressVO> addressVOS = BeanUtil.copyToList(addressList, AddressVO.class);
        // 所有vo地址根据id分类
        Map<Long, List<AddressVO>> AddressVOMap = new HashMap<>(0);
        if(CollUtil.isNotEmpty(addressList)) {
            AddressVOMap = addressVOS.stream()
                    .collect(Collectors.groupingBy(AddressVO::getUserId));
        }

        // 转vo返回
        List<UserVO> list = new ArrayList<>(users.size());
        for (User user : users) {
            // 转vo
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            userVO.setAddresses(AddressVOMap.get(user.getId()));
            list.add(userVO);
        }

        return list;
    }

1.5.3 逻辑删除

1.5.3 枚举处理器

1.5.4 JSON处理器

(1)@TableName(autoResultMap = true)

(2)

@TableField(typeHandler = JacksonTypeHandler.class)
private UserInfo info;

1.6 分页功能

1.6.1 配置(先配置,底层是拦截器拦截)

1.6.2 通用分页实体

(1)先定义一个通用实体

(2)需要查询的实体继承(1)

 @Override
    public PageDTO<UserVO> queryUsersPage(UserQuery query) {
        String name = query.getName();
        Integer status = query.getStatus();

        Page<User> page = Page.of(query.getPageNo(), query.getPageSize());
        if (StrUtil.isNotBlank(query.getSortBy())){
            page.addOrder(new OrderItem().setColumn(query.getSortBy()).setAsc(query.getIsAsc()));// query.getSortBy(),query.getIsAsc()
        }else{
            page.addOrder(new OrderItem().setColumn("update_time").setAsc(false));
        }
        Page<User> p = lambdaQuery()
                .like(name != null, User::getUsername, name)
                .eq(status != null, User::getStatus, status)
                .page(page);

        PageDTO<UserVO> pageDTO = new PageDTO<>();
        pageDTO.setTotal(p.getTotal()); // 条数
        pageDTO.setPages(p.getPages()); // 页面
        List<User> records = p.getRecords();
        if(CollUtil.isEmpty(records)){
            pageDTO.setList(Collections.emptyList());
        }else{
            pageDTO.setList(BeanUtil.copyToList(records, UserVO.class));
        }
        return pageDTO;
    }

1.6.3 基于分页和封装条件编写通用MP分页实体

PageQuery – 泛型

package com.itheima.mp.query;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.mp.domain.po.User;
import io.swagger.annotations.ApiModel;
import lombok.Data;

@Data
@ApiModel(value = "分页查询实体")
public class PageQuery {

    private Integer pageNo = 1;
    private Integer pageSize = 5;
    private String sortBy;
    private Boolean isAsc = true;

    public <T>Page<T> toMpPage(OrderItem...items){
        Page<T> page = Page.of(pageNo, pageSize);
        if (StrUtil.isNotBlank(sortBy)){
            page.addOrder(new OrderItem().setColumn(sortBy).setAsc(isAsc));// query.getSortBy(),query.getIsAsc()
        }else if(items != null){
            page.addOrder(items);
        }
        return page;
    }
    public <T>Page<T> toMpPage(String column, boolean isAsc){
        return toMpPage(new OrderItem().setColumn(column).setAsc(isAsc));
    }

    public <T>Page<T> toMpPageDefaultSortByCreateTime(){
       return toMpPage(new OrderItem().setColumn("create_time").setAsc(isAsc));
    }
    public <T>Page<T> toMpPageDefaultSortByUpdateTime(){
        return toMpPage(new OrderItem().setColumn("update_time").setAsc(isAsc));
    }



}

PageDTO – 泛型加函数式接口

package com.itheima.mp.domain.dto;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.mp.domain.po.User;
import com.itheima.mp.domain.vo.UserVO;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "分页查询结果")
public class PageDTO<T> {
    private Long total;
    private Long pages;
    private List<T> list;

    // 其他对象转PageDTO对象,使用static变为静态方法,让别人创建时就可以调用
    // <PO, VO>不可以放在static之前,是因为类的泛型参数是在类实例化时确定的,而静态方法在实例化之前就可以被调用,因此无法直接引用类的泛型参数
    public static <PO, VO> PageDTO<VO> of(Page<PO> p, Class<VO> voClass){
        PageDTO<VO> pageDTO = new PageDTO<>();
        pageDTO.setTotal(p.getTotal()); // 条数
        pageDTO.setPages(p.getPages()); // 页面
        List<PO> records = p.getRecords();
        if(CollUtil.isEmpty(records)){
            pageDTO.setList(Collections.emptyList());
        }else{
            // 变量名一样的PO到VO的转换
            pageDTO.setList(BeanUtil.copyToList(records, voClass)); // VO是没有.class的,所以要传参进来
        }
        return pageDTO;

    }
    // 变量名不一样的PO到VO的转换
    // 那就要传行为,也就是一个行为即函数,那就要传一个函数式接口了 Function
    public static <PO, VO> PageDTO<VO> of(Page<PO> p, Function<PO, VO> convertor){
        PageDTO<VO> pageDTO = new PageDTO<>();
        pageDTO.setTotal(p.getTotal()); // 条数
        pageDTO.setPages(p.getPages()); // 页面
        List<PO> records = p.getRecords();
        if(CollUtil.isEmpty(records)){
            pageDTO.setList(Collections.emptyList());
        }else{
            // 利用流处理,map()里的传参就是函数式接口,之后再收集为list
            pageDTO.setList(records.stream().map(convertor).collect(Collectors.toList())); // VO是没有.class的,所以要传参进来
        }
        return pageDTO;

    }

}

缺点:

这是定义在两个类内部了,也就是与MP强耦合,

可以单独写方法,然后写实体与MP转换的,以后有别的,就再写

1.6.2简化结果:

2 Docker

https://b11et3un53m.feishu.cn/wiki/MWQIw4Zvhil0I5ktPHwcoqZdnec

2.1 MobaXterm

2.2 docker安装

Docker安装3个命令搞定,其他的都太麻烦了,命令开始后基本选第一个就都完事了

sudo yum install curl
bash <(curl -sSL https://gitee.com/SuperManito/LinuxMirrors/raw/main/ChangeMirrors.sh)
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)

启动和校验

# 启动Docker
systemctl start docker

# 停止Docker
systemctl stop docker

# 重启
systemctl restart docker

# 设置开机自启
systemctl enable docker

# 执行docker ps命令,如果不报错,说明安装启动成功
docker ps

2.3 部署mysql

docker run -d \
  --name mysql \
  -p 3306:3306 \
  -e TZ=Asia/Shanghai \
  -e MYSQL_ROOT_PASSWORD=123456 \
  mysql
命令解读

镜像源问题

https://blog.csdn.net/qq_62404706/article/details/141687367?spm=1001.2014.3001.5501

Navicat查看

镜像与容器

2.4 常见命令

docker ps 查看是否有docker容器运行,不要总docker run,这样的话是在创建容器

案例

// 查看 https://docker.fxxk.dedyn.io/_/nginx
// 拉取
docker pull nginx
// 查看
docker images
// 保存镜像
docker save --help
docker save -o nginx.tar nginx:latest //nginx:latest :后面是版本号(必要)
// 删除镜像
docker rmi nginx:latest
// 因为保存了nginx.tar 可以load回来
docker load -i nginx.tar
// 运行nginx -d是后台运行 -e 环境变量,没有不写就行
docker run -d --name nginx -p 80:80 nginx
//ps 也可以加格式化方式访问,格式会更加清爽 加 -a 查看不止运行中的
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"
// 停止
docker stop nginx
// 进入容器
docker exec -it nginx bash 
// 删除容器
docker rm nginx // 要先停止运行或者加 -f

起别命

# 修改/root/.bashrc文件
vi /root/.bashrc
内容如下:
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'
alias dis='docker images'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

执行命令,让别名生效

source /root/.bashrc

2.5 数据卷

容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦

定义

数据卷(volume)是一个虚拟目录,是容器内目录宿主机目录之间映射的桥梁。

以Nginx为例,我们知道Nginx中有两个关键的目录:

  • html:放置一些静态资源
  • conf:放置配置文件

如果我们要让Nginx代理我们的静态资源,最好是放到html目录;如果我们要修改Nginx的配置,最好是找到conf下的nginx.conf文件。

但遗憾的是,容器运行的Nginx所有的文件都在容器内部。所以我们必须利用数据卷将两个目录与宿主机目录关联,方便我们操作。如图:

在上图中:

  • 我们创建了两个数据卷:confhtml
  • Nginx容器内部的conf目录和html目录分别与两个数据卷关联。
  • 而数据卷conf和html分别指向了宿主机的/var/lib/docker/volumes/conf/_data目录和/var/lib/docker/volumes/html/_data目录

这样以来,容器内的confhtml目录就 与宿主机的confhtml目录关联起来,我们称为挂载。此时,我们操作宿主机的/var/lib/docker/volumes/html/_data就是在操作容器内的/usr/share/nginx/html/_data目录。只要我们将静态资源放入宿主机对应目录,就可以被Nginx代理了。

小提示

<font style="background-color:rgb(255,245,235);">/var/lib/docker/volumes</font>这个目录就是默认的存放所有容器数据卷的目录,其下再根据数据卷名称创建新目录,格式为<font style="background-color:rgb(255,245,235);">/数据卷名/_data</font>

为什么不让容器目录直接指向宿主机目录呢

  • 因为直接指向宿主机目录就与宿主机强耦合了,如果切换了环境,宿主机目录就可能发生改变了。由于容器一旦创建,目录挂载就无法修改,这样容器就无法正常工作了。
  • 但是容器指向数据卷,一个逻辑名称,而数据卷再指向宿主机目录,就不存在强耦合。如果宿主机目录发生改变,只要改变数据卷与宿主机目录之间的映射关系即可。

不过,我们通过由于数据卷目录比较深,不好寻找,通常我们

允许让容器直接与宿主机目录挂载而不使用数据卷

一般是宿主机和数据卷产生映射,数据卷和容器产生映射,这样宿主机跟容器就有了映射

案例和提示

挂载本地目录或文件

# 挂载本地目录
-v 本地目录:容器内目录
# 挂载本地文件
-v 本地文件:容器内文件

2.6 自定义镜像

定义与java镜像

镜像结构

Dockerfile

https://docs.docker.com/engine/reference/builder/

2.7 网络

容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。

所以,我们必须借助于docker的网络功能来解决这个问题

2.8 部署前端的坑点

如果不加network ,不把nginx加入到自己定义的网段,nginx找不到相应的域名,那么就启动不了Nginx

2.9 部署后端的坑点

这个local是-后面的,记得重构为applicantion-local.yaml

2.10 docker compose

2.10 Nginx

cmd的相关命令

# 启动nginx
start nginx.exe
# 停止
nginx.exe -s stop
# 重新加载配置
nginx.exe -s reload
# 重启
nginx.exe -s restart

3 微服务

3.1 单体架构优缺点

JMeter高并发测试-hi接口

黑马商城测试.jmx

总结->单体缺点: 某个接口并发次数太高,tomcat资源占用过高,影响其他接口

3.2 微服务1

3.2.1 SpringCloud

https://spring.io/projects/spring-cloud

3.2.2 拆分原则

3.2.3 Maven多模块项目和微服务架构项目

Maven多模块项目和微服务架构是两个不同的概念,它们分别属于软件开发的不同领域。

  1. Maven多模块项目
    • Maven是一个项目管理和构建自动化工具,它使用pom.xml文件来描述项目的构建过程、依赖关系等。
    • 一个Maven多模块项目(Multi-module Maven project)是指一个包含多个子模块(module)的项目,每个子模块都有自己的pom.xml文件,并且可以独立编译和运行。这些模块通常在同一个版本控制仓库中,可以一起构建和部署。
    • 多模块项目的优点在于可以更好地组织和管理大型项目,每个模块负责不同的功能,有助于团队协作和代码的模块化。
  2. 微服务架构
    • 微服务架构是一种软件开发架构风格,它将一个单一应用程序拆分成一组小服务,每个服务运行在其独立的进程中,并通过轻量级的通信机制(通常是HTTP RESTful API)进行交互。
    • 微服务架构的目的是提高软件系统的可维护性、可扩展性和部署的灵活性。每个微服务可以独立开发、部署、扩展和替换。
    • 在微服务架构中,每个服务通常由一个小团队负责,团队可以选择合适的技术栈来构建服务。

Maven多模块项目与微服务架构的关系

  • Maven多模块项目可以作为微服务架构中单个服务的构建方式。例如,一个微服务可能由多个Maven模块组成,每个模块负责不同的功能或组件。
  • 但是,仅仅使用Maven多模块项目并不意味着你的架构就是微服务架构。微服务架构更关注的是服务的独立性、可扩展性和部署的灵活性,而Maven多模块项目更多关注于项目的构建和管理。

总结来说,Maven多模块项目是一种项目管理和构建的方法,而微服务架构是一种软件设计和部署的架构风格。两者可以结合使用,但它们本身并不等同。一个项目可以是Maven多模块的,但不一定是微服务架构;反之,一个微服务架构的项目可能并不使用Maven作为构建工具。

3.2.4 远程调用

RestTemplate

3.2.5 服务治理

3.2.4 的问题

注册中心原理

Nacos注册中心

nacos.sql

服务注册

服务发现(负载均衡)

连不上数据库

3.2.6 OpenFeign

介绍

快速入门
之前

现在

连接池

3.3 微服务2

3.3.1 网关

快速入门

路由属性

springboot网关拦截器与SpringMVC的拦截器(自动装配+条件注解只在微服务生效不在网关生效)

直接启动gateway是会找不到MvcConfig这个文件的,因为MvccConfig(META-INF)这个文件是放在common模块的,gateway底层不是Springmvc那一套,所以用条件生效的注解 红框 ,mvcc核心api有说明就要加载,没有就不用,gateway就不会加载,启动就不会报错

网关-》过滤器(基于响应式编程)-》拦截器(SpringMVC)-》服务

微服务登录解决方案(openfeign)

3.3.2 配置管理

nacos配置管理

https://b11et3un53m.feishu.cn/wiki/UMgpwmmQKisWBIkaABbcwAPonVf

3.3 服务保护和分布式事务

https://b11et3un53m.feishu.cn/wiki/QfVrw3sZvihmnPkmALYcUHIDnff

3.3.1 雪崩问题(级联失败)

解决方案


http://www.kler.cn/news/367573.html

相关文章:

  • Stable Diffusion视频插件Ebsynth Utility使用方法
  • 使用Llama Index与Streamlit实现一个从文本中提取专业术语和定义网页小程序
  • React基础使用教程
  • 解码专业术语——应用系统开发项目中的专业词汇解读
  • 颐驰06持续交付,明日科技赋能出行生活
  • axure中继器
  • 哈希表之哈希数组、HashSet
  • 随机变量、取值、样本和统计量之间的关系
  • 智能科学与技术(一级学科)介绍
  • 从0开始深度学习(16)——暂退法(Dropout)
  • C++笔记---位图
  • PHP如何抛出和接收错误
  • C语言[求x的y次方]
  • 7.hyperf安装【Docker】
  • 京东电商下单黄金链路:防止订单重复提交与支付的深度解析
  • Pseudo Multi-Camera Editing 数据集:通过常规视频生成的伪标记多摄像机推荐数据集,显著提升模型在未知领域的准确性。
  • 背包九讲——混合背包问题
  • 虾类图像分割系统:改进亮点优化
  • 前端项目接入sqlite轻量级数据库sql.js指南
  • ffmpeg视频滤镜: 色温- colortemperature
  • Windows 11 绕过 TPM 方法总结,24H2 通用免 TPM 镜像下载 (Updated Oct 2024)
  • java项目之在线考试系统设计与实现(springboot)
  • 通过AWS Bedrock探索 Claude 的虚拟桌面魔力:让 AI 代替你动手完成任务!
  • 时间数据可视化基础实验(南丁格尔玫瑰图)——Python热狗大胃王比赛数据集
  • 蓝桥杯普及题
  • Android中导入讯飞大模型ai智能系统