feat:引入常量方法

This commit is contained in:
lbw
2025-12-09 18:42:50 +08:00
parent 46fc80223b
commit 7ef76d2386
19 changed files with 832 additions and 2 deletions

View File

@@ -0,0 +1,69 @@
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 指定父项目 -->
<parent>
<groupId>com.yinlihupo</groupId>
<artifactId>enlish-framework</artifactId>
<version>${revision}</version>
</parent>
<!-- 指定打包方式 -->
<packaging>jar</packaging>
<artifactId>enlish-common</artifactId>
<name>${project.artifactId}</name>
<description>平台通用模块,如一些通用枚举、工具类等等</description>
<dependencies>
<!-- 避免编写那些冗余的 Java 样板式代码,如 get、set 方法等 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<!-- 解决 LocalDateTime 的序列化问题 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<!-- 入参校验 -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<!-- 相关工具类 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,38 @@
package com.yinlihupo.framework.common.constant;
import java.time.format.DateTimeFormatter;
public interface DateConstants {
/**
* DateTimeFormatter年-月-日 时:分:秒
*/
DateTimeFormatter DATE_FORMAT_Y_M_D_H_M_S = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
* DateTimeFormatter年-月-日
*/
DateTimeFormatter DATE_FORMAT_Y_M_D = DateTimeFormatter.ofPattern("yyyy-MM-dd");
/**
* DateTimeFormatter
*/
DateTimeFormatter DATE_FORMAT_H_M_S = DateTimeFormatter.ofPattern("HH:mm:ss");
/**
* DateTimeFormatter年-月
*/
DateTimeFormatter DATE_FORMAT_Y_M = DateTimeFormatter.ofPattern("yyyy-MM");
/**
* DateTimeFormatter月-日
*/
DateTimeFormatter DATE_FORMAT_M_D = DateTimeFormatter.ofPattern("MM-dd");
/**
* DateTimeFormatter
*/
DateTimeFormatter DATE_FORMAT_H_M = DateTimeFormatter.ofPattern("HH:mm");
}

View File

@@ -0,0 +1,12 @@
package com.yinlihupo.framework.common.constant;
public interface GlobalConstants {
/**
* 用户 ID
*/
String USER_ID = "userId";
}

View File

@@ -0,0 +1,15 @@
package com.yinlihupo.framework.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum DeletedEnum {
YES(true),
NO(false);
private final Boolean value;
}

View File

@@ -0,0 +1,16 @@
package com.yinlihupo.framework.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum StatusEnum {
// 启用
ENABLE(0),
// 禁用
DISABLED(1);
private final Integer value;
}

View File

@@ -0,0 +1,9 @@
package com.yinlihupo.framework.common.exception;
public interface BaseExceptionInterface {
String getErrorCode();
String getErrorMessage();
}

View File

@@ -0,0 +1,19 @@
package com.yinlihupo.framework.common.exception;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class BizException extends RuntimeException {
// 异常码
private String errorCode;
// 错误信息
private String errorMessage;
public BizException(BaseExceptionInterface baseExceptionInterface) {
this.errorCode = baseExceptionInterface.getErrorCode();
this.errorMessage = baseExceptionInterface.getErrorMessage();
}
}

View File

@@ -0,0 +1,69 @@
package com.yinlihupo.framework.common.response;
import lombok.Data;
import java.util.List;
@Data
public class PageResponse<T> extends Response<List<T>> {
// 当前页码
private long pageNo;
// 总数据量
private long totalCount;
// 每页展示的数据量
private long pageSize;
// 总页数
private long totalPage;
public static <T> PageResponse<T> success(List<T> data, long pageNo, long totalCount) {
PageResponse<T> pageResponse = new PageResponse<>();
pageResponse.setSuccess(true);
pageResponse.setData(data);
pageResponse.setPageNo(pageNo);
pageResponse.setTotalCount(totalCount);
// 每页展示的数据量
long pageSize = 10L;
pageResponse.setPageSize(pageSize);
// 计算总页数
long totalPage = (totalCount + pageSize - 1) / pageSize;
pageResponse.setTotalPage(totalPage);
return pageResponse;
}
public static <T> PageResponse<T> success(List<T> data, long pageNo, long totalCount, long pageSize) {
PageResponse<T> pageResponse = new PageResponse<>();
pageResponse.setSuccess(true);
pageResponse.setData(data);
pageResponse.setPageNo(pageNo);
pageResponse.setTotalCount(totalCount);
pageResponse.setPageSize(pageSize);
// 计算总页数
long totalPage = pageSize == 0 ? 0 : (totalCount + pageSize - 1) / pageSize;
pageResponse.setTotalPage(totalPage);
return pageResponse;
}
/**
* 获取总页数
*/
public static long getTotalPage(long totalCount, long pageSize) {
return pageSize == 0 ? 0 : (totalCount + pageSize - 1) / pageSize;
}
/**
* 计算分页查询的 offset
*/
public static long getOffset(long pageNo, long pageSize) {
// 如果页码小于 1默认返回第一页的 offset
if (pageNo < 1) {
pageNo = 1;
}
return (pageNo - 1) * pageSize;
}
}

