From fb616b724c60105903505fae13d655cd6cafe3f2 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 1 Jul 2025 11:57:25 +0800 Subject: [PATCH 1/4] feat: update config --- src/main/resources/application.properties | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index b59558ad2..50bce4d82 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,14 +1,23 @@ +# for mysql spring.datasource.url=${MYSQL_URL:jdbc:mysql://localhost:3306/openisle} spring.datasource.username=${MYSQL_USER:root} spring.datasource.password=${MYSQL_PASSWORD:password} spring.jpa.hibernate.ddl-auto=update +# for jwt +app.jwt.secret=${JWT_SECRET:ChangeThisSecretKeyForJwt} +app.jwt.expiration=${JWT_EXPIRATION:86400000} + +# ========= Optional ========= +# for resend email send service, you can improve your service by yourself resend.api.key=${RESEND_API_KEY:} +# your email services: ... + +# for tencent cloud image upload service, you can improve your service by yourself cos.base-url=${COS_BASE_URL:https://example.com} cos.secret-id=${COS_SECRET_ID:} cos.secret-key=${COS_SECRET_KEY:} cos.region=${COS_REGION:ap-guangzhou} cos.bucket-name=${COS_BUCKET_NAME:} +# your image upload services: ... -app.jwt.secret=${JWT_SECRET:ChangeThisSecretKeyForJwt} -app.jwt.expiration=${JWT_EXPIRATION:86400000} From 371fccfa535b94e67ceaee587b85d94d24b2eaf4 Mon Sep 17 00:00:00 2001 From: Tim <135014430+nagisa77@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:16:30 +0800 Subject: [PATCH 2/4] Fix CosImageUploader test to allow random filenames --- src/test/java/com/openisle/service/CosImageUploaderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/openisle/service/CosImageUploaderTest.java b/src/test/java/com/openisle/service/CosImageUploaderTest.java index cba91f9b2..395481648 100644 --- a/src/test/java/com/openisle/service/CosImageUploaderTest.java +++ b/src/test/java/com/openisle/service/CosImageUploaderTest.java @@ -16,6 +16,6 @@ class CosImageUploaderTest { String url = uploader.upload("data".getBytes(), "img.png").join(); verify(client).putObject(any(PutObjectRequest.class)); - assertEquals("http://cos.example.com/img.png", url); + assertTrue(url.matches("http://cos.example.com/[a-f0-9]{32}\\.png")); } } From 83c7659b88e65234c6847b27e249a47e33e1c906 Mon Sep 17 00:00:00 2001 From: Tim <135014430+nagisa77@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:20:15 +0800 Subject: [PATCH 3/4] fix integration test to include auth for admin endpoint --- .../openisle/integration/PublishModeIntegrationTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/openisle/integration/PublishModeIntegrationTest.java b/src/test/java/com/openisle/integration/PublishModeIntegrationTest.java index 34319a13f..270b4dde2 100644 --- a/src/test/java/com/openisle/integration/PublishModeIntegrationTest.java +++ b/src/test/java/com/openisle/integration/PublishModeIntegrationTest.java @@ -58,6 +58,12 @@ class PublishModeIntegrationTest { return rest.exchange(url, HttpMethod.POST, new HttpEntity<>(body, h), Map.class); } + private ResponseEntity get(String url, Class type, String token) { + HttpHeaders h = new HttpHeaders(); + if (token != null) h.setBearerAuth(token); + return rest.exchange(url, HttpMethod.GET, new HttpEntity<>(h), type); + } + @Test void postRequiresApproval() { String userToken = registerAndLogin("eve", "e@example.com"); @@ -74,7 +80,7 @@ class PublishModeIntegrationTest { List list = rest.getForObject("/api/posts", List.class); assertTrue(list.isEmpty(), "Post should not be listed before approval"); - List> pending = (List>) rest.getForObject("/api/admin/posts/pending", List.class); + List> pending = get("/api/admin/posts/pending", List.class, adminToken).getBody(); assertEquals(1, pending.size()); assertEquals(postId.intValue(), ((Number)pending.get(0).get("id")).intValue()); From bbae932434f828c8ddbf2188df2b2083ff5abe14 Mon Sep 17 00:00:00 2001 From: Tim <135014430+nagisa77@users.noreply.github.com> Date: Tue, 1 Jul 2025 13:21:24 +0800 Subject: [PATCH 4/4] docs: overhaul README --- README.md | 102 +++++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 51af298f8..2aa874958 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,75 @@ -# OpenIsle +

+ OpenIsle +

+ 一款简洁的社区后台示例 +

+ +

