第1步
- 搞一个2核2G的服务器
我用学生300元的阿里云代金卷白嫖了一个2核2G的服务器
配置:2核2G
使用 CentOS Stream 10 64位 系统
- 咱们直接用
阿里云专属镜像源装Docker
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
| # 1. 安装必要的工具(Stream 10 最小化安装可能缺这些) dnf install -y yum-utils device-mapper-persistent-data lvm2
# 2. 添加阿里云的 Docker 镜像源(适配 CentOS Stream 10) yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 3. 由于是 Stream 10,需要把源里的 $releasever 改成 10(否则会报错找不到源) sed -i 's/$releasever/10/g' /etc/yum.repos.d/docker-ce.repo
# 4. 安装 Docker 核心(社区版) dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 5. 启动 Docker 并设置开机自启 systemctl start docker systemctl enable docker
# 6. 配置阿里云镜像加速器(让你拉镜像像坐火箭) mkdir -p /etc/docker tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://kzwy2ejs.mirror.aliyuncs.com"] } EOF systemctl daemon-reload systemctl restart docker
|
第2步
部署一个 Redis 7
AI 给的docker run -d --restart=always --name=my-redis -p 6379:6379 redis:7-alpine不能用
进入https://hub.docker.com/_/redis网址一探究竟
使用 docker pull redis:7.4.10-alpine
点击 “添加出方向规则”,按以下配置填写:
| 字段 |
填写内容 |
| 授权策略 |
允许 |
| 优先级 |
100 |
| 协议类型 |
自定义 TCP |
| 访问来源(本实例) |
留空或默认(表示从本机发起) |
| 访问目的 |
0.0.0.0/0(允许访问所有外网 IP) |
| 端口范围 |
1/65535(允许所有端口) |
| 描述 |
允许所有出站流量 |
一直不行,更改镜像源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| sudo mkdir -p /etc/docker # 创建 Docker 配置目录 # 配置镜像源 sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://docker.m.daocloud.io", "https://docker.xuanyuan.me", "https://dc.j8.work" ] } EOF
sudo systemctl daemon-reload # 重新加载 Docker 配置 sudo systemctl restart docker # 重启 Docker docker info | grep -A 5 "Registry Mirrors" # 检查镜像源
|
使用 docker pull redis:7-alpine 命令拉取镜像
执行 docker run -d --restart=always --name=my-redis -p 6379:6379 redis:7-alpine 命令启动 Redis 容器
docker ps 命令查看容器运行状态
docker exec -it my-redis redis-cli ping 如果返回 PONG,恭喜你,一个运行在容器里的 Redis 7 已经就绪!
第3步
docker exec -it my-redis redis-cli 进入 Redis 命令行
1 2 3 4
| SET user:1001 "zhangsan" # 设置键值对 GET user:1001 # 获取键对应的值 EXPIRE user:1001 60 # 设置键的过期时间 TTL user:1001 # 获取键的剩余过期时间
|
第4步
开发一个最小web应用
model
LogEntry.java
1 2 3 4 5 6 7 8 9
| @Data public class LogEntry { private String id; private String content; private LocalDateTime createTime; }
|
service
LogService.java
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
| @Service public class LogService {
@Autowired private StringRedisTemplate redisTemplate;
private static final String LOGS_KEY = "work_logs";
public Long getTodayCount() { String todayKey = "stats:" + LocalDate.now().toString(); return redisTemplate.opsForHyperLogLog().size(todayKey); }
public void saveLog(String content) { String id = UUID.randomUUID().toString(); String timestamp = LocalDateTime.now() .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); String logEntry = id + "|" + content + "|" + timestamp; redisTemplate.opsForList().leftPush(LOGS_KEY, logEntry); redisTemplate.expire(LOGS_KEY, 30, java.util.concurrent.TimeUnit.DAYS);
String todayKey = "stats:" + LocalDate.now().toString(); redisTemplate.opsForHyperLogLog().add(todayKey, id); redisTemplate.expire(todayKey, 30, TimeUnit.DAYS); }
public List<LogEntry> getRecentLogs(int limit) { List<String> rawList = redisTemplate.opsForList().range(LOGS_KEY, 0, limit - 1); List<LogEntry> result = new ArrayList<>(); if (rawList != null) { for (String raw : rawList) { String[] parts = raw.split("\\|", 3); if (parts.length == 3) { LogEntry entry = new LogEntry(); entry.setId(parts[0]); entry.setContent(parts[1]); entry.setCreateTime(LocalDateTime.parse(parts[2], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); result.add(entry); } } } return result; } }
|
controller
LogController.java
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
| @Controller public class LogController {
@Autowired private LogService logService;
@GetMapping("/logs") public String listLogs(Model model) { List<LogEntry> logs = logService.getRecentLogs(20); model.addAttribute("logs", logs); model.addAttribute("logs", logService.getRecentLogs(20)); model.addAttribute("todayCount", logService.getTodayCount()); return "logs"; }
@PostMapping("/logs/save") public String saveLog(@RequestParam("content") String content) { if (content != null && !content.trim().isEmpty()) { logService.saveLog(content.trim()); } return "redirect:/logs"; }
@GetMapping("/logs/export") public String exportLogs(Model model) { List<LogEntry> logs = logService.getRecentLogs(1000); model.addAttribute("logs", logs); return "export"; } }
|
templates
log.html
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
| <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>每日一记 - 工作日志</title> <style> body { font-family: Arial, sans-serif; max-width: 800px; margin: 40px auto; padding: 20px; } input[type="text"] { width: 70%; padding: 10px; } button { padding: 10px 20px; background: #4CAF50; color: white; border: none; cursor: pointer; } .log-item { border-bottom: 1px solid #eee; padding: 10px 0; } .time { color: #888; font-size: 0.9em; } </style> </head> <body> <h2>📊 今日已写 <span th:text="${todayCount}">0</span> 条</h2> <h1>📝 每日一记</h1>
<form action="/logs/save" method="post"> <input type="text" name="content" placeholder="今天做了什么?" required> <button type="submit">记录</button> </form>
<h2>📋 最近日志</h2> <div th:if="${logs != null && logs.size() > 0}"> <div class="log-item" th:each="log : ${logs}"> <div th:text="${log.content}">日志内容</div> <div class="time" th:text="${log.createTime}">时间</div> </div> </div> <p th:if="${logs == null || logs.size() == 0}" style="color: #888;">还没有日志,开始记录吧!</p> </body> </html>
|
第5步
开放6379端口
给Redis加密
docker exec -it my-redis redis-cli CONFIG SET requirepass "wgfun@Redis"
docker exec -it my-redis redis-cli -a "wgfun@Redis" ping 测试密码是否正确
安装JDK21
dnf install java-21-openjdk-devel -y
上传服务器
scp target/WorkLog-0.0.1-SNAPSHOT.jar root@115.28.210.219:/root/
启动SpringBoot项目
nohup java -jar /root/WorkLog-0.0.1-SNAPSHOT.jar > /root/app.log 2>&1 &
打开浏览器访问 http://115.28.210.219:8080/logs
第六步
思考