View File

@@ -0,0 +1,73 @@
package com.yinlihupo.framework.common.response;
import com.yinlihupo.framework.common.exception.BaseExceptionInterface;
import com.yinlihupo.framework.common.exception.BizException;
import lombok.Data;
import java.io.Serializable;
@Data
public class Response<T> implements Serializable {
// 是否成功,默认为 true
private boolean success = true;
// 响应消息
private String message;
// 异常码
private String errorCode;
// 响应数据
private T data;
// =================================== 成功响应 ===================================
public static <T> Response<T> success() {
Response<T> response = new Response<>();
return response;
}
public static <T> Response<T> success(T data) {
Response<T> response = new Response<>();
response.setData(data);
return response;
}
// =================================== 失败响应 ===================================
public static <T> Response<T> fail() {
Response<T> response = new Response<>();
response.setSuccess(false);
return response;
}
public static <T> Response<T> fail(String errorMessage) {
Response<T> response = new Response<>();
response.setSuccess(false);
response.setMessage(errorMessage);
return response;
}
public static <T> Response<T> fail(String errorCode, String errorMessage) {
Response<T> response = new Response<>();
response.setSuccess(false);
response.setErrorCode(errorCode);
response.setMessage(errorMessage);
return response;
}
public static <T> Response<T> fail(BizException bizException) {
Response<T> response = new Response<>();
response.setSuccess(false);
response.setErrorCode(bizException.getErrorCode());
response.setMessage(bizException.getErrorMessage());
return response;
}
public static <T> Response<T> fail(BaseExceptionInterface baseExceptionInterface) {
Response<T> response = new Response<>();
response.setSuccess(false);
response.setErrorCode(baseExceptionInterface.getErrorCode());
response.setMessage(baseExceptionInterface.getErrorMessage());
return response;
}
}

View File

@@ -0,0 +1,81 @@
package com.yinlihupo.framework.common.util;
import com.yinlihupo.framework.common.constant.DateConstants;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.Date;
/**
* @author lbwxxc
* @date 2025/6/2 16:24
* @description: 日期工具类
*/
public class DateUtils {
public static long localDateTime2Timestamp(LocalDateTime localDateTime) {
return localDateTime.toInstant(ZoneOffset.UTC).toEpochMilli();
}
public static long dateTime2Timestamp(Date date) {
return date.toInstant().toEpochMilli();
}
/**
* LocalDateTime 转 String 字符串
*/
public static String localDateTime2String(LocalDateTime time) {
return time.format(DateConstants.DATE_FORMAT_Y_M_D_H_M_S);
}
/**
* LocalDateTime 转友好的相对时间字符串
*/
public static String formatRelativeTime(LocalDateTime dateTime) {
// 当前时间
LocalDateTime now = LocalDateTime.now();
// 计算与当前时间的差距
long daysDiff = ChronoUnit.DAYS.between(dateTime, now);
long hoursDiff = ChronoUnit.HOURS.between(dateTime, now);
long minutesDiff = ChronoUnit.MINUTES.between(dateTime, now);
if (daysDiff < 1) { // 如果是今天
if (hoursDiff < 1) { // 如果是几分钟前
return minutesDiff + "分钟前";
} else { // 如果是几小时前
return hoursDiff + "小时前";
}
} else if (daysDiff == 1) { // 如果是昨天
return "昨天 " + dateTime.format(DateConstants.DATE_FORMAT_H_M);
} else if (daysDiff < 7) { // 如果是最近一周
return daysDiff + "天前";
} else if (dateTime.getYear() == now.getYear()) { // 如果是今年
return dateTime.format(DateConstants.DATE_FORMAT_M_D);
} else { // 如果是去年或更早
return dateTime.format(DateConstants.DATE_FORMAT_Y_M_D);
}
}
/**
* 计算年龄
* @param birthDate 出生日期LocalDate
* @return 计算得到的年龄(以年为单位)
*/
public static int calculateAge(LocalDate birthDate) {
// 获取当前日期
LocalDate currentDate = LocalDate.now();
// 计算出生日期到当前日期的 Period 对象
Period period = Period.between(birthDate, currentDate);
// 返回完整的年份(即年龄)
return period.getYears();
}
}

View File

