GithubHelp home page GithubHelp logo

blog-contents's People

Stargazers

ai8848 avatar

Watchers

yeguo avatar

blog-contents's Issues

Maven


title: Maven
date: 2023-08-30 11:40
updated: 2023-08-30 11:40
category: 知识笔记
tags:

  • maven

一、依赖管理

1.依赖传递冲突问题

  • 路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高
  • 声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的
  • 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的

2.可选依赖

​ 将自己项目使用的依赖隐藏(不透明)

	<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
			<!--隐藏依赖,true-->
			<optional>true</optional>
   		</dependency>

3.排除依赖

​ 排除使用的依赖中使用的其他依赖,解决和自己项目的依赖冲突

	<dependency>
      <groupId>top.aidjajd</groupId>
      <artifactId>aidjajd_project</artifactId>
      <version>1.0-SNAPSHOT</version>
      <!--排除依赖log4j-->
              <exclusions>
                <exclusion>
                <!--写入排除坐标不需要写version-->
                  <groupId>log4j</groupId>
                  <artifactId>log4j</artifactId>
                </exclusion>
              </exclusions>
    </dependency>

4.依赖范围

  • 依赖的jar默认情况可以在任何地方使用,可以通过scope标签设定其作用范围
    作用范围
  • 主程序范围有效(main文件夹范围内)
  • 测试程序范围有效(test文件夹范围内)》
  • 是否参与打包(package指令范围内)
Scope 主代码 测试代码 打包 范例
compile(默认) Y Y Y log4j
test Y junit
provided Y Y servlet-api
runtime Y jdbe

5.依赖范围传递性

间接依赖\直接-> compile(默认) test provided runtime
compile(默认) compile test provided runtime
test
provided
runtime runtime test provided runtime

二、生命周期与插件

Maven对项目构建的生命周期划分为3套

  • clean:清理工作
  • default:核心工作,例如编译,测试,打包,部署等
  • site:产生报告,发布站点等

主要关注阶段:clean -> compile -> test -> package -> install

生命周期过程每一个阶段对应一个插件(plugin)

Docker 私有仓库


title: Docker 私有仓库
author: yeguo
date: 2023-07-28 11:00
updated: 2023-07-28 11:00
category: 技术杂谈
tags:

  • docker

一、私有仓库搭建

# 1、拉取私有仓库镜像 
docker pull registry
# 2、启动私有仓库容器 
docker run -id --name=registry -p 5000:5000 registry
# 3、打开浏览器 输入地址http://私有仓库服务器ip:5000/v2/_catalog,看到{"repositories":[]} 表示私有仓库 搭建成功
# 4、修改daemon.json   
vim /etc/docker/daemon.json    
# 在上述文件中添加一个key,保存退出。此步用于让 docker 信任私有仓库地址;注意将私有仓库服务器ip修改为自己私有仓库服务器真实ip 
{"insecure-registries":["私有仓库服务器ip:5000"]} 
# 5、重启docker 服务 
systemctl restart docker
docker start registry

二、将镜像上传至私有仓库

# 1、标记镜像为私有仓库的镜像     
docker tag centos:7 私有仓库服务器IP:5000/centos:7
 
# 2、上传标记的镜像     
docker push 私有仓库服务器IP:5000/centos:7

三、 从私有仓库拉取镜像

#拉取镜像 
docker pull 私有仓库服务器ip:5000/centos:7

HTTPS 原理


title: HTTPS原理
author: yeguo
date: 2024-02-15 11:14
updated: 2024-02-15 11:14
category: 技术杂谈
tags:

  • https

https过程

​ 在TLS/SSL握手过程中,ClientHelloServerHello 消息本身通常不加密,它们是明文传输的。这是因为在握手的初步阶段,双方还没有建立起加密通道,因此初始的握手消息需要在明文中传递。

1.客户端Hello: 客户端在握手开始时向服务器发送ClientHello消息,其中包含一个随机数(ClientRandom),以及其他一些握手参数。

2.服务器Hello: 服务器在接收到ClientHello后,向客户端发送ServerHello消息,其中包含另一个随机数(ServerRandom),以及选择的加密套件、协商的协议版本等信息。

ServerHello 阶段通常包含服务器的数字证书。数字证书中包含了服务器的公钥以及与之相关的信息,如证书颁发者、有效期等。这个数字证书是由服务器的证书链中的最顶层证书签发的,而这个最顶层的证书通常由一个受信任的证书颁发机构(CA,Certificate Authority)签发。

​ 客户端在收到 ServerHello 消息中的数字证书后,会验证证书的合法性,包括检查证书的签名是否有效、证书是否在有效期内、证书是否由受信任的CA签发等。验证通过后,客户端可以提取服务器的公钥,用于后续密钥协商和加密通信的建立。这个公钥通常用于协商会话密钥的加密

  1. CA验证: 客户端在收到服务器的证书后,需要验证服务器证书的有效性。这个验证过程包括以下几个步骤:
    • 证书链验证: 客户端需要检查服务器证书是否是由可信的CA签发的。客户端本地存储了一组信任的CA的根证书,用于验证服务器证书链的合法性。
    • 证书是否过期: 客户端检查服务器证书的有效期,确保它没有过期。
    • 域名匹配: 客户端检查服务器证书中的域名是否与实际连接的域名匹配。这是为了防止中间人攻击。
  2. 公钥提取: 如果服务器证书通过了验证,客户端就可以从服务器证书中提取服务器的公钥。
  3. 密钥交换: 客户端使用服务器的公钥来加密一个Pre-Master Secret并发送给服务器。服务器使用自己的私钥解密这个消息,得到Pre-Master Secret

**3.生成Pre-Master Secret:**客户端使用这两个随机数以及其他一些握手参数,例如支持的加密算法、协商的协议版本等,生成一个共同的Pre-Master Secret

4.Pre-Master Secret的安全传输: 客户端将生成的Pre-Master Secret通过服务器的公钥进行加密,然后发送给服务器。这一步使用了非对称加密,确保了Pre-Master Secret在传输过程中的安全性。

5.Master Secret的生成算法: 一旦服务器收到已加密的Pre-Master Secret并解密,客户端和服务器都使用以下算法计算Master Secret:

MasterSecret = PRF(PreMasterSecret, "master secret", ClientHello.random + ServerHello.random)
// "master secret"是PRF中的标识符,指示生成Master Secret。PRF 表示伪随机函数(Pseudo-Random Function)

6.Master Secret生成: 服务器收到已加密的Pre-Master Secret后,使用自己的私钥进行解密,获取Pre-Master Secret。然后,客户端和服务器都使用双方生成的随机数以及Pre-Master Secret计算出一个共同的Master Secret

7.生成会话密钥: 通过Master Secret再次使用密钥派生函数(PRFHKDF),生成最终用于对称加密通信的对称会话密钥。

伪随机函数密钥导出

伪随机函数(Pseudo-Random Function,PRF)是一种能够生成近似于真随机函数的算法,其输出表现为随机性。在SSL/TLS握手过程中,PRF的主要作用是生成密钥材料,例如生成Master Secret。

在SSL/TLS中,PRF的具体实现取决于协议版本。在TLS 1.2及之前的版本中,PRF的定义如下:

PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
  • secret 是Pre-Master Secret。
  • label 是一个字符串标识符,用于区分生成不同的密钥材料。
  • seed 是随机数。