-OpenIsle 是一个基于 Spring Boot 的社区后端平台示例,提供注册、登录和基于 JWT 的认证功能,支持使用 MySQL 作为数据库,并通过可插拔的邮件发送组件发送注册邮件。 +## 💡 简介 -## 功能特性 +OpenIsle 基于 Spring Boot 构建,提供社区后台常见的注册、登录、文章与评论等能力,适合用作二次开发的起点,完全开源。 -- **注册/登录**:用户可以注册并登录,密码使用 BCrypt 加密保存。 -- **JWT 认证**:登录成功后返回 JWT,后续请求需在 `Authorization` 头中携带 `Bearer` token。 -- **邮件通知**:邮件发送通过 `EmailSender` 抽象实现,默认提供 `ResendEmailSender` 实现,可根据需要扩展。 -- **灵活配置**:数据库地址、账户密码、Resend API Key 等均可通过环境变量或 `application.properties` 配置。 -- **角色权限**:内置 `ADMIN` 和 `USER` 两种角色,`/api/admin/**` 接口仅管理员可访问。 -- **文章/评论**:支持发表文章并在文章下发布评论,评论可多级回复。 -- **图片上传**:图片上传通过 `ImageUploader` 抽象实现,示例中提供基于腾讯云 COS 的 `CosImageUploader`。 -- **用户头像**:`User` 模型新增 `avatar` 字段,可通过 `UserController` 上传并更新。 +## ⚡ 动机 -## 快速开始 +* 学习和实践现代 Java Web 开发 +* 快速搭建可扩展的社区或论坛应用 +* 提供清晰的代码示例和简单易懂的配置 -### 环境准备 +## ✨ 特性 + +* **用户体系**:注册、登录,密码使用 BCrypt 加密 +* **JWT 认证**:登录后获得 Token,接口通过 `Authorization: Bearer` 认证 +* **邮件通知**:抽象 `EmailSender`,默认实现基于 Resend +* **角色权限**:内置 `ADMIN` 与 `USER`,管理员接口以 `/api/admin/**` 提供 +* **文章与评论**:支持分类、评论及多级回复 +* **图片上传**:`ImageUploader` 可接入不同云存储,示例中实现了腾讯云 COS +* **灵活配置**:数据库、邮件、存储等信息均可通过环境变量或 `application.properties` 设置 +* **简洁架构**:业务、持久化与安全配置清晰分层,便于扩展 + +## 🚀 快速开始 + +### 环境要求 - Java 17+ - Maven 3+ - MySQL 数据库 -### 构建与运行 +### 运行 -1. 修改 `src/main/resources/application.properties`,或通过环境变量配置: - - `MYSQL_URL`:数据库连接 URL,例如 `jdbc:mysql://localhost:3306/openisle`。 - - `MYSQL_USER`:数据库用户名。 - - `MYSQL_PASSWORD`:数据库密码。 - - `RESEND_API_KEY`:Resend 邮件服务 API Key。 - - `COS_BASE_URL`:腾讯云 COS 访问域名,用于生成图片链接。 - - `JWT_SECRET`:JWT 签名密钥。 - - `JWT_EXPIRATION`:JWT 过期时间(毫秒)。 - -2. 构建并运行: +1. 按需修改 `src/main/resources/application.properties` 或设置以下环境变量: + - `MYSQL_URL`:数据库连接 URL,如 `jdbc:mysql://localhost:3306/openisle` + - `MYSQL_USER`:数据库用户名 + - `MYSQL_PASSWORD`:数据库密码 + - `RESEND_API_KEY`:Resend 邮件服务 API Key + - `COS_BASE_URL`:腾讯云 COS 访问域名 + - `JWT_SECRET`:JWT 签名密钥 + - `JWT_EXPIRATION`:JWT 过期时间(毫秒) +2. 启动项目: ```bash mvn spring-boot:run ``` -启动后访问: +启动后可访问主要接口: -- `POST /api/auth/register`:注册新用户,参数示例: - ```json - { - "username": "test", - "email": "test@example.com", - "password": "password" - } - ``` -- `POST /api/auth/login`:登录,返回 `{ "token": "..." }`。 -- 其他受保护接口示例:`GET /api/hello`,需在请求头加入 `Authorization: Bearer `。 -- 管理员接口示例:`GET /api/admin/hello`,需要具备 `ADMIN` 角色。 +- `POST /api/auth/register`:注册新用户 +- `POST /api/auth/login`:登录并获取 Token +- 需要认证的接口示例:`GET /api/hello`(需 `Authorization` 头) +- 管理员接口示例:`GET /api/admin/hello` -## 目录结构 +## 🏘️ 社区 -``` -src/main/java/com/openisle -├── OpenIsleApplication.java // 应用入口 -├── config // Spring Security 配置 -├── controller // 控制器 -├── model // 数据模型 -├── repository // 数据访问层 -└── service // 业务逻辑 -``` +欢迎通过 [Issues](https://github.com/nagisa77/OpenIsle/issues) 交流反馈。 -## 许可 +## 📄 授权 + +本项目以 MIT License 发布,欢迎自由使用与修改。 + +## 🙏 鸣谢 + +- [Spring Boot](https://spring.io/projects/spring-boot) +- [JJWT](https://github.com/jwtk/jjwt) +- [Lombok](https://github.com/projectlombok/lombok) +- 以及所有开源贡献者 -本项目使用 MIT License,可自由修改和分发。