# portfolio **Repository Path**: frailty/portfolio ## Basic Information - **Project Name**: portfolio - **Description**: 作品集集中展示与管理 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-07 - **Last Updated**: 2026-07-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 作品集展示与管理平台 个人作品集展示与管理平台,用于集中展示代码/开发项目,支持项目管理后台。 ## 功能特性 - **项目展示** - 卡片式列表展示,支持封面图、标题、描述、技术栈 - **分类筛选** - 按分类过滤项目 - **详情页** - Markdown 内容渲染,代码语法高亮 - **后台管理** - 项目增删改查,图片上传 - **权限认证** - Sa-Token JWT 认证,支持 30 天 Token 有效期 - **一键部署** - 前后端打包为单一 JAR 文件 ## 技术栈 ### 后端 | 技术 | 说明 | |------|------| | Java 17 | 运行环境 | | Solon 3.9.7 | 轻量级 Java 框架 | | Sa-Token 1.44.0 | 身份认证 | | MyBatis-Flex 1.11.3 | ORM 框架 | | SQLite | 嵌入式数据库 | ### 前端 | 技术 | 说明 | |------|------| | Vue 3.5 + TypeScript | 核心框架 | | Vite 8 | 构建工具 | | Tailwind CSS 4 | 样式框架 | | Pinia | 状态管理 | | Vue Router | 路由管理 | | marked + highlight.js | Markdown 渲染与代码高亮 | ## 项目结构 ``` portfolio/ ├── build.bat # Windows 一键打包脚本 ├── build.sh # Linux/macOS 一键打包脚本 ├── LICENSE ├── README.md │ ├── portfolio-client/ # 前端项目 │ ├── src/ │ │ ├── api/ # API 请求封装 │ │ ├── assets/ # 静态资源 │ │ ├── components/ # 公共组件 │ │ │ ├── Navbar.vue # 导航栏 │ │ │ └── ProjectCard.vue # 项目卡片 │ │ ├── router/ # 路由配置 │ │ ├── stores/ # Pinia 状态 │ │ ├── views/ # 页面视图 │ │ │ ├── Home.vue # 首页(项目列表) │ │ │ ├── ProjectDetail.vue # 项目详情 │ │ │ └── admin/ # 管理后台 │ │ │ ├── Dashboard.vue │ │ │ ├── Login.vue │ │ │ ├── ProjectList.vue │ │ │ └── ProjectEdit.vue │ │ ├── App.vue │ │ ├── main.ts │ │ └── style.css │ ├── public/ # 公共资源 │ ├── index.html │ ├── package.json │ └── vite.config.ts │ └── portfolio-server/ # 后端项目 ├── portfolio-app/ # 主应用模块 │ ├── src/main/java/com/portfolio/ │ │ ├── Main.java # 启动类 │ │ ├── config/ # 配置类 │ │ │ ├── AppFilter.java │ │ │ ├── AppRouterInterceptor.java │ │ │ ├── CrossOriginConfig.java │ │ │ ├── DatabaseInitConfig.java │ │ │ ├── MybatisFlexConfig.java │ │ │ └── SaTokenConfig.java │ │ └── controller/ # 控制器 │ │ ├── ProjectController.java │ │ ├── SpaController.java │ │ └── UploadController.java │ └── src/main/resources/ │ ├── app.yml # 主配置 │ ├── app-dev.yml # 开发环境配置 │ ├── app-prod.yml # 生产环境配置 │ └── schema.sql # 数据库表结构 │ ├── portfolio-auth/ # 认证模块 │ └── src/main/java/com/portfolio/ │ ├── config/SecurityConfig.java │ ├── controller/AuthController.java │ ├── service/ │ └── utils/StpInterfaceImpl.java │ ├── portfolio-common/ # 公共模块 │ └── src/main/java/com/portfolio/common/ │ ├── domain/entity/ # 实体类 │ ├── domain/mapper/ # Mapper 接口 │ ├── domain/vo/ # 视图对象 │ ├── service/ # 服务层 │ └── utils/ # 工具类 │ ├── portfolio.db # SQLite 数据库文件 └── uploads/ # 上传文件存储目录 ``` ## 快速开始 ### 环境要求 - **Java**: 17+ - **Node.js**: 18+ - **Maven**: 3.8+ ### 一键打包(推荐) ```bash # Windows build.bat # Linux / macOS chmod +x build.sh ./build.sh ``` 打包产物:`portfolio-server/portfolio-app/target/portfolio-app.jar` ### 手动构建 #### 1. 前端开发 ```bash cd portfolio-client pnpm install pnpm dev ``` 前端启动在 http://localhost:5173,自动代理 API 请求到后端。 #### 2. 后端运行 ```bash cd portfolio-server mvn package -DskipTests java -jar portfolio-app/target/portfolio-app.jar ``` 后端启动在 http://localhost:8080 #### 3. 前端生产构建 ```bash cd portfolio-client pnpm build ``` 构建产物自动输出到 `portfolio-server/portfolio-app/src/main/resources/static/` ## 部署文档 ### 服务器部署 #### 1. 上传 JAR 文件 将 `portfolio-app.jar` 上传到服务器: ```bash scp portfolio-app/target/portfolio-app.jar user@server:/opt/portfolio/ ``` #### 2. 创建启动脚本 创建 `start.sh`: ```bash #!/bin/bash JAR_FILE="/opt/portfolio/portfolio-app.jar" PID_FILE="/opt/portfolio/app.pid" # 停止旧进程 if [ -f $PID_FILE ]; then kill $(cat $PID_FILE) 2>/dev/null fi # 启动应用 nohup java -jar $JAR_FILE --server.port=8080 > app.log 2>&1 & echo $! > $PID_FILE echo "Portfolio started on http://localhost:8080" ``` #### 3. 配置反向代理(Nginx) ```nginx server { listen 80; server_name your-domain.com; # 前端静态资源 location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 上传文件访问 location /uploads/ { alias /opt/portfolio/uploads/; expires 7d; add_header Cache-Control "public, immutable"; } # API 请求 location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` #### 4. 配置 HTTPS(可选) 使用 Let's Encrypt 免费证书: ```bash certbot --nginx -d your-domain.com ``` #### 5. 设置开机自启(systemd) 创建 `/etc/systemd/system/portfolio.service`: ```ini [Unit] Description=Portfolio Application After=network.target [Service] Type=simple User=your-user WorkingDirectory=/opt/portfolio ExecStart=/usr/bin/java -jar /opt/portfolio/portfolio-app.jar Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target ``` 启用服务: ```bash sudo systemctl daemon-reload sudo systemctl enable portfolio sudo systemctl start portfolio ``` ### 环境变量配置 可通过环境变量覆盖默认配置: | 变量名 | 说明 | 默认值 | |--------|------|--------| | `server.port` | 服务端口 | 8080 | | `sa-token.timeout` | Token 有效期(秒) | 2592000(30天) | | `sa-token.is-concurrent` | 是否允许多端登录 | true | | `snowflake.worker` | 雪花算法 Worker ID | 1 | | `snowflake.datacenter` | 雪花算法 Datacenter ID | 1 | 示例: ```bash java -jar portfolio-app.jar \ --server.port=9000 \ --sa-token.timeout=604800 \ --snowflake.worker=2 ``` ## 默认账号 | 用户名 | 密码 | |--------|------| | admin | admin123 | > ⚠️ 建议首次登录后修改密码 ## API 接口 ### 认证接口 | 方法 | 路径 | 说明 | 认证 | |------|------|------|------| | POST | `/auth/login-pwd` | 密码登录 | 否 | 请求体: ```json { "username": "admin", "password": "admin123" } ``` ### 公开接口 | 方法 | 路径 | 说明 | 认证 | |------|------|------|------| | GET | `/project/list` | 项目列表(支持 `?category=` 筛选) | 否 | | GET | `/project/{id}` | 项目详情 | 否 | ### 管理接口 | 方法 | 路径 | 说明 | 认证 | |------|------|------|------| | GET | `/project/admin/page` | 分页查询(支持 `?page=` `?size=`) | 是 | | GET | `/project/admin/{id}` | 获取单个项目 | 是 | | POST | `/project/admin` | 新增项目 | 是 | | PUT | `/project/admin` | 更新项目 | 是 | | DELETE | `/project/admin/{id}` | 删除项目 | 是 | | POST | `/upload/image` | 上传图片(返回 URL) | 是 | ### 上传接口 | 方法 | 路径 | 说明 | |------|------|------| | POST | `/upload/image` | 上传图片,返回 `{ url: "/uploads/2025/01/xxx.png" }` | 上传图片后通过 `/uploads/xxx.png` 访问。 ## 数据库 使用 SQLite,无需额外安装。数据库文件:`portfolio-server/portfolio.db` ### 表结构 ```sql -- 账号表 CREATE TABLE account ( id INTEGER PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, role VARCHAR(20) DEFAULT 'admin', create_time BIGINT, update_time BIGINT ); -- 项目表 CREATE TABLE project ( id INTEGER PRIMARY KEY, title VARCHAR(200) NOT NULL, description VARCHAR(500), content TEXT, tech_stack VARCHAR(500), github_url VARCHAR(500), demo_url VARCHAR(500), cover_image VARCHAR(500), category VARCHAR(100), featured INT DEFAULT 0, sort_order INT DEFAULT 0, status INT DEFAULT 1, create_time BIGINT, update_time BIGINT ); ``` ## 许可证 MIT License