P_MD5P_SHA-1 是基于MD5和SHA-1散列函数的伪随机函数。S1和S2是通过拆分Pre-Master Secret而得到的两个半分。

在TLS 1.2中,PRF的计算方式得到了改变,引入了更灵活的PRF(secret, label, seed) = P_hash(secret, label + seed),其中P_hash 是一个基于HMAC(Hash-based Message Authentication Code)的伪随机函数,可以使用不同的散列算法,如SHA-256或SHA-384。

TLS 1.3进一步简化了密钥交换的流程,使用了更现代的密码学原语,并且取消了显式的PRF。在TLS 1.3中,密钥的生成主要通过HKDF(HMAC-based Extract-and-Expand Key Derivation Function)实现。

TLS 1.3中的HKDF算法会使用双方生成的随机数。在握手过程中,客户端和服务器各自生成一个随机数,并在握手消息中交换这些随机数。这些随机数用于增加握手过程的熵,从而提高密钥的随机性。

在HKDF的上下文中,这些随机数被作为输入之一,用于派生出最终的对称密钥。这样,不同的会话将有不同的随机数,导致生成不同的密钥,增强了密钥的唯一性和安全性。

TLS 1.3中使用的HKDF(HMAC-based Extract-and-Expand Key Derivation Function)算法是基于HMAC(Hash-based Message Authentication Code)的。HKDF包括两个步骤:Extract和Expand。

  1. Extract: 在这一步,将原始输入(包括双方生成的随机数)通过一个伪随机函数(PRF)与salt(如果提供的话)进行HMAC运算,生成一个伪随机密钥(PRK,Pseudo-Random Key)。

    公式表示为:PRK = HMAC-Hash(salt, input)

  2. Expand: 利用PRK和其他信息(比如上下文标签,长度等),通过多次调用伪随机函数派生出最终的对称密钥。

    公式表示为:OKM = HKDF-Expand(PRK, info, L)

    其中,OKM是输出密钥材料,HKDF-Expand是一个用于扩展密钥材料的函数,info包含了上下文标签和其他信息,L是输出密钥材料的长度。

具体的哈希函数、PRF和其他参数的选择取决于协商时所选择的密码套件,HKDF是一个灵活的密钥派生方案,可以适应不同的密码学要求。

加密套件

加密套件是TLS通信中用于协商加密算法、鉴别方法等参数的一组规范。在TLS握手过程中,客户端和服务器会协商选用一个加密套件,这个套件定义了一组加密算法、鉴别方法和其他相关参数。

TLS 1.3支持的一些加密套件包括:

  • TLS_AES_128_GCM_SHA256: 使用AES-128-GCM进行加密和认证,以及SHA-256进行鉴别。
  • TLS_AES_256_GCM_SHA384: 使用AES-256-GCM进行加密和认证,以及SHA-384进行鉴别。
  • TLS_CHACHA20_POLY1305_SHA256: 使用ChaCha20-Poly1305进行加密和认证,以及SHA-256进行鉴别。

这些套件包括了对称加密算法、鉴别算法和其他相关参数的组合。具体选用哪个套件取决于客户端和服务器双方的支持和协商结果。

数字证书

数字证书是一种用于在网络中进行安全通信的电子证明书。它用于验证与证书相关联的实体(通常是一个网站或服务)的身份。数字证书的主要组成部分包括:

  1. 主体信息(Subject): 证书中指定了证书所属实体的信息,如组织、组织单元、通用名(通常是域名)等。
  2. 公钥: 证书中包含了与该证书相关联实体的公钥。这个公钥用于加密通信或验证数字签名。
  3. 证书颁发者信息(Issuer): 证书的颁发者,即签发该证书的证书颁发机构(CA)。CA是一个受信任的第三方,用于证明证书中所含公钥确实属于证书中所指明的实体。
  4. 签名: 证书的数字签名是由颁发者使用其私钥生成的,用于验证证书的完整性和真实性。
  5. 有效期: 证书有一个有效期限,超过这个期限,证书将不再被认为是有效的。

数字证书通过在通信中引入第三方(CA)的信任,提供了一种机制来确保通信的安全性和真实性。在HTTPS中,服务器通常会提供数字证书以证明其身份,同时客户端会验证证书的有效性。这样,双方可以协商出一个对称密钥,用于后续通信的加密。

数字签名

数字签名是一种用于验证文档、消息或数据的完整性和来源真实性的技术。数字签名通过使用加密算法生成一个与特定数据相关联的数字代码(签名),并将其附加到原始数据上。这个数字签名可以被其他人用于验证数据的完整性和签名者的身份。

下面是数字签名的基本步骤:

  1. 生成消息摘要(Hash): 对原始数据应用哈希函数,生成一个固定长度的消息摘要(哈希值)。这个哈希值通常是一个唯一表示原始数据的字符串。
  2. 使用私钥加密摘要: 发送者使用其私钥对生成的消息摘要进行加密,形成数字签名。
  3. 附加数字签名: 数字签名被附加到原始数据上,形成签名的数据。
  4. 传输数据: 签名的数据和公钥一同传输给接收者。
  5. 验证签名: 接收者使用发送者的公钥解密数字签名,得到消息摘要。然后,接收者对接收到的原始数据应用哈希函数,生成一个新的消息摘要。
  6. 比较摘要: 接收者比较用私钥解密得到的消息摘要与重新计算的消息摘要。如果两者匹配,证明数据完整且签名者是可信的。

数字签名的关键在于私钥只能由签名者持有,而公钥可以被分发给任何需要验证签名的人。这样,任何人都可以使用公钥验证数字签名,但只有持有相应私钥的实体才能生成有效的数字签名。

数字签名验证

数字签名验证通常涉及以下步骤:

  1. 获取公钥: 首先,需要获取签名者的公钥。在数字证书中,公钥通常包含在证书中,而证书本身可以通过一系列的信任链验证(通过 CA 或其他手段)获取。
  2. 获取消息摘要: 要验证数字签名,需要对原始数据进行哈希运算,得到消息的摘要。这个哈希值通常是通过安全的哈希算法(如SHA-256)生成的。
  3. 解码数字签名: 数字签名通常是二进制数据。需要使用签名者的公钥对数字签名进行解码,以获取原始的数字签名值。
  4. 验证签名: 将解码后的数字签名与消息摘要进行比较。如果它们一致,说明数字签名有效,消息未被篡改。

​ 如果在这个过程中的任何一步失败,或者签名不匹配,那么验证将失败,表示消息可能已经被篡改或签名者并非预期的实体。

​ 需要注意的是,数字签名的有效性与签名者的私钥和签名算法有关。只有持有相应私钥的实体才能生成有效的数字签名。

服务器获取数字证书

