卓越之旅:在优秀案例中精进,编织技术梦想

本文最后更新于:6 天前

不知道少了什么感觉,没有以前快乐。

写在前面

2024 年 7 月 12 日

为什么会突然想到写这样一篇博客呢?我简单反省过这半年来的学习规划,确实很长时间没有更新过专精编程技术的博客了。

在今年这个最关键的时间节点,我很清楚自己最需要做什么。

在今年上半年有过的唯一一段工作经历,让我越发清醒地意识到:在持续备战秋招的忙碌生活中,我必须要找到自己真正喜欢并愿意长期付之以时间的爱好。

最近很喜欢研究象棋,也在尝试了解学习视频剪辑的艺术,更多的是通过读书,写作来记录生活,陶冶情操。

那段工作经历让我真正意识到,工作只是生存的一部分,上班之余的时间才算是真正的生活。

所以我更希望能够在工作之余的闲暇时间,做点什么来充实自己的业余生活。

我发觉到长期处于烦闷无聊的工作中,我对编程学习的兴趣在逐渐消退了,我需要重新汲取外部优质资源。

站在巨人的肩膀上,开启我的编程精进之路。

项目

仿网易云音乐

🍖 推荐阅读:

网易云音乐 (163.com)

Node.js — Node.js, the difference between development and production (nodejs.org)

项目启动

2024 年 7 月 12 日

前端项目跑起来:

当在命令行中遇到 'vue-cli-service' 不是内部或外部命令,也不是可运行的程序或批处理文件 这个错误时,这通常意味着你的系统中没有正确安装 Vue CLI 或者其可执行文件 vue-cli-service 没有被添加到系统的 PATH 环境变量中。以下是一些解决这个问题的步骤:

image-20240712170550777

  1. 确认 Vue CLI 是否已安装

首先,你需要确认 Vue CLI 是否已经安装在你的机器上。打开命令行工具,输入以下命令来检查 Vue CLI 是否安装以及其版本:

1
2
3
bash复制代码

vue --version

如果系统提示 vue 命令找不到,那么你需要安装 Vue CLI。

  1. 安装 Vue CLI

如果 Vue CLI 没有安装,你可以通过 npm(Node.js 的包管理器)来安装它。首先,确保你已经安装了 Node.js 和 npm。然后,在命令行中运行以下命令来全局安装 Vue CLI:

1
2
3
bash复制代码

npm install -g @vue/cli

或者使用 yarn(如果你更倾向于使用 yarn):

1
2
3
bash复制代码

yarn global add @vue/cli
  1. 尝试再次运行你的项目

在完成上述步骤后,回到你的 Vue 项目目录,并尝试再次运行:

1
2
3
bash复制代码

vue-cli-service serve

4.要是还是不行,就直接执行:

1
npm install

本项目后端依赖于这个开源的网易云音乐 API 接口项目,请自行下载并运行:NeteaseCloudMusicApi

后端启动

2024 年 7 月 21 日

本项目后端依赖于这个开源的网易云音乐 API 接口项目,请自行下载并运行:

NeteaseCloudMusicApi

image-20240721134317108

这个错误提示 CERT_HAS_EXPIRED 表示你尝试连接到 npm 注册表时使用的 SSL 证书已经过期。这通常是因为你的 npm 客户端配置使用了过时的注册表 URL 或者你的系统日期和时间设置不正确。以下是一些解决这个问题的步骤:

  1. 检查系统日期和时间
    确保你的计算机的系统日期和时间设置是正确的。错误的日期和时间设置可能导致 SSL 证书验证失败。

  2. 检查 npm 配置
    运行 npm config list 来查看当前的 npm 配置,特别是 registry 的值。它应该指向 https://registry.npmjs.org/。如果指向的是 http 而非 https,或者是一个其他非官方镜像,请考虑修改它。

    你可以使用以下命令来设置 npm 的默认注册表地址:

    1
    2
    3
    bash复制代码

    npm config set registry https://registry.npmjs.org/
  3. 清除 npm 缓存
    有时候清除 npm 缓存可以解决奇怪的安装问题。你可以使用以下命令来清除缓存:

    1
    2
    3
    bash复制代码

    npm cache clean --force
  4. 检查网络设置
    如果你在公司或学校网络环境中,可能存在网络代理或防火墙设置阻止了 https 连接的正确验证。你可以尝试暂时关闭这些设置或使用其他网络环境来查看问题是否仍然存在。

  5. 更新 npm 和 Node.js
    确保你的 npm 和 Node.js 都是最新版本。旧版本的 npm 可能不支持 TLS 1.2 或更高版本。你可以通过运行以下命令来更新 npm:

    1
    2
    3
    bash复制代码

    npm install -g npm

    如果需要更新 Node.js,你可以从 Node.js 官网 下载最新版本。

  6. 检查代理和 SSL 证书
    如果你在使用代理或 SSL 证书,请确保它们是最新的,并且正确配置在你的系统上。

  7. 尝试使用 VPN
    有时网络问题可能由地理位置或 ISP 限制引起。尝试使用 VPN 连接到其他网络,看看是否可以解决问题。

再次执行,又出现这个问题:

image-2024072113500477

1
`ERR_SOCKET_TIMEOUT` 错误表明 npm 在尝试从 npm 注册表下载包时,由于网络问题导致连接超时。这通常与网络连接质量、代理设置、防火墙规则或 npm 服务器的响应速度有关。以下是一些解决这个问题的步骤:

如果你在中国大陆或其他地区,使用 npm 官方注册表可能受到网络延迟或限制的影响。你可以考虑使用 npm 镜像,如淘宝的 npm 镜像(cnpm):

1
2
3
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 然后使用 cnpm 代替 npm
cnpm install

我尝试安装 cnpm,结果有报错:

image-20240721135453761

遇到 CERT_HAS_EXPIRED 错误通常意味着你尝试连接的服务器使用的 SSL 证书已经过期。然而,在这个情况下,你尝试访问的是淘宝的 npm 镜像(https://registry.npm.taobao.org),这是一个被广泛使用的、应该保持证书有效的镜像。

这个问题可能由以下几个原因引起:

  1. 系统时间设置错误:检查你的计算机的系统时间是否正确。错误的系统时间会导致 SSL 证书验证失败,因为证书的有效期是基于时间的。
  2. 网络中间人攻击(MITM):虽然不太可能,但你的网络可能被配置为拦截 SSL/TLS 连接,并使用自己的证书。这通常发生在公司网络或受限制的网络环境中。
  3. 本地 SSL/TLS 证书存储问题:你的系统可能无法正确访问或验证 SSL 证书链。
  4. npm 配置问题:尽管你已经检查了 proxy 配置,但还有其他与 SSL 相关的配置可能需要检查,如 strict-ssl

为了解决这个问题,你可以尝试以下步骤:

  • 检查系统时间:确保你的系统时间是准确的。

  • 使用命令行工具检查 SSL 证书:你可以使用如 openssl 的命令行工具来检查 https://registry.npm.taobao.org 的 SSL 证书是否有效。例如:

    1
    2
    3
    bash复制代码

    openssl s_client -connect registry.npm.taobao.org:443

    查看输出中的证书信息,特别是有效期部分。

  • 暂时禁用 SSL 验证(仅作为测试,不推荐长期使用):
    你可以通过设置 strict-sslfalse 来暂时禁用 npm 的 SSL 验证。但请注意,这会使你的连接容易受到中间人攻击。

    1
    2
    3
    4
    npm config set strict-ssl false
    npm install -g cnpm --registry=https://registry.npm.taobao.org
    # 记得之后将其设置回 true
    npm config set strict-ssl true
  • 清理 npm 缓存
    虽然这不太可能是证书问题的直接解决方案,但清理缓存有时可以解决一些奇怪的问题。

    1
    2
    3
    bash复制代码

    npm cache clean --force
  • 使用其他网络:尝试连接到其他网络(如家庭网络或移动热点),以查看问题是否仍然存在。

  • 更新 npm 和 Node.js:确保你的 npm 和 Node.js 都是最新版本。

  • 联系淘宝 npm 镜像的支持:如果以上步骤都不能解决问题,可能需要联系淘宝 npm 镜像的支持团队,询问他们是否有关于证书过期的已知问题。

请注意,禁用 SSL 验证(strict-ssl=false)应该只作为最后的手段,并且仅在你完全信任你的网络环境时使用。在生产环境中,始终应该保持 SSL 验证启用。

执行成功!

image-20240721140507470

执行以下命令,启动后台:

1
node app.js

image-20240721142332268

启动前台页面:

image-20240721142357687

访问,项目效果如下:

image-20240721142531038

image-20240721142503392

image-20240721142511135

仿 B 站项目

项目启动

2024 年 7 月 21 日

了解整体代码结构,熟悉数据库库表和字段,修改数据库配置。

暂时不做 Elasticsearch 和 阿里云 OSS 对象存储的配置。

xxxxxxxxxx     4.0.0            com.memory.api        memory-api        0.0.1-SNAPSHOT        ../pom.xml    ​    com.memory.client    memory-client    0.0.1-SNAPSHOT​                        com.memory.common            memory-common            0.0.1-SNAPSHOT                            com.belerweb            pinyin4j            2.5.1                            com.memory            memory-client-spring-boot-starter            0.0.1            ​                                        org.springframework.boot                spring-boot-maven-plugin                                                            repackage                                                    repackage                                                                                    ​xml

👆 这是 Category 表没有默认主键,添加上即可:

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Category {
@TableId(type = IdType.AUTO)
private String mcId;
private String scId;
private String mcName;
private String scName;
private String descr;
private String rcmTag;
}

image-20240721192005290

ES 配置问题,直接注销掉 ElasticsearchConfig 配置,以及 ESUtils 自动注入。

OSS 配置问题,同样的,只不过引用的地方比较多,暂时都注释掉相关代码。

当然,可以简单配置自己本地的 Elasticsearch 和 阿里云 OSS ,现在为了简便就直接注释掉部分代码,先把项目跑起来再说。

后端直接启动 BackendApplication 即可。

前端更容易了,执行 npm install 安装依赖无误后,直接执行 vue-cli-service serve 启动项目:

image-20240721193910677

至此,项目启动成功,效果如下:

image-20240721193959515

image-20240721194005561

配置更改

2024 年 7 月 27 日

这天一直在抽空学习 Vue 基础,今晚也总算抽出时间来观摩观摩这个项目。

修改了 Redis 和 Elasticsearch 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
redis:
database: 4
host: localhost
port: 6379
password: Dw990831
jedis:
pool:
min-idle: 10
max-idle: 10
max-active: 100
max-wait: -1
timeout: 5000
1
2
3
4
5
6
# Elasticsearch
elasticsearch:
host: localhost
port: 9200
username: root
password: 123456

image-20240727235753087

这个问题是连接本地 Redis 客户端失败了:

image-20240728000254042

这样问题虽然没解决,但是起码注册流程跑通了,登陆还有问题,归根结底还是 Jedis 数据库连接至配置问题,这部分内容明天学习。

2024 年 8 月 21 日

image-20240821233613716

今天晚上回来分别把 Redis 和 Elasticsearch 在本地配置完善并启动后,成功实现了视频上传功能,视频已经能正确上传至阿里云存储桶中。

前后台用户注册登录也令人相当满意,视频审核也测试完成,就是上传视频的封面显示有些问题,而且目前不支持在线浏览视频。

待解决。

在线聊天

2024 年 10 月 4 日

端口监听,连接管理,发送消息,接收消息,消息存储,消息状态(已读,未读);

聊天列表,窗口状态(在线,离开);

实时通信

2025 年 2 月 28 日

IM即时通讯的实现方式_即时聊天实现-CSDN博客

2024 年 10 月 4 日

假期第四天,总算步入正轨了。

上午学习了仿 B 站项目的基于 Netty 的在线聊天功能,涉及到连接管理,消息管理,窗口管理等核心功能,对在线聊天实现有了更多新的想法。

下午会继续学习 WebSocket 实现实时通信,今天就要把这块儿内容搞定,最好写出 Demo 代码长期巩固记忆,日后在实践中运用。

2024 年 10 月 5 日

OkHttp系列一、使用OkHttp进行网络请求的4个步骤-CSDN博客

OkhttpClient的使用-CSDN博客

WebSocket 入门:简易聊天室大家好,我是前端西瓜哥,今天我们用 WebSocket 来实现一个简单的聊天室。 W - 掘金 (juejin.cn)

Java 项目中的 WebSocket 实现这种方式需要 tomcat 7.x,JEE7 的支持。 这种方式需要 spr - 掘金 (juejin.cn)

服务端

服务端完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package com.memory.simplewebsocket.server;

import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
* ClassName: TomcatWebsocketServer
* Package: com.memory.simplewebsocket.server
* Description:
*
* @Author Memory
* @Create 2024/10/5 10:11
* @Version 1.0
*/

@Component
@ServerEndpoint("/chat/{userId}")
public class TomcatWebsocketServer {
// 管理连接
private static Map<Long, Session> clients = new HashMap<>();
// 日志打印
private Logger logger = LoggerFactory.getLogger(ServerEndpoint.class);
// 用户
private Long userId;

/**
* 开启连接, 触发
*
* @param session 会话
* @param userId 用户
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") Long userId) {
this.userId = userId;
// 存储用户和对应会话
clients.put(userId, session);
logger.info(String.format("用户 %d 已上线,新的连接 ------------------> %s", this.userId, session.getId()));
}

/**
* 收到消息, 触发
*
* @param message 消息
* @param session 会话
*/
@OnMessage
public void onMessage(String message, Session session) {
logger.info(String.format("收到来自 %d 的消息 ------------------> %s", userId, message));
// 向全体在线成员推送这条消息
sendMessageFromOneToAll(message);
}

/**
* 关闭连接, 触发
*
* @param session 会话
*/
@OnClose
public void onClose(Session session) {
clients.remove(session);
logger.info(String.format("连接关闭 ------------------> %s", session.getId()));
}

/**
* 连接错误, 触发
*
* @param session 会话
* @param throwable 异常
*/
@OnError
public void onError(Session session, Throwable throwable) {
logger.info(String.format("连接错误 ------------------> %s", session.getId()));
throwable.printStackTrace();
}

/**
* 广播消息
*
* @param message 消息
*/
public void sendMessageFromOneToAll(String message) {
clients.forEach((userId, session) -> {
try {
session.getBasicRemote().sendText(String.format("广播来自 %d 的消息 ------------------> %s%n", this.userId, message));
} catch (IOException e) {
e.printStackTrace();
}
});
}
}

客户端

客户端完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package com.memory.simplewebsocket.listener;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;

import java.util.Scanner;


/**
* ClassName: TomcatWebsocketListener
* Package: com.memory.simplewebsocket.listener
* Description:
*
* @Author Memory
* @Create 2024/10/5 10:20
* @Version 1.0
*/

public class ChatClient1 extends WebSocketListener {
private static final String SERVER_URL = "ws://localhost:8080/chat/1";

public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(SERVER_URL).build();
WebSocket webSocket = client.newWebSocket(request, new ChatClient1());

Scanner scanner = new Scanner(System.in);
System.out.println("请输入消息:");

while (true) {
String message = scanner.nextLine();

if (message.equals("exit")) {
webSocket.close(1000, "Client is closing the connection");
break;
}
webSocket.send(message);
}
}

@Override
public void onOpen(WebSocket webSocket, okhttp3.Response response) {
System.out.println("连接已打开");
}

@Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println("收到消息: " + text);
}

@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
System.out.println("连接已关闭: " + code + " - " + reason);
}

@Override
public void onFailure(WebSocket webSocket, Throwable t, okhttp3.Response response) {
System.out.println("连接失败: " + t.getMessage());
}
}

依赖导入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<dependencies>
<!--spring-boot-starter-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring-boot-starter-websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--spring-boot-starter-test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--okhttp-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
</dependencies>

我使用的 SpringBoot 版本是 3.2.10,这里的 okhttp 版本也要是最新的 4.12.0,否则客户端启动会报错:

image-20241005105327273

这就是版本不兼容了,修改 okhttp 依赖版本即可:

image-20241005104021109

image-20241005105839804

编写 Websocket 配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.memory.simplewebsocket.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
* @author yuanyiwen
* @create 2019-12-03 18:38
* @description
*/
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}

启动服务端,

1
2
3
4
5
spring:
application:
name: simple-websocket
server:
port: 8080

image-20241005135826514

基于Java 的 WebSocket 服务器端实现,它使用了Jakarta WebSocket API,这里指定了 WebSocket 服务器端点的路径:

1
2
3
4
5
6
7
8
9
10
11
12
@Component
@ServerEndpoint("/chat/{userId}")
public class TomcatWebsocketServer {
// 管理连接
private static Map<Long, Session> clients = new HashMap<>();
// 日志打印
private Logger logger = LoggerFactory.getLogger(ServerEndpoint.class);
// 用户
private Long userId;

...................................
}

服务端启动后,监听本机 8080 端口,等待客户端连接:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 开启连接, 触发
*
* @param session 会话
* @param userId 用户
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") Long userId) {
this.userId = userId;
// 存储用户和对应会话
clients.put(userId, session);
logger.info(String.format("用户 %d 已上线,新的连接 ------------------> %s", this.userId, session.getId()));
}

我们编写了两个客户端类,模拟两个用户在线连接到服务器进行通信:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* ClassName: TomcatWebsocketListener
* Package: com.memory.simplewebsocket.listener
* Description:
*
* @Author Memory
* @Create 2024/10/5 10:20
* @Version 1.0
*/

public class ChatClient1 extends WebSocketListener {
private static final String SERVER_URL = "ws://localhost:8080/chat/1";

public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(SERVER_URL).build();
WebSocket webSocket = client.newWebSocket(request, new ChatClient1());

Scanner scanner = new Scanner(System.in);
System.out.println("请输入消息:");

while (true) {
String message = scanner.nextLine();

if (message.equals("exit")) {
webSocket.close(1000, "Client is closing the connection");
break;
}
webSocket.send(message);
}
}

......................................................
}

image-20241005140705618

image-20241005140714226

用户上线后发送消息,显然广播成功了,都能收到对方发来的消息,再看看服务端这边:

image-20241005140909624

