初版代码提交
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<?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>fun.nojava</groupId>
|
||||
<artifactId>jog-system</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>jog-common</artifactId>
|
||||
<name>Jog Common</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations-jakarta</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package fun.nojava.common.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RateLimit {
|
||||
|
||||
String key() default "";
|
||||
|
||||
int maxCount() default 10;
|
||||
|
||||
int duration() default 60;
|
||||
|
||||
TimeUnit unit() default TimeUnit.SECONDS;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package fun.nojava.common.constant;
|
||||
|
||||
public final class BlogConstants {
|
||||
|
||||
private BlogConstants() {}
|
||||
|
||||
public static final int DEFAULT_PAGE_SIZE = 15;
|
||||
public static final int MAX_PAGE_SIZE = 100;
|
||||
public static final int ARTICLE_SUMMARY_LENGTH = 120;
|
||||
public static final int MAX_TAGS_PER_ARTICLE = 5;
|
||||
public static final int MAX_COMMENT_LEVEL = 3;
|
||||
public static final int IMAGE_MAX_SIZE_MB = 10;
|
||||
public static final long DRAFT_AUTO_SAVE_INTERVAL_SECONDS = 30L;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package fun.nojava.common.constant;
|
||||
|
||||
public final class SecurityConstants {
|
||||
|
||||
private SecurityConstants() {}
|
||||
|
||||
public static final String TOKEN_HEADER = "Authorization";
|
||||
public static final String TOKEN_PREFIX = "Bearer ";
|
||||
public static final String REFRESH_TOKEN_KEY = "refresh:token:";
|
||||
public static final String CAPTCHA_KEY = "captcha:";
|
||||
public static final String LOGIN_FAIL_COUNT_KEY = "login:fail:";
|
||||
public static final String IP_BLOCK_KEY = "ip:block:";
|
||||
public static final String REGISTER_LIMIT_KEY = "register:limit:";
|
||||
|
||||
public static final int MAX_LOGIN_FAIL_ADMIN = 5;
|
||||
public static final int MAX_LOGIN_FAIL_USER = 5;
|
||||
public static final int CAPTCHA_TRIGGER_COUNT = 3;
|
||||
public static final int ADMIN_LOCK_MINUTES = 30;
|
||||
public static final int USER_LOCK_MINUTES = 15;
|
||||
public static final int IP_BLOCK_THRESHOLD = 10;
|
||||
public static final int IP_BLOCK_MINUTES = 15;
|
||||
public static final int REGISTER_LIMIT_PER_HOUR = 3;
|
||||
|
||||
public static final int MAX_ACTIVE_SESSIONS = 3;
|
||||
|
||||
public static final long ACCESS_TOKEN_EXPIRE_SECONDS = 7200L;
|
||||
public static final long REFRESH_TOKEN_EXPIRE_SECONDS = 86400L;
|
||||
public static final long REFRESH_TOKEN_REMEMBER_EXPIRE_SECONDS = 1209600L;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package fun.nojava.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ArticleStatus {
|
||||
|
||||
DRAFT(0, "草稿"),
|
||||
PUBLISHED(1, "已发布"),
|
||||
RECYCLE(2, "回收站");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
public static ArticleStatus fromCode(int code) {
|
||||
for (ArticleStatus status : values()) {
|
||||
if (status.code == code) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid ArticleStatus code: " + code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package fun.nojava.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ArticleVisibility {
|
||||
|
||||
PUBLIC(0, "公开"),
|
||||
PRIVATE(1, "私密"),
|
||||
FOLLOWERS_ONLY(2, "仅粉丝可见");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
public static ArticleVisibility fromCode(int code) {
|
||||
for (ArticleVisibility v : values()) {
|
||||
if (v.code == code) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid ArticleVisibility code: " + code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package fun.nojava.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CommentStatus {
|
||||
|
||||
PENDING(0, "待审核"),
|
||||
APPROVED(1, "已通过"),
|
||||
BLOCKED(2, "已屏蔽"),
|
||||
DELETED(3, "已删除");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
public static CommentStatus fromCode(int code) {
|
||||
for (CommentStatus status : values()) {
|
||||
if (status.code == code) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid CommentStatus code: " + code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package fun.nojava.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum LoginType {
|
||||
|
||||
ADMIN(0, "管理员登录"),
|
||||
USER(1, "用户登录");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package fun.nojava.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum NotificationType {
|
||||
|
||||
COMMENT_REPLY(0, "回复评论"),
|
||||
LIKE(1, "点赞"),
|
||||
SYSTEM(2, "系统通知");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package fun.nojava.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum UserStatus {
|
||||
|
||||
NORMAL(0, "正常"),
|
||||
LOCKED(1, "锁定");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
public static UserStatus fromCode(int code) {
|
||||
for (UserStatus status : values()) {
|
||||
if (status.code == code) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid UserStatus code: " + code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package fun.nojava.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum UserType {
|
||||
|
||||
ADMIN(0, "超级管理员"),
|
||||
USER(1, "注册用户");
|
||||
|
||||
private final int code;
|
||||
private final String description;
|
||||
|
||||
public static UserType fromCode(int code) {
|
||||
for (UserType type : values()) {
|
||||
if (type.code == code) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid UserType code: " + code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package fun.nojava.common.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
private final int code;
|
||||
|
||||
public BusinessException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode) {
|
||||
super(errorCode.getMessage());
|
||||
this.code = errorCode.getCode();
|
||||
}
|
||||
|
||||
public BusinessException(ErrorCode errorCode, String message) {
|
||||
super(message);
|
||||
this.code = errorCode.getCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package fun.nojava.common.exception;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ErrorCode {
|
||||
|
||||
BAD_REQUEST(400, "参数错误"),
|
||||
UNAUTHORIZED(401, "未认证"),
|
||||
FORBIDDEN(403, "无权限"),
|
||||
NOT_FOUND(404, "资源不存在"),
|
||||
METHOD_NOT_ALLOWED(405, "请求方法不允许"),
|
||||
CONFLICT(409, "操作冲突"),
|
||||
RATE_LIMITED(429, "请求过于频繁"),
|
||||
INTERNAL_ERROR(500, "服务器内部错误"),
|
||||
|
||||
ACCOUNT_LOCKED(1001, "账号已被锁定"),
|
||||
ACCOUNT_DISABLED(1002, "账号已被禁用"),
|
||||
EMAIL_NOT_VERIFIED(1003, "邮箱未验证"),
|
||||
EMAIL_ALREADY_EXISTS(1004, "邮箱已被注册"),
|
||||
PASSWORD_TOO_WEAK(1005, "密码强度不足"),
|
||||
LOGIN_FAIL_TOO_MANY(1006, "登录失败次数过多"),
|
||||
IP_BLOCKED(1007, "IP已被临时封禁"),
|
||||
CAPTCHA_REQUIRED(1008, "需要输入验证码"),
|
||||
CAPTCHA_INVALID(1009, "验证码无效"),
|
||||
TOKEN_INVALID(1010, "Token无效"),
|
||||
TOKEN_EXPIRED(1011, "Token已过期"),
|
||||
SESSION_KICKED(1012, "会话已被踢出"),
|
||||
|
||||
ARTICLE_NOT_FOUND(2001, "文章不存在"),
|
||||
ARTICLE_NO_PERMISSION(2002, "无权操作该文章"),
|
||||
TAG_LIMIT_EXCEEDED(2003, "标签数量超出限制"),
|
||||
CATEGORY_NOT_FOUND(2004, "分类不存在"),
|
||||
CATEGORY_DISABLED(2005, "分类已禁用"),
|
||||
CATEGORY_HAS_ARTICLES(2006, "分类下存在文章,无法删除"),
|
||||
UPLOAD_FILE_INVALID(2007, "上传文件不合法"),
|
||||
UPLOAD_FILE_TOO_LARGE(2008, "上传文件过大"),
|
||||
|
||||
COMMENT_NOT_FOUND(3001, "评论不存在"),
|
||||
COMMENT_AUDIT_PENDING(3002, "评论待审核"),
|
||||
COMMENT_NO_PERMISSION(3003, "无权操作该评论"),
|
||||
COMMENT_LEVEL_EXCEEDED(3004, "评论层级超限");
|
||||
|
||||
private final int code;
|
||||
private final String message;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package fun.nojava.common.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@Schema(description = "统一响应结果")
|
||||
public class ApiResult<T> {
|
||||
|
||||
@Schema(description = "业务状态码")
|
||||
private int code;
|
||||
|
||||
@Schema(description = "提示信息")
|
||||
private String message;
|
||||
|
||||
@Schema(description = "响应数据")
|
||||
private T data;
|
||||
|
||||
@Schema(description = "响应时间戳")
|
||||
private long timestamp;
|
||||
|
||||
public static <T> ApiResult<T> success() {
|
||||
return new ApiResult<>(200, "success", null, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static <T> ApiResult<T> success(T data) {
|
||||
return new ApiResult<>(200, "success", data, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static <T> ApiResult<T> success(String message, T data) {
|
||||
return new ApiResult<>(200, message, data, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static <T> ApiResult<T> error(int code, String message) {
|
||||
return new ApiResult<>(code, message, null, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public static <T> ApiResult<T> error(fun.nojava.common.exception.ErrorCode errorCode) {
|
||||
return new ApiResult<>(errorCode.getCode(), errorCode.getMessage(), null, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package fun.nojava.common.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "ID返回")
|
||||
public class IdVO {
|
||||
|
||||
@Schema(description = "ID")
|
||||
private Long id;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package fun.nojava.common.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "分页请求参数")
|
||||
public class PageParam {
|
||||
|
||||
@Schema(description = "页码,从1开始")
|
||||
@Min(value = 1, message = "页码最小为1")
|
||||
private int page = 1;
|
||||
|
||||
@Schema(description = "每页条数")
|
||||
@Min(value = 1, message = "每页条数最小为1")
|
||||
@Max(value = 100, message = "每页条数最大为100")
|
||||
private int pageSize = 15;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package fun.nojava.common.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "分页结果")
|
||||
public class PageResult<T> {
|
||||
|
||||
@Schema(description = "数据列表")
|
||||
private List<T> records;
|
||||
|
||||
@Schema(description = "总记录数")
|
||||
private long total;
|
||||
|
||||
@Schema(description = "当前页码")
|
||||
private int page;
|
||||
|
||||
@Schema(description = "每页条数")
|
||||
private int pageSize;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package fun.nojava.common.util;
|
||||
|
||||
import fun.nojava.common.model.ApiResult;
|
||||
import fun.nojava.common.model.PageResult;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class ApiResultUtils {
|
||||
|
||||
private ApiResultUtils() {}
|
||||
|
||||
public static <T> ApiResult<PageResult<T>> page(List<T> records, long total, int page, int pageSize) {
|
||||
PageResult<T> pageResult = new PageResult<>(records, total, page, pageSize);
|
||||
return ApiResult.success(pageResult);
|
||||
}
|
||||
|
||||
public static <T> ApiResult<PageResult<T>> page(Page<T> springPage) {
|
||||
PageResult<T> pageResult = new PageResult<>(
|
||||
springPage.getContent(),
|
||||
springPage.getTotalElements(),
|
||||
springPage.getNumber() + 1,
|
||||
springPage.getSize()
|
||||
);
|
||||
return ApiResult.success(pageResult);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user