服务器通常会从数字证书颁发机构(CA,Certificate Authority)处获得数字证书。下面是简要的过程:

  1. 证书请求生成: 服务器首先生成一个证书请求(CSR,Certificate Signing Request)。这包含了将包含在证书中的信息,如公钥、组织信息等。
  2. 私钥生成: 同时,服务器会生成一对密钥,包括公钥和私钥。私钥是秘密的,服务器会妥善保存它。
  3. CSR提交给CA: 服务器将生成的CSR提交给选择的CA。CSR中包含了服务器的公钥以及一些其他身份信息。
  4. CA验证: CA会对服务器提交的信息进行验证,确保服务器拥有CSR中提到的域的控制权。这个过程可能涉及到不同的验证方法,包括电子邮件验证、DNS记录添加等。
  5. 颁发证书: 一旦验证通过,CA将颁发数字证书,并在其中包含服务器的公钥。该证书还包含CA的数字签名,用于验证证书的真实性。
  6. 证书安装: 服务器收到数字证书后,将其安装在服务器上。同时,私钥也需要与证书一起保存。

​ 通常情况下,数字证书的有效期是有限的,因此在证书到期之前,服务器可能需要定期更新证书,通常是通过提交新的CSR给CA进行重新签发。

​ 需要注意的是,一些大型的CA可能会向企业出售数字证书,而其他一些CA可能会提供免费的证书服务。选择CA通常取决于用例的需求和信任级别。

​ 对于传统的服务器通信,服务器通常只需要一次性地获取证书,然后可以用该证书与多个客户端建立安全连接。证书是服务器身份的标识,用于证明服务器是可信的。一旦服务器获取了有效的数字证书,它就可以与多个客户端建立安全通信,而不需要为每个客户端单独申请证书。

​ 这是因为数字证书是为特定的域名(或IP地址)签发的,并不是为特定的客户端。当客户端与服务器建立连接时,它会验证服务器的数字证书是否有效,以确保与服务器通信的安全性。因此,服务器只需要在初始设置中获取并配置好证书,之后便可以与多个客户端进行通信。

Git常用命令


title: Git常用命令
author: yeguo
date: 2023-07-26 16:01
updated: 2023-07-26 16:01
category: 技术杂谈
tags:

  • git

设置用户签名
git config --global user.name 用户名
git config --global user.email 邮箱
初始化本地库
git init // 初始化当前目录
git init 目录 //指定目录初始化
查看本地库状态
git status
添加到暂存区
git add 文件名
提交到本地库
git commit -m "提交说明" 文件名
查看历史记录
git reflog
git log //详细的历史记录
版本穿梭
git reset --hard 版本号
创建分支
git branch 分支名
查看分支
git branch -v
切换分支
git checkout 分支名
合并分支
git merge 分支名
合并无同祖先分支
git merge 远程库链接或别名/分支 --allow-unrelated-histories
git merge git-demo/main --allow-unrelated-histories //例
修改分支名
git branch -m 旧名字 新名字
创建远程库别名
git remote add 别名 远程库链接
查看别名
git remote -v
推送到远程库
git push 别名/远程库链接 分支
从远程库拉取
git pull 别名/远程库链接 拉取分支
远程分支最新更新
git fetch 别名/远程库链接 分支
克隆到本地
git clone 远程库链接 

Docker Compose


title: Docker Compose
author: yeguo
date: 2023-07-28 11:00
updated: 2023-07-28 11:00
category: 技术杂谈
tags:

  • docker
  • docker-compose

一、安装Docker Compose

# Compose目前已经完全支持Linux、Mac OS和Windows,在我们安装Compose之前,需要先安装Docker。下面我 们以编译好的二进制包方式安装在Linux系统中。 
curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# 设置文件可执行权限 
chmod +x /usr/local/bin/docker-compose
# 查看版本信息 
docker-compose -version

二、卸载Docker Compose

# 二进制包方式安装的,删除二进制文件即可
rm /usr/local/bin/docker-compose

三、 使用docker compose编排nginx+springboot项目

  1. 创建docker-compose目录
mkdir ~/docker-compose
cd ~/docker-compose
  1. 编写 docker-compose.yml 文件
version: '3'
services:
  nginx:
   image: nginx
   ports:
    - 80:80
   links:
    - app
   volumes:
    - ./nginx/conf.d:/etc/nginx/conf.d
  app:
    image: app
    expose:
      - "8080"
  1. 创建./nginx/conf.d目录
mkdir -p ./nginx/conf.d
  1. 在./nginx/conf.d目录下 编写nginx.conf文件
server {
    listen 80;
    access_log off;

    location / {
        proxy_pass http://app:8080;
    }
   
}
  1. 在~/docker-compose 目录下 使用docker-compose 启动容器
docker-compose up
  1. 测试访问
http://192.168.149.135/hello

用户中心开发


title: 用户中心开发
date: 2024-04-15 17:09
updated: 2024-04-15 17:09
category: 开发记录
tags:

一、技术选型

前端:三件套 + React + 组件库 Ant Design + Umi + Ant Design Pro(现成的管理系统)

后端:

  • java
  • spring(依赖注入框架,帮助你管理 Java 对象,集成一些其他的内容)
  • springmvc(web 框架,提供接口访问、restful接口等能力)
  • druid连接池
  • mybatis(Java 操作数据库的框架,持久层框架,对 jdbc 的封装)
  • mybatis-plus(对 mybatis 的增强,不用写 sql 也能实现增删改查)
  • springboot(快速启动 / 快速集成项目。不用自己管理 spring 配置,不用自己整合各种框架)
  • junit 单元测试库
  • mysql 数据库

部署:服务器 / 容器(平台)

二、初始化项目

1.前端初始化

​ 1.初始化项目:使用umijs脚手架初始化项目√

​ 2.引入组件:√

​ 3.项目瘦身:删除不需要文件√

2.后端初始化

​ 1.初始化项目:使用springboot模板初始化,引入依赖,√

​ 2.数据库连接池:druid连接池整合√

​ 3.持久层工具:mybatis-plus整合√

​ 4.数据库连接:数据库连接测试√

​ 5.数据库表:数据库表设计√

三、后端

一、用户表设计

id(主键)bigint

username 昵称 varchar

userAccount 登录账号

avatarUrl 头像 varchar

gender 性别 tinyint

userPassword 密码 varchar

phone 电话 varchar

email 邮箱 varchar

userStatus 用户状态 int 0 - 正常

createTime 创建时间(数据插入时间)datetime

updateTime 更新时间(数据更新时间)datetime

isDelete 是否删除 0 1(逻辑删除)tinyint

userRole 用户角色 0 - 普通用户 1 - 管理员

二、注册接口

/api/user/register POST

1.用户输入:用户在前端输入账号、密码、校验密码

2.后端校验:校验用户账号、密码、校验密码是否有效

  • 每个都不能为空 √
  • 账号长度不小于4位√
  • 密码不小于8位√
  • 账号不能包含特殊字符√
  • 密码和校验密码相同√
  • 账号不能重复√

3.密码加密:使用sm4算法密码加密√

4.插入数据库表:将该用户insert用户表中√

5.返回数据:对成功数据封装响应类返回

6.测试√
校验错误处都抛出业务异常

三、登录接口

/api/user/login POST

1.用户输入:用户在前端输入账号、密码

2.后端校验:校验用户账号、密码是否有效

3.数据库查询:查询用户,如果user为空则返回

4.查询结果:存在,对前端密码加密和查询到的对比

5.密码正确:为用户设置session

6.返回数据:正确则脱除敏感信息后封装成响应类返回信息

7.测试√

校验错误处都抛出业务异常

四、其他接口

/api/user/current GET // 查询当前用户

/api/user/logout POST // 退出登录

/api/user/selectAll GET // 查询所有