@@ -0,0 +1,92 @@
package com.yinlihupo.framework.common.util;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.CollectionType;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class JsonUtils {
private static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
static {
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
OBJECT_MAPPER.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化问题
}
/**
* 初始化:统一使用 Spring Boot 个性化配置的 ObjectMapper
*/
public static void init(ObjectMapper objectMapper) {
OBJECT_MAPPER = objectMapper;
}
/**
* 将对象转换为 JSON 字符串
*/
@SneakyThrows
public static String toJsonString(Object obj) {
return OBJECT_MAPPER.writeValueAsString(obj);
}
/**
* 将 JSON 字符串转换为对象
*/
@SneakyThrows
public static <T> T parseObject(String jsonStr, Class<T> clazz) {
if (StringUtils.isBlank(jsonStr)) {
return null;
}
return OBJECT_MAPPER.readValue(jsonStr, clazz);
}
/**
* 将 JSON 字符串转换为 Map
*/
public static <K, V> Map<K, V> parseMap(String jsonStr, Class<K> keyClass, Class<V> valueClass) throws Exception {
// 创建 TypeReference指定泛型类型
TypeReference<Map<K, V>> typeRef = new TypeReference<Map<K, V>>() {
};
// 将 JSON 字符串转换为 Map
return OBJECT_MAPPER.readValue(jsonStr, OBJECT_MAPPER.getTypeFactory().constructMapType(Map.class, keyClass, valueClass));
}
/**
* 将 JSON 字符串解析为指定类型的 List 对象
*/
public static <T> List<T> parseList(String jsonStr, Class<T> clazz) throws Exception {
// 使用 TypeReference 指定 List<T> 的泛型类型
return OBJECT_MAPPER.readValue(jsonStr, new TypeReference<>() {
@Override
public CollectionType getType() {
return OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz);
}
});
}
/**
* 将 JSON 字符串解析为指定类型的 Set 对象
*/
public static <T> Set<T> parseSet(String jsonStr, Class<T> clazz) throws Exception {
return OBJECT_MAPPER.readValue(jsonStr, new TypeReference<>() {
@Override
public Type getType() {
return OBJECT_MAPPER.getTypeFactory().constructCollectionType(Set.class, clazz);
}
});
}
}

View File

@@ -0,0 +1,34 @@
package com.yinlihupo.framework.common.util;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Objects;
public class NumberUtils {
/**
* 数字转换字符串
*/
public static String formatNumberString(long number) {
if (Objects.isNull(number)) {
return "0";
}
if (number < 10000) {
return String.valueOf(number); // 小于 1 万显示原始数字
} else if (number >= 10000 && number < 100000000) {
// 小于 1 亿,显示万单位
double result = number / 10000.0;
DecimalFormat df = new DecimalFormat("#.#"); // 保留 1 位小数
df.setRoundingMode(RoundingMode.DOWN); // 禁用四舍五入
String formatted = df.format(result);
return formatted + "";
} else {
return "9999万"; // 超过 1 亿,统一显示 9999万
}
}
}

View File

@@ -0,0 +1,75 @@
package com.yinlihupo.framework.common.util;
import java.util.regex.Pattern;
public final class ParamUtils {
private ParamUtils() {
}
// ============================== 校验昵称 ==============================
// 定义昵称长度范围
private static final int NICK_NAME_MIN_LENGTH = 2;
private static final int NICK_NAME_MAX_LENGTH = 24;
// 定义特殊字符的正则表达式
private static final String NICK_NAME_REGEX = "[!@#$%^&*(),.?\":{}|<>]";
/**
* 昵称校验
*
* @param nickname
* @return
*/
public static boolean checkNickname(String nickname) {
// 检查长度
if (nickname.length() < NICK_NAME_MIN_LENGTH || nickname.length() > NICK_NAME_MAX_LENGTH) {
return false;
}
// 检查是否含有特殊字符
Pattern pattern = Pattern.compile(NICK_NAME_REGEX);
return !pattern.matcher(nickname).find();
}
// ============================== 校验小哈书号 ==============================
// 定义 ID 长度范围
private static final int ID_MIN_LENGTH = 6;
private static final int ID_MAX_LENGTH = 15;
// 定义正则表达式
private static final String ID_REGEX = "^[a-zA-Z0-9_]+$";
/**
* 小哈书 ID 校验
*
* @param xiaohashuId
* @return
*/
public static boolean checkXiaohashuId(String xiaohashuId) {
// 检查长度
if (xiaohashuId.length() < ID_MIN_LENGTH || xiaohashuId.length() > ID_MAX_LENGTH) {
return false;
}
// 检查格式
Pattern pattern = Pattern.compile(ID_REGEX);
return pattern.matcher(xiaohashuId).matches();
}
/**
* 字符串长度校验
*
* @param str
* @param length
* @return
*/
public static boolean checkLength(String str, int length) {
// 检查长度
if (str.isEmpty() || str.length() > length) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,22 @@
package com.yinlihupo.framework.common.validator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneNumberValidator.class)
public @interface PhoneNumber {
String message() default "手机号格式不正确, 需为 11 位数字";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,18 @@
package com.yinlihupo.framework.common.validator;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> {
@Override
public void initialize(PhoneNumber constraintAnnotation) {
}
@Override
public boolean isValid(String phoneNumber, ConstraintValidatorContext context) {
// 校验逻辑:正则表达式判断手机号是否为 11 位数字
return phoneNumber != null && phoneNumber.matches("\\d{11}");
}
}