feat: 初始化 SpringBoot + 前端全栈博客项目

This commit is contained in:
admin
2026-10-22 06:29:05 +00:00
commit cb08080ca7
5 changed files with 180 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
FROM maven:3.9-eclipse-temurin-17 AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.3</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>my-blog-backend</artifactId>
<version>1.0.0</version>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,41 @@
package com.example.blog;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@SpringBootApplication
@RestController
@CrossOrigin(origins = "*")
@RequestMapping("/api/posts")
public class BlogApplication {
private static final List<Map<String, String>> posts = new ArrayList<>();
static {
Map<String, String> p1 = new HashMap<>();
p1.put("id", "1");
p1.put("title", "Hello World! 我的第一篇云端博客");
p1.put("content", "这是运行在 Google Cloud 台湾节点上的 Spring Boot 3.x 容器!");
p1.put("author", "旺总");
p1.put("date", "2026-10-22");
posts.add(p1);
}
@GetMapping
public List<Map<String, String>> getPosts() {
return posts;
}
@PostMapping
public Map<String, String> addPost(@RequestBody Map<String, String> post) {
post.put("id", String.valueOf(posts.size() + 1));
posts.add(0, post);
return post;
}
public static void main(String[] args) {
SpringApplication.run(BlogApplication.class, args);
}
}
+17
View File
@@ -0,0 +1,17 @@
version: '3.8'
services:
backend:
build: ./backend
container_name: blog-backend
restart: always
ports:
- "8089:8080"
frontend:
image: nginx:alpine
container_name: blog-frontend
restart: always
ports:
- "8088:80"
volumes:
- ./frontend:/usr/share/nginx/html
+80
View File
@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>我的个人技术博客</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, sans-serif; background: #f8fafc; color: #1e293b; padding: 40px 20px; }
.container { max-width: 800px; margin: 0 auto; }
header { margin-bottom: 30px; text-align: center; }
h1 { font-size: 28px; color: #0f172a; margin-bottom: 8px; }
p.desc { color: #64748b; font-size: 14px; }
.form-box { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); margin-bottom: 30px; }
input, textarea { width: 100%; padding: 10px; margin-bottom: 12px; border: 1px solid #cbd5e1; border-radius: 6px; font-size: 14px; }
button { background: #3b82f6; color: white; border: none; padding: 10px 20px; border-radius: 6px; cursor: pointer; font-weight: bold; }
button:hover { background: #2563eb; }
.post-card { background: white; padding: 24px; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05); margin-bottom: 20px; transition: transform 0.2s; }
.post-card:hover { transform: translateY(-2px); }
.post-title { font-size: 20px; font-weight: bold; color: #1e293b; margin-bottom: 8px; }
.post-meta { font-size: 12px; color: #94a3b8; margin-bottom: 14px; }
.post-content { color: #334155; line-height: 1.6; }
</style>
</head>
<body>
<div class="container">
<header>
<h1>⚡ 旺总的技术全栈博客</h1>
<p class="desc">基于 Spring Boot 3 + Vue 架构 · Docker 容器驱动 · CI/CD 自动部署</p>
</header>
<div class="form-box">
<input type="text" id="title" placeholder="文章标题...">
<input type="text" id="author" placeholder="作者名 (默认: 旺总)" value="旺总">
<textarea id="content" rows="3" placeholder="写点什么..."></textarea>
<button onclick="publish()">发布新文章</button>
</div>
<div id="posts">加载中...</div>
</div>
<script>
const API_URL = '/api/posts';
async function loadPosts() {
try {
const res = await fetch(API_URL);
const data = await res.json();
document.getElementById('posts').innerHTML = data.map(p => `
<div class="post-card">
<div class="post-title">${p.title}</div>
<div class="post-meta">👤 ${p.author || '旺总'} · 📅 ${p.date || '刚刚'}</div>
<div class="post-content">${p.content}</div>
</div>
`).join('');
} catch (e) {
document.getElementById('posts').innerHTML = '<p style="color:red">无法连接后端 API</p>';
}
}
async function publish() {
const title = document.getElementById('title').value;
const author = document.getElementById('author').value;
const content = document.getElementById('content').value;
if (!title || !content) return alert('标题和内容不能为空!');
await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, author, content, date: new Date().toLocaleDateString() })
});
document.getElementById('title').value = '';
document.getElementById('content').value = '';
loadPosts();
}
loadPosts();
</script>
</body>
</html>