/api/user/remove POST // 删除

...

五、封装常量类

public class UserConstant {
    /**
     * 用户登录态key
     */
    public static final String USER_LOGIN_STATE = "userLoginState";

    /**
     * 普通用户
     */
    public static final int DEFAULT_ROLE = 0;

    /**
     * 管理员
     */
    public static final int ADMIN_ROLE = 1;
}

六、封装通用类

1.封装通用响应类

public class Result<T> implements Serializable {

    private int code;

    private T data;

    private String message;

    private String description;

    public Result(int code, T data, String message) {
        this.code = code;
        this.data = data;
        this.message = message;
    }
    // 以下重载构造函数可以根据自己业务需要书写提供语法糖
     public Result(int code,T data) {
        this(code,data,"成功");
    }
    // 失败不返回数据
    public Result(ErrorCode errorCode){
        this(errorCode.getCode(),null, errorCode.getMessage());
    }
    public Result(ErrorCode errorCode,String description) {
        this.code = errorCode.getCode();
        this.data = null;
        this.message = errorCode.getMessage();
        this.description = description;
    }
    public Result(int code,T data,String message,String description) {
        this.code = code;
        this.data = data;
        this.message = message;
        this.description = description;
    }
}

2.封装工具类创建响应对象

public class ResultUtils {
    // 成功
    public static <T> Result<T> success(T data) {
        return new Result<>(20000,data);
    }

    // 失败
    public static <T> Result<T> err(ErrorCode errorCode) {
        return new Result<>(errorCode);
    }
	 // 以下重载构造函数可以根据自己业务需要书写提供语法糖
    public static <T> Result<T> err(ErrorCode errorCode,String description) {
        return new Result<>(errorCode,description);
    }

    public static <T> Result<T> err(int code,String message,String description) {
        return new Result<>(code,null,message,description);
    }
}

3.封装业务错误码类

public enum ErrorCode {

    NOT_LOGIN(40000,"未登录"),
    PARAMS_ERROR(40001,"请求参数错误"),
    USER_USED_ERROR(40002,"账号已存在"),
    NOT_AUTHORITY(40003,"无权限"),
    NOT_FOUND_ERROR(40004,"未找到"),
    PASSWORD_ERROR(40005,"密码错误"),
    SYSTEM_ERROR(50000,"运行时异常")
    ;


    private int code;

    private String message;
    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;

    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

七、封装业务异常类

业务返回错误处直接抛出异常,在全局异常处理器集中处理异常,并返回给前端

public class BusinessException extends RuntimeException{

    private final int code;
    private final String description;


    public BusinessException(int code, String message, String description) {
        super(message);
        this.code = code;
        this.description = description;
    }

    public BusinessException(ErrorCode errorCode, String description) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
        this.description = description;
    }

    public BusinessException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
        this.description = "";
    }

    public int getCode() {
        return code;
    }

    public String getDescription() {
        return description;
    }
}

八、全局异常处理器

使用spring提供@RestControllerAdvice注解,全局异常控制器处理抛出的异常,使用lombok的@slf4j来记录日志

@Slf4j
@RestControllerAdvice
public class GlobalException {

    @ExceptionHandler(BusinessException.class)
    public Result businessExceptionHandler(BusinessException e) {
        log.error("businessException:",e.getMessage(),e.getDescription());
        return ResultUtils.err(e.getCode(),e.getMessage(),e.getDescription());
    }

    @ExceptionHandler(RuntimeException.class)
    public Result runtimeExceptionHandler(RuntimeException e) {
        log.error("runtimeException:",e);
        return ResultUtils.err(ErrorCode.SYSTEM_ERROR,"运行时异常");
    }
}

九、全局拦截器

实现HandlerInterceptor接口实现preHandle()方法在请求处理前进行全局的处理

@Component
public class GlobalPreInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false); // 参数设置为false,如果Session不存在则返回null
        if (session == null || session.getAttribute(UserConstant.USER_LOGIN_STATE) == null) {
            // Session不存在或用户未登录,可以进行相应的处理
           throw new BusinessException(ErrorCode.NOT_LOGIN,"未登录");
        }
        return true;
    }
}

十、注册拦截器

将全局拦截器注册到配置类中

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private GlobalPreInterceptor globalPreInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(globalPreInterceptor)
                .addPathPatterns("/**") // 拦截所有路径
                .excludePathPatterns("/user/login","/user/register",
                        "/user/logout"); // 不拦截登录路径
    }
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedOriginPatterns("*")
                .allowedMethods("*")
                .allowedHeaders("*")
                .maxAge(3600); // 允许携带身份验证信息
    }
}

十一、多环境

springboot可以根据配置文件后缀识别当前环境,application.yml为基本配置,启用某个环境,环境中与基本配置中相同的属性会覆盖掉,其他的会使用基本配置.
application.yml,application-production.yml,application-test.yml多个配置文件
可通过以下命令来启用某环境配置

java -jar xxxx.jar --spring.profiles.active=production
//启用生产环境配置

四、前端

一、umijs

1.app.tsx 运行时配置
getInitialState()函数

  • 每次初始化getInitialState()会查询当前用户,将一些返回值存入InitialState,全局可取

  • 每次刷新页面都会执行getInitialState()

  • 切换页面不执行

layout: RunTimeLayoutConfig

  • onPageChange()只要改变有路由的页面就会执行,无论手动还是页面的跳转

二、目录结构

.
├── config
│   └── config.ts
├── dist
├── mock
│   └── app.ts|tsx
├── src
│   ├── .umi
│   ├── .umi-production
│   ├── layouts
│   │   ├── BasicLayout.tsx
│   │   ├── index.less
│   ├── models
│   │   ├── global.ts
│   │   └── index.ts
│   ├── pages
│   │   ├── index.less
│   │   └── index.tsx
│   ├── utils 
│   │   └── index.ts
│   ├── services 
│   │   └── api.ts
│   ├── app.(ts|tsx)
│   ├── global.ts
│   ├── global.(css|less|sass|scss)
│   ├── overrides.(css|less|sass|scss)
│   ├── favicon.(ico|gif|png|jpg|jpeg|svg|avif|webp)
│   └── loading.(tsx|jsx)
├── node_modules
│   └── .cache
│       ├── bundler-webpack
│       ├── mfsu
│       └── mfsu-deps
├── .env
├── plugin.ts 
├── .umirc.ts 
├── package.json
├── tsconfig.json
└── typings.d.ts

三、配置文件

umi max提供了很多插件如

export default defineConfig({
	routes,//路由的配置
 	fastRefresh: true,//快速热更新配置
 	model: {},//数据流插件
 	initialState: {},//一个全局的初始数据流,可以用它在插件之间共享数据
	antd: {},//antd 插件
	request: {},//网络请求配置
	access: {},//权限插件
	headScripts: [
    // 解决首次加载时白屏的问题
    {
      src: '/scripts/loading.js',
      async: true,
    },
  ],
    mfsu: {//打包提速
    strategy: 'normal',
  },
  proxy: proxy.dev//代理
})

四、配置代理

将带有/api前缀请求代理到后端地址解决开发时跨域问题,build后失效

export default proxyConfig{
	dev: {
    '/api/': {
      target: 'http://localhost:8080/',
      changeOrigin: true,
    },
  },
}