显然服务端能正常管理登录用户和对应会话资源,并处理消息广播,让所有在线用户都能收到消息

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 收到消息, 触发
*
* @param message 消息
* @param session 会话
*/
@OnMessage
public void onMessage(String message, Session session) {
logger.info(String.format("收到来自 %d 的消息 ------------------> %s", userId, message));
// 向全体在线成员推送这条消息
sendMessageFromOneToAll(message);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 广播消息
*
* @param message 消息
*/
public void sendMessageFromOneToAll(String message) {
clients.forEach((userId, session) -> {
try {
session.getBasicRemote().sendText(String.format("广播来自 %d 的消息 ------------------> %s%n", this.userId, message));
} catch (IOException e) {
e.printStackTrace();
}
});
}

2024 年 10 月 5 日

再实现两个网页版客户端,交流通信会更加直观。

两个客户端源码基本相同,就这一套:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>在线用户二号</title>
</head>
<body>
<div id="chat">
</div>
<input type="text" id="messageInput" placeholder="Type your message">
<button onclick="sendMessage()">Send</button>
<script>
const socket = new WebSocket('ws://localhost:8080/chat/2');

socket.onopen = (event) => {
console.log('WebSocket connection opened:', event);
};

socket.onmessage = (event) => {
const messageDiv = document.getElementById('chat');
const messageParagraph = document.createElement('p');
messageParagraph.textContent = event.data;
messageDiv.appendChild(messageParagraph);
};

socket.onclose = (event) => {
console.log('WebSocket connection closed:', event);
};

function sendMessage() {
const messageInput = document.getElementById('messageInput');
const message = messageInput.value;
socket.send(message);
messageInput.value = '';
}
</script>
</body>
</html>

这里重新设置下服务端广播逻辑,只广播当前非当前会话的消息,因为当前会话的消息就是自己的消息,不需要给自己广播,特殊处理:

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 收到消息, 触发
*
* @param message 消息
* @param session 会话
*/
@OnMessage
public void onMessage(String message, Session session) {
logger.info(String.format("收到来自 %d 的消息 ------------------> %s", userId, message));
// 向全体在线成员推送这条消息
sendMessageFromOneToAll(session, message);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 广播消息
*
* @param session 会话
* @param message 消息
*/
public void sendMessageFromOneToAll(Session session, String message) {
clients.forEach((userId, client) -> {
try {
if (client != session) {
client.getBasicRemote().sendText(String.format("广播来自 %d 的消息 ------------------> %s%n", this.userId, message));
} else {
client.getBasicRemote().sendText(String.format("自己发送的消息 ------------------> %s%n", message));
}
} catch (IOException e) {
e.printStackTrace();
}
});
}

就这样,我们实现了两个在线用户的通信交流,相当有趣,这也是时隔一年多以来再次系统地研究如何实现实时通信:

image-20241005143136271

image-20241005143131814

很好玩啊,总算亲手实践了 Websocket 实现实时通信。

windows 脚本编程

2024 年 7 月 13 日

image-20240713075227778

image-20240713075309570

毕设小项目

2024 年 7 月 21 日

今天尝试跑几个 Spring + Vue 项目,看看能不能成功运行。

MemorySearch 忆搜阁

2024年8月8日

今天早上刷知乎,看到了这样一段有意义的话,原文我已经记不大清楚,大致意思是这样的:

我面试过很多求职者,现在的IT行业求职的人普遍太水了,只要你稍微努努力都能甩开身边人一大截。

像我以前面试过的那些人,问的那些简单的八股文都很难回答上来,计算机专业最基本的科学素养都没有。

没什么可问的就盘问项目吧,可很多人也是支支吾吾说不清楚,不论是个人项目还是工作中参与到的企业项目,开发过程都跟自己没关系一样好像。

我来教你怎么把项目说清楚,面试官不管从哪个角度问都能回答得滴水不漏:

你整体回顾一遍项目,分别从三个角度来写这个项目是做什么用的,里面涉及到了哪些技术亮点或难点,你又是怎么解决的。

写这个的目的不是为了再巩固一遍如何分析这个项目所用到的技术栈,完全不需要这样细致入微的描述。

只需要从宏观角度上简洁明了的介绍这个项目到底是怎么回事就行,不管别人怎么问,你都能从容不迫面不改色地聊项目,这样在面试中会很加分。

那么,开始吧,我已经完全过了一遍这个项目了,开始动手写一篇文章。

2024 年 8 月 8 日

这个项目是一个基于 Spring Boot + Elastic Stack 技术栈 + Vue.js聚合搜索中台。它不仅是一个强大的搜索引擎,更是一个内容丰富的社区平台。

什么是聚合搜索中台,它最核心的功能就是给使用者提供了丰富的搜索搜索体验。我们经常逛浏览器,打开任何一个搜索引擎,比如百度必应谷歌,在搜索框中查找资料检索数据很方便,体验很好。

所以我也想动手实现这样一个搜索中台,不需要实现很多花哨的操作。像平时做那些简单的后台管理系统项目时,也有实现过简单的搜索功能,根据某个字段的 id 或者描述,写最简单的 SQL 语句加上简单的条件判断,就实现简单的数据查询。

但这样的搜索功能是远远不够的,我注意到了 Elasticsearch,了解到了 Elastic Stack 技术栈,这样的工具很适合用来实现在海量数据中作检索和分析,借此机会也能真正实践运用 Elastic Stack 技术栈。

我连接到了 Elastic Stack 技术栈中的很多有意思的东西:ES 的安装,DSL 查询语句(布尔查询,聚合查询,复合查询等),下载了 Kibana ,在 dash Board 处能清晰地写 DSL 语句。Elasticseach 是一个文档型数据库,ES 和 MySQL 之间经常会有比较。我学习了如何插入索引,更新索引,新增文档数据,作简单的布尔查询。除此之外还有分词器的安装和使用,让我更清晰地理解了 ES 构建索引和基于倒排索引查询文档的底层原理。

我最关心的还是两点:如何使用 Elasticseach 实现高级的查询效果呢,我学习了关键词语高亮,搜索词条建议,热门话题分析等 DSL 语句的编写,用很多的 Demo 语句实践了这些丰富的查询功能。

ElastidSearch 中的数据都要从数据库 MySQL 中同步过来,所以我掌握了 Logstash 数据同步管道的相关配置,学会了如何使用 Logstash 监听本地 MySQL 变更的数据,并同步指定的字段到 Elasticsearch 中。比如说我要实现诗词的关键词语高亮,搜索词条建议和热门话题分析等功能,我会选择同步 MySQL 数据库中诗词数据对应的几个字段,同步这些字段的数据到 Elasticseach 中。

可说的太多了吧,我怎么感觉这种方式不太靠谱,因为写完这段文字之后我都不想再回头看一遍。。

除了简历上提到的:使用 Spring AOP 切面编程实现权限校验和全局请求拦截,配置定时任务抓取外源数据并解析到本地数据库,深入学习 Elastic Stack 技术栈,掌握倒排索引,分词机制,查询 DSL,实现关键词语高亮,搜索词条建议,热门话题分析等功能,运用多种设计模式简化编码提高效率,自主搭建 Logstash 数据同步管道同步数据,使用 CompletableFuture 异步编程减少批量插入数据的等待时间。

还有:限流,Redis 实现热门搜索统计以及缓存性能优化,互动创作平台等功能。

Github 优质项目

2024 年 9 月 21 日

变化挺大。这讯飞星火还更新了嘛,

image-20240921194602183

掘金有个大模型帖子站点,挺不错。

Electron 小白入门手册——跨端桌面应用开发的前世今生简史今天我们就从原生桌面开发、QT、NW、Electron、 - 掘金 (juejin.cn)

疯狂地涉猎了桌面开发,移动端开发等领域,圆满了。

优秀的开源项目 - Java陈序员 (chencoding.top)

AI 图书管理

2024 年 9 月 24 日

GPT智能图书管理系统后台Vue2-SpringBoot2

GPT智能图书管理系统前台Vue2-SpringBoot2

image-20240923092639180

image-20240923093021291

image-20240923093036696

image-20240923093101909

image-20240923093110935

这个项目还是曹老板上网扒下来的,我一看就知道是整合星球内部项目的,做的相当完善,学习了。

2024 年 9 月 25 日

书接上回,今天总算完成了秋招面试中的第二场流程面试 - 深圳捷顺科技一面,期望后续会有消息吧。

下午闲来无事,拉下来跑跑项目学习下,了解认识程序员小白条,是个很有趣的人。

友情链接 | 小白条的个人博客 (luoye6.github.io)

看过了一遍 READE,md 文档,基本了解了整个项目的核心业务逻辑及其功能实现,一年多以来的 bug 跟踪及优化调整,基本掌握。

项目启动

后端启动完成,建库建表完成,修改数据库连接配置,解决 yaml 配置文件中文编码问题,Swagger 接口文档功能正常。

image-20240925162612612

image-20240925162353269

前端项目启动完毕,基本理清页面目录结构,登录失败,奶奶的没有用户数据。

image-20240925163906760

加小白条好友位,要一下模拟数据资源。

Spring 模块

2024 年 10 月 4 日

spring: Spring 学习相关代码 (gitee.com)

image-20241004160256897

一个小时的时间里,从我收录的两个 Sprign Demo 代码专栏中,系统学习了一遍 SpringAOP 相关知识。

特别是切点表达式和通知的使用方法。

拦截器/过滤器

谈谈 Spring 的过滤器和拦截器我们在进行 Web 应用开发时,时常需要对请求进行拦截或处理,故 Spring 为我 - 掘金 (juejin.cn)

从使用教程、实现原理、差异对比全方面带你玩转业务系统中高频使用的过滤器与拦截器 (qq.com)

限流算法

RabbitMQ

Docker 部署

Guava

MyBatis-Plus

函数式编程

SpringMVC 扩展点

Stream 流

LocalDateTime

JWT

生产者/消费者

[05 有哪几种实现生产者消费者模式的方法? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Java 并发编程 78 讲-完/05 有哪几种实现生产者消费者模式的方法?.md)

商城

2025 年 1 月 10 日

再见Jenkins!一款更适合国人的自动化部署工具,贼带劲!在开发或生产环境中,我们有时候会上服务器器然后敲命令来部署项 - 掘金 (juejin.cn)

项目主页 | mall学习教程 (macrozheng.com)

macro (macrozheng) - Gitee.com

2025 年 1 月 14 日

下午四点多,启动后端四个模块:MallAdminApplicationMallDemoApplicationMallPortalAppliactionMallSearchApplication

修改下配置,MySQL,MongoDB,RabbitMQ,Elasticsearch。

2025 年 1 月 15 日

尝试起下前端页面。

1
npm install

项目主页 | mall学习教程 (macrozheng.com)

官网能看到双端预览效果,商城系统看多了挺头疼,我想想应该怎么改才好,要是能直接拿过来该多好。

不过自己当然也希望能学点新东西,捋清楚代码业务逻辑,写业务能更加熟练点,考虑面更广泛一些,也想能多了解下前端知识。

Vue 从来没有系统学习过,最近这些项目确实看得脑袋昏昏沉沉。

后台管理前端项目起来了。

1
Your application is running here: http://localhost:8090

image-20250115152933952

移动端还没,不过为什么移动端项目缺少 package.json 文件呢。

1
2
3
4
5
6
7
8
15:24:51.213 项目 mall-app-web 开始编译
15:24:51.926 正在下载编译工具,请稍后...
15:26:32.145 编译工具下载成功
15:26:33.673 请注意运行模式下,因日志输出、sourcemap以及未压缩源码等原因,性能和包体积,均不及发行模式。
15:26:33.844 正在编译中...
15:26:34.949 INFO Starting development server...
15:26:44.664 预编译器错误:代码使用了scss/sass语言,但未安装相应的编译器插件,正在从插件市场安装该插件:
15:26:44.665 https://ext.dcloud.net.cn/plugin?name=compile-node-sass at App.vue:1

image-20250115152825451

image-20250115153120208

2025 年 2 月 24 日

今天还不计划该写代码,先根据电影院网上订票系统设计与实现,对应精简下基于JavaWeb的汽配销售管理系统设计与实现。

项目官网:《mall学习教程》

毕业设计

2025 年 1 月 9 日

从现在开始逐步完善下毕设作品和论文撰写吧。

昨天下午起了项目,数据库建表 sql 语句文件都有,不过却缺少一个关键角色表,这些博主们老奸巨猾的操作。

新增角色表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
DROP TABLE IF EXISTS `auth`;
CREATE TABLE auth
(
auth_id INT(10) NOT NULL AUTO_INCREMENT COMMENT '授权ID,主键',
user_group VARCHAR(64) COMMENT '用户组',
mod_name VARCHAR(64) NOT NULL COMMENT '模块名',
table_name VARCHAR(64) NOT NULL COMMENT '表名',
page_title VARCHAR(255) NOT NULL COMMENT '页面标题',
path VARCHAR(255) NOT NULL COMMENT '路由路径',
position VARCHAR(32) NOT NULL COMMENT '位置',
mode VARCHAR(32) NOT NULL DEFAULT '_blank' COMMENT '跳转方式',
`add` TINYINT(3) NOT NULL DEFAULT 1 COMMENT '是否可增加',
`del` TINYINT(3) NOT NULL DEFAULT 1 COMMENT '是否可删除',
`set` TINYINT(3) NOT NULL DEFAULT 1 COMMENT '是否可修改',
`get` TINYINT(3) NOT NULL DEFAULT 1 COMMENT '是否可查看',
field_add TEXT COMMENT '添加字段',
field_set TEXT COMMENT '修改字段',
field_get TEXT COMMENT '查询字段',
table_nav_name VARCHAR(500) COMMENT '跨表导航名称',
table_nav VARCHAR(500) COMMENT '跨表导航',
`option` TEXT COMMENT '配置',
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (auth_id)
) COMMENT ='用户权限管理表';

启动项目成功。

image-20250109151140651

image-20250109151124609

不过登录时控制台出现报错,是数据库字符集问题:

1
2
3
4
5
6
7
8
9
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2b10b7cc]
2025-01-09 13:14:53.015 ERROR 8720 --- [io-5000-exec-10] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/api] threw exception [Request processing failed; nested exception is org.springframework.jdbc.UncategorizedSQLException:
### Error querying database. Cause: java.sql.SQLException: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='
### The error may exist in file [D:\Project\springboot汽车销售管理系统[编号:project97848]\project\target\classes\mapper\BaseMapper.xml]
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: select * from `auth` WHERE `user_group` = '管理员'
### Cause: java.sql.SQLException: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='
; uncategorized SQLException; SQL state [HY000]; error code [1267]; Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='; nested exception is java.sql.SQLException: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation '='] with root cause

就这张表特殊,改掉。

image-20250109151508690

不信了,这样竟然还不行。

1
2
3
4
5
drop database if exists `mall`;
create database if not exists `mall`
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
use `mall`;

起来啦,果然删除重新建库建表完美解决问题。

image-20250109161056301

2025 年 2 月 24 日

今天下午三点多简单过了一遍优秀毕业论文,六篇毕业论文五花八门的,最终选定这一篇作为参考:电影院网上订票系统设计与实现。

2025 年 2 月 26 日

基本搞清楚后台管理系统控制器逻辑。

2025 年 2 月 28 日

这张数据库表是关键。

1
pms_product_category

获取商品分类及其子分类。

1
2
3
4
/**
* 获取商品分类及其子分类
*/
List<PmsProductCategoryWithChildrenItem> listWithChildren();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="selectByExample" parameterType="com.macro.mall.model.PmsBrandExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from pms_brand
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>

获取品牌列表。

1
2
3
4
5
6
7
8
9
10
@ApiOperation(value = "根据品牌名称分页获取品牌列表")
@RequestMapping(value = "/list", method = RequestMethod.GET)
@ResponseBody
public CommonResult<CommonPage<PmsBrand>> getList(@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "showStatus", required = false) Integer showStatus,
@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize) {
List<PmsBrand> brandList = brandService.listBrand(keyword, showStatus, pageNum, pageSize);
return CommonResult.success(CommonPage.restPage(brandList));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="selectByExample" parameterType="com.macro.mall.model.PmsBrandExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from pms_brand
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>

品牌分类总表

品牌ID 品牌名称 所属分类 国家 成立时间 代表产品线 品牌档次
1 博世 (Bosch) 维修保养/车载电器 德国 1886 燃油泵、刹车片、车载电器 高端
2 曼牌 (MANN) 维修保养 德国 1941 滤清器 中高端
3 美孚 (Mobil) 维修保养 美国 1882 全合成润滑油 高端
4 布雷博 (Brembo) 改装件/维修保养 意大利 1961 刹车卡钳、刹车盘 高端
5 70迈 车载电器 中国 2016 行车记录仪 中端
6 盯盯拍 车载电器 中国 2013 智能行车记录仪 中端
7 飞利浦 (Philips) 车载电器 荷兰 1891 车载空气净化器 高端
8 牧宝 汽车装饰 中国 1994 真皮座椅套 中高端
9 尼罗河 汽车装饰 中国 2005 冰丝座椅套 经济型
10 HKS 改装件 日本 1973 涡轮套件、排气系统 高端
11 雅泛迪 (Advanti) 改装件 新加坡 1998 轻量化轮毂 中高端
12 特斯拉 (Tesla) 全新整车 美国 2003 新能源整车 高端
13 丰田 (Toyota) 全新整车 日本 1937 燃油/混动车型 中高端
14 五菱 全新整车 中国 1985 微型电动车 经济型
15 固特异 (Goodyear) 汽车装饰 美国 1898 防水脚垫 中端

库表设计

2025 年 2 月 28 日

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 产品分类 
-- auto-generated definition
create table pms_product_category
(
id bigint auto_increment
primary key,
parent_id bigint null comment '一级分类编号(0表示一级分类)',
name varchar(64) null comment '分类名称',
level int(1) null comment '分类级别(0 - 1级 1 - 2级)',
product_count int null comment '商品数量',
product_unit varchar(64) null comment '商品数量单位',
nav_status int(1) null comment '是否显示在导航栏:0->不显示;1->显示',
show_status int(1) null comment '显示状态:0->不显示;1->显示',
sort int null comment '排序字段',
icon varchar(255) null comment '图标',
keywords varchar(255) null comment '关键词',
description text null comment '分类描述'
)
comment '产品分类' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- 品牌表 
-- auto-generated definition
create table pms_brand
(
id bigint auto_increment comment 'id'
primary key,
name varchar(64) null comment '品牌名称',
first_letter varchar(8) null comment '首字母',
sort int null comment '排序字段',
factory_status int(1) null comment '是否为品牌制造商(0 - 不是 1-是)',
show_status int(1) null,
product_count int null comment '产品数量',
product_comment_count int null comment '产品评论数量',
logo varchar(255) null comment '品牌logo',
big_pic varchar(255) null comment '专区大图',
brand_story text null comment '品牌故事'
)
comment '品牌表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
-- 商品信息 
-- auto-generated definition
create table pms_product
(
id bigint auto_increment comment 'id'
primary key,
brand_id bigint null comment '品牌id',
product_category_id bigint null comment '商品分类',
feight_template_id bigint null,
product_attribute_category_id bigint null comment '属性分类id',
name varchar(200) not null comment '商品名称',
pic varchar(255) null comment '商品样图',
product_sn varchar(64) not null comment '货号',
delete_status int(1) null comment '删除状态(0 - 未删除;1 - 已删除)',
publish_status int(1) null comment '上架状态(0 - 下架;1 - 上架)',
new_status int(1) null comment '新品状态(0 - 不是新品;1 - 新品)',
recommand_status int(1) null comment '推荐状态(0 - 不推荐;1 - 推荐)',
verify_status int(1) null comment '审核状态:0->未审核;1->审核通过',
sort int null comment '排序',
sale int null comment '销量',
price decimal(10, 2) null comment '销售价格',
promotion_price decimal(10, 2) null comment '促销价格',
gift_growth int default 0 null comment '赠送的成长值',
gift_point int default 0 null comment '赠送的积分',
use_point_limit int null comment '限制使用的积分数',
sub_title varchar(255) null comment '副标题',
description text null comment '商品描述',
original_price decimal(10, 2) null comment '市场价',
stock int null comment '库存',
low_stock int null comment '库存预警值',
unit varchar(16) null comment '单位',
weight decimal(10, 2) null comment '商品重量,默认为克',
preview_status int(1) null comment '是否为预告商品:0->不是;1->是',
service_ids varchar(64) null comment '以逗号分割的产品服务:1->无忧退货;2->快速退款;3->免费包邮',
keywords varchar(255) null,
note varchar(255) null,
album_pics varchar(255) null comment '画册图片,连产品图片限制为5张,以逗号分割',
detail_title varchar(255) null,
detail_desc text null,
detail_html text null comment '产品详情网页内容',
detail_mobile_html text null comment '移动端网页详情',
promotion_start_time datetime null comment '促销开始时间',
promotion_end_time datetime null comment '促销结束时间',
promotion_per_limit int null comment '活动限购数量',
promotion_type int(1) null comment '促销类型:0->没有促销使用原价;1->使用促销价;2->使用会员价;3->使用阶梯价格;4->使用满减价格;5->限时购',
brand_name varchar(255) null comment '品牌名称',
product_category_name varchar(255) null comment '商品分类名称'
)
comment '商品信息' charset = utf8
row_format = DYNAMIC;

商品列表,商品分类,品牌列表,基本梳理完毕;商品属性,商品属性分类,商品属性值,待处理。

2025 年 3 月 5 日

完善系统流程图,接下来应该是代码开发环节。

表结构优先处理,十五张表应该是合适的,最多二十张表吧。

  • pms_*:商品模块相关表
  • oms_*:订单模块相关表
  • sms_*:营销模块相关表
  • ums_*:权限模块相关表
  • cms_*:内容模块相关表

商品模块相关表:

1
2
3
相册表,画册图片表,品牌表,商品评价表,商品评价回复表,运费模板表,商品会员价格表,
商品信息表,商品分类表,商品属性表,商品属性分类表,商品属性参数表,商品分类和商品属性关系表,
商品满减表,商品阶梯价格表,商品操作日志表,商品审核记录表,商品库存表,

品牌表,商品信息表,商品分类表,商品属性表,商品属性分类表,商品属性参数表,商品库存表,商品满减表,商品评价表,商品评价回复表。

订单模块相关表:

1
购物车表,公司收发货地址表,订单表,订单商品信息表,订单操作历史记录表,订单退货申请表,退货原因表,设置表,

购物车表,公司收发货地址表,订单表,订单退货申请表。

内容模块相关表:

1
2
3
4
帮助表,帮助分类表,用户举报表,
优选专区表,优选专区和产品关系表,
专题表,专题分类表,专题评论表,专题商品关系表,
话题表,话题分类表,话题评论表,

用户反馈表。

营销模块相关表:

1
2
3
优惠券表,优惠券领取使用记录表,优惠券和产品关系表,优惠券和产品分类关系表,
限时购表,限时购通知表,限时购与商品关系表,限时购场次表,
首页轮播广告表,首页推荐商品表,新鲜好物商品表,人气推荐商品表,首页推荐专题表,

优惠券表,优惠券领取使用表,首页轮播广告表,促销活动通知表。

权限模块相关表:

1
后台用户表,后台用户登录日志表,后台用户和权限关系表,后台用户和角色关系表,成长值变化历史记录表,积分变化历史记录表,积分消费设置表,会员表,会员登记表,会员登录记录表,用户和标签关系表,会员和商品分类关系表,会员收货地址表,会员积分成长规则表,会员统计信息表,用户标签表,会员任务表,后台菜单表,后台用户权限表,后台资源表,资源分类表,后台用户角色表,后台用户角色和菜单关系表,后台用户角色和权限关系表,后台用户角色资源关系表。

用户表,用户角色表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- 品牌表 
-- auto-generated definition
create table pms_brand
(
id bigint auto_increment comment 'id'
primary key,
name varchar(64) null comment '品牌名称',
first_letter varchar(8) null comment '首字母',
sort int null comment '排序字段',
factory_status int(1) null comment '是否为品牌制造商(0 - 不是 1-是)',
show_status int(1) null,
product_count int null comment '产品数量',
product_comment_count int null comment '产品评论数量',
logo varchar(255) null comment '品牌logo',
big_pic varchar(255) null comment '专区大图',
brand_story text null comment '品牌故事'
)
comment '品牌表' charset = utf8
row_format = DYNAMIC;

大概二十一张表。

2025 年 3 月 5 日

商品模块相关表:品牌表,商品信息表,商品分类表,商品属性表,商品属性分类表,商品属性值表,商品满减表,商品评价表,商品评价回复表。

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 品牌表 
create table pms_brand
(
id bigint auto_increment comment 'id'
primary key,
name varchar(64) null comment '品牌名称',
first_letter varchar(8) null comment '首字母',
product_count int null comment '产品数量',
logo varchar(255) null comment '品牌logo',
brand_story text null comment '品牌故事'
)
comment '品牌表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 商品信息表 
create table pms_product
(
id bigint auto_increment comment 'id'
primary key,
name varchar(200) not null comment '商品名称',
description text null comment '商品描述',
brand_id bigint null comment '所属品牌',
product_category_id bigint null comment '所属分类',
product_attribute_category_id bigint null comment '所属属性分类',
pic varchar(255) null comment '商品样图',
publish_status int(1) null comment '上架状态(0 - 下架;1 - 上架)',
sale int null comment '销量',
price decimal(10, 2) null comment '销售价格',
promotion_price decimal(10, 2) null comment '促销价格',
promotion_type int(1) null comment '促销类型:0->使用原价;1->使用满减价格;2->使用促销价;4->限时购',
stock int null comment '库存',
low_stock int null comment '库存预警值',
weight decimal(10, 2) null comment '商品重量,默认为克',
)
comment '商品信息表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 商品分类表 
create table pms_product_category
(
id bigint auto_increment
primary key,
name varchar(64) null comment '分类名称',
description text null comment '描述',
parent_id bigint null comment '上级分类级别(0表示一级分类)',
level int(1) null comment '所属分类级别(0 - 1级 1 - 2级)',
product_count int null comment '商品数量',
product_unit varchar(64) null comment '商品数量单位',
icon varchar(255) null comment '图标'
)
comment '商品分类表 ' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
-- 商品属性表 
create table pms_product_attribute
(
id bigint auto_increment
primary key,
name varchar(64) null comment '属性名称',
product_attribute_category_id bigint null comment '所属分类',
select_type int(1) null comment '选择类型:0->唯一;1->单选;2->多选',
input_list varchar(255) null comment '可选列表,以逗号隔开',
type int(1) null comment '属性类型;0->规格;1->参数'
)
comment '商品属性参数表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
-- 商品属性分类表 
create table pms_product_attribute_category
(
id bigint auto_increment
primary key,
name varchar(64) null comment '属性分类名',
attribute_count int default 0 null comment '包含值数量'
)
comment '商品属性分类表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
-- 商品属性值表 
create table pms_product_attribute_value
(
id bigint auto_increment
primary key,
product_id bigint null comment '所属商品',
product_attribute_id bigint null comment '所属属性',
value varchar(64) null comment '参数值'
)
comment '商品属性值表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 商品评价表 
create table pms_comment
(
id bigint auto_increment
primary key,
product_id bigint null comment '所属商品',
member_id bigint null comment '所属用户',
content text null comment '评价内容',
pics varchar(1000) null comment '上传图片地址,以逗号隔开',
create_time datetime null comment '评价时间',
star int(3) null comment '评价星数:0->5',
collect_counnt int null comment '点赞数量',
read_count int null comment '阅读数量',
replay_count int null comment '回复数量'
)
comment '商品评价表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
-- 评价回复表 
create table pms_comment_replay
(
id bigint auto_increment
primary key,
comment_id bigint null comment '所属评论',
member_id varchar(255) null comment '所属用户',
content varchar(1000) null comment '回复内容',
create_time datetime null comment '回复时间'
)
comment '评价回复表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
-- 商品满减表(只针对同商品) 
create table pms_product_full_reduction
(
id bigint(11) auto_increment
primary key,
product_id bigint null comment '所属商品',
full_price decimal(10, 2) null comment '满减金额',
reduce_price decimal(10, 2) null comment '减少金额'
)
comment '商品满减表(只针对同商品)' charset = utf8
row_format = DYNAMIC;

订单模块相关表:购物车表,公司收发货地址表,订单表,订单退货申请表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 购物车表 
create table oms_cart_item
(
id bigint auto_increment
primary key comment 'id',
product_id bigint null comment '购买商品',
member_id bigint null comment '购买用户',
quantity int null comment '购买数量',
price decimal(10, 2) null comment '需付金额',
price_reduce decimal(10, 2) null comment '实付金额',
product_pic varchar(1000) null comment '商品主图',
create_date datetime null comment '创建时间',
modify_date datetime null comment '修改时间',
delete_status int(1) default 0 null comment '是否删除',
product_category_id bigint null comment '所属分类',
product_brand varchar(200) null comment '所属品牌',
product_attr_id varchar(500) null comment '所属商品属性'
)
comment '购物车表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-- 订单表
create table oms_order
(
id bigint auto_increment comment 'id'
primary key,
member_id bigint not null comment '下单用户',
payment_time datetime null comment '支付时间',
pay_amount decimal(10, 2) null comment '实支金额',
freight_amount decimal(10, 2) null comment '运费金额',
total_amount decimal(10, 2) null comment '订单总金额',
promotion_amount decimal(10, 2) null comment '促销优化金额(促销价、满减)',
coupon_amount decimal(10, 2) null comment '优惠券抵扣金额',
pay_type int(1) null comment '支付方式:0->未支付;1->支付宝;2->微信',
status int(1) null comment '订单状态:0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单',
receiver_name varchar(100) not null comment '收货人姓名',
receiver_phone varchar(32) not null comment '收货人电话',
note varchar(500) null comment '订单备注',
delivery_company varchar(64) null comment '物流公司(配送方式)',
delivery_sn varchar(64) null comment '物流单号',
receiver_detail_address varchar(200) null comment '收货详细地址',
confirm_status int(1) null comment '确认收货状态:0->未确认;1->已确认',
delivery_time datetime null comment '发货时间',
)
comment '订单表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 退货申请 
create table oms_order_return_apply
(
id bigint auto_increment
primary key comment 'id',
order_id bigint null comment '订单id',
company_address_id bigint null comment '收货地址',
product_id bigint null comment '退货商品',
create_time datetime null comment '申请时间',
return_amount decimal(10, 2) null comment '退款金额',
return_name varchar(100) null comment '退货人姓名',
return_phone varchar(100) null comment '退货人电话',
status int(1) null comment '申请状态:0->待处理;1->退货中;2->已完成;3->已拒绝',
handle_time datetime null comment '处理时间',
product_count int null comment '退货数量',
reason varchar(200) null comment '退货原因',
proof_pics varchar(1000) null comment '凭证图片,以逗号隔开',
handle_note varchar(500) null comment '处理备注',
handle_man varchar(100) null comment '处理人员',
)
comment '退货申请' charset = utf8
row_format = DYNAMIC;

内容模块相关表:用户反馈表。

1
2
3
4
5
6
7
8
9
10
11
12
-- 用户反馈表 
create table cms_member_report
(
id bigint null comment 'id',
report_member_id bigint null comment '反馈人',
report_content varchar(100) null comment '反馈内容',
report_type int(1) null comment '反馈类型:0->商品信息;1->活动内容;2->用户评价',
report_status int(1) null comment '反馈状态:0->未处理;1->已处理',
handle_status int(1) null comment '处理结果:0->无效;1->有效;2->恶意',
)
comment '用户反馈表' charset = utf8
row_format = DYNAMIC

营销模块相关表:优惠券表,优惠券领取使用表,首页轮播广告表,促销活动通知表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- 优惠券表 
create table sms_coupon
(
id bigint auto_increment
primary key comment 'id',
type int(1) null comment '所属类型;0->注册赠券;1->购物赠券;2->店铺赠券;3->全场赠券;',
name varchar(100) null comment '名称',
count int null comment '数量',
amount decimal(10, 2) null comment '金额',
per_limit int null comment '每人限领张数',
min_point decimal(10, 2) null comment '使用门槛;0表示无门槛',
start_time datetime null comment '有效时间',
end_time datetime null comment '失效时间',
note varchar(200) null comment '备注',
enable_time datetime null comment '可领取日期',
publish_count int null comment '发行数量',
receive_count int null comment '已领取数量',
)
comment '优惠券表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
-- 促销活动表
create table sms_flash_promotion
(
id bigint auto_increment
primary key comment 'id',
title varchar(200) null comment '活动名称',
start_date date null comment '开始日期',
end_date date null comment '结束日期',
status int(1) null comment '上下线状态',
create_time datetime null comment '创建时间'
)
comment '促销活动表' charset = utf8
row_format = DYNAMIC
1
2
3
4
5
6
7
8
9
10
11
12
13
-- 轮播广告表 
create table sms_home_advertise
(
id bigint auto_increment
primary key comment 'id',
name varchar(100) null comment '广告名称',
pic varchar(500) null comment '轮播图片',
start_time datetime null comment '开始时间',
end_time datetime null comment '结束时间',
status int(1) null comment '上下线状态:0->下线;1->上线',
)
comment '轮播广告表' charset = utf8
row_format = DYNAMIC;

权限模块相关表:后台用户表,注册用户表,用户角色表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 后台用户表 
create table ums_admin
(
id bigint auto_increment
primary key comment 'id'
user_name varchar(64) null comment '账号名',
password varchar(64) null comment '密码',
icon varchar(500) null comment '头像',
email varchar(100) null comment '邮箱',
note varchar(500) null comment '备注信息',
user_role int(1) null comment '用户角色',
create_time datetime null comment '创建时间',
login_time datetime null comment '最后登录时间',
status int(1) default 1 null comment '帐号启用状态:0->禁用;1->启用'
)
comment '后台用户表' charset = utf8
row_format = DYNAMIC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 注册用户表
create table ums_member
(
id bigint auto_increment
primary key comment 'id',
user_name varchar(64) null comment '用户名',
password varchar(64) null comment '密码',
nickname varchar(64) null comment '昵称',
user_role int(1) null comment '用户角色',
phone varchar(64) null comment '手机号码',
email varchar(100) null comment '邮箱',
status int(1) null comment '帐号启用状态:0->禁用;1->启用',
icon varchar(500) null comment '头像',
gender int(1) null comment '性别:0->未知;1->男;2->女',
birthday date null comment '生日',
city varchar(64) null comment '所在城市',
job varchar(100) null comment '职业',
personalized_signature varchar(200) null comment '个性签名',
create_time datetime null comment '注册时间'
)
comment '注册用户表' charset = utf8
row_format = DYNAMIC;
1
2
3
4
5
6
7
8
9
10
11
12
13
-- 用户角色表 
create table ums_role
(
id bigint auto_increment
primary key comment 'id',
name varchar(100) null comment '角色名称',
description varchar(500) null comment '角色描述',
count int null comment '包含用户数量',
create_time datetime null comment '创建时间',
status int(1) default 1 null comment '启用状态:0->禁用;1->启用',
)
comment '后台用户角色表' charset = utf8
row_format = DYNAMIC;

好极了,目前缩减至十九张表。

2025 年 3 月 6 日

历时两天,完成数据库概念设计和数据库逻辑设计。

功能结构

2025 年 3 月 3 日

项目主页 | mall学习教程 (macrozheng.com)

功能需求分析,前台功能和后台功能。

角色用例分析,管理员角色用例和普通用户角色用例。

系统功能结构设计,前台功能结构设计和后台功能结构设计。

系统流程分析,从注册登录,到检索选择自己想要的商品,完善收获地址信息下单后添加进购物车,最终支付订单的整个流程。

这块儿详细写两个流程分析,用户登录注册,以及购买商品的整个流程。

系统流程图,数据库设计,数据库概念设计和逻辑设计。

系统实现,后台登录模块和后台管理模块,前台登录模块和前台使用模块。

系统测试,网站登录测试,选购商品测试,支付下单测试。

基本就是以上几点内容。针对每一条再做细节优化和内容填充。


功能需求分析。

前台功能:首页智能推荐商品详情展示购物下单功能活动精准推送我的个人空间

后台功能:商品管理功能,订单管理功能,营销管理功能,权限管理功能和用户管理功能。

前台功能通俗版

  1. 首页猜你喜欢
    • 轮播大图推爆款 | 品牌直营专区 | 新人必买清单 | 根据浏览记录智能推荐
  2. 商品详情百科
    • 分类找货更方便 | 商品图文详情页(参数对比一目了然) | 秒杀/新品专属福利区
  3. 从购物车到付款
    • 加购商品随时改 | 自动计算优惠价 | 多支付方式一键下单 | 物流实时追踪
  4. 活动精准推送
    • 节日大促专题页(如618/双11) | 限时抢购倒计时 | 猜你喜欢个性化推荐
  5. 我的个人空间
    • 优惠券/收藏夹管理 | 收货地址簿 | 浏览足迹回溯 | 商品评价记录

角色用例分析。

管理员角色用例:商品管理,订单管理,促销管理,运营管理,权限管理,用户管理,内容管理,统计报表,财务管理。

普通用户角色用例:登录和注册,修改个人资料,查看促销活动,查看优惠券,浏览商品,浏览详情页,查看账户余额,添加购物车,多方式支付下单,查看我的订单。

系统功能结构设计。

系统前台功能:登录,注册,个人中心,首页门户,商品推荐,商品搜索,商品展示,购物车,订单流程,帮助中心,客户服务。

系统后台功能:商品管理,订单管理,促销管理,运营管理,权限管理,用户管理,内容管理,财务管理。

系统流程分析。

本系统涉及到的主要流程有:用户登录注册,浏览选购,选择规格加购,支付订单,收货评价。

登录注册流程:

用户下单流程:用户选择商品检查库存确认订单信息支付订单

本系统主要流程如下

  1. 注册/登录
    • 新用户手机号一键注册,老用户支持微信/账号密码登录
    • 后台支撑:用户权限管理、登录日志风控(防刷号)
  2. 浏览选购
    • 首页搜商品(关键词搜索/分类导航)、看详情页(参数对比/买家秀)
    • 后台支撑:商品分类管理、库存状态实时同步
  3. 选规格加购
    • 选择颜色/尺寸/套餐,加入购物车或直接购买
    • 后台支撑:SKU库存动态扣减、购物车有效期设置
  4. 支付订单
    • 合并购物车商品,选择优惠券抵扣,微信/支付宝/银行卡支付
    • 后台支撑:订单状态流转(待付款→已支付)、支付流水对账
  5. 收货评价
    • 查看物流轨迹,确认收货后发表带图评价
    • 后台支撑:物流接口对接、评价内容审核

用户购物下单流程

  1. 用户选择商品
    • 用户在商城浏览商品,根据喜好选择商品型号(如颜色、尺寸等)。
  2. 检查库存
    • 如果商品库存充足,用户可以加入购物车或立即购买;如果库存不足,则提示“库存不足,无法购买”。
  3. 确认订单信息
    • 用户点击“立即购买”后,进入订单确认页面,显示商品信息、总金额、优惠券抵扣及支付方式(如余额支付、微信支付等)。
  4. 支付订单
    • 用户点击“支付”后:
      • 若支付成功(余额充足或第三方支付成功),订单生成,库存扣减,用户收到订单成功通知;
      • 若支付失败(余额不足或支付超时),订单取消,返回支付页面重新操作。

系统流程图。

数据库设计,数据库概念设计和逻辑设计。

系统测试,网站登录测试,选购商品测试,下单支付测试。

剩下的这三块核心内容今天先暂时不做补充,补充前三章内容先。

【毕业设计】– 如何使用Visio画系统功能结构图_系统功能模块图怎么画-CSDN博客

毕业论文中的系统总体设计流程图如何画-百度经验 (baidu.com)

系统流程

2025 年 3 月 4 日

完成系统流程图。

系统实现

2025 年 3 月 7 日

项目主页 | mall学习教程 (macrozheng.com)

后台功能模块

后台登录模块:

后台管理模块:

前台功能模块

前台登录模块:

前台使用模块:

2025 年 4 月 1 日

自从半个多月前中期答辩结束后,再没有关注论文和毕设,今天估摸着工作量,只有修改数据库。

数据库商品品牌,对应商品信息,规格,这些都要一个个调整,前端页面展示才算正常。

好无聊的工作。

2025 年 4 月 2 日

盯盯拍价格_百度搜索 (baidu.com)

盯盯拍促销广告_百度图片搜索 (baidu.com)

汽配销售广告海报_百度图片搜索 (baidu.com)

特斯拉_百度图片搜索 (baidu.com)

基于Java Web的汽车销售管理系统的设计与实现—附源码97848_基于web的汽车销售信息管理系统设计与实现-CSDN博客

image-20250402212144516

十点二十分了,搞了五个多小时。

2025 年 4 月 10 日

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@所有人,请注意:目前我在修改论文中发现的共性问题
1.相关技术:挑选3-4个系统用到的核心技术介绍,尽量用自己的语句描述,不能照搬AI,这一部分容易造成较高的查重率
说明:这一部分不是必要的,根据自己的系统实际情况设置
2.需求分析:需要补充系统整体用例图,大部分同学都是按角色单独罗列的!!!
例如:参考以下这篇论文中3.1节的系统整体用例图用
3.系统总体设计:包含系统架构设计、功能结构设计、类设计(指系统整体类设计)
4.系统详细设计:需包含系统核心功能模块(至少3个)的类的详细设计、数据库设计(包括E-R模型和主要数据库表设计)
说明:系统总体设计和详细设计中,大部分同学都没有关于类的设计,需要补充类设计!!!
例如:参考以下这篇论文中4.1节架构设计、4.4节的系统类设计、5.1节中核心功能类的详细设计
5.系统实现:包含系统核心功能模块的详细实现(用顺序图表示)、数据库的连接、系统各个运行功能截图
说明:大部分同学都没有用顺序图描述核心功能的实现,需要补充!!!
例如:参考以下这篇论文中5.1节中核心功能的顺序图如何实现
6.系统测试:包括测试目的和意义、测试用例(至少3个系统核心功能的)、测试结果
7.结论:1)本文用什么技术实现了系统的什么功能,即本文所做的工作的总结;2)对本系统存在的不足作总结及未来的计划的改进

用户登录实现

2025 年 4 月 11 日

用户登录详细设计。

1
用户登录模块包含用户认证、权限验证和日志记录,涉及到的类有用户类(User)、角色类(Role)、权限类(Permission)和登录日志类(LoginLog)。用户类中除了基本的属性如username、password和status外,还包含checkPassword方法用于验证用户输入的密码是否与存储的加密,isLocked方法用于检查账户是否被锁定,encryptPassword方法用于密码加密存储。角色类通过hasPermission方法验证用户是否拥有特定权限,addPermission方法用于动态添加权限。权限类通过isApiPermission方法判断权限类型,getFullPermissionCode方法生成完整的权限标识。登录日志类中的createSuccessLog静态方法用于快速创建成功登录日志记录,自动填充IP、设备和时间等信息。这些类通过关联关系协同工作,用户类关联多个角色类形成用户-角色关系,角色类关联多个权限类构成角色-权限映射,用户类与登录日志类形成一对多的登录记录关系,共同完成从用户认证到权限控制的完整流程。类详细设计如下。

用户登录类关系图。

classDiagram
    %% 类定义
    class User {
        -id: Long
        -username: String
        -password: String
        -status: Integer
        +checkPassword(inputPassword: String): boolean
        +isLocked(): boolean
        +encryptPassword(rawPassword: String): void
    }

    class Role {
        -id: Long
        -code: String
        -name: String
        +hasPermission(permissionCode: String): boolean
        +addPermission(permission: Permission): void
    }

    class Permission {
        -id: Long
        -code: String
        -resourceType: String
        +isApiPermission(): boolean
        +getFullPermissionCode(): String
    }

    class LoginLog {
        -id: Long
        -userId: Long
        -ip: String
        -device: String
        +createSuccessLog(user: User, request: HttpServletRequest): LoginLog
    }

    %% 类关系
    User "1" *-- "n" Role : "拥有"
    Role "1" *-- "n" Permission : "包含"
    User "1" ..> "n" LoginLog : "生成"
1
用户登录模块中相关的数据库表包含用户表(sys_user)、角色表(sys_role)、权限表(sys_permission)、用户角色关联表(sys_user_role)、角色权限关联表(sys_role_permission)以及登录日志表(sys_login_log)。通过用户表中的用户状态字段与角色权限体系建立连接,在用户登录时进行多层级验证,包括密码校验、账户状态检查和权限加载。登录日志表记录了每次登录的详细上下文信息,包括IP地址、设备类型和操作结果,这些数据通过用户ID与用户表关联。权限控制体系采用RBAC模型,用户通过角色关联权限,权限表中的权限编码字段与前端菜单及接口权限绑定,形成完整的访问控制链。数据库表结构中,用户表存储加密后的密码和盐值,角色表定义数据权限范围,权限表标记资源类型和操作标识,关联表维护多对多关系,登录日志表实现审计追踪,各表通过外键约束确保数据一致性,共同支撑从身份认证到权限管理的全流程。数据库表结构如下。

数据库表结构。

表5-1 后台用户表

列名 数据类型 主键 是否为空 说明
id bigint Y N 用户ID
username varchar(64) N N 登录账号(唯一)
password varchar(128) N N BCrypt加密后的密码
salt varchar(32) N N 加密盐值
phone varchar(20) N Y 绑定手机号(唯一)
email varchar(100) N Y 绑定邮箱(唯一)
avatar varchar(255) N Y 头像URL
status tinyint(1) N N 状态(0-禁用,1-正常,2-锁定)
last_login_ip varchar(50) N Y 最后登录IP
last_login_time datetime N Y 最后登录时间
create_time datetime N N 创建时间
update_time datetime N Y 更新时间
is_deleted tinyint(1) N N 逻辑删除(0-未删,1-已删)

