2025年4月工作经验记录

1 Git放弃所有更改

  • 放弃所有未提交的修改和新增文件
1
2
git restore .         # 放弃所有工作区的修改
git clean -fd # 删除所有未被追踪的文件和目录(新增的文件)
  • 放弃所有暂存区和工作区的更改:已经add但是没有commit
1
2
git reset --hard      # 清除暂存区和工作区的所有更改(回到上一次提交状态)
git clean -fd # 删除未被跟踪的文件和目录
  • 放弃所有更改,强制回到远程分支状态
1
2
3
git fetch origin
git reset --hard origin/你的分支名
git clean -fd

2 pm2

PM2(Process Manager 2) 是一个非常流行的 Node.js 应用进程管理器,主要用于生产环境中对 Node.js 应用进行进程守护、负载均衡、日志管理等功能的管理工具。

  • 安装
1
npm install -g pm2
  • 启动应用
1
pm2 start app.js

可以为应用命名:

1
pm2 start app.js --name my-app

也可以指定一些参数:

1
2
pm2 start app.js --watch     # 监控文件变化自动重启
pm2 start app.js -i max # 启动多进程集群模式
  • 查看运行状态
1
pm2 list

显示所有 PM2 管理的进程信息,包括名称、状态、内存占用、CPU 使用率等。

  • 停止、重启、删除应用
1
2
3
pm2 stop my-app
pm2 restart my-app
pm2 delete my-app

配置文件:可以创建 ecosystem.config.js 来管理多个项目,示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ecosystem.config.js
module.exports = {
apps: [
{
name: 'my-app', // 应用名称
script: './app.js', // 启动脚本
instances: 2, // 实例数(0 为自动,max 为 CPU 核心数)
exec_mode: 'cluster', // 进程模式,cluster or fork
watch: true, // 是否监听文件变动自动重启
max_memory_restart: '300M', // 超过内存限制后自动重启
env: {
NODE_ENV: 'development', // 默认环境变量
PORT: 3000
},
env_production: {
NODE_ENV: 'production', // 生产环境变量
PORT: 8080
}
}
]
}
1
2
pm2 start ecosystem.config.js # 默认会使用 env 中的环境变量
pm2 start ecosystem.config.js --env production # 会使用 env_production 中的变量(如设置的 PORT=8080 和 NODE_ENV=production)

3 ResultMap

在 MyBatis 中,**ResultMap 用于将数据库中的字段映射到 Java 实体类的属性上**。

默认情况下,MyBatis 会根据 字段名和属性名一致 来自动映射但如果数据库字段和 Java 类属性不完全对应,比如:

数据库字段名 Java属性名
threshold_distance thresholdDistance
preset_status status

在这种情况下,通常有几个方法来解决:

  • 开启驼峰映射:适用于数据库字段是下划线,Java实体类字段是驼峰
1
2
3
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
  • 使用@TableField注解:Java实体类字段采用一些缩写等形式
1
2
@TableField("internet_address")
private String ia;

作用:将 Java 中的 javaFieldName 字段,映射到数据库中的 db_column_name 字段。

  • 使用ResultMap进行复杂映射
1
2
3
4
5
6
7
8
9
<resultMap id="AirportPresetPointMap" type="com.xxx.AirportPresetPoint">
<id column="id" property="id"/>
<result column="preset_status" property="status"/>
<result column="threshold_distance" property="thresholdDistance"/>
</resultMap>

<select id="selectById" resultMap="AirportPresetPointMap">
SELECT * FROM airport_preset_point WHERE id = #{id}
</select>

4 lambda和effectively final

遇到了这样的问题:

1
2
3
4
5
6
7
8
String craftSite = "545";
// 对craftSite进行了修改
craftSite = "432";
// ...
int index = IntStream.range(0, craftSites.length)
.filter(i -> craftSite.equals(craftSites[i]))
.findFirst()
.orElse(-1); // -1 表示没找到

上面的代码,在craftSite处报错:Variable used in lambda expression should be final or effectively final

effectively final 是 Java 8 引入的新概念,意思是:一个变量虽然没加 final,但从声明之后就没再修改过,那它就是 effectively final,也能在 lambda 中使用。

原因:在 Java 中,lambda 表达式里引用的变量必须是 不可变的或实际上未改变的

解决方式:提取为 final 局部变量再用

1
2
3
4
5
6
7
8
9
String craftSite = "545";
// 对craftSite进行了修改
craftSite = "432";
// 将craftSite提取为final局部变量
final String targetCraftSite = craftSite;
int index = IntStream.range(0, craftSites.length)
.filter(i -> targetCraftSite.equals(craftSites[i]))
.findFirst()
.orElse(-1);

5 前端响应类型和后端返回的数据结构不一致

遇到了这样的问题,前端的统一响应类型为:

1
2
3
4
5
6
7
8
9
10
11
12
// src/api/interface/index.ts

// 请求响应参数(不包含data)
export interface Result {
code: string;
message: string;
}

// 请求响应参数(包含data)
export interface ResultData<T = any> extends Result {
data?: T;
}

但是和后端对接时,后端返回的数据结构为:

1
2
3
4
5
6
{
"code": "0",
"msg": "success",
"data": "success",
"count": "0"
}

这样在前端请求时:

1
2
3
4
5
6
7
8
export const getRtspUrlApi = cameraCode => {
return http.get<any>(`http://ip:port/device/rtsp?cameraCode=${cameraCode}`);
};

// 封装代码
get<T>(url: string, params?: object, _object = {}): Promise<ResultData<T>> {
return this.service.get(url, { params, ..._object });
}

会报错,无任何报错信息,并且后续代码无法执行,如下图:

image-20250418105439046

在无法修改后端返回的数据结构的情况下(可能因为后端的同事不想修改或不好修改,或者这套后端并不和现在的前端适配),则使用fetch进行单独处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 该接口返回格式不一致,需要使用fetch进行请求
export const getRtspUrlApi = cameraCode => {
return fetch(`http://ip:port/device/rtsp?cameraCode=${cameraCode}`, {
method: 'GET',
}).then(async (response) => {
const res = await response.json();

if (res.code === '0') {
const parsed = JSON.parse(res.data);
return parsed.rtspUrl;
} else {
throw new Error(res.msg || '接口返回错误');
}
}).catch((err) => {
throw err;
});
}

6