Linux
Linux的是类Unix系统,作者是Linus,也是git的作者。符合GPL(General Public License)就可以Linux的使用、修改、再发布。
Linux四部分:
- 内核:驱动、内存管理、进程管理、文件系统、网络协议栈…。作用:管理硬件和提供最基本的系统服务
- 系统库:libc(C标准库)、libm(数学库)、libdl(动态链接库)、libpthread(线程库)、第三方库…。作用:提供常用函数和接口供开发使用。
- shell:用户使用Linux的接口
- 应用程序:Google、Vim、Git、MySQL、Nginx
Linux的发行版还包括包管理器(apt\yum)、GUI、系统工具等,比如Ubuntu(个人用户)、Debian、CentOS、Kali(网络安全和渗透测试)
安装Linux:
- 虚拟机工具:VMware、VirtualBox、Hyper-V(window的WSL)、Multipass
- Docker
- 云服务器
Linux根目录:
- bin、sbin:可执行二进制文件
- home、root
- usr、opt、etc、
- lib\lib32\lib64、dev、mnt
- boot、sys、proc
- var、temp
Vim
一般服务器没有图形界面,只能使用Vim编辑器。vim是vi的提升版本(improved)。apt install vim -y
命令模式:
a\A i\I o\O
表示进入插入模式,:
表示进入尾行模式。插入模式、尾行模式按ESC进入命令模式。- 移动光标:
h j k l
表示左下上右;ctrl + f/b/d/u
表示下页、上页、下半页、上半页;^ $
表示行首、行末。gg G 3g
表示首行、尾行、第三行。:3
表示第三行。 3yy
表示复制三行;3dd
表示删除三行,D
表示清空本行;3p
表示复制三次粘贴板上的内容。ctrl + r
表示撤回,u
表示重做。
行末模式:
- 查找:
/hello | ?hello
表示向下、向上查找。n | N
表示下一个、上一个。/hello\c
表示无视大小写 - 替换:
:2,5s/hello/world/g
表示2,5行,g表示此行全部。:s/hello/world
表示此行第一个替代。:%s/hello/world
表示每行第一个替代。
还有~\.vimrc
文件:可以设置一些常用的
set nu # set nonu
syntax on
set ic # 忽略大小写
tip:vimrc中rc表示run commands。
常用命令
ls -haltri # i:inode节点、t:time、r:reverse
echo "hello world" > hello.txt # 覆盖文件之前的内容
echo "second" >> hello.txt # 追加文件内容
touch hello.txt # 创建文件、更新文件时间
cat hello.txt
ln -s hello.txt hello_soft.txt # 软连接
ln hello.txt hello_hard.txt # 硬连接
# 硬连接:文件; 软连接:文件或目录
# 权限
chmod u+x hello.txt # ugoa +- rwx
chmod 777 hello.txt # 等效
chmod root:root file # 修改 所有者:所属组
mkdir dir # 删除空目录 rmdir dir
mkdir -p dir1/dir2 # rm -r dir1。linux删除不可逆
cp -r dir1 dir_copy
mv hello.txt dir/hello_move.txt
date whoami pwd tree
du # 目录
df -h # 磁盘
which ls
# 安装jdk1.8(java8)
apt list | grep jdk
sudo apt install openjdk-8-jdk
java -version
# 解压
tar -xvzf file.tgz
inode:文件类型、权限、所有者、文件大小、时间戳、数据块指针。
命令
ps -ef # e表示所有 f表示信息
# 其中tty表示Teletypewriter, tty1,tty2表示物理终端界面; ?表示没有终端相连
# 文件和进程的关系
lsof -u root -p 1234 # 打开文件list,root中进程为1234所打开的文件
lsof file # 哪些进程在使用file
lsof -i :80 # 查看80端口的进程
lsof -i tcp # 或者udp
# FD文件描述符: cwd/rtd/dir/txt/NOFD/mem/pipe/socket/chr/blk
# TYPE: REG(常规文件)DIR(目录)CHR(字符设备)
Shell
脚本的作用:定时处理(比如定时清理、定时备份)、批处理…
Shell种类:sh、bash(默认)、csh、ksh、zsh、powershell。可以cat /etc/shells
查看。
.profile
和 .bashrc
:用户打开bash前会使用这两个文件进行初始化环境。配置之后使用. bashrc 或 source .bashrc
/etc/bash
下的文件是对所有用户都有效。
环境变量
echo $SHELL # 默认bash
echo $HOME
echo $PATH
echo $0 # 表示当前的shell解释器。默认bash
export name=adair # 在运行的shell中就可以获取
常用的$:
- $0、$1、 2 、 2、 2、#:表示文件名、第一个参数、第二个参数、参数个数
- ∗ 、 *、 ∗、@:前者表示作为整体;后者表示按参数传递
- ? 、 ?、 ?、 、 、 、!:表示最后一个命令返回的结果;表示此进程PID;最后一个后台命令的PID
if中的数字比较:eq、ne、lt、le、gt、ge。
if中的字符串比较[[ "$str1" == "$str2" ]]
:!=、>、== *、=~、-z、-n
举个例子
#!/bin/bash # 默认解释器
is_prime() {
local num=$1 # 局部变量必须使用local,否则为全局变量
if [ $num -lt 2 ]; then
return 1
fi
for ((i=2; i*i<=num; i++)); do
if [ $((num % i)) -eq 0 ]; then
return 1
fi
done
return 0
}
read -p "输入数字:" number
if ! [[ "$number" =~ ^[0-9]+$ ]]; then # 正则表达式符
echo "no number"
exit 1
fi
if is_prime $number; then # 函数返回0表示OK
echo "$number 是素数"
else
echo "$number 不是素数"
fi
猜数字
#!/bin/bash
# 等效 $(($RANDOM%10+1))
number=$(shuf -i 1-10 -n 1) # 也可以使用反引号
echo "随机数为$number"
while true; do
echo "输入猜的值"
read guess
if [[ $guess -eq $number ]]; then
echo "对了, 请选择是否继续y/n"
read choice
if [[ $choice = "y" ]] || [[ $choice = "Y" ]]; then
number=$(($RANDOM % 10 + 1))
echo "随机数为$number"
continue
else
break
fi
elif [[ $guess -lt $number ]]; then
echo "小了"
else
echo "大了"
fi
done
管道:
如果输入bash confirm.sh
,则会一直循环输入。可以直接yes | bash confirm.sh
#!/bin/bash
for ((i=0; i<3; i++)); do
read -p "输入y|n" flag
echo "i=$i flag=$flag"
if [ "$flag" == "y" ]; then
continue
fi
done
shell也可以结合:
- grep awk sed 等文本处理
- 函数和数组等高级特性。
- 系统管理和监控
RegEx
基本字符匹配:.、[ ]、[^ ]、|、
字符类:\d、\w、\s、\D、\W、\S。定位符:^、$、\b、\B、
量词:?、+、*、{n}、{n,m}、{n,}。贪婪匹配:ab{3,}、ab{3,}?
旗帜:i、m、s、g、
分组:(abc)、(?:abc)
前瞻:dog(?=cat)、dog(?!cat)。后顾:(?<=cat)dog、(?<!cat)dog
前面的字符都是有特定意义的,如果需要这个字符本身,需要进行转义。但是转义字符同样需要转义\\
。
基本类型:^$. [1-8B-Yc-x] [^] | \d \w \b \s \大写
量词:? + * {n} {n,m} {n,} {n,}?
前瞻:dog(?=cat) dog(?!cat) 后顾:(?<=cat)dog (?<!cat)dog
分组:(abc) (?:abc)。\1
旗帜:i\g\s\m
部分解释:
.
匹配除\n
的任意字符,s
让.
也可匹配\n
^$
表示文本开始和结束。m
让^$
表示每行开始和结束。\b
:比如\b\d+\b
匹配%300
而不是s300
其他版本的RE:
- POSIX基本的BR、扩展的ERE。
- 其他版本的比如Python、Java、JS等。具体情况看文档。
拓展结合:
- grep 和 sed 和 awk
Git
版本控制系统:集中式(比如:SVN)、分布式(比如Git)
Git的使用方式:命令行、GUI、IDE插件/扩展。
git配置:
# system 系统配置/etc/gitconfig:对所有用户生效。global 全局配置~/.gitconfig:所有仓库生效。 不带范围.git/config:默认此仓库
git config --global user.name "adair"
git config --global user.email "123@qq.com"
git config --global credential.helper store # 存储密码,不用git push每次都要输入密码
git config --global --list # 查看属性
.gitignore的内容:
- 中间文件或者结果文件,class文件\o文件
- log\temp
- user\password、Token等
.a # 忽略所有a类型文件
!lib.a # 不包括lib.a
/TODO # 忽略根目录下的TODO文件
build/ # 忽略任何目录的bulid文件夹
doc/*.o # 忽略doc当前目录下o
doc/**/*.class # 忽略doc所有下的class
不过项目都有相应的模板,不用自己写。https://github.com/github/gitignore
.git/ 文件夹
- config:配置的信息,core、user、branch( -a)
- refs/ (分支):heads/ (本地分支);remotes/(远程);tags/
- index:暂存区指针; HEAD: 版本库中。 指向object/:里面都是对象
- logs/ :HEAD(git log的内容);refs/:相应git branch -a其他所引用的内容
创建仓库:
# 本质都是有.git才是仓库。否则就是个普通文件夹
git init # 把当前文件夹为git仓库
git init local-git # 创建文件夹local-git为git仓库
git clone url # 克隆
git clone git@github.com:name/repo.git
git clone git@192.168.8.242:v40_7.1.git
添加和提交
# 工作区、暂存区、本地库。push 远程库
ls # 工作区ls
git ls-files # 暂存区ls
git status # 状态:??(Untracked)、M(modifid)、A(added)、D(deleted)、R(renamed)、U(updated)、
修改file # 返回 git restore file \ git checkout file
git add file # 返回 git restore --staged file \ git reset HEAD(原理) \
git commit -m "message" # -a -v
git commit --amend # 补充提交, 可以-m
git log # --online --graph
版本回退
# 回退之前的版本
git reset --soft commmitID # 指定commitID,且恢复工作区和暂存区
git reset --hard commmitID # 指定commitID的,不恢复
git reset commmitID # 指定commitID,且恢复工作区。默认--mixed
# 从之前的版本到当前版本
git reflog # 查看所有的提交的commitID
# HEAD 当前版本
# HEAD^ HEAD~ 上一个版本
# HEAD~2 上两个版本
内容对比
git diff # 工作区 vs 暂存区
git diff HEAD # 工作区 vs 本地库
git diff commitID1 commitID2 # 两个版本的比较,
git diff commitID1 commitID2 file.txt # 只比较file.txt
# 也可以使用HEAD
git diff 分析
zql@adair-pc:~/git-learn/123$ git diff HEAD
diff --git a/m1 b/m1 # a/m1: 新版 b/m1: 旧版
index 0e6c128..83e9726 100644 # 新版和旧版索引(hash) 100普通文件, 644权限
--- a/m1
+++ b/m1
@@ -1,3 +1,4 @@ # 旧版:1,3行。 新版:1,4行
123456
123
q
+123 # +表示新增的
删除文件
git rm file.txt # 综合 rm file.txt(工作区) 和 git rm --cached file.txt(暂存区)
git mv m1.txt m2.txt # 改名,git status . 出现renamed
分支
git branch # 查看本地分支; -r:remote; -a:all;
git branch dev # 创建分支。git branch -d dev # 删除分支,没有合并则需要D
git checkout/switch dev # 切换分支。checkout -b,创建并切换
# main、dev合并分支,不冲突
git merge dev # 当前在main,则合并dev分支。并且自动会让你输入message,表示一次提交commitID。
# main、feat合并分支,冲突
git merge feat # 此处会把冲突的文件内容合并,重新整理冲突文件。
git commit -am "zql:conflict merge" # 需要重新提交,产生commitID
git merge --abort # 表示终止提交
# rebase
git rebase dev # 表示以dev为根,把main接到dev上。形成直线历史
git rebase main # 同理
git merge dev冲突
# 提示冲突,
<<<<<<< HEAD
456
=======
123
>>>>>>> dev
# 修改冲突之后在进行git commit
通过(github.com gitee.com)账户名和密码的方式克隆remote。
ssh配置,远程克隆到本地:
- 本地生成公钥密钥。
cd ~/.ssh # 切换到~/.ssh下
ssh-keygen -t rsa -b 4096 # rsa类型,4096个bit位数
# 输入相应的名称比如demo,密码demo
# 生成demo.pub,密钥demo
vim config # 增加以下内容
```
Host github.com
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/demo
```
-
把公钥复制到GitHub中。
ssh -T git@gitee.com
测试 -
本地创建一个空仓库,
git remote add origin git@github.com:adair-zhang/learn-github.git
关联远程即可。
tip:这样创建空库再关联太慢了,不如clone。
本地推送到远程:
- GitHub中创建一个空仓库
- 在本地仓库中进行连接GitHub的空仓库
git remote add origin git@github.com:adair-zhang/learn-github.git
git branch -M main # 强制修改当前名(默认为master),修改为main
git push # git push -u origin main 第一次推送到远程。main其实是main(本地):main(远程)缩写
git fetch # 默认git fetch origin main,此时并不在最新的commitID。然后合并git merge
git pull # 等效fetch + merge。默认是git pull origin main
代码托管平台:
- GitHub、gitee、gitlab
- 私有化部署:在自己服务器上部署一个gitlab代码托管平台。可以使用Docker进行部署。
# 比如my-repo是本地关联到github上。
git remote add gitlab git@gitlab.com:name/myrepo.git # 本地再次关联到gitlab上
git remote -v # 可以查看本地关联远程的情况
git push gitlab main # 推送到gitlab
git remote add github2 git@github.com:adair-zhang/first-repo.git # 关联其他仓库
git remote -v # 表示仓库关联的远程信息
git的GUI:GitHub Desktop、SourceTree、GitKraken等
也可以在VS code中进行操作:
- windows安装git
- 然后可以使用vs code中的git
git本质
常用命令
拓展配置:
- post-git
git心得:
commit
之前先review
,查看代码是否错误,规范- 平时开发
test
分支,不要在master
分支
C语言
丹尼斯创造为了Unix编写。
范围:Unix\Linux\Windows、git\vim、MySQL\Redis、Nginx
静态语言:编译时确定变量类型, C\C++\Java\Rust
动态语言:运行时确定变量类型,Python\JavaScript\Ruby\PHP
编译器:
- GCC:GNU Compiler Collection,包含了C、C++、Objective-C、Ada、Go等多种编译器
- Clang:编译C、C++、Objective-C、Objective-C++的编译器前端。采用LLVM为后端,在MacOS下使用
安装开发开发环境:MinGW,安装后 gcc -v
测试。
IDE:CLion、Code::Blocks
VS code
安装好MinGW中的gcc。vs code中不提供编译器。
vs code中然后再增加扩展中,Code Runner
就可以直接运行C的源码了
基本语法
数据类型:
- 基本数据类型:short、int、long、long long、char、float、double
- 派生数据类型:数组、指针、结构体、枚举、共用体、void
#define MAX 100 // 宏定义
int num; // 全局变量,静态变量int默认0
int main(){
int age; // 不赋值,则默认内存的随机值
const double PI = 3.14; // const表示常量
}
tip:sizeof(long)在win中始终是4,linux中sizeof(long)为4(32位系统),为8(64位系统)
goto:
int main() {
for (size_t i = 0; i < 3; i++) {
printf("%d\n", i);
if(i == 1) goto out;
}
out:
printf("hello\n");
}
指针
int main() {
int a = 300;
int *p = &a;
printf("a = %d\n", a);
printf("p = %p\n", p);
printf("*p = %d\n", *p);
printf("p + 1 = %p\n", p+1); // 地址+4字节
int **p2 = &p; // 指向指针的指针。
printf("p2 = %p\n", p2);
printf("*p2 = %p\n", *p2); // 为p的地址
printf("**p2 = %d\n", **p2);
}
数组
int main() {
int arr[5] = {1, 2, 3, 4}; // 默认初始值为0
int *p = arr;
*p = 10; // 修改a[0] = 10
printf("*p = %d\n", *p); // a[0]值
// +1表示指向下一个元素。sizeof(int)=4,所以加4。如果是double,加8
p += 1;
printf("*p = %d\n", *p); // a[1]值
// 二维数组
int b[3][4] = {
{1, 2, 3, 4},
{1, 2, 3, 5},
{1, 2, 3, 6}
};
}
堆栈
int main() {
// 栈内存:比较小,几M ~ 几十M
int a = 1;
int b = 2;
int c = func(a,b);
// 堆内存:很大,可以申请使用
int *p = (int *)malloc(sizeof(int));
*p = 100;
printf("*p = %d", *p);
free(p); // 释放p所指空间,防止内存溢出
p = NULL; // 防止野指针。
}
函数
// Demo1: 函数声明。项目开发中,则会声明函数在头文件,实现函数则文件\库中。
int add(int a, int b); // 声明。也可以int add(int, int)
//或者,直接把实现体放到前面
int main() { }
int add(int a, int b){
return a+b;
}
// Demo2: 函数指针。项目开发中,实现一个回调函数,就把函数指针作为参数传递给另外一个函数,在此使用指针来执行此函数,比如事件处理或消息传递。
#include <stdio.h>
int add(int a, int b){
return a+b;
}
int substract(int a, int b){
return a-b;
}
typedef int (*Operation)(int, int);
int main() {
// 等效 int (*p)(int, int) = add;
Operation p = substract;
printf("%d\n", p(3,4));
}
static
void test() {
static int a = 0;
a += 1;
printf("a=%d\n", a);
}
int main() {
test(); // print a=1
test(); // print a=2
}
// static修饰全局变量和函数时:表示只能在当前文件使用,用于模块封装,防止命名冲突
string
#include <string.h> // 引入头文件
int main() {
// 字符串本身就是字符数组,也可以使用指针表示。
char a[20] = "hi"; // 等效{'h', 'i', '\0'};
char *b = "hello";
printf("%s\n", a);
printf("%s\n", b+1); // 输出:ello
// 字符串函数:strcpy\strcmp\.\strncat\strncpy\strncmp
strcat(a, b);
printf("%s\n", a);
}
结构体struct
typedef struct student {
char name[20];
int age;
float score;
}Student;
int main() {
struct student stu1 = {"Tom", 18, 60.1}; // Student stu1 =...
strcpy(stu1.name, "Tommy");
stu1.age = 19;
printf("%s, %d, %f", stu1.name, stu1.age, stu1.score);
}
共用体union
union student {
// 两个变量共用一个地址。
char name[10];
int age;
};
int main() {
union student stu1;
stu1.age = 97;
printf("%s, %d", stu1.name, stu1.age); // a, 97
}
枚举enum
enum day { // 下面的属性默认从0开始
MON,
TUE,
WED
};
int main() {
enum day day1 = TUE;
printf("%d", day1); // 1
/**
* 亦可
* enum day {
MON = 3,
TUE,
WED
};
*/
}
库引用
// a.h
#ifndef A_H // 解决库重复引用导致的重复定义问题。
#define A_H
int a = 1;
#endif
// b.h
#include "a.h"
// hello.c
#include <stdio.h>
#include "a.h"
#include "b.h"
int main() {
printf("hello %d\n", a); // 如果没有上面的条件编译。报错:重复定义
}
编译链接过程:
- 预处理:
- 头文件和条件编译、宏定义
- 除掉注释
- 编译阶段:源文件转为汇编代码
- 语法检查、类型检查
- 代码优化:常量表达式直接计算出来、删掉无用代码
- 汇编阶段:汇编代码转为机器码(目标文件
.o
) - 链接阶段:把所有目标文件使用的库文件链接起来,形成可执行文件。分为静态链接和动态链接。
- 静态链接:会将库默认直接嵌入到可执行文件中,运行时不再依赖外部库。
- 动态链接:程序运行时加载库。多个程序可以共享一个动态库,节省资源。
库:已经编译好的文件
- 静态库:
.a
(Linux中)、.lib
(win中),并不是只用于静态链接。 - 动态库:
.so
(Linux中)、.dll
(win中),并不是只用于动态链接。
有空再看:
特性 | C | C++ | C# | Objective-C | Objective-C++ |
---|---|---|---|---|---|
编程范式 | 过程化编程 | 面向对象、过程化 | 面向对象 | 面向对象 | 面向对象 + 泛型编程 |
内存管理 | 手动管理 | 手动管理 | 自动垃圾回收 | ARC | ARC + 手动管理 |
平台 | 跨平台 | 跨平台 | Windows、跨平台 | macOS、iOS | macOS、iOS + 跨平台 |
运行时 | 静态编译 | 静态编译 | 静态编译 | 动态运行时 | 动态运行时 |
模板编程 | 无 | 支持模板编程 | 无 | 无 | 支持模板编程 |
使用场景 | 操作系统、嵌入式 | 应用程序开发、游戏 | 企业应用、Web 开发 | macOS、iOS 开发 | 混合 C++ 和 Objective-C |
典型应用 | 操作系统、硬件驱动 | 高性能应用、游戏 | Web 应用、游戏开发 | iOS/macOS 应用开发 | iOS/macOS 应用开发 |
C:如果你需要控制硬件或开发底层系统,C 是最合适的选择。
C++:如果你需要高效且灵活的面向对象编程,并且涉及到复杂的数据结构或系统性能要求,C++ 更为合适。
C#:如果你开发 Windows 应用、Web 应用或跨平台应用,C# 是一个非常现代和高效的选择。
Objective-C:如果你在开发 iOS 或 macOS 应用,Objective-C 是一个必备语言,尤其是在 Swift 出现之前。
Objective-C++:如果你需要结合 C++ 的高效性和 Objective-C 的面向对象特性,尤其是在需要同时调用 C++ 库和 Objective-C 库时,可以使用 Objective-C++。
高级特性
- 如何编译makefile
- gdb调试器
- 栈溢出漏洞
编译运行机制
开发环境
常用工具
使用技巧
Makefile
构建工具make中的makfile相当于 maven中 pom.xml ,Node.js(npm) 中 package.json。
安装:
choco install make // win安装: 位置C:\ProgramData\chocolatey\bin\make.exe
sudo apt install make // linux
基本语法规则:
target: soureces
rules
...
Demo:
目前有源文件
// message.h
void message();
// message.c
#include <stdio.h>
void message() {
printf("hello world\n");
}
// hello.c
#include "message.h"
int main() {
message();
}
makefile
.PHONY: clean all
CFLAGS = -Wall -g -O2
target = hello world
object = hello.o message.o
# source = hello.c message.c
all: hello world
@echo "all done"
$(target): $(object)
gcc $(CFLAGS) $(object) -o $@
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
clean:
rm -f *.o hello
解释:
.PHONY 表明 make clean/all 后面接的是命令,而不是文件(比如有个clean文件)
CFLAGS 设置编译选项,-Wall所有警告,-g调试,-O2中度优化
$(target): $(object)
gcc $(CFLAGS) $(object) -o $@
当所需$(object)没有时,向下查找生成目标。
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
所有的c转为o: message.o 和 hello.o,
message.o: message.c
gcc $(CFLAGS) -c message.c -o message.o
makefile中自动变量:$@ 表示target; $< 表示源文件第一个参数
CMake
makefile 无需手动编写,CMake自动生成,配置文件为 CMakeLists.txt 文件
sudo apt install cmake // linux安装cmake
vs code使用cmake
- 创建CMakeLists.txt
# 常用配置。手写
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
set(SOURCES hello.c message.c)
add_executable(hello ${SOURCES})
- 执行
cmake
命令,自动识别CMakeLists.txt,并生成Makefile文件。 - 依旧执行命令:
make
自动生成可执行文件hello,清理make clean
Maven
Maven 在配置文件 pom.xml (Project Object Model)
- 管理依赖,将依赖jar和依赖的依赖jar的导入项目。手动导入依赖麻烦、可能冲突。
- 构建管理:java源文件 转为 class字节码,然后打包成可执行的jar或者war。执行 构建、打包、部署等工作。
Maven仓库:
- 本地仓库:~/.m2/repository/。本地没有则会去私服和中央仓库中查找并下载到本地,提高效率。
- 私服仓库:公司或组织的仓库,可以私用Nexus构建。非必须的
- 中央仓库:Maven官方仓库
安装:windows中,官网下载bin二进制压缩包,配置环境变量 MAVEN_HOME
和 path。mvn -v
查看版本。
# linux中安装
sudo apt install maven # 自动配置环境变量。
# 如果使用解压包,则.bashrc下
export MAVEN_HOME=../..
export PATH=$MAVEN_HOME/bin:$PATH
配置.\config\settings.xml
<!--配置本地仓库地址-->
<localRepository>D:\environment\apache-maven-3.9.6\mvn_resp</localRepository>
<!--配置中央仓库镜像,由于Maven在国内访问慢-->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
<!--配置对应jdk,可以不配-->
<profile>
<id>jdk-1.4</id>
<activation>
<jdk>1.4</jdk>
</activation>
<repositories>
<repository>
<id>jdk14</id>
<name>Repository for JDK 1.4 builds</name>
<url>http://www.myhost.com/maven/jdk14</url>
<layout>default</layout>
<snapshotPolicy>always</snapshotPolicy>
</repository>
</repositories>
</profile>
demo
Linux中创建demo:
# 创建mvn项目
mvn archetype:generate -DgroupId=net.geek -DartifactId=maven-sample -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false
# 编译,target下生成class字节码
mvn compile
# 打包:maven-sample-1.0-SNAPSHOT.jar
mvn package
# 运行项目 cp:classpath。输入:Hello World!
java -cp target/maven-sample-1.0-SNAPSHOT.jar net.geek.App
IDEA中创建demo
- 依然选择maven-archetype-quickstart,然后选择GroupId,ArtifactId。即可创建成功
- 可以在IDEA的settings中修改Maven的home和配置
从IDEA中可以看到maven的各种生命周期,各种生命周期都是有对应的插件实现的,插件也就是java类,maven本质上就是通过接口调用这类来实现生命周期,而且default中生命周期有顺序的,直接执行后一个命令,会自动执行之前的命令:
- clean
- default:validate; compile; test; package; verify; install(将jar安装到本地仓库); deploy(将jar部署到公司的私服仓库);
- site:生成网站的信息和文档为静态网站。会生成index.html可以在浏览器中查看
tip:install的位置,比如D:\environment\apache-maven-3.9.6\mvn_resp\net\hour\mvn-exapmle\1.0-SNAPSHOT\mvn-exapmle-1.0-SNAPSHOT.jar。(net\hour包名、mvn-exapmle项目名、1.0-SNAPSHOT版本)
比较常用命令:
- mvn clean package
- mvn clean install
pom.xml中使用GAV(groupId artifactId version)标定一个jar包,version中snapshot (快照,开发中)和 release(开发完)
<!-- groupId不爆红说明有这个组,下面同理 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
</dependency>
<!--依赖传递: 直接依赖context,它会引用间接依赖core\aop\beans等-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.2.1</version>
</dependency>
依赖范围:
<dependencies>
<!--test: 只用于测试单元的源码,不会被正式源码引用,不会被打包-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!--compile默认:编译和运行都需要-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
<scope>compile</scope>
</dependency>
<!--provided:编译需要,运行不需。比如lombok简化Setter\Getter-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
<!--servlet运行时Tomcat或其他Web容器会提供,所以也是provided-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!--runtime: 运行时需要,编译无需,比如jdbc驱动-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.4</version>
<scope>runtime</scope>
</dependency>
<!--system: 只能在本地电脑使用,因为源码放在git中,而git一般忽略jar,
除非其他环境手动引入这些jar
最好引入到私服仓库,其他成员只用pom即可-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>system</scope>
<systemPath>${basedir}/lib/junit-3.8.1.jar</systemPath>
</dependency>
</dependencies>
父子工程:多个模块的依赖管理
- 创建maven-parent项目,同上demo。把此项目src删除。
- 在父类项目中,创建多个module,并命名为child-a、child-c、child-d、
- 可以在IDEA右侧栏中看到相应模块。
<!--maven-parent 的 pom.xml-->
<groupId>net.geek</groupId>
<artifactId>maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!--pom值: 表示父类-->
<packaging>pom</packaging>
<modules>
<module>child-a</module>
<module>child-b</module>
<module>child-c</module>
</modules>
<!--child-a 的 pom.xml-->
<parent>
<groupId>net.geek</groupId>
<artifactId>maven-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>child-a</artifactId>
<!--表示jar,还可以war-->
<packaging>jar</packaging>
maven-parent 的 pom.xml:这样dependencies由于无条件继承,父子耦合高
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>6.2.1</spring.version>
</properties>
<!--child-* 无条件继承-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
降低耦合度:
<!--maven-parent 的 pom.xml:子类不继承-->
<!--properties 可以定义通用的属性,以便后面引用-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>6.2.1</spring.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!--child-a 的 pom.xml:继承,默认version为父类的-->
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
</dependencies>
依赖冲突:比如A和B,A引入D,B通过引入C再引入D?或者A和B同时引入D?D是不同的版本,到底用那个版本。
- maven本身有第一的规则:最短路径优先,先声明优先。
- 开发者:通过exclusions标签排除依赖、optional标签标记可选依赖。
spring-jdbc版本此时就会冲突,此时child-a由于路径一样,则先声明优先,使用child-b中的spring-jdbc的版本。
<!--child-a 的 pom.xml,引入child-b和 child-c -->
<dependency>
<groupId>net.geek</groupId>
<artifactId>child-b</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.geek</groupId>
<artifactId>child-c</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--child-b 的 pom.xml-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
</dependency>
<!--child-c 的 pom.xml-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
</dependency>
如果开发者想使用child-c中的spring-jdbc版本
// 方式一:修改child-a的pom.xml,exclusions排除
<dependency>
<groupId>net.geek</groupId>
<artifactId>child-b</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.geek</groupId>
<artifactId>child-c</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
// 方式二:修改child-b的pom.xml, optional标签为ture表示可选(非必须的 )
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.1</version>
<optional>true</optional>
</dependency>
Nexus
Nexus用于私服仓库。
安装和使用:
- win中下载对应压缩包并解压,
- 通过./etc/nexus-default.properties知道端口为8081
- 开启服务
nexus.exe/run
,通过浏览器localhost:8081
访问。
Nexus网页介绍:
- 默认有maven-releases(本地hosts)、maven-snapshots(本地hosts)、maven-central(中央仓库)、maven-public(包含三者)、
- 开发者也可创建其他仓库,nexus不仅支持maven2;也支持docker,npm,yum之类的包文件
从Nexus下载:
<!-- ./conf/settings.xml 配置mirror和server -->
<mirror>
<id>maven-nexus</id>
<mirrorOf>*</mirrorOf>
<name>nexus私服</name>
<url>http://localhost:8081/repository/maven-public/</url>
</mirror>
<server>
<id>maven-nexus</id>
<username>admin</username>
<password>admin</password>
</server>
上传Nexus,即deploy:
<!-- pom.xml-->
<version>1.0.0</version>
<!-- 配置nexus的id和具体仓库的url -->
<distributionManagement>
<!-- 会根据version值是否有SNAPSHOTS,自动决定是releases还是snapshots仓库 -->
<repository>
<id>maven-nexus</id>
<url>http://localhost:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>maven-nexus</id>
<url>http://localhost:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
tip:默认不许重复上传正式版本,比如1.0.0,第二次进行deploy就会报错。
import依赖范围
Nginx
最常用的Web服务器。一个Master进程管理多个Work进程。
安装方式:
- 包管理器:linux通过apt、win通过choco、mac通过brew
- 编译安装:下载对应C语言源码,预编译、编译、安装的方式
- 使用Docker:
docker pull nginx
安装好之后,执行nginx.exe
即可启动服务,在浏览器中 localhost
即可访问,
nginx -s quit/stop
停止服务
nginx.conf为配置文件,规定了一些work数量,文件类型等。nginx -s reload
修改之后重新加载(signal)
hexo
需要装hexo,前提需安装 Node.js和 git
npm install -g hexo-cli;
hexo init blog;
cd blog;
npm install; # 安装hexo默认的依赖
hexo g; # generate 生成静态文件
hexo s; # server 本地开发服务器,通常在localhost:4000
# 此时只是hexo的服务
# 把hexo生成的blog部署的nginx:把blog/public/* 复制到nginx的html下即可。
反向代理
先安装go:choco install go
默认C:\Program Files\Go\bin
main_8000.go;然后创建内容相同的main_8001.go; main_80001.go;
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!8000")
}
func main() {
// 设置处理请求的路由
http.HandleFunc("/", handler)
// 启动服务器,监听8080端口
fmt.Println("Server is running on http://localhost:8000")
if err := http.ListenAndServe(":8000", nil); err != nil {
fmt.Println("Error starting server:", err)
}
}
启动服务
go run main_8000.go; # 其他两个同理
# 浏览器中可以localhost:8000 访问
配置反向代理nginx.conf:通过 localhost/app
即可轮训访问8000\8001\8002,
http{
...
upstream backend {
ip_hash;
server 127.0.0.1:8000 weight=3;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
server {
...;
location /app {
proxy_pass http://backend;
}
}
...
}
负载均衡:weight=3表示大部分在此服务器;ip_hash表示在一台服务器比如只在8000,解决session互传
HTTPS配置
HTTP + SSL = HTTPS。默认http端口为80,https端口为443。一些主流的云平台可以申请到免费的ssl(Secure Sockets Layer)证书,也可以通过自签名生成证书和密钥,已经被TLS(Transport Layer Security)所取代。
安装openssl命令:choco
。默认C:\Program Files\SSL\bin
cd ssl # 创建一个ssl文件夹
#
openssl genpkey -algorithm RSA -out server.key
openssl req -new -key server.key -out server.csr # 输入对应的信息,比如国家,公司,邮箱...
openssl x509 -req -in server.csr -signkey server.key -out server.crt
nginx.config
# 解决重定向问题
server {
listen 80;
server_name localhost;
# 重定向到 HTTPS 版本
return 301 https://localhost$request_uri;
}
server {
listen 443 ssl; # 监听 443 端口,并启用 SSL
server_name localhost; # 你的域名
ssl_certificate D:/environment/nginx-1.27.3/ssl/server.crt; # 证书文件
ssl_certificate_key D:/environment/nginx-1.27.3/ssl/server.key; # 私钥文件
ssl_protocols TLSv1.2 TLSv1.3; # 推荐的 SSL/TLS 协议版本
# ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256'; # 强加密套件
ssl_prefer_server_ciphers on; # 强制使用服务器配置的加密算法
# ssl_dhparam /path/to/dhparam.pem; # Diffie-Hellman 参数,用于增加安全性,确保生成该文件(见后文)
ssl_session_cache shared:SSL:10m; # 缓存会话以提高性能
ssl_session_timeout 1d; # 设置 SSL 会话超时
# listen 80;
# server_name localhost;
#charset koi8-r;
location /app {
proxy_pass http://backend;
}
}
然后 https://localhost
虚拟机
demo1:
可以在一台服务器部署多个站点,比如一个server 就相当于一个服务器
为了方便表示nginx.conf 的 server 配置在servers/local.conf 中
# nginx.conf
http {
...;
include servers/*.conf;
}
# 新建servers/local.conf,把nginx.conf 中的server拷过来
server{
}
demo2:
npm create vite # 选择Vue和TypeScript
npm install # 安装依赖node_modules/
npm run build # 生成dist/ 下面有index.html
同样把这个网站部署到nginx上
server {
listen 5173;
server_name localhost;
location / {
root D:/environment/nginx-1.27.3/vuedemo/dist;
index index.html index.htm;
}
}
然后 https://localhost:5173
MySQL
数据库DB是按照数据结构进行组织、存储、管理数据的仓库,DBMS是数据库管理系统,常见RDBMS有MySQL
安装:
- 命令行,
choco | apt
- win在官网下载安装包
docker pull mysql
需要进行一些配置
# 创建文件在项目下 my.init
[mysqld]
basedir=D:\environment\mysql-8.0.33-winx64\
datadir=D:\environment\mysql-8.0.33-winx64\data\
port=3306
# 输入命令
mysqld --initialize # 初始化mysql,会生成data
mysqld --install
net start mysql # 启动mysql服务
mysql -u root -p # 登陆,密码在data/*.err
alter user 'root'@'localhost' identified with mysql_native_password by 'newpassworld';
常用命令
show databases;
use mysql;
show tables;
select * from tables_priv;
Redis
MongoDB
Docker
Kubernetes
堡垒机
Node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境:
- 异步和事件驱动:非阻塞 I/O 模型,适用于大量并发
- 单线程
- 模块化,内置模块(fs、http、path)
安装:
- 下载Node.js安装包到environment\目录下。
node -v | npm -v
测试 - 目录下创建文件夹node_cache,node_global。默认
npm config set prefix "...\Nodejs\node_global"
npm config set cache "...\Nodejs\node_cache"
npm config get registry # 配置国内镜像
npm config get prefix
npm config list
- 系统变量,NODE_PATH为…\Nodejs\node_global\node_modules。并在PATH中添加%NODE_PATH%
- 用户变量,…\AppData\Roaming\npm修改为…\Nodejs\node_global
- 测试:
npm install express -g
安装在\node_global\node_modules\express
Windows
命令
tasklist | findstr "nginx" # 查找任务
taskkill /f /t /im nginx.exe # 终止任务,f强制,t递归子进程,im映像名称
# net命令:网络和系统管理
net stop nginx # 先停止系统的nginx服务,否则停止nginx,也会重新启动
# netstat:查看端口
netstat -ano # a:all n:number o:pid
常见问题
端口占用
# 8080 端口被占用
netstat -ano | findstr "8080" # 查找端口对应的pid(1234)
tasklist | findstr "1234" # 根据pid找到任务,
# 终止任务
tasklist /f /t /pid 1234
tasklist /f /t /im demo.task
tps://localhost:5173`
MySQL
数据库DB是按照数据结构进行组织、存储、管理数据的仓库,DBMS是数据库管理系统,常见RDBMS有MySQL
安装:
- 命令行,
choco | apt
- win在官网下载安装包
docker pull mysql
需要进行一些配置
# 创建文件在项目下 my.init
[mysqld]
basedir=D:\environment\mysql-8.0.33-winx64\
datadir=D:\environment\mysql-8.0.33-winx64\data\
port=3306
# 输入命令
mysqld --initialize # 初始化mysql,会生成data
mysqld --install
net start mysql # 启动mysql服务
mysql -u root -p # 登陆,密码在data/*.err
alter user 'root'@'localhost' identified with mysql_native_password by 'newpassworld';
常用命令
show databases;
use mysql;
show tables;
select * from tables_priv;
Redis
MongoDB
Docker
Kubernetes
堡垒机
Node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境:
- 异步和事件驱动:非阻塞 I/O 模型,适用于大量并发
- 单线程
- 模块化,内置模块(fs、http、path)
安装:
- 下载Node.js安装包到environment\目录下。
node -v | npm -v
测试 - 目录下创建文件夹node_cache,node_global。默认
npm config set prefix "...\Nodejs\node_global"
npm config set cache "...\Nodejs\node_cache"
npm config get registry # 配置国内镜像
npm config get prefix
npm config list
- 系统变量,NODE_PATH为…\Nodejs\node_global\node_modules。并在PATH中添加%NODE_PATH%
- 用户变量,…\AppData\Roaming\npm修改为…\Nodejs\node_global
- 测试:
npm install express -g
安装在\node_global\node_modules\express
Windows
命令
tasklist | findstr "nginx" # 查找任务
taskkill /f /t /im nginx.exe # 终止任务,f强制,t递归子进程,im映像名称
# net命令:网络和系统管理
net stop nginx # 先停止系统的nginx服务,否则停止nginx,也会重新启动
# netstat:查看端口
netstat -ano # a:all n:number o:pid
常见问题
端口占用
# 8080 端口被占用
netstat -ano | findstr "8080" # 查找端口对应的pid(1234)
tasklist | findstr "1234" # 根据pid找到任务,
# 终止任务
tasklist /f /t /pid 1234
tasklist /f /t /im demo.task