表5-2 角色表

列名 数据类型 主键 是否为空 说明
id bigint Y N 角色ID
code varchar(50) N N 角色编码(如ROLE_ADMIN)
name varchar(50) N N 角色名称
data_scope tinyint(1) N Y 数据权限(0-全部,1-本部门)
description varchar(200) N Y 描述
create_time datetime N N 创建时间
update_time datetime N Y 更新时间
is_deleted tinyint(1) N N 逻辑删除

表5-3 权限表

列名 数据类型 主键 是否为空 说明
id bigint Y N 权限ID
code varchar(100) N N 权限码(如user:add)
name varchar(50) N N 权限名称
resource_type varchar(20) N N 资源类型(menu/button/api)
url varchar(255) N Y 接口URL
method varchar(10) N Y HTTP方法(GET/POST等)
parent_id bigint N Y 父权限ID(树形结构)
order_num int N Y 排序权重
create_time datetime N N 创建时间

表5-4 用户角色关联表

列名 数据类型 主键 是否为空 说明
user_id bigint Y(联合主键) N 用户ID
role_id bigint Y(联合主键) N 角色ID

表5-5 角色权限关联表

列名 数据类型 主键 是否为空 说明
role_id bigint Y(联合主键) N 角色ID
permission_id bigint Y(联合主键) N 权限ID

表5-6登录日志表

列名 数据类型 主键 是否为空 说明
id bigint Y N 日志ID
user_id bigint N Y 用户ID
username varchar(64) N Y 用户名(冗余)
ip varchar(50) N Y 登录IP
location varchar(100) N Y IP解析的地理位置
device varchar(200) N Y 设备信息
status tinyint(1) N N 登录结果(0-失败,1-成功)
error_msg varchar(200) N Y 失败原因
login_time datetime N N 登录时间
1
图5-2所示的用户登录流程图完整呈现了系统实现用户身份认证的核心流程,该流程通过分层验证机制(账户状态检查→密码匹配验证→权限树加载)确保安全准入,最终生成携带用户身份信息的JWT令牌并完成审计日志记录,各环节严格对应图5-1类图设计的实体关系与功能方法。

用户登录流程图。

flowchart TD
    A([开始]) --> B[用户输入用户名密码]
    B --> C{系统验证}
    C -->|用户不存在/禁用/锁定| D[返回错误信息]
    C -->|用户正常| E[验证密码]
    E -->|密码错误| F[记录失败日志]
    F --> G{失败次数>=5?}
    G -->|是| H[锁定账户]
    G -->|否| D
    E -->|密码正确| I[加载权限生成JWT]
    I --> J[记录成功日志]
    J --> K[返回令牌信息]
    K --> L([结束])
    D --> L
    H --> D
1
当用户在前端页面输入用户名和密码并点击登录按钮时,系统首先会通过用户输入的用户名在数据库中查询对应的User对象,如果用户不存在或状态为禁用/锁定则立即返回登录失败信息并记录到LoginLog中;如果用户存在且状态正常,则调用User的checkPassword方法验证输入的密码是否与数据库中存储的加密密码匹配,密码验证失败会更新用户失败次数并在达到阈值时锁定账户,同时记录失败日志;密码验证通过后,系统会根据User关联的Roles和Permissions生成该用户的完整权限集合,创建一个包含用户基本信息和权限的JWT令牌返回给前端,同时记录一条成功的LoginLog日志包含用户IP、设备和时间等信息,最后更新用户的最后登录时间。在整个流程中,任何异常情况都会触发相应的错误处理机制,确保系统安全性和数据一致性。这个流程涵盖了用户认证、权限处理、安全控制和日志记录等关键环节,为后续绘制详细的登录时序图提供了完整的逻辑基础。顺序图如图 5-3

绘制用户登录时序图。

%% 用户登录时序图
sequenceDiagram
    actor 用户 as 用户
    participant 前端 as 前端页面
    participant LoginController as LoginController
    participant AuthService as AuthService
    participant UserRepository as UserRepository
    participant User as User
    participant LoginLogService as LoginLogService
    participant JwtTokenUtil as JwtTokenUtil
    participant RolePermissionMapper as RolePermissionMapper

    用户 ->> 前端: 输入用户名/密码,点击登录
    前端 ->> LoginController: POST /api/login {username, password}
    LoginController ->> AuthService: authenticate(username, password)
    
    %% 用户验证阶段
    alt 用户不存在/禁用/锁定
        AuthService ->> UserRepository: findByUsername(username)
        UserRepository -->> AuthService: null 或 User(status=0/2)
        AuthService -->> LoginController: 抛出UserNotFoundException/AccountLockedException
        LoginController -->> 前端: 返回4xx错误及原因
        前端 -->> 用户: 显示错误提示
    else 用户正常
        AuthService ->> UserRepository: findByUsername(username)
        UserRepository -->> AuthService: User对象
        AuthService ->> User: checkPassword(inputPassword)
        
        %% 密码验证分支
        alt 密码错误
            User -->> AuthService: false
            AuthService ->> UserRepository: incrementFailedAttempts(userId)
            AuthService ->> LoginLogService: logFailure(userId, ip, "密码错误")
            AuthService -->> LoginController: 抛出BadCredentialsException
            LoginController -->> 前端: 返回401错误
            前端 -->> 用户: 显示密码错误
        else 密码正确
            User -->> AuthService: true
            AuthService ->> RolePermissionMapper: loadPermissions(userId)
            RolePermissionMapper -->> AuthService: List<Permission>
            AuthService ->> JwtTokenUtil: generateToken(userDetails)
            JwtTokenUtil -->> AuthService: JWT令牌
            AuthService ->> LoginLogService: logSuccess(userId, ip, device)
            AuthService ->> UserRepository: updateLastLogin(userId, time)
            AuthService -->> LoginController: LoginResponse(JWT, userInfo)
            LoginController -->> 前端: 返回200及JWT
            前端 ->> 前端: localStorage.setItem("token", JWT)
            前端 -->> 用户: 跳转到首页
        end
    end

选购下单实现

2025 年 4 月 11 日

1
商品选购下单模块包含商品展示、购物车管理、订单生成和支付处理,涉及到的类有商品类(Product)、品牌类(Brand)、商品分类分类(Category)、订单类(Order)和订单详情类(OrderItem)。商品类中除了基本属性如name、price和stock外,还包含reduceStock方法用于原子性扣减库存,isAvailable方法综合校验商品状态与库存。品牌类通过isActive方法验证品牌可用性,其logo和brandStory字段支撑前端品牌页展示。分类类借助getChildCategories方法构建多级分类树,productCount字段实现分类商品统计。订单类通过calculateFinalPrice方法计算实付金额(含促销、运费等),cancelOrder方法处理订单状态逆向流转并触发库存释放。这些类通过强关联协同工作,商品类关联唯一品牌类形成商品-品牌归属关系,关联唯一分类类建立商品-分类层级体系,订单类通过组合模式管理订单明细项(OrderItem),在明细中冗余存储商品快照信息(如brandName、categoryName),确保历史订单数据不受商品信息变更影响,共同完成从商品浏览到支付结算的完整电商交易闭环。类详细设计如下。

选购下单类关系图。

classDiagram
    %% 1. 类定义(属性与数据库表字段严格对应)
    class Brand {
        +id: Long
        +name: String
        +firstLetter: String
        +productCount: Integer
        +logo: String
        +brandStory: String
        +isActive() Boolean
    }

    class Product {
        +id: Long
        +name: String
        +description: String
        +price: BigDecimal
        +promotionPrice: BigDecimal
        +stock: Integer
        +lowStock: Integer
        +publishStatus: Integer
        +brandId: Long
        +productCategoryId: Long
        +reduceStock() Boolean
        +calculatePromotionPrice() BigDecimal
    }

    class Category {
        +id: Long
        +name: String
        +level: Integer
        +parentId: Long
        +productCount: Integer
        +productUnit: String
        +getChildCategories() List~Category~
    }

    class Order {
        +id: Long
        +totalAmount: BigDecimal
        +payAmount: BigDecimal
        +status: Integer
        +payType: Integer
        +deliverySn: String
        +calculateFinalPrice() BigDecimal
        +cancelOrder() Boolean
    }
    
     class OrderItem {
        +productName: String
        +brandName: String
        +categoryName
    }

    %% 2. 关系定义(箭头类型与表外键匹配)
    Product "1" --> "1" Brand : "brand_id"
    Product "1" --> "1" Category : "product_category_id"
    Order "1" *-- "n" OrderItem : "id"
    Product ..> OrderItem : "快照关联"
1
商品选购下单模块的数据库设计包含品牌管理、商品信息、分类体系、订单交易、购物车和评价系统,涉及的核心表包括品牌表(pms_brand)、商品信息表(pms_product)、商品分类表(pms_category)、订单表(oms_order)、购物车表(oms_cart)和商品评价表(pms_review)。品牌表通过id和name字段维护品牌基础信息,商品信息表以brand_id和product_category_id关联品牌与分类,并包含publish_status和promotion_type字段管理上下架及促销状态。订单表通过member_id关联用户,status字段标记订单生命周期(0-待付款到5-无效订单),购物车表冗余存储product_brand和product_category_id确保数据一致性,商品评价表通过star和pics字段实现多维度的评价展示。所有表均包含create_time、update_time和is_delete字段实现软删除与审计追踪,构成完整的电商交易数据体系。数据库表结构如下:

选购下单数据库表。

表5-7 品牌表

列名 数据类型 主键 是否为空 说明
id bigint Y F id
name varchar(64) F F 品牌名称
first_letter varchar(8) F F 首字母
product_count int F F 产品数量
logo varchar(255) F F 品牌logo
brand_story text F F 品牌故事
create_time datetime F F 创建时间
update_time datetime F F 更新时间
is_delete int(1) F F 是否删除(0->已删除;1->未删除)

表5-8 商品信息表

列名 数据类型 主键 是否为空 说明
id bigint Y N id
description text N N 商品描述
brand_id bigint N N 所属品牌
product_category_id bigint N N 所属分类
product_attribute_category_id bigint N N 所属属性分类
name varchar(200) N N 商品名称
pic varchar(255) N N 商品样图
publish_status int(1) N N 上架状态(0->下架;1->上架)
sale int N N 销量
price decimal(10, 2) N N 销售价格
promotion_price decimal(10, 2) N N 促销价格
promotion_type int(1) N N 促销类型(0->使用原价;1->使用满减价格;2->使用促销价;4->限时购)
stock int N N 库存
low_stock int N N 库存预警值
weight decimal(10, 2) N N 商品重量(默认为克)
create_time datetime N N 创建时间
update_time datetime N N 更新时间
is_delete int(1) N N 是否删除(0->已删除;1->未删除)

表5-9 商品分类表

列名 数据类型 主键 是否为空 说明
id bigint Y N id
name varchar(64) N N 分类名称
description text N N 描述
parent_id bigint N N 上级分类级别(0表示一级分类)
level int(1) N N 所属分类级别(0->1级;1->2级)
product_count int N N 商品数量
product_unit varchar(64) N N 商品数量单位
icon varchar(255) N N 图标
create_time datetime N N 创建时间
update_time datetime N N 更新时间
is_delete int(1) N N 是否删除(0->已删除;1->未删除)

表5-10 订单表

列名 数据类型 主键 是否为空 说明
id bigint Y N id
member_id bigint N N 下单用户
payment_time datetime N N 支付时间
pay_amount decimal(10, 2) N N 实支金额
freight_amount decimal(10, 2) N N 运费金额
total_amount decimal(10, 2) N N 订单总金额
promotion_amount decimal(10, 2) N N 促销优化金额(促销价、满减)
coupon_amount decimal(10, 2) N N 优惠券抵扣金额
pay_type int(1) N N 支付方式(0->未支付;1->支付宝;2->微信)
status Int(1) N N 订单状态(0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单)
receiver_name varchar(100) N N 收货人姓名
receiver_phone varchar(32) N N 收货人电话
note varchar(500) N N 订单备注
delivery_company varchar(64) N N 物流公司(配送方式)
delivery_sn varchar(64) N N 物流单号
receiver_detail_address varchar(200) N N 收货详细地址
confirm_status int(1) N N 确认收货状态(0->未确认;1->已确认)
delivery_time datetime N N 发货时间
create_time datetime N N 创建时间
update_time datetime N N 更新时间
is_delete int(1) N N 是否删除(0->已删除;1->未删除)

表5-11 购物车表

列名 数据类型 主键 是否为空 说明
id bigint Y N id
product_id bigint N N 购买商品
member_id bigint N N 购买用户
quantity int N N 购买数量
price decimal(10, 2) N N 需付金额
price_reduce decimal(10, 2) N N 实付金额
product_pic varchar(1000) N N 商品主图
product_category_id bigint N N 所属分类
product_brand varchar(200) N N 所属品牌
product_attr_id varchar(500) N N 所属商品属性
create_time datetime N N 创建时间
update_time datetime N N 更新时间
is_delete int(1) N N 是否删除(0->已删除;1->未删除)

表5-12 商品评价表

列名 数据类型 主键 是否为空 说明
id bigint Y N id
product_id bigint N N 所属商品
member_id bigint N N 所属用户
content text N N 评价内容
star int(3) N N 评价星数(0-5)
pics varchar(1000) N N 上传图片地址(以逗号隔开)
collect_counnt int N N 点赞数量
read_count int N N 阅读数量
replay_count int N N 回复数量
create_time datetime N N 创建时间
update_time datetime N N 更新时间
is_delete int(1) N N 是否删除(0->已删除;1->未删除)
1
当用户在前端页面选择商品并触发addToCart操作时,系统首先通过ProductService.checkStock方法校验商品库存状态,若库存不足或商品已下架则立即返回STOCK_LIMIT错误码;若库存充足则调用CartService.addItem将商品数据写入购物车表,并返回实时计算的购物车总价。用户点击结算按钮时,前端调用OrderService.createDraftOrder生成预订单,该方法内部通过PromotionService.calculateDiscount计算满减、折扣等优惠规则,并执行InventoryService.lockStock预占库存,最终返回包含订单号、实付金额的预订单数据。用户确认支付后,系统通过PaymentService.process对接第三方支付渠道,支付成功时调用OrderService.confirmPayment更新订单状态为"待发货",同步触发InventoryService.confirmStockDeduction确认库存扣减和CartService.clear清空购物车;若支付失败或超时,则通过OrderService.cancelOrder回滚订单状态,并执行InventoryService.releaseStock释放预占库存。整个流程通过Order.status状态机(0-待付款→1-待发货→3-已完成)驱动业务流转,任何环节的异常都会通过标准化错误码(如PAY_TIMEOUT、STOCK_CONFLICT)中断流程并恢复数据一致性,确保在高并发场景下仍能维持库存准确性和订单最终状态的可追溯性。该流程完整覆盖了电商交易核心链路,为图5-3所示的时序图提供了精确的方法级交互基础。

选购下单时序图。

sequenceDiagram
    actor 用户 as 用户
    participant 前端 as 前端
    participant ProductService as 商品服务
    participant CartService as 购物车服务
    participant OrderService as 订单服务
    participant PromotionService as 促销服务
    participant PaymentService as 支付服务
    participant InventoryService as 库存服务

    用户 ->> 前端: 添加商品到购物车
    前端 ->> ProductService: checkStock(productId, quantity)
    alt 库存充足
        ProductService --> 前端: {stock: 10, price: 99}
        前端 ->> CartService: addItem(userId, productData)
        CartService --> 前端: 更新后的购物车数据
    else 库存不足
        ProductService --> 前端: {errorCode: "STOCK_LIMIT"}
    end

    用户 ->> 前端: 点击结算
    前端 ->> OrderService: createDraftOrder(cartItems)
    OrderService ->> PromotionService: calculateDiscount(cartItems)
    PromotionService --> OrderService: {discount: 20}
    OrderService ->> InventoryService: lockStock(productId, quantity)
    OrderService --> 前端: {orderNo: "NO123", amount: 79}

    用户 ->> 前端: 确认支付
    前端 ->> PaymentService: process(orderNo, amount)
    alt 支付成功
        PaymentService ->> OrderService: confirmPayment(orderNo)
        OrderService ->> InventoryService: confirmStockDeduction(orderNo)
        OrderService ->> CartService: clear(userId)
        PaymentService --> 前端: {status: "SUCCESS"}
    else 支付失败
        PaymentService --> 前端: {errorCode: "PAY_FAILED"}
        OrderService ->> InventoryService: releaseStock(orderNo)
    end
1
当用户选择商品时,系统首先检查库存状态,库存充足则加入购物车,不足则提示;用户结算后生成待支付订单,支付成功则扣减库存并标记订单完成,支付失败或超时则释放预占库存并取消订单,最终形成从选购到订单终态的核心闭环流程。

选购下单程序流程图。

flowchart TD
    A(开始) --> B[选择商品]
    B --> C{库存检查}
    C -->|有货| D[加入购物车]
    C -->|无货| E[提示库存不足]
    D --> F[结算生成订单]
    F --> G[支付处理]
    G -->|成功| H[扣减库存]
    H --> I[订单完成]
    G -->|失败| J[释放库存]
    J --> K[订单取消]
    I & K --> L(结束)

订单管理实现

2025 年 4 月 11 日

1
订单管理模块围绕订单主类(Order)展开,关联订单明细类(OrderItem)、物流信息类(OrderDelivery)和操作日志类(OrderLog)。订单主类通过status字段驱动状态流转(0待付款→1待发货→3已完成),其cancel()方法处理取消逻辑并触发库存释放,confirmReceive()方法完成收货确认。订单明细类通过productName和price等快照字段保留交易时商品状态,物流信息类依赖track()方法实时查询物流轨迹,操作日志类记录所有关键操作(如取消、发货)。订单主类以组合关系管理明细(1对多),以聚合关系关联物流信息(11),并通过日志形成完整审计链条,构成从创建到完结的闭环管理体系。

订单实现类关系图。

classDiagram
    %% 订单主类(聚合根)
    class Order {
        -id: Long
        -orderSn: String
        -userId: Long
        -totalAmount: BigDecimal
        -payAmount: BigDecimal
        -status: Integer
        -paymentTime: DateTime
        -deliverySn: String
        
        +cancel(): void
        +confirmReceive(): void
        +generateSn(): String
    }

    %% 订单明细类(实体)
    class OrderItem {
        -id: Long
        -orderId: Long
        -productId: Long
        -productName: String
        -price: BigDecimal
        -quantity: Integer
        
        +calcSubtotal(): BigDecimal
    }

    %% 物流信息类(值对象)
    class OrderDelivery {
        -id: Long
        -orderId: Long
        -deliveryCompany: String
        -deliverySn: String
        -receiverAddress: String
        
        +track(): String
    }

    %% 操作日志类(实体)
    class OrderLog {
        -id: Long
        -orderId: Long
        -action: String
        -operator: String
        
        +logAction(): void
    }

    %% 关系定义
    Order "1" *-- "n" OrderItem : 包含 >
    Order "1" o-- "1" OrderDelivery : 使用 >
    Order "1" *-- "n" OrderLog : 记录 >
1
订单管理模块的数据库设计围绕订单表(order)展开,通过订单明细表(order_item)记录商品快照信息,物流信息表(order_delivery)跟踪配送状态,操作日志表(order_log)审计关键操作。订单表以status字段(0待付款/1待发货/2已发货/3已完成)驱动核心流程,通过order_sn保证业务唯一性,并关联user_id标记用户归属;订单明细表通过order_id外联主订单,保留product_name和快照数据确保历史订单不受商品变更影响;物流信息表记录delivery_company和delivery_sn实现物流追踪;操作日志表通过action字段(如"支付"/"取消")和operator记录操作轨迹。所有表均包含create_time实现时间维度追溯,退货申请表(order_return)作为扩展支持售后流程,形成从订单创建、状态变更到最终完结的完整数据闭环。

订单管理数据库表。

表5-12 订单表

列名 数据类型 主键 是否为空 说明
id bigint Y N id
member_id bigint N N 下单用户
payment_time datetime N N 支付时间
pay_amount decimal(10, 2) N N 实支金额
freight_amount decimal(10, 2) N N 运费金额
total_amount decimal(10, 2) N N 订单总金额
promotion_amount decimal(10, 2) N N 促销优化金额(促销价、满减)
coupon_amount decimal(10, 2) N N 优惠券抵扣金额
pay_type int(1) N N 支付方式(0->未支付;1->支付宝;2->微信)
status Int(1) N N 订单状态(0->待付款;1->待发货;2->已发货;3->已完成;4->已关闭;5->无效订单)
receiver_name varchar(100) N N 收货人姓名
receiver_phone varchar(32) N N 收货人电话
note varchar(500) N N 订单备注
delivery_company varchar(64) N N 物流公司(配送方式)
delivery_sn varchar(64) N N 物流单号
receiver_detail_address varchar(200) N N 收货详细地址
confirm_status int(1) N N 确认收货状态(0->未确认;1->已确认)
delivery_time datetime N N 发货时间
create_time datetime N N 创建时间
update_time datetime N N 更新时间
is_delete int(1) N N 是否删除(0->已删除;1->未删除)

表5-13 订单明细表

列名 数据类型 主键 是否为空 说明
id bigint Y N 明细ID
order_id bigint N 关联订单ID
product_id bigint Y 商品ID(允许商品删除后为空)
product_name varchar(200) N 商品名称快照
price decimal(10,2) N 成交单价快照
quantity int N 购买数量
create_time datetime N 创建时间

表5-14 订单操作日志表

列名 数据类型 主键 是否为空 说明
id bigint Y N 物流记录ID
order_id bigint N 关联订单ID
delivery_company varchar(32) N 物流公司(如顺丰、中通)
delivery_sn varchar(64) N 物流单号
receiver_address varchar(200) N 完整收货地址
create_time datetime N 创建时间

表5-15 物流信息表

列名 数据类型 主键 是否为空 说明
id bigint Y N 物流记录ID
order_id bigint N 关联订单ID
delivery_company varchar(32) N 物流公司(如顺丰、中通)
delivery_sn varchar(64) N 物流单号
receiver_address varchar(200) N 完整收货地址
create_time datetime N 创建时间

表5-16 退货申请表

列名 数据类型 主键 是否为空 说明
id bigint Y N 退货ID
order_id bigint N 关联订单ID
product_id bigint N 退货商品ID
reason varchar(200) N 退货原因
status int N 状态(0待处理/1通过/2拒绝)
create_time datetime N 申请时间
1
流程始于用户提交订单,系统首先检查库存,充足则生成预订单(状态0),不足则直接终止;用户支付时分支判断:成功则扣减库存、生成物流单并更新状态为1,失败则释放库存;发货后用户可查询物流轨迹,最终确认收货将状态置为3。流程以订单状态(0/1/3)为核心驱动,库存操作(预占/扣减/释放)和物流生成作为关键子流程,异常路径(如支付超时)自动触发状态回滚,形成从创建到完成的线性闭环。

订单管理程序流图。

flowchart TD
    A([开始]) --> B{用户操作}
    B -->|提交订单| C[库存预占]
    C --> D{库存充足?}
    D -->|是| E[生成预订单\n状态=0]
    D -->|否| F[返回库存不足]
    E --> G{用户操作}
    G -->|确认支付| H[调用支付接口]
    H --> I{支付成功?}
    I -->|是| J[扣减库存]
    J --> K[生成物流单]
    K --> L[更新订单\n状态=1]
    I -->|否| M[释放库存]
    M --> N[保持状态=0]
    L --> O{用户操作}
    O -->|查询物流| P[获取物流轨迹]
    O -->|确认收货| Q[更新订单\n状态=3]
    Q --> R([结束])
    N --> R
    F --> R
1
当用户提交订单时,系统调用OrderService.createOrder()预占库存并生成待支付订单(状态0);用户支付成功后,PaymentService触发confirmPayment()更新订单状态为1(待发货),同步扣减库存并生成物流单;支付失败时通过cancelOrder()释放库存。用户可通过DeliveryService.track()查询物流轨迹,确认收货后调用confirmReceive()将状态更新为3(已完成)。全流程通过OrderLog记录操作日志,任何异常(如库存不足、支付超时)均中断流程并恢复数据一致性,确保订单状态与库存、物流的严格同步。

订单管理时序图。

sequenceDiagram
    actor 用户 as 用户
    participant 前端 as 前端
    participant OrderService as 订单服务
    participant PaymentService as 支付服务
    participant InventoryService as 库存服务
    participant DeliveryService as 物流服务

    用户 ->> 前端: 提交订单
    前端 ->> OrderService: createOrder(商品列表)
    OrderService ->> InventoryService: lockStock(商品ID,数量)
    InventoryService -->> OrderService: 锁定结果
    OrderService -->> 前端: 返回预订单(状态0)

    用户 ->> 前端: 确认支付
    前端 ->> PaymentService: processPayment(订单ID)
    alt 支付成功
        PaymentService ->> OrderService: confirmPayment(订单ID)
        OrderService ->> InventoryService: confirmDeduction(订单ID)
        OrderService ->> DeliveryService: prepareDelivery(订单ID)
        DeliveryService -->> OrderService: 物流单号
        OrderService -->> 前端: 支付成功(状态1)
    else 支付失败
        PaymentService ->> OrderService: cancelOrder(订单ID)
        OrderService ->> InventoryService: releaseStock(订单ID)
        OrderService -->> 前端: 支付失败(状态0)
    end

    用户 ->> 前端: 查询物流
    前端 ->> DeliveryService: track(物流单号)
    DeliveryService -->> 前端: 返回物流轨迹

    用户 ->> 前端: 确认收货
    前端 ->> OrderService: confirmReceive(订单ID)
    OrderService ->> OrderLog: 记录操作日志
    OrderService -->> 前端: 订单完成(状态3)

需求分析

2025 年 4 月 12 日

整体用例图。

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#1a1a1a', 'actorBorder': '#ffffff'}}}%%
graph TD
    %% 参与者定义
    actor1(("消费者"))
    actor2(("管理员"))
   
    %% 前台系统用例
    A[浏览智能推荐商品]
    B[查看商品详情]
    C[购物车管理]
    D[下单支付]
    E[参与促销活动]
    F[管理个人空间]
    F1[查看订单]
    F2[管理收货地址]
    F3[管理收藏夹]
    
    %% 后台系统用例
    G[商品管理]
    G1[上架商品]
    G2[商品分类管理]
    H[订单管理]
    H1[物流跟踪]
    I[营销管理]
    I1[活动配置]
    J[用户管理]
    K[权限管理]
    K1[角色分配]
    
    %% 连接关系
    actor1 --> A
    actor1 --> B
    actor1 --> C
    actor1 --> D
    actor1 --> E
    actor1 --> F
    F --> F1
    F --> F2
    F --> F3
    D -.->|<<include>>| H1
    E -.->|<<include>>| I1
    
    actor2 --> G
    actor2 --> H
    actor2 --> I
    actor2 --> J
    actor2 --> K
    G --> G1
    G --> G2
    H --> H1
    I --> I1
    K --> K1

选购下单用例图。

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#1a1a1a', 'actorBorder': '#ffffff'}}}%%
graph TD
    %% 参与者定义(简笔画风格)
    actor_consumer(("消费者"))
    actor_admin(("管理员"))

    %% 前台功能(白色椭圆框)

    uc1[商品浏览]
    uc2[商品筛选]
    uc3[规格选择]
    uc4[订单确认]
    uc5[支付订单]

    %% 后台功能(白色椭圆框)
    uc6[商品管理]
    uc7[订单管理]
    uc8[库存管理]

    %% 前台流程连接
    actor_consumer --> uc1
    uc1 -->|<<include>>| uc2
    uc2 --> uc3
    uc3 --> uc4
    uc4 -->|<<include>>| uc5
    uc5 -.->|触发| uc8

    %% 后台管理连接
    actor_admin --> uc6
    actor_admin --> uc7
    uc6 -->|<<extend>>| uc8
    uc7 -->|<<extend>>| uc4
graph LR
   商品管理 -- "包含(必须调用)" --> 库存管理

订单管理用例图。

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#1a1a1a', 'actorBorder': '#ffffff'}}}%%
graph TD
    %% 参与者定义
    actor_consumer(("消费者"))
    actor_admin(("管理员"))

    %% 核心状态节点(白色椭圆框)
    s1[待付款]
    s2[待发货]
    s3[已发货]
    s4[已完成]
    s5[已关闭]
    s6[退货处理]

    %% 功能操作节点
    o1[订单列表展示]
    o2[查看订单状态]
    o3[订单筛选]
    o4[删除订单]
    o5[退货申请处理]
    o6[退货原因设置]

    %% 状态流转(实线箭头)
    s1 -->|支付成功| s2
    s1 -->|超时未付| s5
    s2 -->|商家发货| s3
    s3 -->|签收| s4
    s3 -->|发起退货| s6
    s6 -->|处理完成| s5

    %% 功能连接(虚线箭头)
    actor_consumer -.-> o1
    actor_consumer -.-> o2
    actor_admin --> o3
    actor_admin --> o4
    actor_admin --> o5
    actor_admin --> o6
    o5 --> s6

    %% 特殊关系标注
    o1 .->|<<include>>| o2
    o5 .->|<<extend>>| o6

系统类关系图。

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#f8f9fa', 'classText': '#333'}}}%%
classDiagram
    %% 用户中心模块
    class User {
    }
    class Role {
    }
    class Permission {
    }
    class LoginLog {
    }

    User "1" *-- "1..*" Role : 聚合
    Role "1" *-- "n" Permission : 组合
    User "1" --> "n" LoginLog : 关联

    %% 商品中心模块
    class Product {
    }
    class Brand {
    }
    class Category {
    }
    class ProductAttribute {
    }

    Product "1" *-- "1" Brand : 聚合
    Product "1" *-- "1" Category : 聚合
    Product "1" *-- "n" ProductAttribute : 组合

    %% 订单中心模块
    class Order {
    }
    class OrderItem {
    }
    class OrderDelivery {
    }
    class OrderLog {
    }
    class PaymentInfo {
    }

    Order "1" *-- "n" OrderItem : 组合
    Order "1" --> "1" OrderDelivery : 关联
    Order "1" --> "n" OrderLog : 关联
    Order "1" --> "1" PaymentInfo : 组合

    %% 跨模块关系
    User "1" --> "n" Order : 关联
    Product "1" --> "n" OrderItem : 关联
    Category "1" --> "n" Category : 自关联
    Brand ..> OrderItem : 依赖

2025 年 4 月 13 日