五、命名空间API内定义类型

如定义响应、注册params、注册响应数据类型

declare namespace API {
    type Response<T> = {
       code: number;
       data: T;
       message: string; 
       description?: string;
    },
    type RegisterParams={
        userAccount:string;
        userPassword:string;
        checkPassword:string;
        type?: string;
  	},
    type RegisterResult = number;
    type CurrentUser = {
        userRole: number;
        ...//其他属性
    }
}

六、封装umi提供的request接口

如下

export async function register(body: API.RegisterParams, options?: { [key: string]: any }) {
  return request<API.Response<API.RegisterResult>>('/api/user/register', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}
...//其他接口

七、request配置多环境

可以配置请求拦截器和相应拦截器,来进行个性化处理,可以配置根据当前环境更改基础请求地址,方便开发

export const request = {
  baseURL: process.env.NODE_ENV==='production'?"https://production.envriment.com":"http://localhost:8080",
  // 请求拦截器
  requestInterceptors: [
    (config) => {
    // 拦截请求配置,进行个性化处理。
      const url = config.url.concat('?token = 123');
      return { ...config, url};
    }
  ],

  // 响应拦截器
  responseInterceptors: [
    (response) => {
       // 拦截响应数据,进行个性化处理
       const { data } = response;
       if(!data.success){
         message.error('请求失败!');
       }
       return response;
    }
  ]
};

八、权限管理

/src/access.ts是默认的权限定义文件

// /src/access.ts
export default function access(initialState: { currentUser?: API.CurrentUser } | undefined) {
  const { currentUser } = initialState ?? {};
  return {
    canAdmin: currentUser && currentUser.userRole === 1,
  };
}

路由配置文件中,只有是canAdmin才能访问/admin路径下页面

export default[
    { path: '/welcome', name: '欢迎', icon: 'smile', component: './Welcome' },
    {
        path: '/admin',
        name: '管理页',
        icon: 'crown',
        access: 'canAdmin', // 只有canAdmin能访问
        routes: [
          { path: '/admin', redirect: '/admin/user-manage' },
        ],
      },
]

九、加入注册、用户管理页面

/src/pages/目录是页面目录,在该目录下加入自己需要的页面。需要其他组件在/src/components/ 目录下进行开发或引入

五、前后端联调

对已有接口进行前后端联调,检查bug,解决

六、前后端分离,跨域解决

一、nginx配置代理解决跨域

location ^~ /api/ { 
    proxy_pass http://127.0.0.1:8080/api/;
    add_header 'Access-Control-Allow-Origin' $http_origin; 
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; 
    add_header Access-Control-Allow-Headers '*'; 
    if ($request_method = 'OPTIONS') { 
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Origin' $http_origin; 
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X- Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; 
        add_header 'Access-Control-Max-Age' 1728000; 
        add_header 'Content-Type' 'text/plain; charset=utf-8'; 
        add_header 'Content-Length' 0; return 204; 
    } 
}

二、后端解决跨域问题

1.配置 @crossorigin 注解

@CrossOrigin(origins = { "http://xxx.com/"}, methods = { RequestMethod.DELETE },allowCredentials = "true")
  • origins: 同样是指定允许跨域请求的源,即允许访问资源的域名。在这里,同样只允许来自 "http://xxx.com" 的跨域请求。
  • methods: 允许请求的方法。
  • allowCredentials: 指定是否允许发送身份验证信息(例如 cookie)到目标域。在这里设置为 true,表示允许发送身份验证信息。

2.在web全局请求拦截器配置

@Configuration
public class WebMvcConfg implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //设置允许跨域的路径
        registry.addMapping("/**")
                //设置允许跨域请求的域名 
                //当**Credentials为true时,**Origin不能为星号,需为 具体的ip地址【如果接口不带cookie,ip无需设成具体ip】 
                .allowedOrigins(
            	"http://127.0.0.1:9527", 
           		"http://127.0.0.1:8082",
                "http://127.0.0.1:8083")
                //是否允许证书 不再默认开启 
                .allowCredentials(true) 
                //设置允许的方法 
                .allowedMethods("*")
                //跨域允许时间 
                .maxAge(3600);
    }
    // 或
     @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            //当 Credentials为true时,Origin不能为星号,需为 具体的ip地址【如果接口不带cookie,ip无需设成具体ip】,使用allowedOriginPatterns可以带*
                .allowedOriginPatterns("*")
           		 //设置允许的方法 
                .allowedMethods("*")
               	//指定是否允许发送身份验证信息(例如 cookie)到目标域
                .allowCredentials(true)
             	//跨域允许时间 
            	.maxAge(3600); // 允许携带身份验证信息
	}

}

七、nginx配置ssl

这个配置文件最后引入到nginx.conf主配置文件的http区域中

server {
	#SSL 默认访问端口号为 443
	listen 443 ssl;
	#请填写绑定证书的域名
	server_name example.com; 
 
	# gzip config
	gzip on;
	gzip_min_length 1k;
	gzip_comp_level 9;
	gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
	gzip_vary on;
	gzip_disable "MSIE [1-6]\.";

	root /usr/share/nginx/html;
	index index.html index.htm;
	include /etc/nginx/mime.types;
    	  
	#请填写证书文件的相对路径或绝对路径 注意容器nginx配置路径是挂载对应目录
	ssl_certificate /ssl/domain_bundle.crt; 
	#请填写私钥文件的相对路径或绝对路径
	ssl_certificate_key /ssl/domain.key; 
	ssl_session_timeout 5m;
	#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
	ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;

	#请按照以下协议配置
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_prefer_server_ciphers on;
    // 网关支持
    location ^~ /api/ { 
		rewrite ^/api(.*)$ $1 break;
		proxy_pass http://172.17.0.1:8080/;
		add_header 'Access-Control-Allow-Origin' $http_origin; 
		add_header 'Access-Control-Allow-Credentials' 'true';
		add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; 
		add_header Access-Control-Allow-Headers '*'; 
		if ($request_method = 'OPTIONS') { 
		add_header 'Access-Control-Allow-Credentials' 'true';
		add_header 'Access-Control-Allow-Origin' $http_origin; 
		add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
		add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X- Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; 
		add_header 'Access-Control-Max-Age' 1728000; 
		add_header 'Content-Type' 'text/plain; charset=utf-8'; 
		add_header 'Content-Length' 0; return 204; 
} 
}
    location / {
		try_files $uri /index.html;
    }
    if ($host != "example.com") {  
        return 403;  # 如果请求的域名不匹配,返回 403 禁止访问
    }

}

server {
	listen 80;
	#请填写绑定证书的域名
	server_name example; 
	#把http的域名请求转成https
	return 301 https://$host$request_uri; 
}

八、多方式部署上线

一、原生部署

1.前端:在服务器端手动安装nginx

或者:centos直接用yum下载不需要下面这么麻烦,

使用yum直接下载nginx,将构建的dist目录放在配置的root目录下 √