类关系图,类设计。

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#f8f9fa', 'classText': '#333'}}}%%
classDiagram
    %% 用户中心模块
    class User {
        +用户ID
        +用户名
        +密码(加密)
        +手机号
        +注册时间
        +login()
        +logout()
        +getUserInfo()
    }
    class Role {
        +角色ID
        +角色名称
        +描述
        +assignPermission()
        +checkPermission()
    }
    class Permission {
        +权限ID
        +权限码
        +描述
        +verify()
    }
    class LoginLog {
        +日志ID
        +登录IP
        +登录时间
        +记录日志()
    }

    User "1" *-- "1..*" Role : 聚合
    Role "1" *-- "n" Permission : 组合
    User "1" --> "n" LoginLog : 关联

    %% 商品中心模块
    class Product {
        +商品ID
        +商品名称
        +库存量
        +售价
        +上架状态
        +addToCart()
        +updateStock()
    }
    class Brand {
        +品牌ID
        +品牌名称
        +logo地址
        +getBrandInfo()
    }
    class Category {
        +分类ID
        +分类名称
        +父分类ID
        +getSubCategories()
    }
    class ProductAttribute {
        +属性ID
        +属性名
        +
        +bindToProduct()
    }

    Product "1" *-- "1" Brand : 聚合
    Product "1" *-- "1" Category : 聚合
    Product "1" *-- "n" ProductAttribute : 组合

    %% 订单中心模块
    class Order {
        +订单ID
        +订单状态
        +总金额
        +下单时间
        +calculateTotal()
        +changeStatus()
    }
    class OrderItem {
        +订单项ID
        +购买数量
        +成交价
        +calculateSubtotal()
    }
    class OrderDelivery {
        +物流单号
        +收货地址
        +发货时间
        +trackDelivery()
    }
    class PaymentInfo {
        +支付单号
        +支付方式
        +支付状态
        +processPayment()
    }

    Order "1" *-- "n" OrderItem : 组合
    Order "1" --> "1" OrderDelivery : 关联
    Order "1" --> "1" PaymentInfo : 组合

    %% 跨模块关系
    User "1" --> "n" Order : 关联
    Product "1" --> "n" OrderItem : 关联
    Category "1" --> "n" Category : 自关联
    Brand ..> OrderItem : 依赖

功能结构

2025 年 4 月 13 日

graph TD
    A[汽配销售管理系统] --> B[前台功能]
    A --> C[后台功能]
    
    %% 前台功能模块
    B --> B1[用户认证]
    B1 -->|包含| B11(登录)
    B1 -->|包含| B12(注册)
    
    B --> B2[个人中心]
    B2 -->|包含| B21(个人信息管理)
    B2 -->|包含| B22(收货地址管理)
    
    B --> B3[商品服务]
    B3 -->|包含| B31(首页门户)
    B3 -->|包含| B32(商品推荐)
    B3 -->|包含| B33(商品搜索)
    B3 -->|包含| B34(商品展示)
    
    B --> B4[交易流程]
    B4 -->|包含| B41(购物车)
    B4 -->|包含| B42(订单流程)
    B4 -->|包含| B43(支付管理)
    
    B --> B5[辅助功能]
    B5 -->|包含| B51(帮助中心)
    B5 -->|包含| B52(客服服务)
    
    %% 后台功能模块
    C --> C1[商品管理]
    C1 -->|包含| C11(商品上架)
    C1 -->|包含| C12(库存管理)
    C1 -->|包含| C13(品牌/分类管理)
    
    C --> C2[订单管理]
    C2 -->|包含| C21(订单审核)
    C2 -->|包含| C22(物流跟踪)
    C2 -->|包含| C23(退换货处理)
    
    C --> C3[营销管理]
    C3 -->|包含| C31(促销活动)
    C3 -->|包含| C32(优惠券管理)
    
    C --> C4[用户管理]
    C4 -->|包含| C41(用户权限)
    C4 -->|包含| C42(角色管理)
    
    C --> C5[系统管理]
    C5 -->|包含| C51(内容管理)
    C5 -->|包含| C52(财务管理)
    C5 -->|包含| C53(数据统计)

查重

2025 年 4 月 23 日

不得不说这是个好消息。

今天早上,这项工作圆满结束了。

早降重论文降重系统官网_解决毕业论文重复率高_机器智能降重_论文润色修改 (zaojiangchong.com)

这个工具倒也挺好用。

image-20250423204254467

image-20250423204328012

image-20250423204342674

整整两周,总算结束了,开启下一个阶段。

2025 年 4 月 21 日

论文检测 (fanyu.com)

image-20250421122822491

维普查重真要命,查重率,AIGC,格式,艹。

AIGC 文段汇总。

1
内容摘要:本文设计并实现了一个基于JavaWeb的汽配销售管理系统,旨在解决传统汽配销售模式效率低下、管理粗放的问题。系统采用SpringBoot框架开发,整合了MySQL数据库、MyBatis等技术,实现了前后端分离的模块化架构。系统角色包括管理员和消费者两类,实现了面向消费者的商品选购、订单支付功能和面向管理员的商品管理、订单处理、用户权限控制等后台管理功能;通过可行性分析验证了经济、操作及技术层面的可行性,基于角色用例分析设计了消费者和管理员两类用户的操作流程,并通过数据库逻辑设计构建了19张核心数据表,覆盖商品、订单、营销等业务场景。系统测试表明,该系统的实现能有效提升汽配销售企业的运营效率,优化客户体验,并为行业数字化转型提供参考。

修改:

1
在传统的汽配商品销售模式中免不了出现效率低下、管理粗放等问题,故本论文设计并实现了一个基于JavaWeb的汽配销售管理系统。该系统采用当今市面上Java主流开发框架实现,其中后台系统使用SpringBoot框架整合MyBatis、MySQL数据库等技术,而前台界面则使用Vue.js技术实现用户点击交互。普通消费者可以在前台前台商城中进行汽配商品检索及浏览、选购下单以及订单支付,后台管理员则主要负责商品管理、订单流程追踪以及用户权限控制等后台管理功能。在投入系统开发前,认真讨论并验证了该系统在经济、操作和技术层面的可信性,合理规划并整理出核心功能列表,并绘制与之对应的用例分析图。除此之外,结合前面列举的核心功能列表,使用MySQL数据库设计了总计19张核心数据库表,覆盖了汽配销售的多个业务场景。在核心功能开发完毕后,在系统测试环节中设计了全面的测试用例,检验逐步完善该系统健壮性,提升用户体验。
1
Abstract This paper presents the design and implementation of a JavaWeb-based auto parts sales management system to address the inefficiencies and poor management in traditional sales models. Developed using the SpringBoot framework, the system integrates technologies such as MySQL and MyBatis, adopting a modular architecture with front-end and back-end separation.The system features two user roles (administrator and consumer), providing consumer-oriented functions like product selection and order payment, as well as administrator-focused backend management including product management, order processing, and user permission control.Feasibility analysis confirms the system's viability in economic, operational, and technical aspects. Role-based use case analysis defines workflows for both consumers and administrators, while logical database design establishes 19 core tables covering business scenarios like products, orders, and marketing. System testing demonstrates that this solution effectively enhances operational efficiency for auto parts enterprises, optimizes customer experience, and serves as a reference for industry digital transformation.

修改:

1
In the traditional sales model of auto parts commodities, problems such as low efficiency and rough management are inevitable. Therefore, this paper designs and implements an auto parts sales management system based on JavaWeb. This system is implemented by adopting the mainstream Java development framework currently available on the market. Among them, the back-end system uses the SpringBoot framework to integrate technologies such as MyBatis and MySQL databases, while the front-end interface uses Vue.js technology to achieve user click interaction. Ordinary consumers can search and browse auto parts products, select and place orders, and make order payments in the front-end mall. The back-end administrators are mainly responsible for back-end management functions such as product management, order process tracking, and user permission control. Before devoting to the system development, the credibility of the system at the economic, operational and technical levels was carefully discussed and verified. The core function list was reasonably planned and sorted out, and the corresponding use case analysis diagram was drawn. In addition, combined with the list of core functions listed earlier, a total of 19 core database tables were designed using the MySQL database, covering multiple business scenarios of auto parts sales. After the core functions were developed, comprehensive test cases were designed in the system testing stage to verify and gradually improve the robustness of the system and enhance the user experience.
1
当今社会,汽配销售行业正面临着前所未有的挑战和机遇,信息技术日新月异,消费者需求日益多样化。传统的汽配销售管理模式已经难以满足现代市场的需求,企业急需一种高效智能的汽配销售管理系统来提升客户服务质量并增强市场竞争力。 通过设计和实现基于Java Web的汽配销售管理系统,企业可以更加高效地管理销售流程、优化库存配置、提升客户服务质量。系统的实现将推动汽配销售行业向数字化、智能化方向发展,促进技术创新和业务模式创新,为企业带来新的增长点和竞争优势。 这种系统有助于汽配销售企业更好地了解市场需求,提高市场反应速度。研究和分析汽配销售管理系统具有重要的现实意义,有助于推动汽配销售行业的技术创新和管理创新,提高整个行业的竞争力,为消费者提供更加优质的购车体验。

修改:

1
当今社会信息技术日新月异,消费者需求也日益多样化,传统的汽配销售行业正处于转型关键期。随着市场变化更加不可控,过去传统的的汽配销售管理方式显然已经落伍于新时代发展需求,当下的企业迫切需要更加智能的系统来提升服务水平和竞争力。基于Java主流技术栈设计和实现的汽配销售管理系统,恰恰能够迎合大众的汽配商品购买需求,其无论在提升用户体验或是企业管理方面,都具有显著的市场竞争力。在业务流程方面,此类系统在保持原有汽配销售理念不变的条件下,选择极大简化销售环节,通过智能管理方案提升服务效率。用户一旦选择使用此类汽配销售管理系统,就能享受到更便捷的选购流程、更精准的配件推荐以及更完善的售后服务。此外从企业的角度来看,合理使用更加完善的智能化服务,能够解决不同用户的个性化需求,在改善广大客户体验的同时,同样也有利于企业快速掌握市场新动向,为将来可能面临的销售策略调整做好充足准备。
1
从行业发展的角度来看,汽配销售管理系统的研究与优化是推动汽配销售行业数字化转型的关键一步。随着信息技术的飞速发展,传统汽配销售模式已经难以满足现代市场的需求和变化。通过研究和优化汽配销售管理系统,可以有效提高运营效率,降低成本。 其次,从客户体验的角度来看,汽配销售管理系统的研究与优化对于提升客户满意度和忠诚度具有重要意义。系统通过收集和分析客户的购车历史、偏好和反馈,能够为客户提供个性化的购车建议和方案,使客户享受到更加便捷、高效的购车体验。同时,系统还能够提供全面的售后服务支持,包括保养提醒、故障报修等,进一步增强客户的忠诚度和品牌认同感。 Java Web技术作为一种成熟且广泛应用的开发技术,具有高度的可定制性、可扩展性和安全性,非常适合用于构建满足现代汽配销售行业需求的管理系统。通过整合前端用户界面、后端业务逻辑和数据库存储等关键组件,Java Web技术可以为企业提供一个功能强大、易于维护和升级的解决方案。

修改:

1
汽配销售管理系统的优化升级对相关行业发展是至关重要的。随着市场变化,过去传统的汽配销售模式已经不能够满足需求,而新兴的数字化管理系统能够显著提升运行效率。故在现代市场中不断变化的需求中,选择使用新型数字化管理系统来降低企业成本,无疑是最明智的选择。此外,从客户体验来看,这类优化升级后的数字化管理系统,能够记录客户的购买记录和偏好,通过收集分析客户的购买历史,针对性提供个性化的购物推荐方案,让客户明显察觉出选购过程更加便捷。同时,此类系统往往还提供完善的售后服务功能,如配件保养提醒、维修指导实用方案等,这大幅度提升了客户满意度。从技术实现方面看,采用成熟的主流开发框架,能够更加便捷地构建满足现代汽配销售行业需求的管理系统。这种技术方案在满足房前业务需求的同时,最大限度保证了系统能够安稳运行,还便于后续的功能扩展以及维护升级。
1
随着科技的不断发展,汽配销售管理系统也在不断地完善和优化。在国外许多先进的汽配销售管理系统已经投入实际应用,为汽配销售行业带来了极大的便利。例如美国的汽配销售管理系统采用了大数据和人工智能技术,可以根据消费者的购车需求和喜好,为他们推荐最合适的汽车配件型号和配置。此外德国的汽配销售管理系统还具有很强的售后服务功能,可以为消费者提供详细的保养和维修建议,提高消费者的满意度。 在国内随着汽车市场的不断扩大和竞争的加剧,越来越多的汽配销售企业开始关注汽配销售管理系统的研究与开发。目前国内的一些大型汽配销售企业已经开始尝试引入先进的汽配销售管理系统,以提高销售效率和客户满意度。然而由于国内汽配销售行业的快速发展和技术水平的不足,许多企业在引入汽配销售管理系统时仍然面临着许多挑战。因此国内的汽配销售管理系统研究尚处于起步阶段,需要不断地进行技术创新和完善。

修改:

1
当前,汽配销售管理系统在国内外都取得了显著发展。国外先进系统比如美国的智能推荐系统,采用智能推荐技术,能根据车主需求自动匹配配件,给用户提供个性化购买建议。而德国的系统则专注于更完善的售后服务以及专业保养,还提供维修指导详细实用方案。相比之下,国内的汽配销售管理系统尽管起步较晚,但当前已经有大型企业开始使用此类管理系统,用来帮助提升销售效率以及改善服务质量。不过,由于汽配行业发展迅速而相关技术累计不充分,国内的系统应用在投入市场后仍面临着诸多挑战。总体来看,国内汽配销售管理系统还处于发展初期,在智能化和售后服务等方面,仍有很大提升空间,需要继续改进技术和服务。
1
本文围绕汽配销售管理系统的设计与实现展开研究,采用理论分析与工程实践相结合的方法,构建了一套完整的汽配行业数字化解决方案。本文各章节内容如下: 第1章绪论从行业背景出发,分析了传统汽配销售模式在效率和管理方面的痛点,阐述了系统开发对推动行业数字化转型的重要意义。通过对比国内外汽配电商系统的发展现状,明确了本系统在提升运营效率、优化用户体验方面的研究价值,为后续研究奠定了理论基础。 第2章相关技术重点介绍了系统开发采用的技术栈,包括SpringBoot框架的自动配置机制、MyBatis的动态SQL特性以及MySQL数据库的事务支持能力。通过技术选型分析,验证了所选技术在实现高并发交易、数据一致性等核心业务需求方面的适用性。 第3章系统需求分析采用角色用例分析法,明确了消费者和管理员两类用户的核心需求。通过构建功能列表和原型设计,完善并实现了包括订单管理、商品管理等六大模块的系统功能架构。 第4章总体设计从技术架构和功能模块两个维度展开,提出了基于SpringBoot+Vue的前后端分离架构方案。通过数据库ER图和类关系图设计,构建了包含19张核心数据表的数据库模型,形成了覆盖汽配销售全流程的系统级设计方案。 第5章详细设计与实现聚焦系统核心功能模块,采用类图、时序图和流程图为用户登录、选购下单、订单管理等关键业务提供了详细的实现方案。通过代码片段和数据库表结构说明,展示了系统在库存预占、支付回调等业务场景中的具体处理逻辑。 第6章系统测试设计了完整的测试方案,通过多维度验证系统可靠性,特别针对高并发下单、库存一致性等关键场景进行压力测试,确保系统在业务高峰期的稳定表现。 第7章结论总结了系统在提升汽配企业运营效率、优化客户服务体验方面取得的成果,分析了当前实现的局限性,并从智能推荐算法完善方面提出了未来改进方向。

修改:

1
2
3
4
5
6
7
8
由于传统的汽配销售行业可能带来一系列问题,如效率低下、管理粗放等,故本论文以此为切入点,采用理论与实践相结合的方法,深入研究汽配销售管理系统的设计与实现。本论文各章节主要内容如下:
第1章是绪论部分,首先描述了汽配行业现状,指出传统销售模式可能会带来效率或管理方面的问题,以此为论据说明了开发本系统对推动汽配行业发展具有重大作用。后续对比了国内外汽配电商系统的发展现状,进一步明确了本系统确实能极大提升并改善用户体验。
第2章是相关技术,这部分内容详细介绍了本系统开发过程中采用的主流技术栈,其中重点分析了SpringBoot框架、Mybatis框架和MySQL数据库,这些核心技术栈极大了提升系统开发效率。
第3章是系统需求分析,分别从前台商城和后台管理的角度规划出该系统的核心功能模块,其中重点剖析了用户登录、选购下单和订单管理流程,还通过可行性分析验证了该系统在经济、操作和技术层面的可行性。
第4章是总体设计,通过系统分析本系统的技术架构和功能模块,完成了系统的总体设计方案,同时基于业务需求建立了较为完整的数据库模型和类结构设计。
第5章是详细设计与实现,分别对用户登录、选购下单和订单管理三大核心功能进行了全面的详细设计,通过类图、时序图、流程图和数据库表设计,系统性阐述了各功能模块的业务逻辑与实现。
第6章是系统测试,主要针对用户登录、用户选购下单和商品管理功能进行测试,通过设计更全面的测试用例,模拟真实用户操作流程,尽可能覆盖汽配销售环节中多个业务场景。
第7章是结论,简要总结了该系统使用什么样的技术解决了何种难题,同时指出了目前该系统仍有诸多功能待持续完善,包括技术选型优化和功能扩展等方面。
1
2
3
4
5
6
7
8
9
该框架提供了各种现成的功能模块(如安全认证、数据库连接等),开发者只需简单配置就能快速搭建系统骨架。
在本项目中,该框架主要负责处理用户请求、业务逻辑和系统间的协调工作。
通过自动配置机制,SpringBoot能根据项目依赖自动装配所需组件,大幅减少传统Spring框架繁琐的XML配置工作。
该框架内置了Tomcat服务器,无需额外部署即可运行项目,一键自动配置常用功能。
SpringBoot框架还提供了完善的监控端点,可以实时查看应用健康状态、性能指标等信息,极大方便了系统运维。
同时,该框架的starter机制使依赖管理更加简单,只需引入相应starter包即可获得完整功能支持。
SpringBoot框架的重要优势是生态丰富。有成千上万的扩展库可以选择,轻松集成本项目用到的MyBatis、Redis等。
在微服务架构下,SpringBoot与Spring Cloud完美配合,可以快速构建分布式系统。
此外,该框架的自动错误处理机制能捕获并记录,配合统一的日志系统,让问题排查更加便捷。

修改:

1
2
3
相较于Spring框架,SpringBoot框架提供了自动化配置,这大大简化了项目的配置过程。通过约定优于配置的原则,很多常用的配置可以自动完成,开发者可以专注于业务逻辑的实现。
SpringBoot框架还提供了快速的项目启动器,其中默认集成了多种内嵌服务器(如Tomcat、Jetty、Undertow),无需额外配置,即可将应用打包成可执行的JAR文件,方便部署和运行。
SpringBoot通过自动配置功能,根据项目中的依赖关系和约定俗成的规则来配置应用程序,减少了配置的复杂性,使开发者更容易实现应用的最佳实践。通过引入不同的Starter,可以快速集成常用的框架和库(如数据库、消息队列、Web开发等),极大地提高了开发效率。
1
本章详细分析了系统开发过程中使用的核心技术。SpringBoot框架作为系统基础,通过其自动配置和starter机制简化了开发流程,内置的安全组件为登录认证提供了可靠支持。MyBatis框架作为持久层解决方案,其动态SQL特性满足了商品多条件查询需求,二级缓存机制显著提升了数据访问效率。MySQL数据库凭借其稳定的事务特性和索引优化策略,为订单管理等核心业务提供了高效的数据存储支持。这三大核心技术构成了系统稳定运行的技术基石,保证了系统性能和可维护性。

修改:

1
本章重点介绍了系统开发中用到的几个关键技术。SpringBoot作为本系统开发的基础框架,简化了项目的搭建和配置,其内置了安全功能让用户注册登录和权限管理更加方便。Mybatis作为成熟的ORM框架,相较于传统的JDBC技术,极大程度减少了繁琐的配置,提升编码效率,还支持灵活地编写SQL语句,满足业务场景中多种复杂需求。MySQL作为系统的数据库,支持高效的数据存储和较为完备的事务处理机制,在业务场景中还能通过SQL调优(如索引优化,分库分表等)大幅提高查询效率。这三大核心技术是本系统稳定运行的关键,同时系统的性能和可维护性也得到了保证。
1
首先,从经济可行性来看,该系统具有显著投资价值。开发成本主要包括硬件设备采购和软件开发投入,而预期收益则来源于线上销售额增长、广告收入提升等多个方面。投资回报分析显示,系统可在合理周期内收回成本并实现盈利,为汽配销售企业创造可观的经济效益。 其次,操作界面简洁可观。前台采用直观的交互界面,使消费者能够便捷完成商品浏览、下单支付等操作;后台管理系统通过明确的权限设置和操作帮助管理员高效处理商品管理、订单处理等工作。这种双端优化设计确保了系统的易用性。 再次,技术可行性已得到充分验证。基于SpringBoot框架的开发方案,不仅能够快速实现系统核心功能,还能无缝集成MyBatis、MySQL等成熟技术。系统架构支持高并发访问和稳定运行,完全满足汽配销售业务的性能要求。

修改:

1
2
3
4
从经济层面来看,开发这样的系统需要一定的硬件和软件投入,考虑到系统上线后能带来更多线上订单和广告收入,预计能在可接收时间范围内回本并盈利,这对传统的汽配销售企业来说是个不错的投资。
从操作层面来看,本系统的前台商城界面简单清晰,方便消费者浏览汽配商品详情信息和选购下单,而后台管理系统则实现了明确的权限划分,后台管理员能够轻松管理在售商品信息,跟踪订单流水,大幅提升工作效率。
从技术层面看,本系统采用了成熟的开发框架和数据库技术,在保证系统能稳定运行的同时,还支持大量用户同时访问,完全能满足当今汽配销售行业的业务需求。
以上我们分别从经济层面、操作层面和技术层面出发,探究该系统的可行性,探究结果表明本系统成本可控,操作方便,技术可靠,是一个值得投入的项目。
1
本系统功能架构划分为六大核心模块:用户管理、选购下单、订单管理、商品管理、营销管理和权限管理。其中,选购下单与订单管理作为系统的关键功能模块,具有复杂的业务逻辑和紧密的交互关系,其详细用例将在后续章节进行深入分析。 这些功能模块相互衔接,形成了完整的汽配销售业务闭环:前台为用户提供高效的汽配商品购买体验,后台则为汽配厂商提供运营管理支持。后续内容将着重剖析选购下单和订单管理这两个核心模块的具体实现方案。基于上述分析,系统整体用例图如图3-1所示。用户管理功能如表3-1所示。

修改:

1
2
本系统主要由六大功能模块组成,包括用户管理、商品选购、订单管理、商品管理促销活动和权限管理。其中商品选购和订单管理是最核心的功能模块,其中设计的业务流程较为复杂,将在后续详细介绍它们的具体实现方式。
这些功能模块间相互配合,共同构成了完整的汽配销售管理系统。前台商城让顾客浏览选购汽配商品更加便捷,后台管理使得管理员轻松管理在售商品信息,大幅提高工作效率。在接下来的内容中,将重点介绍商品选购下单和订单管理这两个核心模块的具体设计方案。基于上述分析,系统整体功能结构如图3-1所示,用户管理具体功能说明见表3-1
1
在汽配销售场景中,当消费者进入汽配销售系统时,通常已对所需配件的型号、规格等参数有清晰认知,因此系统需要提供精准的商品检索和匹配功能。本系统的选购下单模块通过智能搜索和精准推荐相结合的方式,帮助消费者快速定位目标商品。 选购下单模块的核心业务流程表现为:消费者通过搜索或分类导航找到目标商品后,系统实时展示库存状态和价格信息,并支持按品牌、型号等关键参数进行筛选;消费者确认所需商品的规格和数量后,系统自动生成包含完整商品信息的待支付订单;订单支付流程完成后触发库存扣减机制。这一流程实现了从选购到下单的无缝衔接,同时保障支付和订单信息的安全可靠。基于上述分析,选购下单用例图如图3-2所示。选购下单功能如表3-5所示。

修改:

1
2
在汽配商品销售过程中,顾客通常已经知道自己需要什么样型号的配件,因此,系统必须具备准确检索和匹配商品的功能。在本系统的选购下单功能模块中,通过实现智能搜索以及精准推荐,帮助顾客快速找到想要的商品。
具体购买流程如下:顾客通过搜索或分类查找商品时,系统会立即显示库存情况和价格信息,此时顾客可以按品牌、型号等条件筛选商品。选定商品规格和数量后,系统会自动生成待支付的订单。在完成支付后,系统会自动扣除相应库存。整个选购下单流程从商品选购到下单一气呵成,还确保了支付安全和订单信息安全可靠。选购下单用例图如图3-2所示,具体功能说明如表3-5所示。
1
当消费者完成支付流程后,订单即进入系统管理阶段,成为可被全程跟踪的系统订单。订单管理模块主要业务包括订单处理、物流跟踪及售后服务。 用户下单并提交订单后进入待付款状态;支付成功后,订单转为待发货状态,若超时未支付则自动关闭。商家确认订单后填写物流信息并发货,订单状态更新为已发货,同时系统同步物流轨迹供用户实时跟踪。物流签收后,用户可手动确认收货或由系统在超时后自动完成,订单状态标记为已完成。若发生退货、退款等售后问题,订单可能变更为无效订单或逻辑删除。整个流程覆盖了订单生命周期中的关键环节,并与支付、库存、物流等系统紧密协同,保障交易顺畅与用户体验。基于上述分析,订单管理用例图如图3-3所示。订单管理功能如表3-6所示。

修改:

1
订单管理模块的实现主要涉及到订单状态变化:基于上述选购下单流程,在顾客成功下单后,订单显示待付款。顾客付款成功后,订单状态变为代发货,而商家确认订单并发货后,更新订单状态为已发货,此时顾客可查看到物流信息。在顾客嘴最终收货并确认后,订单状态标记为已完成。整个工作流程中可能出现一些特殊情况,比如顾客选购下单后超时未付款,则订单自动取消;顾客在收货确认后需要退换货,订单则转为售后处理状态,后续由商家进一步跟进。以上流程基本覆盖了订单生命周期中的各个关键环节,自动更新库存,同步物流信息,处理退款售后等问题,整个流程确保了从下单到收货的每个环节都能被有效跟踪和监测管理。订单管理用例图如图3-3所示,具体功能说明如表3-6所示。
1
安全性:系统应实现完善的数据加密机制和基于角色的权限控制,确保用户信息和交易数据安全。 可扩展性:采用模块化架构设计,支持汽配品类和业务功能的灵活扩展,便于后期功能升级。 易用性:系统界面设计应符合汽配行业特点,操作流程简洁明了,确保消费者和管理员都能快速上手使用。 适应性:基于SpringBoot框架开发,具有良好的跨平台特性,能够适配各类操作系统和硬件环境。

修改:

1
2
3
4
5
系统设计需要满足以下关键要求:
从安全保护方面来看,本系统应该采用完备的数据加密技术,避免数据传输过程中的可能出现的监听和窃取安全问题;同时设置不同的账号权限,谨防登录信息伪造等问题,确保用户隐私安全和数据信息安全。
从扩展能力方面来看,本系统应采用模块化设计,在设计初期应该通过广泛地调研分析,充分考虑到后续开发完善过程中的可扩展点,比如增加新的商品种类,支持新的支付方式等。
从使用体验方面来看,本系统前台商城界面和后台管理界面都应该做到简单直观,操作步骤清晰明确,让顾客和管理员都能快速上手使用。
从兼容性能方面来看,本系统应该要基于主流开发框架实现,提供的终端要适配不同品牌的电脑和手机,还要具备一定的跨平台性,以支持多种操作系统。
1
汽配销售管理系统在技术层面采用分层架构设计,基础环境基于JDK1.8开发平台,配合IDEA、HBuilder和Navicat等开发工具;后端以SpringBoot为核心框架,集成SpringSecurity实现认证授权,MyBatis处理数据持久化,Elasticsearch提供搜索服务,同时结合Druid连接池、JWT令牌等组件;终端支持PC浏览器和移动端访问,整体架构通过Nginx实现负载均衡,采用Docker容器化部署,形成了一套完整的前后端分离技术方案。

修改:

1
本汽配销售管理系统采用分层架构设计,主要技术方案包括:使用Java1.8开发平台,配套的开发工具包括但不限于IDEA、HBuilder和Navicat等。同时,整个系统基于主流开发框架SpringBoot开发,这其中集成Security模块实现安全认证,集成Mybatis框架实现高效数据库操作,集成Elasticsearch实现商品检索,此外还集成了数据库连接池以及JWT身份验证令牌等组件。本系统通过Niginx实现流量分发,采用Dokcer实现容器部署,终端还支持PC端、移动端访问。整体采用前后端分离的技术架构。
1
汽配销售管理系统的架构设计是项目开发的关键环节,其核心在于构建前后端分离的双平台体系。本系统采用SpringBoot+MyBatis技术栈实现,通过Docker容器化技术确保部署的灵活性和可扩展性。前台商城系统展示了汽配商品的门户首页,支持多条件筛选搜索商品,提供完整的购物车结算和订单处理等功能。后台管理系统提供了全生命周期的商品管理、基于角色权限控制体系管理以及完善的订单跟踪等功能。以上是汽配销售管理系统的主要功能需求,通过这些功能的设计和实现,为用户提供更加便捷、快速、安全的汽配销售服务。该系统功能结构设计如图4-1所示:

修改:

1
汽配销售系统采用前后端分离的设计方案,主要包括两个部分:前台商城面向广大消费者,主要展示汽配商品详情信息,支持多种条件筛选商品,还提供了购物车下单、订单结算以及物流跟踪等功能;后台管理则面向商家,后台管理员可管理商品上下架,设置不同员工的操作权限,跟踪并处理订单流水。总的来说,本系统采用主流开发技术,使用Docker实现容器部署,确保了系统能稳定运行并方便扩展。通过这样的功能设计,为用户提供了便捷且安全的汽配商品购买体验。本系统功能结构设计如图4-1所示。
1
汽配销售管理系统中的各个类与类之间的关系如图 4-3所示。 该类关系图展现了严谨的面向对象设计架构。以User类为核心的用户中心模块通过聚合关系绑定Role类,形成基于角色的访问控制体系,Role类进一步组合Permission类实现细粒度的权限管理。LoginLog类记录用户登录行为,与User形成关联关系,确保操作可追溯。商品管理模块以Product类为主体,聚合Brand和Category类构建商品分类体系,组合ProductAttribute类实现商品特性扩展。订单处理模块通过Order类作为业务聚合根,严格组合OrderItem类管理订单明细,关联OrderDelivery类处理物流信息,组合PaymentInfo类保障交易完整性。OrderLog类记录订单状态变更,与Order形成操作审计关系。系统巧妙运用多种关系类型:UserOrder的关联体现业务交互,Product与OrderItem的关联实现商品销售,Category的自关联支持多级分类。各类均封装核心业务属性与方法,如User的登录验证、Product的库存管理、Order的状态转换、PaymentInfo的支付处理等,共同构建了完整的汽配销售业务领域模型。类间关系设计合理的关联实现了模块间协同,充分体现了高内聚低耦合的设计思想。

修改:

1
汽配销售管理系统的类结构设计如图4-3所示,主要包含以下核心模块及其相互关系。在用户管理模块中,用户(User)与角色(Role)关联,实现了权限控制。同时角色(Role)包含多个具体权限(Permission),而登录记录(Loginlog)则用来跟踪并记录用户操作。在商品管理模块中,商品(Product)关联品牌(Brand)和分类(Category),商品属性(ProductAttribute)则负责描述商品特性,此外分类(Category)还支持多级子分类。在订单管理模块中,订单(Order)包含多个订单项(OrderItem),同时关联物流(OrderDelivery)和支付信息(PaymentInfo)等,而订单日志(OrderLog)则用来跟踪订单流水并记录订单状态变更。总的来说,各模块之间通过合理的关联关系实现业务协作,用户(User)可以创建多个订单(Order),商品(Product)通过订单项(OrderItem)参与汽配商品销售,此外还参与到本系统的自动处理库存、下单支付等业务流程中。这样的类间关系设计,体现了高内聚低耦合的设计思维,还使得本系统各模块既能独立运作,又能协同工作,确保销售业务流畅运行。
1
用户登录模块包含用户认证、权限验证和日志记录,涉及到的类有用户类、角色类、权限类和登录日志类。用户类中除了基本的属性如username、password和status外,还包含checkPassword方法用于验证用户输入的密码是否与存储的加密。角色类通过hasPermission方法验证用户是否拥有特定权限,addPermission方法用于动态添加权限。权限类通过isApiPermission方法判断权限类型,getPermission方法生成完整的权限标识。登录日志类中的createSuccessLog静态方法用于快速创建成功登录日志记录,自动填充IP、设备和时间等信息。用户类关联多个角色类形成用户-角色关系,角色类关联多个权限类构成角色-权限映射,用户类与登录日志类形成一对多的登录记录关系,共同完成从用户认证到权限控制的完整流程。

修改:

1
用户登录模块主要由以下几个部分组成。其中用户信息(User)包含用户名、密码、状态等基本信息,此外还提供了登录过程中的密码验证功能。在角色管理(Role)中,系统会在不同的操作环节检查用户是否具有某项权限,此外还支持管理员动态添加新的角色权限。在权限控制(Permission)中,主要用来区分不同类型的权限,并借此依次生成完整的权限标识,用以保证系统操作过程中的安全可靠。最后在登录记录(LoginLog)中,系统自动记录了登录IP、设备、时间等信息,区分成功和失败的登录尝试。这些部分之间的关系体现在一个用户可以拥有多个角色,而一个角色可以包含多个权限,此外一个用户还会产生多条登录记录。所以用户登录的整个流程可以总结为,用户在登录界面输入账号密码登录后,系统验证密码并检查权限,记录本次登录信息,并根据权限决定该用户可访问的功能。
1
用户登录模块中相关的数据库表包含用户表、角色表、权限表、用户角色关联表、角色权限关联表以及登录日志表。通过用户表中的用户状态字段与角色权限体系建立连接,在用户登录时进行多层级验证,包括密码校验、账户状态检查和权限加载。登录日志表记录了每次登录的详细上下文信息,包括IP地址、设备类型和操作结果。用户通过角色关联权限、权限表中的权限编码字段与前端菜单及接口权限绑定,形成完整的访问控制链。数据库表结构中,用户表存储加密后的密码和盐值,角色表定义数据权限范围,权限表标记资源类型和操作标识,关联表维护多对多关系,登录日志表实现审计追踪,各表通过外键约束确保数据一致性,共同实现从身份认证到权限管理的全流程。用户表如表5-1所示。

修改:

1
用户登录模块涉及到的数据库表包括以下库表。在用户表中存储了用户账号、加密密码等信息,同时记录登录用户账号状态,判断其是否能正常使用。在角色表中定义了不同角色的权限范围,如管理员、普通用户等。在权限表中记录了本系统可访问的菜单和功能,每种权限都对应有唯一编码。在关联表中保存了用户和角色的对应关系,以及角色与权限的对应关系。在登录日志表中记录了每次登录的IP、设备、操作结果和地址等信息,同时保存登录成功和失败信息。在整个登录验证流程中,检查用户名和密码是否正确,确认该账号是否可用,加载用户拥有的角色和权限,最后记录本次登录信息。这些库表通过相互关联,共同实现了账号安全保护,权限的分级管理以及操作记录追踪。用户表具体结构如表5-1所示。
1
商品选购下单模块的数据库设计包含品牌管理、商品信息、分类体系、订单交易、购物车和评价系统,涉及的核心表包括品牌表、商品信息表商品所属分类表、订单表以及商品评价表。品牌表通过id和name字段维护品牌基础信息,商品信息表以brand_id和product_category_id关联品牌与分类,并包含publish_status和promotion_type字段管理上下架及促销状态。订单表通过member_id关联用户,status字段标记订单生命周期,购物车表冗余存储product_brand和product_category_id确保数据一致性,商品评价表通过star和pics字段实现多维度的评价展示。

修改:

1
商品选购下单模块的数据库设计主要包含以下几个部分。在商品信息相关表中,品牌表记录了商品关联的品牌信息,包括品牌logo、品牌描述和品牌故事等;商品表则记录了商品详情信息,包括商品描述、价格、库存、所属分类等;商品分类表则用来管理商品分类,记录了多级商品所属分类类型。在订单相关表中,订单表记录了用户下单信息,包括选购商品信息、下单用户信息以及收货地址等;而购物车表则负责暂存用户想要购买的商品,在下单支付后清除购相关物车信息。在商品评价系统中,主要由评价表保存用户评分以及评价内容。各表之间,商品关联到所属品牌和分类,订单关联到用户和选购商品,评价则关联到订单和商品详情。
1
订单管理模块围绕订单主类展开,关联订单明细类、物流信息类和操作日志类。订单主类通过status状态标记推动业务进行,其中cancel方法处理取消逻辑并触发库存释放,confirmReceive方法完成收货确认。订单明细类通过productName和price等快照字段保留交易时商品状态,物流信息类依赖track方法实时查询物流轨迹,操作日志类记录所有关键操作。类详细设计如图5-7所示。 订单管理模块的数据库设计围绕订单表展开,通过订单明细表记录商品快照信息,物流信息表跟踪配送状态,操作日志表审计关键操作。订单表通过order_sn保证业务唯一性,并关联user_id标记用户归属;订单明细表通过order_id外联主订单,保留product_name和快照数据确保历史订单不受商品变更影响;物流信息表记录delivery_company和delivery_sn实现物流追踪;操作日志表通过action字段(如支付/取消)和operator记录操作轨迹。所有表均包含create_time实现时间维度追溯,退货申请表作为扩展支持售后流程,形成从订单创建、状态变更到最终完结的完整流程。订单表如表5-12所示。

修改:

1
订单管理模块主要包含以下功能。在订单处理流程中,主要涉及到订单流转和订单状态管理,如待付款、已发货、已完成等,除此之外,还提供了用户取消订单时自动回复库存的功能,以及用户确认收货功能。在订单信息记录中,保存了订单流转过程中的商品商品信息,如名称、价格等,记录了物流配送信息,还支持订单操作记录跟踪功能,如订单支付、订单取消等。故在订单管理相关数据库设计中,订单主表用来记录订单基本信息,订单商品表保存了购买时的商品详情,物流信息表记录了跟踪配送状态,操作记录表则记录了订单流转过程中的所有重要操作。在以上整个操作流程中,每个订单都有唯一编号,订单内的商品信息不受后期改动影响,用户可以实时查询物流状态,后台管理完整记录了订单全流程操作,此外还支持退货退款等售后服务。订单表如表5-12所示。
1
用户登录、选购下单和订单管理三大功能模块构成了汽配销售管理系统的核心业务架构。本章节以这三个关键模块为切入点,对系统的核心功能进行了全面的详细设计。通过类图、时序图、流程图和数据库表设计等多维度建模方式,系统性地阐述了各模块的业务逻辑与数据关系。其中,类图明确了实体间的结构关系,时序图规范了服务间的调用流程,流程图梳理了业务状态流转,数据库表设计严格遵循ACID原则保证数据准确可靠。

修改:

1
汽配销售管理系统的核心功能主要包括用户登录、选购下单和订单管理三大模块,本章详细介绍了这些功能的设计方案。使用类图展示了各功能模块的组成结构,使用时序图说明了系统各部分的交互过程,使用流程图描述了核心业务处理步骤,还是用数据库设计确保了数据准确安全。经过详细设计与实现,整个系统实现了清晰的模块划分、规范的交互流程、完整的业务处理逻辑以及可靠的数据存储方案,能帮助用户顺畅完成心仪商品的选购下单,同时也有利于管理员高效处理订单流水。
1
此功能测试包括几个方面:功能性测试需覆盖正常登录流程、异常输入校验(包括空用户名、空密码、错误凭证等)、密码加密存储与传输机制,以及登录失败次数限制等安全策略;性能测试需验证系统在并发用户登录场景下的响应速度、资源占用情况,确保登录接口在高负载下仍能保持稳定;安全性测试则重点检测SQL注入、XSS攻击等常见安全威胁的防护能力。具体测试内容如下: (1)用户登录测试。测试用例如表6-1所示,测试界面如图6-1所示。

修改:

1
登录功能测试主要包括以下几个方面:测试用户能够正常登录系统,包括输入正确的用户名和密码时能否成功登录,登录后能否正常跳转到系统首页,能否正常使用系统各项功能;测试异常登录情况处理,包括输入错误的用户名或密码时是否提示正确的错误信息,不输入用户名或密码时是否提示必填信息,以及连续多次输入错误密码后账户是否会被锁定;测试多用户同时登录时,系统能够同时处理多个用户登录请求,登录响应时间是否在合理范围内,以及服务器资源是否使用正常。具体测试内容如下: (1)用户登录测试。测试用例如表6-1所示,测试界面如图6-1所示。
1
此功能测试包括几个方面:功能性测试需覆盖商品基础信息管理(包括上架、修改、删除等操作),重点验证必填项校验、格式规范检查、品牌/分类关联性等核心业务规则;流程完整性测试需检测商品信息变更后的数据同步机制,包括前后台数据一致性模块(如库存/订单)的联动更新;性能测试则需评估批量商品信息调整效率,以及高并发访问时的系统稳定性。具体测试内容如下: (1)商品上架测试。测试用例如表6-6所示,测试界面如图6-6所示。

修改:

1
商品管理功能测试主要包括以下几个方面:测试商品上架时,检查商品信息能够正常录入,验证必填信息未填时是否提示错误,测试商品图片上传和展示功能,以及检查商品分类和相关品牌选择是否准确关联;测试商品信息修改时,验证修改商品价格、库存等关键信息后是否生效,检查修改后的商品在前台页面是否正确显示,测试特殊字符输入时的处理;测试商品下架时,检查下架商品是否从前台页面消失,验证已下架的商品在订单中的处理情况,测试下架商品重新上架的功能是否完善。除此之外,还需测试商品信息修改后前台页面是否及时更新,以及库存变动后相关订单能都正确处理等。
1
本章对汽配销售管理系统进行了全面的功能测试和性能验证重点测试了用户认证、商品库存管理、订单状态流转等核心功能模块,验证了系统在业务流程上的正确性和完整性。同时采用压力测试工具对高并发场景下的系统,包括商品查询、订单创建和支付处理等关键环节,特别加强了数据安全和防刷单机制的专项测试。通过模拟真实用户操作流程,确保系统符合业务需求和技术规范。

修改:

1
本章重点测试了汽配销售管理系统的三个核心模块。在用户登录功能测试中,测试用户能否正常登录以及异常登录情况时的处理。在选购下单功能测试中,测试商品搜索筛选、购物车选购、订单创建以及支付等功能的完整性。在商品管理功能测试中,测试商品上下架流程、商品信息修改以及批量处理等。通过模拟真实的用户操作,确保了本系统更加安全可靠,购物流程和商品管理更加便捷顺畅。
1
本文基于Spring Boot框架设计并实现了一套完整的汽配销售管理系统,主要完成了以下工作:首先,通过系统化的需求调研与分析,设计了涵盖用户关系管理、汽配商品生命周期管理和交易流程管理等核心业务模块的体系架构;其次,采用MyBatis持久层框架实现了19张核心数据表的CRUD操作,并运用Redis缓存技术优化了商品查询性能;最后,通过前后端分离的开发模式,完成了包含PC端和移动端的多终端适配方案。系统配销售全流程的数字化管理,包括商品展示、在线交易、选购下单、订单跟踪等核心业务功能,经测试验证可支持500+TPS的高并发访问。 然而,系统仍存在以下待改进之处:在功能层面,当前版本尚未实现智能推荐和供应商协同等扩展功能;在技术层面,分布式事务处理机制有待优化,以应对更复杂的业务场景。未来计划引入机器学习算法优化商品推荐功能,并探索微服务架构改造以提升系统的可扩展性。本系统的设计与实现为汽配行业的数字化转型提供了一个可行的技术解决方案,其架构设计思路也可为同类系统的开发提供参考。

修改:

1
2
本汽配销售管理系统基于SpringBoot框架开发,结合MySQL数据库和Mybatis等技术,实现了三大核心功能。在用户管理功能模块,系统支持安全登录和权限控制,不同的角色享有权限各不相同,可操作不同的功能。在选购下单功能模块,前台商城提供了商品搜索、商品详情信息浏览、选购下单以及在在线支付等功能,后台管理则支持在售商品管理以及订单流水监控等核心功能。总体看来,本系统操作简单,界面清晰,数据处理快速稳定,且支持跨平台和多端(PC端/移动端)访问。
当然,系统仍有待改进之处,已经暴露出的问题包括但不限于:前端商城商品图片加载速度不稳定,有时较缓慢;促销活动模块较为单一,目前仅支持少数促销活动;缺少智能推荐商品功能;后台管理系统中,订单统计报表不够直观。由于本系统设计局限性以及时间关系,计划在未来不断优化和改进该系统中存在的问题,全面考虑系统可扩展点,从更复杂的业务场景出发,采用前沿技术不断拓展优化系统设计,最大程度提升用户体验,使得该系统在当今汽配销售行业中更能发挥重大作用。

2025 年 4 月 21 日

启明智汇 (chachongz.com)

image-20250421122839799

1
卡号:11036487928805360:820400
1
2
3
4
5
6
7
论文查重券】的使用方法:
1、电脑登录启明智汇查重官网
https://qimingzhihui.chachongz.com/
2、选择CopyCheck检测系统
3、输入[论文标题][作者][上传文件]
4[支付方式]选择[检测卡]
5、输入检测卡卡号、卡密检测

image-20250421124206959

特么卡内无余额。。

新论文检测_PaperPass论文检测

查重报告 - PaperRed免费论文查重

艹,今天有的受了。。

查看报告_PaperPass论文检测

改写和重写,18520字。

功能演示

2025 年 4 月 26 日

终于给自己埋下坑了。

系统功能还是得稍作完善,毕竟四天后的预答辩要求演示系统功能,就是糊弄也得好好把系统跑起来才行。

image-20250426123942146

注册登录,测试完毕。

商品管理,优化商品属性,关联品牌,分类,图片上传。

image-20250426162940179

MinIO | 企业级、高性能对象存储

1
2
3
VMware Workstation 无法连接到虚拟机。请确保您有权运行该程序、访问该程序使用的所有目录以及访问所有临时文件目录。

未能将管道连接到虚拟机: 系统找不到指定的文件。

VMware Workstation 无法连接到虚拟机。请确保您有权运行该程序、访问该程序使用的所有目录以及访问所有临时文件目录。VMX进程已经提前退出。_linux_sunnyyu519-华为开发者空间 (csdn.net)

解决办法:VMware Workstation 无法连接到虚拟机。请确保您有权运行该程序、访问该程序使用的所有目录以及访问所有临时文件目录-CSDN博客

他妈还不信了。

重启未解决。。本地虚拟机启动失败确实在意料之外,优化其他功能吧。

1
商品管理,营销管理,用户管理,系统管理,订单管理

图片上传。

ElementUI实现图片上传的功能🌈~(已完成✔) - Mahmud(مەھمۇد) - 博客园 (cnblogs.com)

这部分具体研究,见七牛云章节。

批量设置新品,推荐,查询。

1
Preparing: SELECT p.* FROM sms_home_new_product hp LEFT JOIN pms_product p ON hp.product_id = p.id WHERE hp.recommend_status = 1 AND p.publish_status = 1 ORDER BY hp.sort DESC LIMIT ?, ?;

怎么还查这么个表,删掉。

1
2
3
4
5
delete_status                 int(1)         null comment '删除状态(0 - 未删除;1 - 已删除)',
publish_status int(1) null comment '上架状态(0 - 下架;1 - 上架)',
new_status int(1) null comment '新品状态(0 - 不是新品;1 - 新品)',
recommand_status int(1) null comment '推荐状态(0 - 不推荐;1 - 推荐)',
verify_status int(1) null comment '审核状态:0->未审核;1->审核通过',

改写 SQL 语句,删除关联表。

1
2
3
4
5
6
7
8
<select id="getNewProductList" resultMap="com.macro.mall.mapper.PmsProductMapper.BaseResultMap">
SELECT p.*
FROM pms_product p
WHERE p.recommend_status = 1
AND p.publish_status = 1
ORDER BY p.sort DESC
LIMIT #{offset}, #{limit};
</select>

报错了。

1
{"code":500,"message":"Unknown column 'p.recommend_status' in 'where clause'"}

数据库字段:recommend 拼写错误。

商品的审核状态,后台提供详情列表页面,审核,未审核不予上架。

后台,查看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<el-table-column label="操作" width="160" align="center">
<template slot-scope="scope">
<p>
<el-button
size="mini"
@click="handleShowProduct(scope.$index, scope.row)"
>查看
</el-button>
<el-button
size="mini"
@click="handleUpdateProduct(scope.$index, scope.row)"
>编辑
</el-button>
</p>
<p>
<el-button
size="mini"
@click="handleShowLog(scope.$index, scope.row)"
>日志
</el-button>
<el-button
size="mini"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>删除
</el-button>
</p>
</template>
</el-table-column>
1
2
3
4
5
6
7
8
handleShowProduct(index, row) {
console.log("handleShowProduct", row);
this.$message({
message: `$row`,
type: "warning",
duration: 1000
});
},
1
`商品ID: ${row.id} 名称: ${row.name}`

订单管理。退货管理。购物车管理,通知管理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 商品信息 
-- auto-generated definition
create table pms_product
(
name varchar(200) not null comment '商品名称',
brand_name varchar(255) null comment '品牌名称',
product_category_id bigint null comment '商品分类',
pic varchar(2550) null comment '商品样图',
delete_status int(1) null comment '删除状态(0 - 未删除;1 - 已删除)',
publish_status int(1) null comment '上架状态(0 - 下架;1 - 上架)',
new_status int(1) null comment '新品状态(0 - 不是新品;1 - 新品)',
recommend_status int(1) null comment '推荐状态(0 - 不推荐;1 - 推荐)',
verify_status int(1) null comment '审核状态:0->未审核;1->审核通过',
sale int null comment '销量',
price decimal(10, 2) null comment '销售价格',
sub_title varchar(255) null comment '副标题',
description text null comment '商品描述',
stock int null comment '库存',
promotion_type int(1) null comment '促销类型:0->没有促销使用原价;1->使用促销价;2->使用会员价;3->使用阶梯价格;4->使用满减价格;5->限时购',
)
comment '商品信息' charset = utf8
row_format = DYNAMIC;

商品信息详情。

明天做个查看页面,完善商品管理,订单管理,促销活动。

2025 年 4 月 27 日

受不了。

弹框中包含描述列表,这 ElementUI 怎么咋就这么不靠谱,半天调试不出来,不会在前端组件上再多浪费一点时间了。

添加购物车。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let cartItem = {
price: this.product.price,
productAttr: productSkuStock.spData,
productBrand: this.product.brandName,
productCategoryId: this.product.productCategoryId,
productId: this.product.id,
productName: this.product.name,
productPic: this.product.pic,
productSkuCode: productSkuStock.skuCode,
productSkuId: productSkuStock.id,
productSn: this.product.productSn,
productSubTitle: this.product.subTitle,
quantity: 1
};

这代码有什么毛病。

1
2
3
4
5
6
7
8
chunk-vendors.js:19078  [system] TypeError: Cannot read properties of null (reading 'spData')
at VueComponent.addToCart (VM1025 nMKJ:751:38)
at click (pages-product-product.js:759:37)
at invokeWithErrorHandling (chunk-vendors.js:21356:26)
at invoker (chunk-vendors.js:21681:14)
at invokeWithErrorHandling (chunk-vendors.js:21356:26)
at HTMLElement.invoker (chunk-vendors.js:21677:9)
at original._wrapper (chunk-vendors.js:26565:25)

控制台偷偷报错这么久。

添加购物车成功了,接下来搞下单,订单展示商品有问题。

推荐品牌列表。

1
{"code":500,"message":"Unknown column 's.sort' in 'order clause'"}
1
2
3
4
5
6
7
8
9
<select id="getRecommendSubjectList" resultMap="com.macro.mall.mapper.CmsSubjectMapper.BaseResultMap">
SELECT s.*
FROM
cms_subject s
WHERE
s.recommend_status = 1
AND s.show_status = 1
LIMIT #{offset}, #{limit};
</select>

造了点数据,关联库存表,库存表是关键。

1
2
3
4
5
6
this.memberReceiveAddressList = response.data.memberReceiveAddressList;
console.log(this.memberReceiveAddressList)
this.currentAddress = this.getDefaultAddress();
console.log("----" + this.currentAddress.city);
this.cartPromotionItemList = response.data.cartPromotionItemList;
console.log(this.cartPromotionItemList)

这都能打印出来了,为什么显示不来列表。。

响应式更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
const response = await generateConfirmOrder(JSON.stringify(this.cartIds));
const res = response.data;

// 使用 Vue.set 或展开运算符确保响应式更新
this.cartPromotionItemList = [...res.cartPromotionItemList]; // 深拷贝数组
this.currentAddress = { ...this.getDefaultAddress() }; // 确保地址是响应式

console.log("购物车数据:", this.cartPromotionItemList); // 确认数据格式
} catch (err) {
console.error("加载数据失败:", err);
uni.showToast({ title: "加载失败", icon: "none" });
}

方法 1:强制响应式更新(推荐)

javascript

复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async loadData() {
try {
const response = await generateConfirmOrder(JSON.stringify(this.cartIds));
const res = response.data;

// 使用 Vue.set 或展开运算符确保响应式更新
this.cartPromotionItemList = [...res.cartPromotionItemList]; // 深拷贝数组
this.currentAddress = { ...this.getDefaultAddress() }; // 确保地址是响应式

console.log("购物车数据:", this.cartPromotionItemList); // 确认数据格式
} catch (err) {
console.error("加载数据失败:", err);
uni.showToast({ title: "加载失败", icon: "none" });
}
}

方法 2:确保模板渲染时机

在模板中添加 v-if,避免数据未加载时渲染:

html

运行

复制

1
2
3
4
5
6
7
8
<view v-if="cartPromotionItemList.length > 0">
<view class="g-item" v-for="item in cartPromotionItemList" :key="item.id">
<!-- 商品内容 -->
</view>
</view>
<view v-else>
<text>加载中或购物车为空...</text>
</view>
1
uni.$emit('updateData', { list: res.cartPromotionItemList });

根本没道理,又是无聊的前端。。。

妈的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//创建订单
createOrder() {
let list = this.cartList;
let cartIds = [];
list.forEach(item => {
if (item.checked) {
cartIds.push(item.id);
}
})
if(cartIds.length==0){
uni.showToast({
title:'您还未选择要下单的商品!',
duration:1000
})
return;
}
uni.navigateTo({
url: `/pages/order/createOrder?cartIds=${JSON.stringify(cartIds)}`
})
}

成功了。

image-20250427193019459

详情记录在 Uniapp 章节下。

image-20250427193759934

创建订单。

1
2
3
4
5
6
7
@ApiOperation("根据购物车信息生成订单")
@RequestMapping(value = "/generateOrder", method = RequestMethod.POST)
@ResponseBody
public CommonResult generateOrder(@RequestBody OrderParam orderParam) {
Map<String, Object> result = portalOrderService.generateOrder(orderParam);
return CommonResult.success(result, "下单成功");
}

调试半天,Debug模式没打开。。

1
2
//发送延迟消息取消订单
sendDelayMessageCancelOrder(order.getId());
1
2
3
4
5
6
7
8
@Override
public void sendDelayMessageCancelOrder(Long orderId) {
//获取订单超时时间
OmsOrderSetting orderSetting = orderSettingMapper.selectByPrimaryKey(1L);
long delayTimes = orderSetting.getNormalOrderOvertime() * 60 * 1000;
//发送延迟消息
cancelOrderSender.sendMessage(orderId, delayTimes);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Autowired
private AmqpTemplate amqpTemplate;

public void sendMessage(Long orderId,final long delayTimes){
//给延迟队列发送消息
amqpTemplate.convertAndSend(QueueEnum.QUEUE_TTL_ORDER_CANCEL.getExchange(), QueueEnum.QUEUE_TTL_ORDER_CANCEL.getRouteKey(), orderId, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
//给消息设置延迟毫秒值
message.getMessageProperties().setExpiration(String.valueOf(delayTimes));
return message;
}
});
LOGGER.info("send orderId:{}",orderId);
}

消息队列。

1
2
//发送延迟消息取消订单
// sendDelayMessageCancelOrder(order.getId());

消息队列主要用来处理超时订单的,订单放在队列中,支付超时取消订单。

image-20250427211340398

扣库存。

1
2
3
4
5
/**
* 根据商品的skuId扣减真实库存
*/
int reduceSkuStock(@Param("productSkuId")Long productSkuId,@Param("quantity") Integer quantity);

1
2
3
4
5
6
7
8
9
<update id="reduceSkuStock">
UPDATE pms_sku_stock
SET lock_stock = lock_stock - #{quantity},
stock = stock - #{quantity}
WHERE
id = #{productSkuId}
AND stock - #{quantity} &gt;= 0
AND lock_stock - #{quantity} &gt;= 0
</update>

很好,现在最主要的目标,是搞定支付沙箱,又是一个挑战。

后续也要跟进消息队列的实践以及实现原理学习,明天的主要目标:PPT + 支付沙箱,从业务、技术方面流利讲明白这个系统。

重点是订单和支付。

今晚尝试完善其余所有基本功能,着重优化促销活动、优惠券发放以及使用。

1
2
3
4
<view class="order-item" hover-class="common-hover"  :hover-stay-time="50">
<text class="yticon icon-shouhoutuikuan"></text>
<text>退款/售后</text>
</view>

这前台商城,不太稳定。

优惠券还未测试,我的页面基本没有开发,那家伙犯懒了,拉了坨烂代码。

2025 年 4 月 28 日

早上开始优化完善,前端页面总有问题,不过核心功能即订单创建交付的流程没有受到影响。

促销活动,秒杀活动还是要搞的,支付模块尽可能学习下。

后台模块操作了下,支持功能还挺丰富,结合PPT答辩模板,内容基本可以做到充实,今天下午就开始搞PPT。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
methods: {
/**
* 加载数据
*/
async loadData() {
fetchContent().then(response => {
console.log("onLoad", response.data);
this.advertiseList = response.data.advertiseList;
console.log(this.advertiseList);
this.swiperLength = this.advertiseList.length;

this.titleNViewBackground = this.titleNViewBackgroundList[0];
this.brandList = response.data.brandList;
this.homeFlashPromotion = response.data.homeFlashPromotion;
this.newProductList = response.data.newProductList;
this.hotProductList = response.data.hotProductList;
fetchRecommendProductList(this.recommendParams).then(response => {
this.recommendProductList = response.data;
uni.stopPullDownRefresh();
})
});
},

获取首页内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public HomeContentResult content() {
HomeContentResult result = new HomeContentResult();
//获取首页广告
result.setAdvertiseList(getHomeAdvertiseList());
//获取推荐品牌
result.setBrandList(homeDao.getRecommendBrandList(0,6));
//获取秒杀信息
result.setHomeFlashPromotion(getHomeFlashPromotion());
//获取新品推荐
result.setNewProductList(homeDao.getNewProductList(0,4));
//获取人气推荐
result.setHotProductList(homeDao.getHotProductList(0,4));
//获取推荐专题
result.setSubjectList(homeDao.getRecommendSubjectList(0,4));
return result;
}

获取促销活动列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private HomeFlashPromotion getHomeFlashPromotion() {
HomeFlashPromotion homeFlashPromotion = new HomeFlashPromotion();
//获取当前秒杀活动
Date now = new Date();
SmsFlashPromotion flashPromotion = getFlashPromotion(now);
if (flashPromotion != null) {
//获取当前秒杀场次
SmsFlashPromotionSession flashPromotionSession = getFlashPromotionSession(now);
if (flashPromotionSession != null) {
homeFlashPromotion.setStartTime(flashPromotionSession.getStartTime());
homeFlashPromotion.setEndTime(flashPromotionSession.getEndTime());
//获取下一个秒杀场次
SmsFlashPromotionSession nextSession = getNextFlashPromotionSession(homeFlashPromotion.getStartTime());
if(nextSession!=null){
homeFlashPromotion.setNextStartTime(nextSession.getStartTime());
homeFlashPromotion.setNextEndTime(nextSession.getEndTime());
}
//获取秒杀商品
List<FlashPromotionProduct> flashProductList = homeDao.getFlashProductList(flashPromotion.getId(), flashPromotionSession.getId());
homeFlashPromotion.setProductList(flashProductList);
}
}
return homeFlashPromotion;
}
1
2
3
4
5
6
7
8
9
10
11
/**
* 从Date类型的时间中提取时间部分
*/
public static Date getTime(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.YEAR, date.getYear());
calendar.set(Calendar.MONTH, date.getMonth());
calendar.set(Calendar.DAY_OF_MONTH, date.getDay());
return calendar.getTime();
}

直接造数据。

查询秒杀场次犯癫了,自己返回一个固定日期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="selectByExample" parameterType="com.macro.mall.model.SmsFlashPromotionSessionExample" resultMap="BaseResultMap">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from sms_flash_promotion_session
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
@ApiModelProperty(value = "每日开始时间")
private Date startTime;

@ApiModelProperty(value = "每日结束时间")
private Date endTime;


SmsFlashPromotionSession smsFlashPromotionSession = new SmsFlashPromotionSession();
smsFlashPromotionSession.setId(001L);
smsFlashPromotionSession.setName("上午场次");
smsFlashPromotionSession.setStartTime();
smsFlashPromotionSession.setEndTime();
smsFlashPromotionSession.setStatus(1);
1
2
3
4
5
6
7
8
SmsFlashPromotionSession smsFlashPromotionSession = new SmsFlashPromotionSession();
smsFlashPromotionSession.setId(001L);
smsFlashPromotionSession.setName("上午场次");
smsFlashPromotionSession.setStartTime(new Date("08:00:00")); // 图片中的 startTime
smsFlashPromotionSession.setEndTime(new Date("13:00:00")); // 图片中的 endTime
smsFlashPromotionSession.setStatus(1);

return smsFlashPromotionSession;

2025 年 4 月 30 日

今早结束了预答辩,效果不错,节奏也很不错。

需要完善的两个功能:后端首页数据统计分析图,前台退款售后功能,我的足迹,我的收藏。

2025 年 5 月 3 日

1
2
3
4
5
6
7
8
@ApiOperation("分页获取浏览记录")
@RequestMapping(value = "/list", method = RequestMethod.GET)
@ResponseBody
public CommonResult<CommonPage<MemberReadHistory>> list(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
@RequestParam(value = "pageSize", defaultValue = "5") Integer pageSize) {
Page<MemberReadHistory> page = memberReadHistoryService.list(pageNum, pageSize);
return CommonResult.success(CommonPage.restPage(page));
}
1
2
3
4
5
6
@Override
public Page<MemberReadHistory> list(Integer pageNum, Integer pageSize) {
UmsMember member = memberService.getCurrentMember();
Pageable pageable = PageRequest.of(pageNum - 1, pageSize);
return memberReadHistoryRepository.findByMemberIdOrderByCreateTimeDesc(member.getId(), pageable);
}

返回推荐商品列表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public Page<MemberReadHistory> list(Integer pageNum, Integer pageSize) {
List<PmsProduct> productList = homeService.recommendProductList(pageSize, pageNum);
List<MemberReadHistory> readHistoryList = productList.stream().map(product -> {
MemberReadHistory memberReadHistory = new MemberReadHistory();
memberReadHistory.setProductId(product.getId());
memberReadHistory.setProductName(product.getName());
memberReadHistory.setProductSubTitle(product.getSubTitle());
memberReadHistory.setProductPrice(product.getPrice() + "");
memberReadHistory.setProductPic(product.getPic());
return memberReadHistory;
}).collect(Collectors.toList());

Pageable pageable = PageRequest.of(pageNum, pageSize);
return new PageImpl<>(readHistoryList, pageable, readHistoryList.size());
}

我的收藏,我的关注,最近浏览,全部完成。