# 下载 nginx curl -o nginx-1.21.6.tar.gz http://nginx.org/download/nginx-1.21.6.tar.gz # 解压 nginx tar -zxvf nginx-1.21.6.tar.gz # 进入 nginx 目录
cd nginx-1.21.6 # 安装 nginx 需要的环境 
yum install pcre pcre-devel -y
yum install openssl openssl-devel -y
yum -y install gcc-c++
# 配置文件检查 
./configure --with-http_ssl_module --with-http_v2_module --with-stream
# 编译 
make 
make install
# 查看是否有 nginx 的可执行文件
ls /usr/local/nginx/sbin/nginx
# 配置全局环境变量, shift+g 定位到最后一行,再按 o 在最后一行插入
vim /etc/profile 
#在最后一行添加:export PATH=$PATH:/usr/local/nginx/sbin 
#修改环境变量后执行:source /etc/profile
# 启动nginx
nginx 
# 查看启动情况 
netstat -ntlp #查看启动情况 
# 修改 nginx 配置后,需要运行如下命令,才生效
nginx -s reload

#####
#补充:后端打包后。将编译好的文件压缩为zip
#使用命令解压压缩文件到指定目录
unzip dist.zip -d your_project_directory
#随后进入其中的dist目录使用命令
mv * ../
#将dist目录的所有文件移至外层即your_project_directory目录,并对dist文件夹进行删除
#随后我们对nginx.conf配置文件进行更改
#tips好习惯:在对配置文件进行更改的时候,先对配置文件进行备份
cp nginx.conf nginx.default.conf
#使用自带的vim编译器进行编辑
vim nginx.conf
#tips :报错退出  esc + :wq    
#i 插入模式  o 新增一行
#主要对user进行编辑,修改默认值为root,同时修改lcoation下的root 后为我们解压好的目录
#随后移动这个文件
cp nginx.conf /usr/local/nginx
mv nginx.conf ./conf/
#随后开启nginx服务器,访问服务器的默认公网地址即可
nginx

后端:下载好java,将打包好的jar传到linux服务器,linux下载java,直接命令启动√

// 运行 jar 包
jar -jar ./Your_project.jar --server.port=8080 -spring.profiles.active=production
// 后台运行
# 后台运行 jar 包
nohup java -jar ./Your_project.jar --server.port=8080 -- spring.profiles.active=production & 

jps:查看所有运行的java程序

二、宝塔面板部署

非常方便简单

三、docker容器部署

前端

1.Dockerfile 根据自己需求书写
// Dockerfile
# 使用 NGINX 官方提供的稳定版作为基础镜像
FROM nginx:stable

# 暴露 NGINX 默认的 HTTP 端口
EXPOSE 80

# 在容器启动时自动启动 NGINX 服务
CMD ["nginx", "-g", "daemon off;"]
2.构建镜像,运行
  • 将dockerfile、dist、nginx配置文件放在目录中进行构建镜像

  • 构建镜像:docker build -t project_name:version .

  • 运行容器配置挂载目录,宿主机挂载目录根据自己需求而定

  • docker run -id --name=Your_project_name -p 80:80 -v /service/your_project/dist:/usr/share/nginx/html  -v /service/your_project/logs:/var/log/nginx  -v /service/your_project/nginx:/etc/nginx/conf.d -v 
    /service/your_project/ssl:/ssl 镜像:版本
    

后端

1.Dockerfile 根据自己需求书写
# 使用 maven jdk8作为基础镜像
FROM maven:3.5-jdk-8-alpine as builder

# 指定工作目录/app,cp pom.xml和src ==》 /app目录下
WORKDIR /app
COPY pom.xml .
COPY src ./src

# maven打包跳过测试
RUN mvn package -DskipTests

# 运行,指定环境
CMD ["java","-jar","/app/target/your_project.jar","--spring.profiles.active=production"]
2.构建镜像,运行
  • 如果项目在github仓库中直接clone过来,否则自己打包上传

  • 构建镜像:docker build -t project_name:version .

  • 运行容器配置挂载目录,宿主机挂载目录根据自己需求而定

  • docker run -id --name=Your_project_name  镜像:版本
    

四、云平台托管

云服务商容器平台(腾讯、阿里、微信云)等,可快速部署,更省心省力,注意收费规则

容器平台的好处:

  1. 不用输命令来操作,更方便省事

  2. 不用在控制台操作,更傻瓜式、更简单

  3. 大厂运维,比自己运维更省心

  4. 额外的能力,比如监控、告警、其他(存储、负载均衡、自动扩缩容、流水线)

九、域名绑定,开放端口

一、注册域名

到各大运营商(腾讯、阿里等)注册想要的域名

二、域名解析

将域名解析到服务器地址,nginx绑定相应server_name,如果是云托管平台,使用CNAME解析到平台提供的地址上

三、服务器防火墙开放相应端口

Github+PicGo+Typora构建图床


title: Github+PicGo+Typora构建图床
date: 2024-04-11 19:48
updated: 2024-04-11 19:48
category: 开发记录
tags:

Github+PicGo+Typora构建图床

一、创建Github仓库

二、点击头像,选择Settings

三、选择左侧栏Developer Settings

四、选择Tokens

五、生成新token

六、填个Note (随便填),只勾选repo即可,点击最下面Generate token

七、保存好token,只显示一次

八、Github下载开源的PicGo

九、配置PicGo的GitHub设置

  • 图床配置名: 随意
  • 仓库名为: 用户名/仓库名
  • 分支: 你的分支
  • token: 刚才生成的token
  • 存储路径: 上传仓库中图片目录
    • 设置路径为 pictures,地址返回为
    • https://raw.githubusercontent.com/${your_github_account}/Images/main/pictures/xxx.png
  • 自定义域名: https://cdn.jsdelivr.net/gh/GitHub账号名/仓库名 可以配置cdn
  • https://cdn.jsdelivr.net/gh/是 jsDelivr 的 CDN(内容分发网络)服务地址,可以用于托管 GitHub 仓库中的文件和资源。通过这个地址,你可以直接访问 GitHub 仓库中的文件,而无需使用 GitHub 网站或者 Git 工具

PicGo文档https://picgo.github.io/PicGo-Doc/

十、配置Typora自动自动上传

  • 点击文件==>偏好设置

  • 正常从本地引入图片,引入后出现下拉列表,点击上传图片,可自动上传

Java


title: Java
author: yeguo
date: 2023-08-24 17:41
updated: 2023-08-24 17:41
category: 知识笔记
tags:

  • java

字符串

一、Collection

1.boolean add(E e)e

​ 把给定对象添加到当前集合中

2.void clear()

​ 清空集合中所有元素

3.boolean remove(E e)

​ 把给定的对象在当前集合中删除

4.boolean contains(Object obj)

​ 判断当前集合中是否包含给定的对象

5.boolean isEmpty()

​ 判断当前集合是否为空

6.int size()

​ 返回集合中元素的个数

二、List

1.void add(int index,E element)

​ 在此集合中的指定位置插入指定的元素

2.E remove(int index)

​ 删除指定索引处的元素,返回被删除的元素

3.E set(int index,E element)

​ 修改指定索引处的元素,返回被修改的元素

4.E get(int index)

​ 返回指定索引处的元素

三、TreeSet

1.add(E e)

2.first()

​ 返回集合中第一个元素

3.last()

​ 返回集合中最后一个元素

4.higher(E e)

​ 返回集合中严格大于给定元素的最小元素

5.lower(E e)

​ 返回集合中严格小于给定元素的最大元素

6.pollFirst()

​ 移除并返回集合中的第一个元素

7.pollLast()

​ 移除并返回集合中的最后一个元素

三、ListIterator

​ 在原迭代器基础上添加了可以添加元素方法add()

四、Map

​ 键唯一,值不一定

1.v put(k key, v value)

​ 添加元素,返回被覆盖的元素

2.v remove(Object key)

​ 根据键删除键值对元素

3.void clear()

​ 移除所有的键值对元素

4.boolean containsKey(Object key)

​ 判断集合是否包含指定的键

5.boolean containsValue(Object value)

​ 判断集合是否包含指定的值

6.boolean isEmpty()

​ 判断集合是否为空

7.int size()

​ 集合的长度,也就是集合中键值对的个数

五、集合继承结构图

七、Map继承结构图

八、Stream流

1.单列集合

​ Collection中默认方法 default Stream stream() //创建流

2.双列集合

​ 无,先将键值对转为集合使用Collection的stream()方法 //创建流

3.数组

​ 使用Arrays工具类的静态方法stream() //创建流

4. 零散数据

​ 使用Stream接口中的静态方法stream() //创建流

5.Stream流中间方法

​ 1.Streamfilter(Predicate<? super T> predicate) 过滤

​ 2.Stream limit(long maxSize) 获取前几个元素

​ 3.Stream skip(long n) 跳过前几个元素

​ 4.Stream distinct() 元素去重,依赖(hashCode和equals方法)

​ 5.static Stream concat(Stream a, Stream b) 合并a、b两个流为一个流

​ 6.Stream map(Function<T,R> mapper) 转换流中的数据类型

注意:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
修改Stream流中的数据,不会影响原来集合或者数组中的数据

6.Stream流终结方法

​ 1.void forEach(consumer action) 遍历

​ 2.long count() 统计

​ 3.toArray() 收集流中数据放到数组中

​ 4.collect(Collector collector) 收集流中数据,放到集合中

九、方法引用::(引用符)

1.方法引用条件

​ 1.引用处必须是函数式接口

​ 2.被引用的方法必须已经存在

​ 3.被引用的方法的形参和返回值需要跟抽象方法保持一致

​ 4.被引用方法的功能要满足当前需求

2.方法引用分类

1.引用静态方法

​ 格式:类名::静态方法

​ 范例:Integer::parseInt

2.引用成员方法

​ 格式:对象::成员方法

​ 其他类:其他类对象::方法名

​ 本类: this::方法名 // 静态方法中没有this,需要new一个本类的对象调用

​ 父类: super:: 方法名 //静态方法中没有super ,需要new一个本类的对象调用

3.引用构造方法

​ 格式:类名::new

​ 范例:Student::new

4.其他调用方式

​ 1.使用类名引用成员方法

​ 格式:类名::方法名

​ 范例:String::toUpperCase

​ 规则:
1.需要有函数式接口
​ 2.被引用的方法必须已经存在
​ 3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持 一致,返回值需要保持一致。
​ 4,被引用方法的功能需要满足当前的需求

抽象方法形参的详解:
第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法
在Stream流当中,第一个参数一般都表示流里面的每一个数据。
假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能 引用String这个类中的方法

第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法

总结:如果抽象方法的第一个参数是A类型的只能引用A类中的方法,被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。

​ 2.引用数组的构造方法

​ 格式:数据类型[]::new

​ 范例:int[]::new

​ 创建一个指定类型的数组

​ 细节:数组的类型,需要跟流中数据的类型保持一致。

十、异常

1.结构图

运行时异常和编译时异常的区别?
编译时异常:除了RuntimeExcpetion和他的子类,其他都是编译时异常
编译阶段需要进行处理,作用在于提醒程序员
运行时异常:RuntimeException本身和所有子类,都是运行时异常。编译阶段不报错, 是程序运行时出错的,一般是由于参数传递错误带来的问题

2. Throwable的成员方法

​ 1.public String getMessage() 返回此throwable的详细消息字符串

​ 2.public String toString() 返回此可抛出的简短描述

​ 3.public void printStackTrace() 把异常的错误信息输出在控制台

十一、File

1.三个构造方法

  • public File(String pathname) 根据文件路径创建文件对象
  • public File(String parent,String child)根据父路径名字符串和子路径名字符串创建文件对象
  • public File(File parent,String chilld) 根据父路径文件对象和子路径名字符串创建文件对象

2.常见成员方法

delete方法细节

  • 如果删除的是文件,则直接删除,不走回收站。
  • 如果删除的是空文件夹则直接删除,不走回收站
  • 如果删除的是有内容的文件夹,则删除失败

  • 当调用者File表示的路径不存在时,返回null
  • 当调用者File表示的路径是文件时,返回null
  • 当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
  • 当调用者File表示的路径是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回
  • 当调用者Fil表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
  • 当调用者File表示的路径是需要权限才能访问的文件夹时,返回nu

十二、IO流

一、什么是I0流?

  • 存储和读取数据的解决方案
    I : input
    O: output
    流:像水流一样传输数据

2.10流的作用?

  • 用于读写数据(本地文件,网络)》

3.O流按照流向可以分类哪两种流?
输出流:程序 --->文件
输入流:文件---->程序
4.IO流按照操作文件的类型可以分类哪两种流?
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
5.什么是纯文本文件?
用windows.系统自带的记事本打开并且能读懂的文件
txt文件,md文件,ml文件,lrc文件等

二、字节流

三、编码规则

默认为UTF-8

四、字符流

字符流原理解析
①创建字符输入流对象
底层:关联文件,并创建缓冲区(长度为8192的字节数组)
②读取数据
底层:1.判断缓冲区中是否有数据可以读取
2.缓冲区没有数据:就从文件中获取数据,装到缓冲区中,每次尽可能装满 缓冲区如果文件中也没有数据了,返回-1
3.缓冲区有数据:就从缓冲区中读取。
空参的read方法:一次读取一个字节,遇到中文一次读多个字节,把字节解码并转成十进制返回
有参的read方法:把读取字节,解码,强转三步合并了,强转之后的字符放到数组中.

五、应用场景

  • 字节流:拷贝任意类型的文件
  • 字符流:读取纯文本文件中数据,往纯文本文件中写出数据

Ⅱ高级流

六、缓冲流

七、转换流

1.转换流的名字是什么?

  • 字符转换输入流:InputStreamReader
  • 字符转换输出流:OutputStreamWriter

2.转换流的作用是什么?

  • 指定字符集读写数据(UDK11之后已淘汰)
  • 字节流想要使用字符流中的方法了

八、序列化流

boyohc.png

九、打印流

76pkuu.png

xth71q.png

xvzuwo.png

6lyzg7.png

1.打印流有几种?各有什么特点?

  • 有字节打印流和字符打印流两种
  • 打印流不操作数据源,只能操作目的地
  • 字节打印流:默认自动刷新,特有的println自动换行
  • 字符打印流:自动刷新需要开启,特有的println自动换行

十、解压缩流

十一、多线程

4d6gft.png

一、生命周期

z2ww8b.png

cjw0sw.png

x9ofvr.png

十二、网络编程

十三、反射

1.获取class对象的三种方式

gys1m5.png

2.利用反射获取构造方法

4usg73.png

3.利用反射获取成员变量

lkpspg.png

4.利用反射获取成员方法

f3y5en.png

5.总结

wcl7gq.png

十四、动态代理