登陆有些问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 @Override
public String login(String username, String password) {
String token = null;
//密码需要客户端加密后传递
try {
UserDetails userDetails = loadUserByUsername(username);
if(!passwordEncoder.matches(password,userDetails.getPassword())){
Asserts.fail("密码不正确");
}
if(!userDetails.isEnabled()){
Asserts.fail("帐号已被禁用");
}
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
token = jwtTokenUtil.generateToken(userDetails);
// updateLoginTimeByUsername(username);
insertLoginLog(username);
} catch (AuthenticationException e) {
LOGGER.warn("登录异常:{}", e.getMessage());
}

用户名错了。。

首页订单量统计,这拉下来的项目接口都没写,直接编造数据吧。

重学计划

疯狂 Java

2025 年 2 月 10 日

在 Linux 上搭建 Java 环境_linux安装java-CSDN博客

1
yum list | grep jdk
1
yum install java-1.8.0-openjdk-devel.x86_64
1
java -version

2025 年 3 月 15 日

Mybatis,AI接入,MySQL,微服务,消息队列,Dubbo,WebSocket,Vue,小程序。

其实最重要的还是夯实基础,再去到各个公司官网看看相关业务,有助于针对性学习。

【超详细】MyBatis详解-CSDN博客

MySQL实战45讲 (lianglianglee.com)

2025 年 4 月 15 日

(一)玩命死磕Java内存模型(JMM)与Volatile关键字底层原理引言 本篇文章结合我个人对Java内存模型的理解 - 掘金 (juejin.cn)

1
多条线程同时对一个共享资源进行非原子性操作时会诱发线程安全问题

四十五图,一万五千字!一文让你走出迷雾玩转Maven!Maven是大家的老熟客,几乎每天都会跟他打交道,不过许多人对它似 - 掘金 (juejin.cn)

Vue 基础

2024 年 7 月 26 日

Vue.js - 渐进式 JavaScript 框架 | Vue.js (vuejs.org)

Vue.js 基础理论实操 - itsOli 的专栏 - 掘金 (juejin.cn)

2025 年 1 月 16 日

早上第一件事,学学 Vue。

2025 年 2 月 11 日

Vue.js 安装_vue.js下载-CSDN博客

原生 JS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>前端一万小时-Hello World</title>
</head>
<body>
<div id="app"></div>

<script>
var dom = document.getElementById("app");
dom.innerHTML = "Hello World";
</script>
</body>
</html>

引入 Vue:

vue.js如何下载教程 • Worktile社区

快速上手 | Vue.js (vuejs.org)

1
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{content}}
<!-- 2️⃣-⑥:用 {{}} 包裹 content,写在 #app 这个 div 里。 -->
</div>

<script>
var app = new Vue({
// 2️⃣-②:创建一个 Vue 实例;

el: "#app", // 2️⃣-③:这个实例接收的第一个参数 el,稍后会详细讲解它,暂时不管;

data: {
// 2️⃣-④:接收的第二个参数 data,它指的是数据;

content: "hello world" /*
2️⃣-⑤:定义一个叫 content 的数据,内容是“hello world”,
与原生的作区分。
*/,
},
});
</script>
</body>
</html>

嘿,还搞不明白 Vue.js的下载了。

如何在官网外找到并下载Vue.js:CDN方法详解-CSDN博客

Vue.js 安装 | 菜鸟教程 (runoob.com)

vue源码如何下载 • Worktile社区

Node 体系

2024 年 9 月 23 日

Node.js 知识体系(一):基础概念、历史与应用场景Nodejs 的概念 Node.js 是一个基于 Chrome - 掘金 (juejin.cn)

2025 年 1 月 15 日

Github Actions 构建 Node.js 项目的 CICD 流水线本文介绍了 CI / CD 的概念, 主要是 - 掘金 (juejin.cn)

Node.js入门(1):安装和简介携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看 - 掘金 (juejin.cn)

桌面开发

2024 年 9 月 23 日

Electron 小白入门手册——跨端桌面应用开发的前世今生简史今天我们就从原生桌面开发、QT、NW、Electron、 - 掘金 (juejin.cn)

用 Electron 创建你的第一个应用程序:入门指南Electron 是一个强大的开源框架,可以帮助开发人员使用 we - 掘金 (juejin.cn)

2025 年 1 月 16 日

QT入门看这一篇就够了——超详细讲解(40000多字详细讲解,涵盖qt大量知识)-CSDN博客

安卓开发

2024 年 9 月 23 日

Flutter入门概览1-Flutter篇本系列文章共有三篇,计划分别从Flutter、Dart、工具三个方面介绍,快速 - 掘金 (juejin.cn)

Flutter完整开发实战详解(一、Dart语言和Flutter基础) | 掘金技术征文在如今的 Flutter 大潮下 - 掘金 (juejin.cn)

带你高效入门 Flutter本文面向 Flutter 初学者,旨在用易懂的方式带大家入门。除了 Flutter 代码,还 - 掘金 (juejin.cn)

CodeForge

2024 年 9 月 30 日

一周前的今天,也就是二十三号下午,心里第一次有了这个计划的雏形。

趁着这次长假,好好打磨下平日里没工夫钻研的技术,或者也可以称之为爱好、兴趣,不过这些都已经无所谓了。

我又有了两种新的想法:

简历投递,约面想法,求职。

持续精进,技术提升,兴趣。

首先是最近两个月一直在关注着的秋招,简历优化,网申投递,面试邀约,做不完的测评和笔试,遥遥无期的 offer……

刚来到这里的前两周周末里还回小马村那边,在家的时候就能静下心来好好优化简历,八月十七号那天晚上第一次做出了两页版简历。

从那天晚上开始,便进入了紧锣密鼓的简历网申投递中去,同时简历迭代的周期也越来越短。

八月二十六号,八月二十九号,九月六号,九月九号,九月十四号,九月十九号,九月二十一号,九月二十二号,九月二十九号……

最终的简历模板已经在昨天晚上定型,目前暂时还没有要继续迭代简历的打算,估计这是最终版,但这会儿谁又能真正说清楚呢。

随着简历迭代趋于完善,网申计划也趋于完善。

自中秋节后以来,每天都保持网申投递至少30份简历的节奏,更多的时候一天能投递80+份简历,这需要花费三四个小时左右的时间。

另外写了一篇文档提炼出网申阶段出现频率较高的填充内容,比如主修课程,校园经历,荣誉,兴趣爱好等,尽最大限度提高网申效率。

邮箱里陆陆续续收到了很多中大厂的测评和笔试邀请函,为了直观回顾秋招投递反馈日程,我设计了简要的 Excel 表格把这些记录下来。

这段时间里的测评和笔试倒是真不少,可邀约面试却根本没有,出了八月底的字节流程稍快一些,直到九月底才有水滴和捷顺科技约面。

约面很不顺利。

长达一个多月没有流程推进的时间里,我一直在实习僧,智联招聘和牛客直推上尝试沟通和邀约面试,为即将到来的秋招流程做足准备。

这方面我做得很漂亮,思路也确实正确。

我接到了更多的电话邀约,微信推送,邮箱链接,尽可能从更多的渠道获取面试资质,即便最终的结果一定是肯定的。

我决心要在这场秋招中拿下真正的入职 offer,尽管时间可能花费的比我想象中的还要久。

每周两到三个面试已经成为了家常便饭,在这样的环境下能约到面试本身就是件不容易的事情,我每次都能打起十二分的精神去应对。

从刚开始在等待中就惶恐不安,到后来面对面交流的从容不迫,我已经做到可以完全不惧任何面试情景了。

在这期间还特意总结了一篇面试文档,专门记录了面试流程中的各个环节表达要点,自我介绍,项目介绍,项目亮点分析这些。

当然,每场面试结束后都会快速回忆并产出一段面经要点,这些面经记录均已收录在我的真实面经文档中。

这就是我的网申阶段,这段生活确实有些麻木不仁和无可奈何,但无论如何网申还得继续,每多投出一份网申简历就多一分机会。

尽管目前已知的被收纳进人才库的企业,已经超过了五十家,剩下的都做过了测评和笔试后杳无音讯,我相信更多的都还在初筛流程中。

直到昨天晚上,我确乎认真考虑了一番,节后的求职阶段,在其他求职 APP 上也可以找找机会,机会还是挺多的。

有关求职的话题就暂且谈论到这里,后续如果还有更多突破性的进展,我倒是可以考虑在这里记录。

最近这段日子也确实在争分夺秒中考量之后的学习节奏,而不仅仅是应对即将到来的长假,更是为以后平稳的技术精进打下良好的基础。

不知道要学些什么,那当然不打紧,这都什么年代了网上什么都有,上稀土掘金胡乱看两小时就保证会有很多新奇想法。

我这里就不过多废话,直截了当地排列下最近或者说计划长期付诸的实践,也许能保质保量地贯彻下去:

1
1. AI 人工智能:这方面相对来讲比较轻松且有创造性,也是我最感兴趣的一部分,讯飞星火,ChatGPT,通义灵码,智能图书,智谱清言。
1
2. 技术攻关:这方面可能要花费的时间精力会比较多,我想要写一些 Demo 代码来加强巩固这方面的知识,最好能写成系列博客,像拦截器/限流器,限流算法,函数式编程,SpringMVC 扩展点,Stream 流,JWT 实践,WebSocket 实践,生产者消费者实现,消息队列,Guava,Mybatis-Plus 等等,后续有新的内容也会及时补充进来。
1
3. 博文阅读:以上技术攻关的要点,都是最近看到的技术博客提供的新思路,除了公众号进阶笔记,苏三说技术,小报童专栏这些,稀土掘金上最近也喜欢看首页热门文章,又会关注到很多优秀的专栏。
1
4. 项目实践:这里讲到的开源项目,比如 AI 智能图书管理,仿B站项目这样的,更多地想要在秋招备战阶段尽可能地巩固编码基础,切不可忘记手上功夫,不过就跟上面谈到的,首页热门文章也带给了我很多新想法,比如 Github 热点速递这些确实打开了我的思路。
1
5. 技术扩展:有哪些新的思路呢,我越发对桌面开发,Android 开发,游戏开发这些感兴趣了,百忙之中也会抽出时间来学习了解相关技术,权当作是消遣,Node.js,Vue.js,React.js,Electron,Tarui,Flutter,.Net,C# 等。
1
6. 小程序:这个单独拎出来作为一个栏目,是因为这方面以前也做过实操,这次区别于以上观望的态度,我更想做一些真正产品,学习了解小程序的部署上线,我觉得最近关注的那位大佬的专栏会帮助我实现这项愿望的。
1
7. 项目部署:这个可以说是重中之重,我不做过多强调,Linux 环境,Docker 部署,程序员鱼皮教学视频。
1
8. 博客优化:尽管没有新的博文,但壁纸还是要收集,乱序的博客内容也要稍作整理,还有七牛云老是欠费可不太好。

呐,简单的计划已经罗列出来,如此看来任务还是蛮多的,就看七天以后的造化了。

玩不会想到写这玩意儿竟会花费我一个半小时的时间,不过现在心里面确实明朗了不少,祝我顺利吧,假期里也要保持最佳状态。

不过也要注意休息啊,劳逸结合嘛,在最紧张的阶段也要允许自己枯萎几天。

祝假期愉快,愿前程景气,望仕途顺利。

鸿蒙

2025 年 1 月 15 日

创建和运行Hello World-快速开始-DevEco Studio - 华为HarmonyOS开发者 (huawei.com)

Uniapp

2025 年 4 月 27 日

振奋人心的消息。

创建订单,携带参数,跳转至创建订单页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//创建订单
createOrder() {
let list = this.cartList;
let cartIds = [];
list.forEach(item => {
if (item.checked) {
cartIds.push(item.id);
}
})
if(cartIds.length==0){
uni.showToast({
title:'您还未选择要下单的商品!',
duration:1000
})
return;
}
uni.navigateTo({
url: `/pages/order/createOrder?cartIds=${JSON.stringify(cartIds)}`
})
}

创建订单页面,收货地址,商品信息,优惠信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<view>
<!-- 地址 -->
<navigator url="/pages/address/address?source=1" class="address-section">
<view class="order-content">
<text class="yticon icon-shouhuodizhi"></text>
<view class="cen">
<view class="top">
<text class="name" v-if="currentAddress.name">{{currentAddress.name}}</text>
<text class="mobile" v-if="currentAddress.phoneNumber">{{currentAddress.phoneNumber}}</text>
</view>
<text class="address">{{currentAddress.province}} {{currentAddress.city}} {{currentAddress.region}}
{{currentAddress.detailAddress}}</text>
</view>
<text class="yticon icon-you"></text>
</view>

<image class="a-bg"
</image>
</navigator>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<view class="goods-section">
<view class="g-header b-b">
<text class="name">商品信息</text>
</view>
<!-- 商品列表 -->
<text>调试数据: {{ cartPromotionItemList }}</text>
<text>调试数据: {{ cartPromotionItemList.length }}</text>
<view class="g-item" v-for="item in cartPromotionItemList" :key="item.id">
<image :src="item.productPic"></image>
<view class="right">
<text class="title clamp">{{item.productName}}</text>
<text class="spec">{{item.productAttr | formatProductAttr}}</text>
<text class="promotion clamp">{{item.promotionMessage}}</text>
<view class="price-box">
<text class="price">¥{{item.price}}</text>
<text class="number">x {{item.quantity}}</text>
</view>
</view>
</view>
</view>

发起请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
data() {
return {
maskState: 0, //优惠券面板显示状态
desc: '', //备注
payType: 1, //1微信 2支付宝
couponList: [],
memberReceiveAddressList: [],
currentAddress: {},
cartPromotionItemList: [],
calcAmount: {},
currCoupon: null,
useIntegration: 0,
integrationConsumeSetting: {},
memberIntegration: 0,
cartIds: []
}
},
1
2
3
4
5
6
onLoad(option) {
//商品数据
this.cartIds = JSON.parse(option.cartIds);
console.log("+++" + this.cartIds)
this.loadData();
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//生成确认单信息
async loadData() {
this.isLoading = true;
try {
const response = await generateConfirmOrder(JSON.stringify(this.cartIds));
const res = response.data;

// 使用 Vue.set 或展开运算符确保响应式更新
this.cartPromotionItemList = [...res.cartPromotionItemList]; // 深拷贝数组
this.currentAddress = {
...this.getDefaultAddress()
}; // 确保地址是响应式

uni.$emit('updateData', {
list: res.cartPromotionItemList
});

console.log("购物车数据:", this.cartPromotionItemList); // 确认数据格式
this.memberReceiveAddressList = res.memberReceiveAddressList;
this.currentAddress = this.getDefaultAddress();
this.couponList = [];
for (let item of res.couponHistoryDetailList) {
this.couponList.push(item.coupon);
}
this.calcAmount = res.calcAmount;
this.integrationConsumeSetting = res.integrationConsumeSetting;
this.memberIntegration = res.memberIntegration;
} catch (err) {
console.error("加载数据失败:", err);
uni.showToast({
title: "加载失败",
icon: "none"
});
} finally {
this.isLoading = false;
this.$forceUpdate(); // 强制重新渲染
}

},

这段代码,废了我俩小时总算检索出来了。控制台报错就是这里。购物车地址转换失败,接下来的数据就没有解析。

整个过滤器钩子函数执行中断。

艹。

image-20250427193544980

1
2
3
4
5
6
7
8
9
10
11
12
filters: {
formatProductAttr(jsonAttr) {
let attrArr = JSON.parse(jsonAttr);
let attrStr = '';
for (let attr of attrArr) {
attrStr += attr.key;
attrStr += ":";
attrStr += attr.value;
attrStr += ";";
}
return attrStr
},

2025 年 1 月 15 日

自己开发的App如何上架,详细解读App上架操作流程-腾讯云开发者社区-腾讯云 (tencent.com)

uniapp开发App从开发到上架全过程-腾讯云开发者社区-腾讯云 (tencent.com)

uniapp开发APP从开发到上架全过程(一)-CSDN博客

uniapp开发App从开发到上架全过程(二)-真机调试_uniapp ios真机调试-CSDN博客

Docker

2024 年 12 月 19 日

Docker入门到实践 (一) docker简介与安装_docker与思政-CSDN博客

Docker入门到实践 (二) docker常用命令讲解_docker 入门到实践 (二) docker 常用指令解说-CSDN博客

2025 年 1 月 15 日

centos7安装Docker详细步骤(无坑版教程)-腾讯云开发者社区-腾讯云 (tencent.com)

windows10+VMWare+Centos7下docker的安装,验证与运行(超详细且持续更新) -配置啦-研发运维人员必备网站 (config.net.cn)

centos安装包下载_开源镜像站-阿里云 (aliyun.com)

windows10+VMWare+Centos7下docker的安装,验证与运行(超详细且持续更新) -配置啦-研发运维人员必备网站 (config.net.cn)

Docker 搭建 Minio 对象存储服务MinIO MinIO 是一款基于 Go 语言发开的高性能、分布式的对象存储 - 掘金 (juejin.cn)

手摸手教你使用 Docker 快速搭建 Gitlab 服务本文在 CentOS 虚拟机中使用 Docker 快速搭建了一 - 掘金 (juejin.cn)

上手Linux:安装 Git 的两种方式在 Linux 系统上安装软件有两种常用的方式。一种是下载源码 - 编译 - 安 - 掘金 (juejin.cn)

这篇挺全的:Springboot整合Minio全流程 - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

2025 年 1 月 25 日

今天实践操作下 docker,安装 Docker。

安装

查看 CentOS 操作系统版本和 Linux 内核版本

1
cat /etc/redhat-release
1
uname -r

image-20250125193326081

可以看到 CentOS7 的操作系统为x86_64(64位),系统内核版本为3.10.0,没有问题。

卸载旧版本。

1
yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine

image-20250125193531866

安装docker所需的软件包

1
yum install -y yum-utils device-mapper-persistent-data lvm2

设置yum源为阿里云 (由于国外网站访问速度慢)

1
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

更新yum软件包索引

1
yum makecache fast

安装docker CE(社区版),Docker提供了两个版本:社区版(CE,免费) 和 企业版(EE,收费)

1
yum -y install docker-ce

Linux中yum、rpm、apt-get、wget的区别,yum、rpm、apt-get常用命令,CentOS、Ubuntu中安装wget_apt-get 和yum-CSDN博客

image-20250125194344413

检查版本,是否安装成功。

1
docker version

image-20250125194522470

2025 年 1 月 25 日

Docker入门到实践 (二) docker常用命令讲解_docker 入门到实践 (二) docker 常用指令解说-CSDN博客

2025 年 2 月 10 日

1
yum install -y yum-utils device-mapper-persistent-data lvm2
1
ping: mirrorlist.centos.org: Name or service not known

CentOS7 yum安装报错 “Could not resolve host: mirrorlist.centos.org; Name or service not known” 解决方法_ping: mirrorlist.centos.org: name or service not k-CSDN博客

1、从阿里云下载新的配置文件,两个命令可用,如果虚拟机还没安装wget工具,就使用curl

1
2
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

2、清理缓存

1
yum clean all

3、重新生成缓存

1
yum makecache

4、更新yum源包

1
yum -y update

结束,更换 yum 源成功。

不过这个步骤属实多余,直接按照上面 Doker 安装的命令执行下来,安装 Docker 是相当顺利的。

远程部署

2025 年 2 月 5 日

已经十多天没有学习了吗。

Docker为容器设置环境变量(在docker run命令中设置容器的环境变量、在Dockerfile文件中设置容器的环境变量、在docker-compose.yaml中设置容器的环境变量)_dockerfile设置环境变量-CSDN博客

java获取docker环境变量_mob649e8161738c的技术博客_51CTO博客

新建一个 Web 项目,尝试下 Docker 部署。

docker 部署 java 项目详解-CSDN博客

WAR包和JAR包的区别 - 林泽阿 - 博客园 (cnblogs.com)

IDEA+Docker远程部署Sprin - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

1
2
3
4
5
6
7
8
# 基础镜像
FROM openjdk:8
# 复制主机jar包至镜像内,复制的目录需放置在 Dockerfile 文件同级目录下
ADD target/hello-0.0.1-SNAPSHOT.jar app.jar
# 容器启动执行命令
ENTRYPOINT ["java","-jar", "/app.jar" , "--spring.profiles.active=prod"]
# 对外暴露的端口号
EXPOSE 8080

Docker一键远程部署厚米匹配后端 - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

1
Dw990831@

配置 Docker 一键部署:ssh 远程连接服务器,连接 Docker 守护进程,编写 Dockerfile 文件,配置远程部署。

ssh 远程连接服务器。

image-20250205102013411

连接 Docker 守护进程。

image-20250205103921071

编写 Dockerfile 文件。

1
2
3
4
5
6
7
8
# 基础镜像
FROM openjdk:8
# 复制主机jar包至镜像内,复制的目录需放置在 Dockerfile 文件同级目录下
ADD target/hello-0.0.1-SNAPSHOT.jar app.jar
# 容器启动执行命令
ENTRYPOINT ["java","-jar", "/app.jar"]
# 对外暴露的端口号
EXPOSE 8080

配置远程部署。

image-20250205103822292

怎么查看docker开放的端口通不通_mob64ca12d4a164的技术博客_51CTO博客

特么的,配置都完成了,就看最后一步能不能一键部署成功,结果好像是 Docker 连接失败了。

Docker镜像的创建方法_docker 创建镜像-CSDN博客

那就手动上传 jar 包和 Dockerfile 文件,先构建镜像再运行容器试试看。

学一学。

要构建一个Docker镜像,你需要确保你已经安装了Docker,并且你的Dockerfilehello-0.0.1-SNAPSHOT.jar文件在同一目录下。以下是如何使用Docker命令行工具来构建你的镜像的步骤:

  1. 打开命令行界面

    • 在Windows上,你可以使用PowerShell或命令提示符。
    • 在macOS或Linux上,打开你的终端。
  2. 导航到包含Dockerfile的目录
    使用cd命令导航到包含你的Dockerfilehello-0.0.1-SNAPSHOT.jar文件的目录。例如:

    1
    2
    3
    bash复制代码

    cd path/to/your/directory
  3. 构建Docker镜像
    使用docker build命令来构建你的镜像。你需要为你的镜像指定一个标签(tag),这通常包括一个名称和一个版本号。例如:

    1
    2
    3
    bash复制代码

    docker build -t hello-app:0.0.1 .

    这里的-t hello-app:0.0.1指定了镜像的名称为hello-app和版本号为0.0.1。最后的.表示Dockerfile位于当前目录。

  4. 验证镜像是否构建成功
    使用docker images命令来查看你的本地镜像列表,确认你的hello-app:0.0.1镜像已经成功构建。

    1
    2
    3
    bash复制代码

    docker images
  5. 运行Docker容器
    使用docker run命令来运行你的容器。例如:

    1
    2
    3
    bash复制代码

    docker run -d -p 8080:8080 hello-app:0.0.1

    这里的-d标志表示容器将在后台运行,-p 8080:8080将主机的8080端口映射到容器的8080端口。

  6. 验证容器是否正在运行
    使用docker ps命令来查看正在运行的容器列表。

    1
    2
    3
    bash复制代码

    docker ps
  7. 访问你的应用
    打开你的网页浏览器,访问http://localhost:8080,你应该能够看到你的Java应用正在运行。

试一试。

出问题了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker build -f Dockerfile -t hello 
ERROR: "docker buildx build" requires exactly 1 argument.
See 'docker buildx build --help'.

Usage: docker buildx build [OPTIONS] PATH | URL | -

Start a build
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker build -t hello-app .
[+] Building 30.1s (2/2) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 323B 0.0s
=> ERROR [internal] load metadata for docker.io/library/openjdk:8 30.0s
------
> [internal] load metadata for docker.io/library/openjdk:8:
------
Dockerfile:2
--------------------
1 | # 基础镜像
2 | >>> FROM openjdk:8
3 | # 复制主机jar包至镜像内,复制的目录需放置在 Dockerfile 文件同级目录下
4 | ADD target/hello-0.0.1-SNAPSHOT.jar app.jar
--------------------
ERROR: failed to solve: DeadlineExceeded: DeadlineExceeded: DeadlineExceeded: openjdk:8: failed to resolve source metadata for docker.io/library/openjdk:8: failed to do request: Head "https://registry-1.docker.io/v2/library/openjdk/manifests/8": dial tcp 198.44.185.131:443: i/o timeout

jar 包没有放在同级目录下啊。

算了,看来是基础镜像出问题了,吃完饭上来搞搞。

镜像源修改

docker hello world_docker 输出hello word-CSDN博客

1
docker pull hello-world
1
2
3
4
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker pull hello-world
Using default tag: latest
Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]#

Docker修改国内镜像源_docker更换国内镜像源-CSDN博客

这篇写得很详细了:docker切换国内镜像源_mob64ca12f10f72的技术博客_51CTO博客

使用 docker 命令行设置镜像源,不太好使。

1
sudo docker login --username=<你的用户名> registry.cn-hangzhou.aliyuncs.com

得直接修改 Docker 的 daemon 配置文件。

步骤详解

步骤 1: 备份 Docker 的原始配置文件。

在对 Docker 的配置文件进行修改之前,我们需要先备份原始配置文件,以便在出现问题时能够恢复。

备份原始的配置文件到指定位置

1
sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.bak

代码解释:

  • sudo:以超级用户权限执行命令。

  • cp:复制文件的命令。

  • /etc/docker/daemon.json:Docker 的默认配置文件路径。

  • /etc/docker/daemon.json.bak:备份文件的路径。

步骤 2: 创建或编辑 Docker 的配置文件

确保 Docker 的配置文件存在,如果没有则需要创建一个新的。

检查配置文件是否存在

1
2
sudo mkdir -p /etc/docker/
sudo touch /etc/docker/daemon.json

代码解释:

  • mkdir -p /etc/docker/:创建 Docker 配置目录,如果路径中已存在部分目录则不会报错。

  • touch /etc/docker/daemon.json:创建 daemon.json 文件,如果已存在则更新其时间戳。

步骤 3: 修改镜像源为国内镜像

接下来,我们需要通过编辑 daemon.json 文件来添加国内的镜像源。这里以阿里云的 Docker 镜像为例。

开启编辑器(vi 或其它文本编辑器)

1
sudo vi /etc/docker/daemon.json

在打开的 daemon.json 文件中填写以下内容:

1
2
3
4
5
{
"registry-mirrors": [
"https://<your_ali_cdn>.mirror.aliyuncs.com"
]
}

代码解释:

  • registry-mirrors:这是配置镜像加速器的键,用于指定 Docker 镜像源的地址。

  • “https://.mirror.aliyuncs.com”:将 替换为你在阿里云中获得的加速器地址。你也可以选择其他的国内镜像源,如网易、腾讯等。

步骤 4: 重启 Docker 服务

完成镜像源的配置后,我们需要重启 Docker 服务使其生效。

重启 Docker 服务

1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

代码解释:

  • systemctl daemon-reload:重新加载服务配置。

  • systemctl restart docker:重启 Docker 服务。

步骤 5: 验证镜像源是否修改成功

最后一步是验证配置是否成功。我们可以通过拉取一个镜像来检查。

测试拉取一个镜像(例如:hello-world)

1
docker pull hello-world

代码解释:

  • docker pull hello-world:从 Docker 镜像源拉取 hello-world 镜像,用于测试。

如果镜像能够快速拉取并成功完成,那么就表示你已成功切换至国内镜像源。

阿里云地域Region ID? 地域及其RegionID对照表?_陆陆科技 (llxxkj.cn)

649d1f91988cd.png

1
2
3
4
5
{
"registry-mirrors": [
"https://cn-beijing.mirror.aliyuncs.com"
]
}

漂亮,对照这张表修改配置文件内容,直接执行拉取镜像命令,成功了。

1
2
3
4
5
6
[root@iZ2ze4hnl6pls28qt4w1ttZ docker]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:2498fce14358aa50ead0cc6c19990fc6ff866ce72aeb5546e1d59caac3d0d60f
Status: Downloaded newer image for he

那么跑一下这个镜像吧。

运行一个名为 hello-world 的镜像,容器名为 helloworld,将容器的 80 端口映射到主机的 8080 端口,并在后台运行:

1
docker run -d -p 8080:80 --name helloworld hello-world:latest

查看正在运行中的容器信息。

1
docker ps -a
1
2
3
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb2146386e71 hello-world:latest "/hello" 3 minutes ago Exited (0) 3 minutes ago helloworld

删除镜像。

1
docekr remove helloworld

镜像源问题解决了,构建 Docker 镜像的报错问题还没有进展,检查下 Dockerfile 文件内容。

1
2
3
4
5
6
7
8
# 基础镜像
FROM openjdk:8
# 复制主机jar包至镜像内,复制的目录需放置在 Dockerfile 文件同级目录下
ADD target/hello-0.0.1-SNAPSHOT.jar app.jar
# 容器启动执行命令
ENTRYPOINT ["java","-jar", "/app.jar"]
# 对外暴露的端口号
EXPOSE 8080

5 个提升你 Dockerfile 水平 - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

Dockerfile 有挺多技巧:

  1. 使用 alpine 的镜像,而不是默认的 linux 镜像,可以极大减小镜像体积,比如 node:18-alpine3.14 这种
  2. 使用多阶段构建,比如一个阶段来执行 build,一个阶段把文件复制过去,跑起服务来,最后只保留最后一个阶段的镜像。这样使镜像内只保留运行需要的文件以及 dependencies。
  3. 使用 ARG 增加构建灵活性,ARG 可以在 docker build 时通过 –build-arg xxx=yyy 传入,在 dockerfile 中生效,可以使构建过程更灵活。如果是想定义运行时可以访问的变量,可以通过 ENV 定义环境变量,值使用 ARG 传入。
  4. CMD 和 ENTRYPOINT 都可以指定容器跑起来之后运行的命令,CMD 可以被覆盖,而 ENTRYPOINT 不可以,两者结合使用可以实现参数默认值的功能。
  5. ADD 和 COPY 都可以复制文件到容器内,但是 ADD 处理 tar.gz 的时候,还会做一下解压。

Docker镜像构建知识:Dockerfile 命令详解-腾讯云开发者社区-腾讯云 (tencent.com)

1
2
3
4
5
6
7
8
# 基础镜像
FROM scratch
# 复制主机jar包至镜像内,复制的目录需放置在 Dockerfile 文件同级目录下
ADD hello-0.0.1-SNAPSHOT.jar app.jar
# 容器启动执行命令
ENTRYPOINT ["java","-jar", "/app.jar"]
# 对外暴露的端口号
EXPOSE 8080

构建成功了对吧。

1
2
3
4
5
6
7
8
9
10
11
12
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker build -t hello-app . 
[+] Building 0.4s (5/5) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 313B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load build context 0.2s
=> => transferring context: 17.65MB 0.2s
=> [1/1] ADD hello-0.0.1-SNAPSHOT.jar app.jar 0.0s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:19baea50ee1023afb4c6926836a32e3816a315de477db0fcf3d164e25b1ed5b2

镜像运行失败了。

1
docker run -p 8080:8080 --name helloapp hello-app:latest
1
2
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker run -p 8080:8080 --name helloapp hello-app:latest
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "java": executable file not found in $PATH: unknown.

缺少 Java 环境。

停止容器,删除容器。

1
2
3
4
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
eefe17b7f1e2 hello-app "java -jar /app.jar" 2 minutes ago Created 8080/tcp heuristic_jackson
da15a61a2596 hello-app:latest "java -jar /app.jar" 12 minutes ago Created 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp helloapp
1
2
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker remove eefe17b7f1e2
eefe17b7f1e2

删除镜像。

1
2
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker rmi 19baea50ee10
Untagged: hello-app:latest
1
2
3
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 3 years ago 13.3kB

重新构建镜像。

1
2
3
4
5
6
7
8
9
10
11
12
# 基础镜像
FROM scratch
# 作者信息
MAINTAINER memory
# 安装jdk
RUN apt-get update && apt-get install -y openjdk-8-jdk
# 复制主机jar包至镜像内,复制的目录需放置在 Dockerfile 文件同级目录下
ADD hello-0.0.1-SNAPSHOT.jar app.jar
# 容器启动执行命令
ENTRYPOINT ["java","-jar", "/app.jar"]
# 对外暴露的端口号
EXPOSE 8080

很显然这条命令又报错了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker build -t hello-app .
[+] Building 0.3s (4/5)
> [1/2] RUN apt-get update && apt-get install -y openjdk-8-jdk:
0.215 runc run failed: unable to start container process: exec: "/bin/sh": stat /bin/sh: no such file or directory
------
Dockerfile:6
--------------------
4 | MAINTAINER memory
5 | # 安装jdk
6 | >>> RUN apt-get update && apt-get install -y openjdk-8-jdk
7 | # 复制主机jar包至镜像内,复制的目录需放置在 Dockerfile 文件同级目录下
8 | ADD hello-0.0.1-SNAPSHOT.jar app.jar
--------------------
ERROR: failed to solve: process "/bin/sh -c apt-get update && apt-get install -y openjdk-8-jdk" did not complete successfully: exit code: 1

修改 Dockerfile 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 使用 CentOS 基础镜像
FROM centos:latest
# 作者信息
MAINTAINER memory
# 安装必要的软件包
RUN yum install -y java-1.8.0-openjdk-devel
# 设置工作目录
WORKDIR /app
# 复制 JAR 文件到工作目录
COPY hello-0.0.1-SNAPSHOT.jar app.jar
# 容器启动执行命令
ENTRYPOINT ["java", "-jar", "app.jar"]
# 对外暴露的端口号
EXPOSE 8080

dockerfile安装java环境_mob64ca12f66e6c的技术博客_51CTO博客

docker 容器配置java环境_mob64ca12dd8bce的技术博客_51CTO博客

又忙活了一个多小时许可证后台管理系统,只要着手搞这玩意儿时间就过得可快了,这会儿都快五点钟,该下班了。

再试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 使用 CentOS 基础镜像
FROM centos:latest
FROM openjdk:8-jdk-alpine
# 作者信息
MAINTAINER memory
# 配置java环境变量
ENV JAVA_HOME /opt/jdk/jdk1.8.0_412
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH $PATH:$JAVA_HOME/bin
# 设置工作目录
WORKDIR /app
# 复制 JAR 文件到工作目录
COPY hello-0.0.1-SNAPSHOT.jar app.jar
# 容器启动执行命令
#ENTRYPOINT ["java", "-jar", "app.jar"]
# 对外暴露的端口号
EXPOSE 8080

待解决问题:

1
unable to start container process: exec: "java": executable file not found in $PATH: unknown.

2025 年 2 月 6 日

exec failed: unable to start container process: exec: “ip“: executable file not found in $PATH_oci runtime exec failed: exec failed: unable to st-CSDN博客

问题报错:

1
OCI runtime exec failed: exec failed: unable to start container process: exec: "ip": executable file not found in $PATH: unknown

报错原因:因为该容器的镜像时精简版,内部缺少iproute2导致无法使用ip命令

解决方式:

进入容器

1
docker exec -it 容器名 /bin/bash

进入后:

1
2
3
4
5
6
7
8
# 更新apt
apt-get update

# 安装iproute2
agt install -y iproute2

# 安装完以后退出exit
docker exec -it 容器名 ip addr

这段不太实用,我的问题不在于容器启动后报错,而是容器根本没有启动成功,没法进入一个不在运行过程中的容器。

镜像 Dockerfile 的问题。

如何顺利进入Docker容器内部?-HCRM博客 (huochengrm.cn)

2025 年 2 月 10 日

本地虚拟机 Docker 安装完成,不过还要修改 Docker Hub 阿里云镜像源。

Docker 系列(3) —— 切换 Docker 镜像源-腾讯云开发者社区-腾讯云 (tencent.com)

这样的配置方法相比上面所提供的,也许会更加全面一些。

1
vi /etc/docker/daemon.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"registry-mirrors": [
"https://7bezldxe.mirror.aliyuncs.com/",
"https://docker.mirrors.ustc.edu.cn/",
"https://hub-mirror.c.163.com",
"https://registry.docker-cn.com"
],
"insecure-registries": [],
"debug": false,
"experimental": false,
"features": {
"buildkit": true
}
}
1
systemctl start docker.service
1
systemctl status docker.service
1
docker pull hello-world

Docker基础命令_docker 查看镜像-CSDN博客

1
docker info
1
2
Registry Mirrors:
https://7bezldxe.mirror.aliyuncs.com/

显然更新配置后再次拉取镜像没有生效,镜像源还是没有修改完成。

明天见吧,我的朋友。

Dockerfile 部署

2025 年 2 月 6 日

启动成功!

Snipaste_2025-02-06_09-35-22

删除容器,删除镜像,重新构建镜像再运行容器。

1
docker ps -a
1
docker remove helloapp
1
docker images
1
docker rmi hello-app

更新 Dockerfile 文件,选择使用官方 JDK 镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 使用 CentOS 基础镜像
FROM centos:latest
# 使用官方 JDK 镜像
FROM openjdk:8-jdk-alpine
# 作者信息
MAINTAINER memory
# 查看 JAVA 版本
RUN java -version
# 设置工作目录
WORKDIR /app
# 复制 JAR 文件到工作目录
COPY hello-0.0.1-SNAPSHOT.jar app.jar
# 容器启动执行命令
ENTRYPOINT ["java", "-jar", "app.jar"]
# 对外暴露的端口号
EXPOSE 8080

把 jar 包和编辑完善的 Dockerfile 文件放在同级目录下。

构建镜像。

1
docker build -t hello-app .

image-20250206095024612

创建并运行容器。

1
docker run -p 8080:8080 --name helloapp hello-app:latest

Snipaste_2025-02-06_09-35-22

可以说这是今年的开门红,初步掌握一门新技术:docker 容器部署。

进入正在运行中的容器并以命令行交互。

1
docker exec -it helloapp /bin/bash

或者:

1
docker exec -it helloapp /bin/sh

列表查看。

1
ls
1
2
3
4
5
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker exec -it helloapp /bin/sh
/app # ll
/bin/sh: ll: not found
/app # ls
app.jar

退出容器。

1
exit
1
2
/app # exit
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]#

shell:bash【Bourne-Again SHell】_bourne again shell-CSDN博客

[Linux] Bourne Again Shell-CSDN博客

正巧看到这篇文章,写得很全很详细,点开主页一看竟然是一位年均输出大几百篇技术文章的大佬,不过一九年停更了。

快到饭点了,接下来安排的任务是尝试 docker 部署后台管理项目,以及 docker 远程部署。

同样的步骤,编写 Dockerfile 文件,构建镜像文件,启动并运行容器,接下来就应该开放阿里云服务器端口号了。

倒是接口文档可以正常访问,不过连接数据库失败了。

1
http://8.141.90.145:8082/backend-server/doc.html

获取 docker 容器环境变量。

着手测试。

1
http://localhost:8080/api/test

携带环境变量,启动项目。

1
docker run -p 8080:8080 --name helloapp -e APP_NAME="My Awesome App" -e APP_PORT=8080 hello-app:latest

可以这么干,那就更新下接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 测试接口
*/
@GetMapping("/test")
public String test() {
System.out.println("Hello World");
return "Hello World";
}

/**
* 测试接口2
*/
@GetMapping("/test2")
public String test2() {
Map<String, String> getenv = System.getenv();
System.out.println(getenv);
String appName = System.getenv("APP_NAME");
System.out.println(appName);
String appPort = System.getenv("APP_PORT");
System.out.println(appPort);
return "Hello World";
}

出问题了。

怎么访问不到接口呢。

本地测试没问题啊,docker 部署服务启动也是没问题的,难道是打包更新后的代码出问题了吗,再试试。

1
http://8.141.90.145:8080/api/test2

果然是这样,成功了。

image-20250206153451255

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[root@iZ2ze4hnl6pls28qt4w1ttZ serInfo]# docker run -p 8080:8080 --name helloapp -e APP_NAME="My Awesome App" -e APP_PORT=8080 hello-app:latest

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.7)

2025-02-06 07:30:58.477 INFO 1 --- [ main] org.tellhow.info.hello.HelloApplication : Starting HelloApplication v0.0.1-SNAPSHOT using Java 1.8.0_212 on 9ed306a10b37 with PID 1 (/app/app.jar started by root in /app)
2025-02-06 07:30:58.484 INFO 1 --- [ main] org.tellhow.info.hello.HelloApplication : The following 1 profile is active: "dev"
2025-02-06 07:30:59.972 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2025-02-06 07:30:59.988 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2025-02-06 07:30:59.988 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.70]
2025-02-06 07:31:00.135 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2025-02-06 07:31:00.135 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1499 ms
2025-02-06 07:31:00.679 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2025-02-06 07:31:00.694 INFO 1 --- [ main] org.tellhow.info.hello.HelloApplication : Started HelloApplication in 2.989 seconds (JVM running for 3.58)
Hello world!
2025-02-06 07:31:06.094 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-02-06 07:31:06.095 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2025-02-06 07:31:06.096 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
Hello World
{PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/jvm/java-1.8-openjdk/jre/bin:/usr/lib/jvm/java-1.8-openjdk/bin, HOSTNAME=9ed306a10b37, JAVA_ALPINE_VERSION=8.212.04-r0, LD_LIBRARY_PATH=/usr/lib/jvm/java-1.8-openjdk/jre/lib/amd64/server:/usr/lib/jvm/java-1.8-openjdk/jre/lib/amd64:/usr/lib/jvm/java-1.8-openjdk/jre/../lib/amd64, JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk, APP_NAME=My Awesome App, JAVA_VERSION=8u212, LANG=C.UTF-8, APP_PORT=8080, HOME=/root}
My Awesome App
8080

嘿嘿哈哈,看来通过 Java 代码获取封装在 Docker 容器环境变量中的服务器硬件信息是可取的,开启下一步修改。

1
2
3
4
5
6
Map<String, String> getenv = System.getenv();
System.out.println(getenv);
String appName = System.getenv("APP_NAME");
System.out.println(appName);
String appPort = System.getenv("APP_PORT");
System.out.println(appPort);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 获取现场服务器硬件信息
// 获取容器环境变量
LicenseCheckModel hardwareInfo = new LicenseCheckModel();
String ipAddressEnv = System.getenv(LicenseConstant.IP_ADDRESS_ENV);
String MacAddressEnv = System.getenv(LicenseConstant.MAC_ADDRESS_ENV);
String CpuSerialEnv = System.getenv(LicenseConstant.CPU_SERIAL_ENV);
String MainBoardSerialEnv = System.getenv(LicenseConstant.MAINBOARD_SERIAL_ENV);
if (ObjectUtils.isNotEmpty(ipAddressEnv)) {
hardwareInfo.setIpAddress(Lists.newArrayList(ipAddressEnv.split(",")));
}
if (ObjectUtils.isNotEmpty(MacAddressEnv)) {
hardwareInfo.setMacAddress(Lists.newArrayList(MacAddressEnv.split(",")));
}
if (ObjectUtils.isNotEmpty(CpuSerialEnv)) {
hardwareInfo.setCpuSerial(CpuSerialEnv);
}
if (ObjectUtils.isNotEmpty(MainBoardSerialEnv)) {
hardwareInfo.setMainBoardSerial(MainBoardSerialEnv);
}
// 现场服务器硬件信息
if (ObjectUtils.isEmpty(hardwareInfo)) {
log.error("请输入现场服务器硬件信息!");
throw new CommonException(401, "请输入现场服务器硬件信息!");
}
// 设置现场服务器硬件信息
HardwareInfoContext.setHardwareInfo(hardwareInfo);

接下来的内容,就记录在别的栏目了,纯业务,与技术无关。

2025 年 2 月 7 日

docker 远程部署。

IDEA+Docker远程部署Sprin - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

image-20250207150825887

两天了,刚刚看到这个连接 Docker 失败的提示。

算了,前天的记录内容就网上翻找吧,在此就不做复杂的排版了。

1
Only key-pair ssh auth type is supported for docker connections.

远程部署成功!

image-20250207155252693

2025 年 2 月 8 日

IDEA+Docker远程部署Sprin - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

在IDEA中通过密钥认证的方式使用SSH连接远程Linux服务器_idea ssh密码登录-CSDN博客

SSH

2025 年 2 月 8 日

openssh是什么服务器 • Worktile社区

远程连接服务器,除了账号密码还可以使用 ssh 连接。

IDEA+Docker远程部署Spring - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

在IDEA中通过密钥认证的方式使用SSH连接远程Linux服务器_idea ssh密码登录-CSDN博客

在IDEA中通过密钥认证的方式使用SSH连接远程 Linux 服务器。

昨天使用 Key Pair OpenSSH 连接方式实现 Docker 远程部署,是因为 Docker 远程部署仅支持 Key Pair OpenSSH 连接方式。

然而连接其实是失败了,远程部署显然不应该成功的,还是使用账号密码验证成功,只是来 IDEA 配置中勾选连接方式为 ssh 方式即可。

在 windows 上生成公钥证书。

  • 第一步,执行Win+R命令输入cmd打开DOS命令行窗口。
  • 第二步,在命令行窗口中输入ssh -V查看ssh版本号,判断ssh是否可以用,因为我们需要通过ssh来生成证书文件。
  • 第三步,ssh命令可用的话,就继续在命令行窗口输入ssh-keygen -t rsa生成公钥证书和私钥证书文件。生成的目录也指明了,通常在用户的.ssh目录下,其中id_rsa是私钥证书文件,id_rsa.pub为公钥证书文件。
1
win + R
1
ssh -V
1
ssh-keygen -t rsa

将公钥证书放到 Linux 服务器上。

  • 第一步,复制Windows系统下.ssh目录下生成的公钥证书文件id_rsa.pub的内容。
  • 第二步,在Linux系统的/root/.ssh目录下执行vi authorized_keys命令创建一个名为authorized_keys的文件,然后将第一步复制的id_rsa.pub的内容粘贴到该文件内。这样远程Linux服务器就信任本地的Windows系统服务器了,你可以在本地的Windows系统上通过ssh远程登录Linux系统了。
  • 第三步,测试。在本地Windows系统上输入ssh 用户名@IP地址进行远程登录。如果能登录成功并且能执行Linux命令表示配置成功。
1
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9p7KkIDVnVn9XOi4J6qNkwEJ0iVKqMR5gNxW5o1Qhf++ufpzcgro9eDTLkfLA7i9v3oqB6IUzmzF3lKXEnGEcEz+d60QdSUoJFV2+8kGeCyAfYlSh5hL/DJ79zjwfkWnFqDmAUvznqaYSRxWGLGW3q/7a09EaAuJ2rmI2Arz76DV1Knr7mu1HLmm6TUuHX7cHdnez8azIxhfm/0p4OGK9eulK4YGbn1XCqN8oLJfT+MqYx23rpFZBPtd3sjWaxyIqbpzH7r0cfT3tIhO6URyv3kP4YscVccbf4ImP4aJiOjfyGD+JB7hpuhXC3HtH8mhZsOCuDwwkPyi43J7Eew1yXVnPpHIpYXhtryNOEgJfzcbP3QrqnTynrNKiNZQjfo47JBUWFFeWUbEFcJDshKIYOAZb0G9twqbX3ZraVKVAYYd6kKj5a5sge8Ck+CrPXYFgCm3mWkS3W+wPrTOHgqmuKH4gksZT4Zpc1rTmjOLNlRaOggBW8AMvvovteRdF37s= Lenovo@LAPTOP-5U3S75BI
1
vi authorized_keys
1
ssh 用户名@IP地址
1
2
3
4
5
C:\WINDOWS\system32>ssh root@8.141.90.145
Last login: Sat Feb 8 16:39:45 2025 from 218.94.31.98

Welcome to Alibaba Cloud Elastic Compute Service !
[root@iZ2ze4hnl6pls28qt4w1ttZ ~]#

image-20250208164045006

注意:

  • 其实就是将本地Windows系统上的公钥证书文件id_rsa.pub文件上传到远程Linux系统上的/root/.ssh目录下并且重命名为authorized_keys。

  • 如果已经存在authorized_keys文件了,那么直接将复制的内容添加到文件的最后一行。因为每一行都表示一条信任连接,不要去删除。

IDEA通过SSH连接远程Linux服务器。

  • 第一步,打开File,然后选择Settings...
  • 第二步,选择Tools下的SSH Configurations面板,点击+号选择新建SSH连接。
  • 第三步,输入连接参数。Host输入远程Linux服务器的IP地址;Port输入端口号,默认是22;User name输入登录的用户名;Authentication type选择Key pair表示通过密钥进行验证;Private key file则选择Windows系统下私钥证书id_rsa的目录,即在用户目录下的.ssh子目录中;Passphrase不用填。
  • 第四步,如果有多个连接,那么在SSH Terminal面板中的SSH configuration选择框中选择一台默认连接,或者选择Select SSH configuration on every run表示在每次打开时手动选择要连接的主机。
  • 第五步,在菜单条上的Tools中选择Start SSH Session...开启会话。在出现的Select Host to Connect面板中选择要连接的服务器。
  • 第六步,连接成功!
1
2
3
4
Last login: Sat Feb  8 16:41:19 2025 from 218.94.31.98

Welcome to Alibaba Cloud Elastic Compute Service !
[root@iZ2ze4hnl6pls28qt4w1ttZ ~]#

image-20250208165259585

其他:安装 Open SSH。

openssh是什么服务器 • Worktile社区

适用于 Windows 的 OpenSSH 入门 | Microsoft Learn

尝试使用刚新学会的三板斧实现 th-iois-file-server 项目远程部署,很显然失败了。

1
2
Can not construct instance of com.spotify.docker.client.messages.RegistryAuth: no String-argument constructor/factory method to deserialize from String value ('desktop')
at [Source: N/A; line: -1, column: -1] (through reference chain: java.util.LinkedHashMap["credsStore"])

下周见,我的朋友,今天辛苦了。

MinIO

2025 年 4 月 26 日

MinIO | 企业级、高性能对象存储

image-20250426163420399

他奶奶的,本地虚拟机又启动不了了。

image-20250426164425964

MinIO 对象存储(可以当作图床免费) - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

1
admin, 12345678

2025 年 1 月 15 日

这年头不会还有谁没碰过minio的吧?这可太…🤡文件存储那些“坑”,你踩过几个?想象一下,你正在开发一个新项目,老 - 掘金 (juejin.cn)

MinIO+Docker从零搭建一个文件 - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

MinIO 对象存储(可以当作图床免费) - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

Springboot整合Minio全流程 - 编程导航 - 程序员编程学习交流社区 (codefather.cn)

centos7安装Docker详细步骤(无坑版教程)-腾讯云开发者社区-腾讯云 (tencent.com)

Docker 搭建 Minio 对象存储服务MinIO MinIO 是一款基于 Go 语言发开的高性能、分布式的对象存储 - 掘金 (juejin.cn)

虚拟机

2025 年 1 月 13 日

ubuntu与centos的对比和选择「建议收藏」-腾讯云开发者社区-腾讯云 (tencent.com)

CentOS、Ubuntu、Debian三个linux比较异同_debian和ubuntu的区别-CSDN博客

虚拟机。

在虚拟机上进行的最多的操作便是部署项目,以及间歇性熟悉基本的 Linux 命令。

最近需要抽出时间来巩固下 Linux 基本操作命令,学习如何编写脚本来获取 Linux 服务器硬件信息。

2025 年 1 月 14 日

Linux获取电脑硬件信息_linux 获取计算机信息-CSDN博客

9个Linux 常用查看系统硬件信息命令(实例详解)-腾讯云开发者社区-腾讯云 (tencent.com)

如何制作centos安装光盘 centos光盘映像文件怎么安装_mob6454cc6c1f4a的技术博客_51CTO博客

centos安装包下载_开源镜像站-阿里云 (aliyun.com)

Linux 脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/bash

OUTPUT_FILE="$HOME/Desktop/OutputFile.txt"

echo "开始获取本机信息..."

# 清空或创建输出文件
> "$OUTPUT_FILE"

# 获取本机IP地址
echo "本机IP地址:" >> "$OUTPUT_FILE"
ip addr show | grep -Eo 'inet ([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}' | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# 获取本机MAC地址
echo "本机MAC地址:" >> "$OUTPUT_FILE"
ip link show | grep -Eo '(([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2})' >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# 获取本机CPU序列号(注意:Linux系统通常没有CPU序列号的概念,这里用CPU型号代替)
echo "CPU型号:" >> "$OUTPUT_FILE"
lscpu | grep -E 'Model name|CPU(s):' >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# 获取本机主板序列号
echo "主板序列号:" >> "$OUTPUT_FILE"
sudo dmidecode -s baseboard-serial-number >> "$OUTPUT_FILE" 2>/dev/null

echo "本机信息获取完成,结果已保存到 $OUTPUT_FILE"

# 暂停,以便用户查看输出文件(在终端中按任意键继续)
read -p "按任意键退出..." dummy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
本机IP地址:
127.0.0.1
192.168.118.16
192.168.122.1
172.30.0.1
172.18.0.1
172.17.0.1

本机MAC地址:
00:00:00:00:00:00
00:00:00:00:00:00
54:14:a7:16:a5:e7
ff:ff:ff:ff:ff:ff
52:54:00:55:4a:6c
ff:ff:ff:ff:ff:ff
52:54:00:55:4a:6c
ff:ff:ff:ff:ff:ff
02:42:21:c3:65:a2

CPU型号:

主板序列号:
/66VXC73/CNPE10009806QG/

本机 CPU 序列号:

1
2
3
4
# 获取本机CPU序列号(注意:Linux系统通常没有CPU序列号的概念,这里用CPU型号代替)
echo "CPU型号:" >> "$OUTPUT_FILE"
lscpu | grep -E 'Model name|CPU(s):' >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
1
lscpu

2025 年 1 月 17 日

WSL是什么?和虚拟机有什么区别_wsl和虚拟机区别-CSDN博客

WSL和虚拟机,哪个更适合你 (baidu.com)

WSL和虚拟机的区别是什么?_linux_我想要身体健康-华为开发者空间 (csdn.net)

手把手教你如何安装使用,适用于 Linux 的 Windows 子系统WSL_wsl安装-CSDN博客

颠覆虚拟机的大神——WSL来了 - zhangzl419 - 博客园 (cnblogs.com)

image-20250117100141936

2025 年 1 月 23 日

解决虚拟机连不上网的五大技巧:从排查到修复,一篇文章让你彻底 (baidu.com)

在线就能用的linux环境(练习命令用)_在线linux模拟环境-CSDN博客

VMware虚拟机无法联网ping不通_vmware虚拟机网络连接不上-CSDN博客

image-20250123113444304

VMware虚拟机网络连接不上怎么办?帮您逐个排查! (abackup.com)

阿里云。

阿里云免费试用 - 阿里云 (aliyun.com)

image-20250123115613845

image-20250123115858152

连上了,他妈的。

image-20250123120205749

Linux系统之安装java开发环境 - 爵岚 - 博客园 (cnblogs.com)