Mysql数据库远程登录失败


title: Mysql数据库远程登录失败
date: 2024-04-09 09:56
updated: 2024-04-09 09:56
category: 技术杂谈
tags:

  • bug
  • mysql

连接数据库报错:Access denied for user ‘root‘@ ‘xxx‘ (using password: YES)

本地的数据库,其他IP地址的访问都是没有权限的,需要的本机用户给予权限才能访问到。

  • 首先登录自己数据库

  • 执行授权

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '您的密码' WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '' WITH GRANTOPTION;
  • 重启服务

Github添加ssh


title: Github添加ssh
date: 2024-04-11 18:10
updated: 2024-04-11 18:10
category: 技术杂谈
tags:

  • git
  • ssh

一、生成ssh密钥

ssh-keygen -t rsa -b 4096 -C "${your_email}@example.com"

your_email 是你的邮箱名

二、输入保存密钥的文件位置,默认为/Users/your_user/.ssh/目录下

Enter file in which to save the key (/c/Users/${your_user}/.ssh/id_rsa):

your_user 是你的用户名

三、若生成过密钥,提示是否覆盖,选择y

/c/Users/${your_user}/.ssh/id_rsa already exists.
Overwrite (y/n)? y

your_user 是你的用户名

四、提示输入密钥密码

Enter passphrase (empty for no passphrase):
Enter same passphrase again:

五、点击头像选择Settings

六、从/Users/${your_user}/.ssh/ 找到id_rsa_pub把公钥粘贴到如示,Add SSH Key

七、测试ssh是否添加成功

$ ssh -T [email protected]
// 输入你之前生成ssh密钥时输入的密码
Enter passphrase for key '/c/Users/${your_user}/.ssh/id_rsa':

your_user 是你的用户名

出现

Hi ${your_github_account}! You've successfully authenticated, but GitHub does not provide shell access.

your_github_account 是你的github账号

表示成功

Docker常用命令


title: Docker常用命令
date: 2023-07-27 17:28
updated: 2023-07-27 17:28
category: 开发记录
tags:

  • docker

#启动docker服务
systemctl start docker
#停止docker服务
systemctl stop docker
#重启docker服务
systemctl restart docker
#查看docker服务状态
systemctl status docker
#设置开机启动docker服务
systemctl enable docker
#查看镜像
docker images
docker images -q # 查看所有镜像的id
#搜索镜像
docker search 镜像名称
#拉取镜像
docker pull 镜像名称/镜像名称:版本号
#删除镜像
docker rmi 镜像id/名称 # 删除指定本地镜像
docker rmi `docker images -q` # 删除所有本地镜像
#查看容器
docker ps # 查看正在运行的容器
docker ps -a # 查看所有容器
docker ps -aq # 查看所有容器id
#创建并启动容器
docker run 参数
docker run -it --name=x1 镜像 /bin/bash #
docker run -id --name=x2 镜像
# -i:保持容器运行,通常与-t同时使用,加it两个参数后,容器创建后自动进入容器,退出后容# 器自动关闭
# -t:为容器重新分配一个伪输入终端,通常与-i同时使用
# -it创建的容器一般称为交互式容器,-id创建容器一般称为守护式容器
# exec在后台运行时进入容器
docker exec -it c1 /bin/bash # 例 退出后容器不会关闭
# --name:为创建的容器命名
# -d 后台运行
#-i 参数表示以交互模式(Interactive Mode)运行容器允许你与容器的主进程进行交互
#停止容器
docker stop 容器名称
#启动容器
docker start 容器名称
#删除容器
docker rm 容器名称
docker rm `docker ps -aq` # 删除所有容器
#查看容器信息
docker inspect 容器名称
#配置数据卷
docker run -it --name=x2 -v 宿主机目录(文件):容器内目录(文件) 镜像
#配置数据卷容器
# 创建c3数据卷容器
docker run -it --name=c3 -v /volume 镜像 /bin/bash
# 创建c1、c2容器,使用--volumes-from设置数据卷
docker run -it --name=c1 --volumes-from c3 镜像 /bin/bash
docker run -it --name=c2 --volumes-from c3 镜像 /bin/bash
#docker应用部署
# 搜索镜像
docker search 应用镜像
# 拉取镜像
docker pull 应用镜像
# 创建容器,设置端口映射和数据卷映射,第一个80是宿主机端口号
docker run -id --name=xxx -p 80:80 -v 宿主机目录:容器内目录    应用镜像 
#镜像制作
# 将容器制作成镜像
docker commit 容器id/镜像名称:版本号
# 将镜像压缩
docker save -o 压缩文件名称 镜像名称:版本号
# 将压缩解为镜像
docker load -i 压缩文件名称
#dockerfile
关键字 作用 备注
FROM 指定父镜像 指定dockerfile基于那个image构建
MAINTAINER 作者信息 用来标明这个dockerfile谁写的
LABEL 标签 用来标明dockerfile的标签 可以使用Label代替Maintainer 最终都是在docker image基本信息中可以查看
RUN 执行命令 执行一段命令 默认是/bin/sh 格式: RUN command 或者 RUN ["command" , "param1","param2"]
CMD 容器启动命令 提供启动容器时候的默认命令 和ENTRYPOINT配合使用.格式 CMD command param1 param2 或者 CMD ["command" , "param1","param2"]
ENTRYPOINT 入口 一般在制作一些执行就关闭的容器中会使用
COPY 复制文件 build的时候复制文件到image中
ADD 添加文件 build的时候添加文件到image中 不仅仅局限于当前build上下文 可以来源于远程服务
ENV 环境变量 指定build时候的环境变量 可以在启动的容器的时候 通过-e覆盖 格式ENV name=value
ARG 构建参数 构建参数 只在构建的时候使用的参数 如果有ENV 那么ENV的相同名字的值始终覆盖arg的参数
VOLUME 定义外部可以挂载的数据卷 指定build的image那些目录可以启动的时候挂载到文件系统中 启动容器的时候使用 -v 绑定 格式 VOLUME ["目录"]
EXPOSE 暴露端口 定义容器运行的时候监听的端口 启动容器的使用-p来绑定暴露端口 格式: EXPOSE 8080 或者 EXPOSE 8080/udp
WORKDIR 工作目录 指定容器内部的工作目录 如果没有创建则自动创建 如果指定/ 使用的是绝对地址 如果不是/开头那么是在上一条workdir的路径的相对路径
USER 指定执行用户 指定build或者启动的时候 用户 在RUN CMD ENTRYPONT执行的时候的用户
HEALTHCHECK 健康检查 指定监测当前容器的健康监测的命令 基本上没用 因为很多时候 应用本身有健康监测机制
ONBUILD 触发器 当存在ONBUILD关键字的镜像作为基础镜像的时候 当执行FROM完成之后 会执行 ONBUILD的命令 但是不影响当前镜像 用处也不怎么大
STOPSIGNAL 发送信号量到宿主机 该STOPSIGNAL指令设置将发送到容器的系统调用信号以退出。
SHELL 指定执行脚本的shell 指定RUN CMD ENTRYPOINT 执行命令的时候 使用的shell
#基于dockerfile构建镜像
docker build -f dockerfile -t centos:7 . 
-f :指定dockerfile 文件(默认不写的话指的是当前目录)
-t :镜像名和标签

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.