image-20250123120857731

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static String fetchCpuId() {
String cpuId = "";
String[] command = {"/bin/bash", "-c", "sudo dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1"};

ProcessBuilder processBuilder = new ProcessBuilder(command);
try {
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
if ((line = reader.readLine()) != null) {
cpuId = line.trim();
}
reader.close();
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new RuntimeException("Command exited with error code: " + exitCode);
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
return cpuId;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static String fetchSerialNumber() {
String serialNumber = "";
// 构建要执行的命令
String[] command = {"/bin/bash", "-c", "sudo dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1"};

// 创建ProcessBuilder对象
ProcessBuilder processBuilder = new ProcessBuilder(command);
try {
// 启动进程
Process process = processBuilder.start();
// 读取命令输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
if ((line = reader.readLine()) != null) {
// 移除输出中的空白字符
serialNumber = line.trim();
}
reader.close();
// 等待进程结束并获取退出码
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new RuntimeException("Command exited with error code: " + exitCode);
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
return serialNumber;
}
1
2
3
4
// CPU序列号(或主板序列号)的正则表达式(宽松匹配)
// 假设序列号由字母、数字、连字符、点和空格组成,长度在10到40个字符之间
private static final String SERIAL_REGEX = "^[A-Za-z0-9\\-.\\s]{8,40}$";
private static final Pattern SERIAL_PATTERN = Pattern.compile(SERIAL_REGEX);

2025 年 1 月 25 日

脚本,命令。

1
sudo dmidecode -t processor | grep 'ID' | awk -F ':' '{print $2}' | head -n 1
1
sudo dmidecode | grep 'Serial Number' | awk -F ':' '{print $2}' | head -n 1
1
ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'
1
ip link show | awk '/ether/ {match($0, /ether ([0-9a-fA-F:]+)/, arr); print $2, arr[1]}'

2025 年 2 月 10 日

CentOS 的安装——超详细教程_centos安装教程详解,面试官不讲武德-CSDN博客

image-20250210094759039

1
2
3
my_CentOS7
admin
admin123

ISO文件_百度百科 (baidu.com)

查看虚拟机centos 7 的 IP 地址和命令 - 数据派 - 博客园 (cnblogs.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[admin@localhost ~]$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens32: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
link/ether 00:0c:29:d7:0d:5c brd ff:ff:ff:ff:ff:ff
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN qlen 1000
link/ether 52:54:00:00:81:b0 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
valid_lft forever preferred_lft forever
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN qlen 1000
link/ether 52:54:00:00:81:b0 brd ff:ff:ff:ff:ff:ff
1
vi /etc/sysconfig/network-scripts/ifcfg-ens33

Linux网络基础_route-ens33-CSDN博客

「科普」BIOS是什么?BIOS怎么进入,BIOS里面可以设置什么东西? (baidu.com)

Linux远程连接没有ens33ip地址问题解决_linuxens33没有ip地址-CSDN博客

linux下修改完配置文件如何保存_linux修改配置文件怎么保存退出-CSDN博客

1
2
3
按w是保存
按wq是保存并退出
按wq!是强制保存并退出

Ubuntu user is not in the sudoers file. This incident will be reported解决办法-CSDN博客

特么的总算找着解决办法了。

1
su -
1
vi /etc/sysconfig/network-scripts/ifcfg-ens32

好熟悉的报错:

1
2
[root@localhost ~]# systemctl start network.service
Job for network.service failed because the control process exited with error code. See "systemctl status network.service" and "journalctl -xe" for details.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@localhost ~]# journalctl -xe
-- Subject: Unit network.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit network.service has begun starting up.
Feb 10 03:31:04 localhost.localdomain network[45746]: Bringing up loopback interface: [ OK ]
Feb 10 03:31:04 localhost.localdomain NetworkManager[743]: <info> [1739187064.9118] audit: op="connection-activate" uuid="28
Feb 10 03:31:04 localhost.localdomain network[45746]: Bringing up interface ens32: Error: Connection activation failed: No s
Feb 10 03:31:04 localhost.localdomain network[45746]: [FAILED]
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain network[45746]: RTNETLINK answers: File exists
Feb 10 03:31:04 localhost.localdomain systemd[1]: network.service: control process exited, code=exited status=1
Feb 10 03:31:04 localhost.localdomain systemd[1]: Failed to start LSB: Bring up/down networking.
-- Subject: Unit network.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit network.service has failed.
--
-- The result is failed.
Feb 10 03:31:04 localhost.localdomain systemd[1]: Unit network.service entered failed state.
Feb 10 03:31:04 localhost.localdomain systemd[1]: network.service failed.
Feb 10 03:31:04 localhost.localdomain polkitd[628]: Unregistered Authentication Agent for unix-process:45740:499336 (system b
lines 1651-1680/1680 (END)

Linux:Job for network.service failed because the control process exited with error code - 宋霏 - 博客园 (cnblogs.com)

虚拟机重启网卡报错:Job for network.service failed because the control process exited with error code.-CSDN博客

没用。

虚拟机报错:Job for network.service failed because the control process exited with error code - 知乎 (zhihu.com)

network.service - LSB: Bring up/down networking Loaded: loaded (/etc/rc.d/init.d/network; bad; v_源知原味的技术博客_51CTO博客

特么十年前的帖子都找来了,没有解决问题。

1
2
无法连接虚拟设备 ide1:0,因为主机上没有相应的设备。
您要在每次开启此虚拟机时都尝试连接此虚拟设备吗?

无法连接虚拟设备 ide1:0,因为主机上没有相应的设备。您要在每次开启此虚拟机时都尝试连接此虚拟设备吗? - jingjing0920 - 博客园 (cnblogs.com)

无法连接虚拟机设备 ide1:0,因为主机上没有相应的设备。您要每次在开启此虚拟机时都尝试连接此虚拟设备吗?_无法连接虚拟设备 ide1:0,因为主机上没有相应的设备。 您要在每次开启此虚拟机时-CSDN博客

好像跟开启虚拟机时的告警信息也无关,同样解决不了问题。

这个方案挺全,试试看:Job for network.service failed because the control process exited with error code.-CSDN博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
HWADDR=00:0c:29:d7:0d:5c
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens32
UUID=28699bd2-8cc2-41d1-91c2-12de41c04007
DEVICE=ens32
ONBOOT=yes

静态 ip 把 BOOTPROTO 改为 static,重启成功了。

不过 ifconfig 还是 没有 ip 地址,为什么呢。

1
2
3
4
5
6
7
8
[root@localhost ~]# ifconfig
ens32: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet6 fe80::20c:29ff:fed7:d5c prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d7:0d:5c txqueuelen 1000 (Ethernet)
RX packets 736 bytes 156623 (152.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 18 bytes 4068 (3.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

查看下你电脑有没有禁用了VMware DHCP service和VMware NAT service 这几个vm服务,如果禁用则开启。

查看了下果真未开启,尝试开启但失败了。

Vmware Linux虚拟机连不上网怎么办?_虚拟机linux无法联网-CSDN博客

我也这么干一遍:先把虚拟机关机,再打开vmware首页 ,打开编辑, 再打开虚拟网络编辑器,选择其中的第一个VMnet0,然后点击左下角的还原默认设置

也还是没啥用。

艹,这就成功了,虚拟机连接网络成功,FinalShell 连接本机虚拟机成功,虚拟机网络配置完成。

这么长时间了,总算搞懂了网络配置里的歪门邪道,年前留下的最后一个问题也总算在今天解决,二十天的时间跨度不过如此。

我什么都能解决。

2025 年 2 月 10 日

一条龙

下载光盘映像文件,根据 .iso 文件创建虚拟机,配置虚拟机硬件信息,设置用户名密码,启动。

看这篇就够了:CentOS 的安装——超详细教程_centos安装教程详解,面试官不讲武德-CSDN博客

重点来了,从去年开始反复困扰我的本机虚拟机连接网络失败的问题,在这里简要分析下整个网络配置中需要注意的点。

1
ifconfig

执行这条命令,虚拟机网卡 ens32 网络连接是有问题的,查看下配置文件。

1
vim /etc/sysconfig/network-scripts/ifcfg-ens32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
HWADDR=00:0c:29:d7:0d:5c
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens32
UUID=28699bd2-8cc2-41d1-91c2-12de41c04007
DEVICE=ens32
ONBOOT=yes

ONBOOT=yes,修改配置文件结束后竟然重启网络服务失败了。

1
2
[root@localhost ~]# systemctl start network.service
Job for network.service failed because the control process exited with error code. See "systemctl status network.service" and "journalctl -xe" for details.

查了很多资料和方案,贴出来最全的博客文章吧,里面所有的方法都试过了.

Job for network.service failed because the control process exited with error code.-CSDN博客

Vmware Linux虚拟机连不上网怎么办?_虚拟机linux无法联网-CSDN博客

最终我尝试把 BOOTPROTO 改为 static 即静态 IP,虚拟机网络服务竟然重启成功,不过 ifconfig 还是 没有 ip 地址,为啥呢。

因为改成静态 ip 了,配置文件里应该相应要增加这些配置信息才对:

1
2
3
IPADDR=192.168.1.100							# 静态ip地址
PREFIX=24 # 或者使用 NETMASK=255.255.255.0 # 子网掩码
GATEWAY=192.168.1.1 # 网关

由于虚拟机未配置动态主机配置协议,那本机即宿主机服务当然不会在运行中,因为win10默认:不存在其他服务应用到这俩服务后就自动关闭。

image-20250210151057680

那还是把 BOOTPROTO 改回 dhcp 即动态主机配置协议吧,结果重启网络服务仍然成功了,执行 ifconfig 命令后结果完全正常。

1
2
3
4
5
6
7
8
9
[admin@localhost ~]$ ifconfig
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.229.128 netmask 255.255.255.0 broadcast 192.168.229.255
inet6 fe80::20c:29ff:fed7:d5c prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d7:0d:5c txqueuelen 1000 (Ethernet)
RX packets 36660 bytes 4378000 (4.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 55849 bytes 14707128 (14.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

这是现在的配置文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
HWADDR=00:0c:29:d7:0d:5c
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens32
UUID=28699bd2-8cc2-41d1-91c2-12de41c04007
ONBOOT=yes

搞半天花里胡哨的,其实就是把 dhcp 改成 static 又改回 dhcp 罢了, 额外操作根本不需要,不过确实节外生枝学到了不少。

本机虚拟机安装及网络配置完全结束。

2025 年 2 月 17 日

filezilla向虚拟机Linux传输文件失败且直接在Linux创建文件夹失败的解决方案_550 could get file size-CSDN博客

SSH客户端连接Linux成功,但是传输文件失败_ssh无法传输文件-CSDN博客

[linux 不能上传文件 - 腾讯云开发者社区 - 腾讯云 (tencent.com)](https://cloud.tencent.com/developer/information/linux 不能上传文件)

VM虚拟机无法传输文件(更新时间24/3/3)-CSDN博客

内网穿透

2025 年 1 月 9 日

有哪些简单实用的端口映射(内网穿透)软件工具?_百度知道 (baidu.com)

内网穿透(frp、zerotier)-CSDN博客

内网穿透几种方式?怎么搭建内网穿透?-贝锐花生壳官网 (oray.com)

内网穿透方案&FRP内网穿透实战(基础版)-CSDN博客

小程序

2025 年 1 月 9 日

从零开始三天学会微信小程序开发(一)看到不少入门的小程序开发者不断的问重复性的问题,我们从实战角度开发了这个课程,希望能 - 掘金 (juejin.cn)

2025 年 3 月 29 日

注册微信小程序,下载安装小程序开发工具,创建小程序项目,预览和发布小程序,了解项目目录结构;

删除一个页面,添加一个新的页面,编写第1个界面,给页面绑定数据,给页面绑定数组数据。

应用列表 - Bmob后端云 (bmobapp.com)

image-20250329105347905

hydrogen-js-sdk: Bmob后端云小程序SDK。 - Gitee.com

在页面之间传递参数,获取评语内容,封装一个方法,按钮绑定方法,看调试器,实现复制、分享功能,如何选择主题。

MongoDB

2025 年 1 月 15 日

高效存储,万物皆可Mongo!SpringBoot+MongoDB教程,「从入门到掌握」🏆本文收录于《Spring B - 掘金 (juejin.cn)

云盘

2025 年 1 月 16 日

百度网盘115G,阿里云盘105G,夸克云盘10G,迅雷云盘1TB。

2025 年 1 月 17 日

onedeive作用是什么,类似百度网盘吗,和百度网盘有什么区别没?_one deive-CSDN博客

(18 封私信 / 7 条消息) 为什么微软的网盘Onedrive不像百度网盘一样支持秒传呢? - 知乎 (zhihu.com)

阿里云盘用来同步备份,百度网盘用来上传保存,夸克云盘用来及时救急,迅雷云盘当然是用来下载文件了。

妈的,百度网盘上传文件大小受到限制,超过4GB就得花钱了;迅雷云盘更夸张,稍微大点有个1G就上传失败,看看阿里云盘。

1
2
3
4
5
6
7
8
‌百度网盘普通用户单个文件上传的最大限制为4GB,而会员用户可以享受更大的上传空间。具体来说,百度网盘超级会员(SVIP)用户在使用Windows客户端和Mac客户端进行大文件上传时,可以上传的最大文件大小如下:
‌普通用户‌:单个文件最大上传限制为4GB。
‌会员用户‌:最大可上传单个文件至20GB。
‌超级会员(SVIP)‌:使用Windows客户端和Mac客户端进行大文件上传时,超级会员V1可上传300G大文件,超级会员V10最高可上传2048G超大文件。
不同用户类型的上传限制
‌普通用户‌:普通用户的总存储空间为2TB,单个文件最大上传限制为4GB。
‌会员用户‌:会员用户的总存储空间和上传速度会有所提升,单个文件最大上传限制为20GB。
‌超级会员(SVIP)‌:超级会员在Windows客户端和Mac客户端上可以上传更大文件,具体大小取决于会员等级,从300G到2048G不等。

9.4 文件的上传和下载-CSDN博客

阿里云盘普通用户限制多久 | 百度网盘企业版 (baidu.com)

我的此电脑设备和驱动器里的百度网盘图标怎么删除? (baidu.com)

1
计算机\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\

image-20250117154128751

DeepSeek

2025 年 2 月 13 日

ChatBox可以免费对话Gemini和Claude千次-CSDN博客

DeepSeek本地化部署全攻略,轻松拥有专属 AI 助手-CSDN博客

本地免费部署DeepSeek教程,个人PC都能安装(附软件)_个人电脑部署deepseek-CSDN博客

攻略丨搭建属于自己的 DeepSeek,本地部署「手搓教程」在此!_本地搭建deepseek-CSDN博客

2025 年 2 月 14 日

10分钟接入AI大模型—Spring Cloud Alibaba_spring ai-CSDN博客

1
2
3
4
5
6
企业方面,大模型将带来数智化升级的进一步加速。举几个例子,通过大模型可以实现:
金融领域中的投资组合优化、风险管理、欺诈检测等;
医疗领域中疾病预测、药物研发、医疗影像分析等;
制造业中的生产计划排程、质量控制、物流管理等;
交通运输领域中的自动驾驶、智能交通管理等;
娱乐领域中游戏开发、电影制作、音乐创作等。

从头开始,八步实现大模型接入|如何用好大模型-CSDN博客

2024年末AI大模型盘点:国内外当前主流大数据模型汇总 (baidu.com)

国内:文心一言豆包Kimi讯飞星火智谱清言通义千问腾讯元宝天工AI盘古赤兔

国外:GPT系列Gemini系列Claude系列

2025年全球AI大模型盘点及对比分析 (baidu.com)

AI 模型接入

Spring Boot 对接文心一言_springboot接入文心一言-CSDN博客

springboot+vue项目接入文心一言API_springboot接入文心一言-CSDN博客

2025 年 2 月 17 日

DeepSeek R1 使用指南:架构、训练、本地部署_deepseek本地训练-CSDN博客

2025 年 2 月 19 日

99%的人都不知道的DeepSeek玩法:榨干算力,性能狂飙!_深度思考r1选与不选的区别-CSDN博客

用朴实直白的语言,不要过度发挥或创造新名词,避免使用过于专业的术语或自创概念。

【图片】这四个模式都是什么意思,有什么区别吗?【deepseek吧】_百度贴吧 (baidu.com)

【图片】【关于深度思考】deepseek说开不开深度思考不影响答案本身_deepseek吧_百度贴吧 (baidu.com)

手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!写在前面 最近,DeepSeek 发布的推理大 - 掘金 (juejin.cn)

2025 年 2 月 21 日

DeepSeek+KIMI超强组合,一人就是一家公司! 保姆级教程 - 知乎 (zhihu.com)

Conda

2025 年 2 月 21 日

conda环境管理与包安装实战-CSDN博客

权限认证

2025 年 2 月 27 日

Spring Security 认证流程,长话简说_springsecurity认证流程-CSDN博客

无人机

2025 年 3 月 17 日

[大疆无人机上云API:Java代码实战全攻略-CSDN博客](https://blog.csdn.net/m0_73978383/article/details/146033672?ops_request_misc=&request_id=&biz_id=102&utm_term=Java 无人机&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-8-146033672.142^v102^control&spm=1018.2226.3001.4187)

[无人机飞行数据java版本api大疆无人机SpringBoot_大疆无人机视频数据实时传输api-CSDN博客](https://blog.csdn.net/qq_38821574/article/details/123356320?ops_request_misc=%7B%22request%5Fid%22%3A%22a21ae00631af52d8a114d4d7be5d89b3%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fall.%22%7D&request_id=a21ae00631af52d8a114d4d7be5d89b3&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-8-123356320-null-null.142^v102^control&utm_term=Java 无人机&spm=1018.2226.3001.4187)

Mybatis

mybatis看这一篇就够了,简单全面一发入魂_mybatis一发入魂-CSDN博客

SQL

Netty

2025 年 3 月 17 日

理解:什么是同步和异步?什么是阻塞和非阻塞?_什么是同步什么是异步-CSDN博客

【硬核】肝了一月的Netty知识点-CSDN博客

[01 初识 Netty:为什么 Netty 这么流行? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Netty 核心原理剖析与 RPC 实践-完/01 初识 Netty:为什么 Netty 这么流行?.md)

消息队列

2025 年 3 月 17 日

RabbitMQ详解,用心看完这一篇就够了【重点】-CSDN博客

Node

2025 年 3 月 18 日

Node.js安装与配置(详细步骤)_nodejs安装及环境配置-CSDN博客

SpringBoot

2025 年 3 月 18 日

[09 数据抽象:Spring Data 如何对数据访问过程进行统一抽象? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/09 数据抽象:Spring Data 如何对数据访问过程进行统一抽象?.md)

[17 安全架构:如何理解 Spring 安全体系的整体架构? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/17 安全架构:如何理解 Spring 安全体系的整体架构?.md)

全面梳理基于 Spring Boot 的 Web 应用程序开发技术组件,其中包括配置体系、数据访问、Web 服务、消息通信、系统安全、系统监控、系统测试等专项主题。这些技术组件涵盖了 Java EE 应用程序开发涉及的方方面面,具有广泛的应用场景。

Spring Boot 可以帮助我们构建从 Web 服务层到数据访问层的全栈式响应式编程技术,从而确保系统的各个环节都具备即时响应性。

回调

2025 年 3 月 18 日

回调机制详解-CSDN博客

七牛云

2025 年 4 月 26 日

Java21 + SpringBoot3集成七牛云对象存储OSS,实现文件上传前言 实现步骤 引入maven依赖 修改配 - 掘金 (juejin.cn)

导入 Maven 依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependencies>
<!-- 七牛云SDK -->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.13.0, 7.13.99]</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<optional>true</optional>
</dependency>
</dependencies>

新增配置信息。

1
2
3
4
5
6
7
8
9
fast-alden:
file:
oss:
qiniu:
access-key: ****************************** # 请从七牛云工作台-个人中心-密钥管理获取
secret-key: ******************************-KL01 # 请从七牛云工作台-个人中心-密钥管理获取
bucket: memory-blog # 七牛云存储空间名称
directory: / # 自定义存储空间内目录
domain: blog.memory-life.icu # 存储空间自定义域名,请提前在存储空间中进行配置

image-20250426182122767

创建七牛云服务配置类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* 七牛云OSS相关配置
*/
@Configuration
@ConfigurationProperties(prefix = "fast-alden.file.oss.qiniu")
@Getter
@Setter
public class QiniuConfig {
/**
* AC
*/
private String accessKey;
/**
* SC
*/
private String secretKey;
/**
* 存储空间
*/
private String bucket;
/**
* 上传目录
*/
private String directory;
/**
* 访问域名
*/
private String domain;
}

编写文件操作服务接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 文件操作服务
*/
public interface FileService {
/**
* 文件上传
*
* @param file 待上传的文件
* @return 访问该文件的url
* @throws IOException
*/
String upload(MultipartFile file) throws IOException;
}

实现文件操作服务类接口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* 七牛云对象存储文件服务
*/
@Service("fileService")
public class QiniuFileServiceImpl implements FileService {
private final QiniuConfig qiniuConfig;

public QiniuFileServiceImpl(QiniuConfig qiniuConfig) {
this.qiniuConfig = qiniuConfig;
}

@Override
public String upload(MultipartFile file) throws IOException {
if (file.isEmpty()) {
throw new RuntimeException("文件是空的");
}
// 创建上传token
Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey());
String upToken = auth.uploadToken(qiniuConfig.getBucket());

// 设置上传配置,Region要与存储空间所属的存储区域保持一致
Configuration cfg = new Configuration(Region.huadongZheJiang2());

// 创建上传管理器
UploadManager uploadManager = new UploadManager(cfg);

String originalFilename = file.getOriginalFilename();
// 构造文件目录和文件名
assert originalFilename != null;
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileKey = qiniuConfig.getDirectory() + UUID.randomUUID() + suffix;

// 上传文件
Response response = uploadManager.put(file.getInputStream(), fileKey, upToken, null, null);

// 返回文件url
return qiniuConfig.getDomain() + fileKey;
}
}

上述代码中有一行用到了Region.huadongZheJiang2(),此处要与自己的存储空间所属的存储区域保持一致,本文中所使用的存储空间属于华东-浙江2区域。

创建控制器类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/file")
public class FileController {
private final FileService fileService;

public FileController(FileService fileService) {
this.fileService = fileService;
}

@PostMapping("/upload")
public String upload(MultipartFile multipartFile) throws IOException {
return fileService.upload(multipartFile);
}
}

Postman 测试下。

image-20250426190924217

请求类型要用 POST 啊,要不返回结果就是这样,看半天没看出问题,到后台找日志才明白。

1
2
3
4
5
6
{
"timestamp": "2025-04-26T11:11:10.502+00:00",
"status": 400,
"error": "Bad Request",
"path": "/admin/login"
}
1
2
3
4
5
8080-exec-7] com.macro.mall.common.log.WebLogAspect   : {"description":"登录以后返回token","username":"admin","startTime":1745665865918,"spendTime":101,"basePath":"http://localhost:8080","uri":"/admin/login","url":"http://localhost:8080/admin/login","method":"POST","ip":"192.168.1.11","parameter":{"username":"admin","password":"macro123"},"result":{"code":200,"message":"操作成功","data":{"tokenHead":"Bearer ","token":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImNyZWF0ZWQiOjE3NDU2NjU4NjYwMTAsImV4cCI6MTc0NjI3MDY2Nn0.X62Muzq1P4MN9I2CLIrBEaHPMN2MP_4_EmZ9q0LgJSvFXnokpW_zHpwsvbuOCPovWyvbIhZwcAVxBiDaJUOGeA"}}}
2025-04-26 19:11:10.496 INFO 9940 --- [nio-8080-exec-3] c.m.m.s.c.JwtAuthenticationTokenFilter : checking username:admin
2025-04-26 19:11:10.499 INFO 9940 --- [nio-8080-exec-3] c.m.m.s.c.JwtAuthenticationTokenFilter : authenticated user:admin
2025-04-26 19:11:10.501 WARN 9940 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "login"]
2025-04-26 19:11:10.502 DEBUG 9940 --- [nio-8080-exec-3] c.m.m.s.component.DynamicSecurityFilter : Authorized public object filter invocation [GET /error]

显然这次成功了,顺利。

image-20250426191234129

1
2
3
4
5
6
{
"timestamp": "2025-04-26T11:14:42.287+00:00",
"status": 404,
"error": "Not Found",
"path": "/file/upload"
}

一直显示未找到服务,原来是代码修改完毕后没重启服务。

image-20250426192513683

1
2
3
2025-04-26 19:18:39.666 DEBUG 1932 --- [nio-8080-exec-5] c.m.m.s.component.DynamicSecurityFilter  : Authorized public object filter invocation [POST /file/upload]
2025-04-26 19:18:39.667 DEBUG 1932 --- [nio-8080-exec-5] c.m.m.s.component.DynamicSecurityFilter : Authorized public object filter invocation [POST /file/upload]
2025-04-26 19:18:46.330 INFO 1932 --- [nio-8080-exec-5] com.macro.mall.common.log.WebLogAspect : {"username":"admin","startTime":1745666319732,"spendTime":6596,"basePath":"http://localhost:8080","uri":"/file/upload","url":"http://localhost:8080/file/upload","method":"POST","ip":"192.168.1.11","result":"blog.memory-life.icu/f585f679-78ae-498d-bbe2-290ffd0f99c5.jpg"}

上传至七牛云成功,不过需要注意下配置上传目录。

1
2
3
4
5
6
7
8
9
fast-alden:
file:
oss:
qiniu:
access-key: ****************************** # 请从七牛云工作台-个人中心-密钥管理获取
secret-key: ******************************-KL01 # 请从七牛云工作台-个人中心-密钥管理获取
bucket: memory-blog # 七牛云存储空间名称
directory: mall/ # 自定义存储空间内目录
domain: blog.memory-life.icu/ # 存储空间自定义域名,请提前在存储空间中进行配置

前台。

组件 | Element

element ui文件或者图片上传(包括自定义上传)_element 实现icon上传按钮-CSDN博客

累了,明天再搞。

学编程这么多年,竟然连前端页面上传图片调用后端接口,这么简单的功能都做不了。

要说这前端就是费劲,官网文档写得跟几把一样。

ElementUI实现图片上传的功能🌈~(已完成✔) - Mahmud(مەھمۇد) - 博客园 (cnblogs.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
<el-form-item label="商品相册:"
><el-upload
class="upload-demo"
action="http://localhost:8080/file/upload"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList"
list-type="picture"
:headers="headersObj"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</el-form-item>
1
2
3
4
5
// 图片上传组件添加Authorization请求头对象,
// 每一次方式请求都有了token请求头,从session里拿到
headersObj: {
Authorization: window.sessionStorage.getItem("token")
}

标记了后台接口地址,这次上传顺利了,不过有个 Token 问题需要解决。

image-20250426215319399

1
2
3
4
5
{
"code": 401,
"message": "暂未登录或token已经过期",
"data": "Full authentication is required to access this resource"
}

后台拿到的 Token 总是 null,为什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 从token中获取JWT中的负载
*/
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
LOGGER.info("JWT格式验证失败:{}", token);
}
return claims;
}

element-ui实现图片上传功能(前台部分)_elementui上传图片-CSDN博客

看到 request.js 里写明确了 Token 获取以及设置方法,每个请求都会携带 Token:

1
2
3
4
5
6
7
8
9
10
11
// request拦截器
service.interceptors.request.use(config => {
if (store.getters.token) {
config.headers['Authorization'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
return config
}, error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
})

auth.js 里明确了方法实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
const TokenKey = 'loginToken'

export function getToken() {
return Cookies.get(TokenKey)
}

export function setToken(token) {
return Cookies.set(TokenKey, token)
}

export function removeToken() {
return Cookies.remove(TokenKey)
}

el-upload 组件内如此设置请求头:

1
2
3
4
5
6
7
8
9
10
11
<el-upload
class="upload-demo"
action="http://localhost:8080/file/upload"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList"
list-type="picture"
:headers="headers"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
1
2
3
4
5
6
7
import { getToken } from "@/utils/auth";

// 图片上传组件添加Authorization请求头对象,
// 每一次方式请求都有了token请求头,从session里拿到
headers: {
Authorization: getToken() // 从 localStorage 获取 token
}

image-20250426221916269

直接调用就行,不需要多于拼接,要不然会遇到如上问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 从token中获取JWT中的负载
*/
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
LOGGER.info("JWT格式验证失败:{}", token);
}
return claims;
}

后端过滤器顺利校验通过,再检查下图片上传效果。

已经能够请求到后台服务接口了,不过接收到的图片参数为 null。

1
2
3
4
@PostMapping("/upload")
public String upload(MultipartFile multipartFile) throws IOException {
return fileService.upload(multipartFile);
}

在 Element UI 的 <el-upload> 组件中,默认会以 multipart/form-data 格式上传文件(即二进制流方式),这与 Spring Boot 后端接口 MultipartFile multipartFile 参数是完全匹配的,不需要额外设置请求类型。

字段名需与后端参数名一致,如下:

1
2
3
4
5
6
7
8
9
10
11
12
<el-upload
class="upload-demo"
action="http://localhost:8080/file/upload"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList"
list-type="picture"
:headers="headers"
name="multipartFile"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>

特么的后端响应成功。

image-20250426222734662

1
2025-04-26 22:29:32.452  INFO 9200 --- [nio-8080-exec-1] com.macro.mall.common.log.WebLogAspect   : {"username":"admin","startTime":1745677633269,"spendTime":139182,"basePath":"http://localhost:8080","uri":"/file/upload","url":"http://localhost:8080/file/upload","method":"POST","ip":"192.168.1.11","result":"blog.memory-life.icu/mall/35b1b8bb-fc6c-401e-87a1-d95eb0c6c3a8.jpeg"}

这个响应同下午使用 Postman 测试结果完全一致。

删除已上传的图片,上传前预览效果,待完善。目前还没有完成上传图片后插入数据库。

这个流程倒是合理,但目前后端商品管理非我实现,改动起来比较困难,暂不做改动,继续修改其他问题。

sequenceDiagram
    participant 前端
    participant 后端
    前端->>后端: 1. 先创建商品(获取商品ID)
    后端-->>前端: 返回商品ID
    前端->>后端: 2. 上传图片(携带商品ID)
    后端->>数据库: 3. 保存图片并关联商品ID

图片上传成功或失败后的反馈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<el-upload
class="upload-demo"
action="http://localhost:8080/file/upload"
:on-preview="handlePreview"
:on-remove="handleRemove"
:file-list="fileList"
list-type="picture"
:headers="headers"
name="multipartFile"
:on-success="handleSuccess"
:on-error="handleError"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
1
2
3
4
5
6
7
8
9
10
11
// 上传成功回调
handleSuccess(response, file, fileList) {
console.log("上传成功", response);
this.$message.success("上传成功");
},

// 上传失败回调
handleError(err, file, fileList) {
console.error("上传失败", err);
this.$message.error("上传失败");
},

后端统一返回结果,便于解析。

1
2
3
4
5
@PostMapping("/upload")
public CommonResult<String> upload(MultipartFile multipartFile) throws IOException {
String upload = fileService.upload(multipartFile);
return CommonResult.success(upload);
}

ElementUI实现图片上传的功能🌈~(已完成✔) - Mahmud(مەھمۇد) - 博客园 (cnblogs.com)

明天再看吧,问题全部在前端,无聊。

操作系统

网络编程

2025 年 4 月 9 日

(二)Java网络编程之爆肝HTTP、HTTPS、TLS协议及对称与非对称加密原理!作为一名程序员,尤其是作为一名后端J - 掘金 (juejin.cn)

(三)Nginx一网打尽:动静分离、压缩、缓存、黑白名单、跨域、高可用、性能优化…想要的这都有!不论前端后端,如果你 - 掘金 (juejin.cn)

(四)网络编程之请求分发篇:负载均衡静态调度算法、平滑轮询加权、一致性哈希、最小活跃数算法实践!现如今所有的技术栈中,只 - 掘金 (juejin.cn)

(五)网络编程之流量接入层设计:基于性能怪兽从零构建日均亿级吞吐量的网关架构!如果你是前端,看完本文会让你认识到后端世界 - 掘金 (juejin.cn)

(六)网络编程之化身一个请求感受浏览器输入URL后奇妙的网络之旅!学技术太枯燥?本文带你如同看小说一样,化身一个网络请求 - 掘金 (juejin.cn)

(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!如若你对于面试要求中的“ - 掘金 (juejin.cn)

1
BIO就是Java的传统IO模型,与其相关的实现都位于java.io包下,其通信原理是客户端、服务端之间通过Socket套接字建立管道连接,然后从管道中获取对应的输入/输出流,最后利用输入/输出流对象实现发送/接收信息,案例如下:
1
2
3
4
5
观察如上结果,其实执行过程原理很简单:

①服务端启动后会执行accept()方法等待客户端连接到来。
②客户端启动后会通过IP及端口,与服务端通过Socket套接字建立连接。
③然后双方各自从套接字中获取输入/输出流,并通过流对象发送/接收消息。
1
2
3
4
5
①先创建对应类型的缓冲区
②通过put这类方法往缓冲区中写入数据
③调用flip()方法将缓冲区转换为读模式
④通过get这类方法从缓冲区中读取数据
⑤调用clear()、compact()方法清空缓冲区数据
1
2
3
4
5
6
7
8
9
在前面咱们详细叙述了Linux五种IO模型以及Java所提供的三种IO模型支持,对于Java-IO这块内容,阻塞、非阻塞、同步、异步等这些区别就不再聊了,认真看下来本文后自然会有答案,最后是需要重点表明一点:NIO、AIO都是单线程处理多个连接,但并不代表着说永远只有一条线程对网络连接进行处理,这里所谓的单线程处理多个连接,其实本质上是指单条线程接收客户端连接。
   从上述这段话中应该可以得知:Java-NIO、AIO本质上对于客户端的网络连接照样会启动多条线程处理,只不过与BIO的区别如下:

Java-BIO:当客户端到来连接请求时,就会分配一条线程处理。
Java-NIO:客户端的连接请求会先注册到选择器上,选择器轮询到有事件触发时,才会分配一条线程处理。
Java-AIO:客户端的连接到来后同样会先注册到选择器上,但客户端的I/O请求会先交由OS处理,当内核将数据拷贝完成后才会分配一条线程处理。

Java-BIO、NIO、AIO本质上都会为一个请求分配一条线程处理,但核心区别在于启动的时机不同,当然,如果非要用一条线程处理多个客户端连接的所有工作也并非不行,但这样会造成系统极为低效,例如1000个文件下载的请求到来,全都交由选择器上监听客户端连接的那条线程处理,其效率诸位可想而知。
最后多叨叨一句,其实Java-NIO、AIO方面的设计,无论是从使用简洁度而言,还是从源码的可观性而言,其实都并不算理想,如若有小伙伴阅读过JUC包的源码,再回来对比NIO包的源码,两者差别甚大,所以本质上在之后的过程中,如若要用到Java-NIO、AIO方面的技术,一般都会采用Netty框架实现,Netty这个网络通信框架则对nio包提供的原生IO-API进一步做了封装,也解决了NIO包下原生API存在的诸多问题,因此在后续的文章中也会重点分析Netty这个框架。

(八)Java网络编程之IO模型篇-内核Select、Poll、Epoll多路复用函数源码深度历险!相信你一定听说过se - 掘金 (juejin.cn)

(九)Java网络编程无冕之王-这回把大名鼎鼎的Netty框架一网打尽!现如今分布式/微服务大行其道,而其根基在于网络编 - 掘金 (juejin.cn)

(十二)探索高性能通信与RPC框架基石:Json、ProtoBuf、Hessian序列化详解如今这个分布式风靡的时代,网 - 掘金 (juejin.cn)

SpringCloud

Elasticsearch

补全计划

广度

2025 年 4 月 16 日

[Java IO流详解:字节流、字符流与缓冲流的使用-CSDN博客](https://blog.csdn.net/Lee0620/article/details/121261869?ops_request_misc=%7B%22request%5Fid%22%3A%22e0787ebc62c941e678443b45683c74ab%22%2C%22scm%22%3A%2220140713.130102334..%22%7D&request_id=e0787ebc62c941e678443b45683c74ab&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-121261869-null-null.142^v102^control&utm_term=Java IO&spm=1018.2226.3001.4187)

[【Java】I/O 操作详解_java io操作-CSDN博客](https://blog.csdn.net/island1314/article/details/142895276?ops_request_misc=&request_id=&biz_id=102&utm_term=Java IO&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-2-142895276.142^v102^control&spm=1018.2226.3001.4187)

[Java多线程(超详细!)_java 多线程-CSDN博客](https://blog.csdn.net/qq_44715943/article/details/116714584?ops_request_misc=%7B%22request%5Fid%22%3A%2221af9c03f92010ed8e3c42eb929a6ed5%22%2C%22scm%22%3A%2220140713.130102334..%22%7D&request_id=21af9c03f92010ed8e3c42eb929a6ed5&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-116714584-null-null.142^v102^control&utm_term=Java 多线程&spm=1018.2226.3001.4187)

Java集合框架详解-CSDN博客

Java反射机制详解及应用-CSDN博客

Java 中的泛型(两万字超全详解)_java 泛型-CSDN博客

2025 年 4 月 17 日

Spring & SpringBoot(详解)-CSDN博客

mybatis看这一篇就够了,简单全面一发入魂_mybatis一发入魂-CSDN博客

Mybatis Plus 看这篇就够了,通俗易懂,一发入魂_com.baomidou.mybatisplus.core.mybatismapperannotat-CSDN博客

Mybatis Plus 看这篇就够了,通俗易懂,一发入魂_com.baomidou.mybatisplus.core.mybatismapperannotat-CSDN博客

RabbitMQ学习笔记(持续更新ing)_setprefetchcount-CSDN博客

[00 开篇词 从零开始:为什么要学习 Spring Boot? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/00 开篇词 从零开始:为什么要学习 Spring Boot?.md)

2025 年 4 月 18 日

[01 家族生态:如何正确理解 Spring 家族的技术体系? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/01 家族生态:如何正确理解 Spring 家族的技术体系?.md)

[02 案例驱动:如何剖析一个 Spring Web 应用程序? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/02 案例驱动:如何剖析一个 Spring Web 应用程序?.md)

[03 多维配置:如何使用 Spring Boot 中的配置体系? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/03 多维配置:如何使用 Spring Boot 中的配置体系?.md)

[04 定制配置:如何创建和管理自定义的配置信息? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/04 定制配置:如何创建和管理自定义的配置信息?.md)

[05 自动配置:如何正确理解 Spring Boot 自动配置实现原理? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/05 自动配置:如何正确理解 Spring Boot 自动配置实现原理?.md)

[06 基础规范:如何理解 JDBC 关系型数据库访问规范? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/06 基础规范:如何理解 JDBC 关系型数据库访问规范?.md)

[07 数据访问:如何使用 JdbcTemplate 访问关系型数据库? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/07 数据访问:如何使用 JdbcTemplate 访问关系型数据库?.md)

[08 数据访问:如何剖析 JdbcTemplate 数据访问实现原理? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/08 数据访问:如何剖析 JdbcTemplate 数据访问实现原理?.md)

[10 ORM 集成:如何使用 Spring Data JPA 访问关系型数据库? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/10 ORM 集成:如何使用 Spring Data JPA 访问关系型数据库?.md)

[17 安全架构:如何理解 Spring 安全体系的整体架构? (lianglianglee.com)](https://learn.lianglianglee.com/专栏/Spring Boot 实战开发/17 安全架构:如何理解 Spring 安全体系的整体架构?.md)

总结

2025 年 1 月 15 日

入职一个一个月以来,每天在整理工作笔记之余,也会抽时间发散思维,记录灵感,去探索一些新的东西。

这个栏目开设在去年夏天,原本计划用来记录拉取学习并系统梳理的新项目,有效扩充技术广度。

这样的想法和行动于我而言很有吸引力,不过在后半年由于就业环境的冲击以及秋招带来的无形压力,国庆以后便被迫短暂搁置了。

从今天开始,我会尝试在这个栏目下持续记录自己的思考过程。

我的编程之旅,或许这个栏目才是其真正的精神续作吧。

最近也会有很多新的想法和开发思路,所有笔记逐步从泰豪实习工作栏目下迁移到这里,并稍作整理了一番。


卓越之旅:在优秀案例中精进,编织技术梦想
https://test.atomgit.net/blog/2024/07/12/卓越之旅:在优秀案例中精进,编织技术梦想/
作者
Memory
发布于
2024年7月12日
更新于
2025年4月30日
许可协议