diff --git a/airpower-core/pom.xml b/airpower-core/pom.xml index 4074e53f6ca953c7361daf5c38ee2ba831527199..74beb284a38455e17ad7265f3f99b4b4fdc49d62 100644 --- a/airpower-core/pom.xml +++ b/airpower-core/pom.xml @@ -5,10 +5,10 @@ cn.hamm airpower - 2.0.1 + 2.0.2 airpower-core - 2.0.1 + 2.0.2 airpower-core AirPower is a fast backend development tool based on SpringBoot3 and JPA. It's the core of AirPower. diff --git a/airpower-core/src/main/java/cn/hamm/airpower/config/Constant.java b/airpower-core/src/main/java/cn/hamm/airpower/config/Constant.java index 05972c6e068647be9ec36939fd42209a84a6a2e3..ded1a3eabfbfa6be4f0f011527d47fbd67c05775 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/config/Constant.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/config/Constant.java @@ -232,4 +232,9 @@ public class Constant { *

Cookie

*/ public static final String COOKIE = "Cookie"; + + /** + *

毫秒转秒

+ */ + public static final int MILLISECONDS_PER_SECOND = 1000; } diff --git a/airpower-core/src/main/java/cn/hamm/airpower/enums/ServiceError.java b/airpower-core/src/main/java/cn/hamm/airpower/enums/ServiceError.java index 1b2e40e8f6f30d1aa64ba1974af8c4d50cf2e7ee..94795b41f1a92061d4ceeccd87a1f6575015a8c4 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/enums/ServiceError.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/enums/ServiceError.java @@ -24,6 +24,10 @@ public enum ServiceError implements IException, IDictionary { // 400 请求参数代码 PARAM_MISSING(4001, "缺少参数"), PARAM_INVALID(4002, "无效的参数"), + INVALID_APP_KEY(4003, "传入的AppKey无效"), + SIGNATURE_INVALID(4004, "签名无效"), + REPEAT_REQUEST(4005, "重复的请求"), + TIMESTAMP_INVALID(4006, "请求时间不在允许范围内"), // 401 需要登录代码 UNAUTHORIZED(401, "获取身份信息失败,请重新登录!"), @@ -35,6 +39,7 @@ public enum ServiceError implements IException, IDictionary { FORBIDDEN_DELETE(4033, "无权删除"), FORBIDDEN_DELETE_USED(4034, "数据正在使用中,无法被删除!"), FORBIDDEN_UPLOAD_MAX_SIZE(4035, "上传的文件大小超过最大限制"), + OPEN_APP_DISABLED(4036, "当前应用已被禁用"), // 404 没有查到数据代码 DATA_NOT_FOUND(404, "没有查到相关的数据"), @@ -45,6 +50,10 @@ public enum ServiceError implements IException, IDictionary { // 500 服务基础代码 SERVICE_ERROR(500, "服务发生错误,请稍后再试"), + DECRYPT_DATA_FAIL(5001, "数据解密失败"), + ENCRYPT_DATA_FAIL(5002, "数据加密失败"), + JSON_DECODE_FAIL(5003, "JSON解码失败"), + API_SERVICE_UNSUPPORTED(501, "请求的接口暂未实现"), // 502 内部错误代码 @@ -59,6 +68,7 @@ public enum ServiceError implements IException, IDictionary { // 5023 邮件相关代码 EMAIL_ERROR(5023, "发送邮件可能出现异常,请检查收件箱"), + ; private final int code; diff --git a/airpower-core/src/main/java/cn/hamm/airpower/interceptor/AbstractRequestInterceptor.java b/airpower-core/src/main/java/cn/hamm/airpower/interceptor/AbstractRequestInterceptor.java index 9f750cda159170ce7f011aa53c4f0e55e3979e37..2cda85c13f7bc1144b64996d445d209dad9941b5 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/interceptor/AbstractRequestInterceptor.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/interceptor/AbstractRequestInterceptor.java @@ -28,8 +28,8 @@ import java.util.Objects; *

全局权限拦截器抽象类

* * @author Hamm.cn - * @see #checkPermissionAccess(Long, String, HttpServletRequest) - * @see #beforeHandleRequest(HttpServletRequest, HttpServletResponse, Class, Method) + * @see #checkUserPermission(Long, String, HttpServletRequest) + * @see #interceptRequest(HttpServletRequest, HttpServletResponse, Class, Method) * @see #getRequestBody(HttpServletRequest) * @see #setShareData(String, Object) */ @@ -73,15 +73,24 @@ public abstract class AbstractRequestInterceptor implements HandlerInterceptor { return false; } } + handleRequest(request, response, clazz, method); + return true; + } - boolean isContinue = beforeHandleRequest(request, response, clazz, method); - if (!isContinue) { - return true; - } + /** + *

请求拦截器

+ * + * @param request 请求 + * @param response 响应 + * @param clazz 控制器 + * @param method 方法 + */ + private void handleRequest(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, Class clazz, Method method) { + interceptRequest(request, response, clazz, method); Access access = Utils.getAccessUtil().getWhatNeedAccess(clazz, method); if (!access.isLogin()) { // 不需要登录 直接返回有权限 - return true; + return; } //需要登录 String accessToken = request.getHeader(Configs.getServiceConfig().getAuthorizeHeader()); @@ -96,43 +105,41 @@ public abstract class AbstractRequestInterceptor implements HandlerInterceptor { //需要RBAC if (access.isAuthorize()) { //验证用户是否有接口的访问权限 - return checkPermissionAccess(userId, Utils.getAccessUtil().getPermissionIdentity(clazz, method), request); + checkUserPermission(userId, Utils.getAccessUtil().getPermissionIdentity(clazz, method), request); } - return true; } - /** *

验证指定的用户是否有指定权限标识的权限

* * @param userId 用户ID * @param permissionIdentity 权限标识 * @param request 请求对象 - * @return 验证结果 + * @apiNote 抛出异常则为拦截 */ - protected abstract boolean checkPermissionAccess( + protected void checkUserPermission( Long userId, String permissionIdentity, HttpServletRequest request - ); + ) { + } /** - *

请求拦截器前置方法

+ *

拦截请求

* * @param request 请求对象 * @param response 响应对象 * @param clazz 控制器类 * @param method 执行方法 - * @return 拦截结果 - * @apiNote 如返回TRUE,则继续走后续拦截,如返回FALSE,则中断拦截,直接放行 + * @apiNote 抛出异常则为拦截 */ @SuppressWarnings({"EmptyMethod", "unused"}) - protected boolean beforeHandleRequest( + protected void interceptRequest( HttpServletRequest request, HttpServletResponse response, Class clazz, Method method ) { - return true; } + /** - *

设置共享数据提供给其他拦截器实用

+ *

设置共享数据

* * @param key KEY * @param value VALUE @@ -144,7 +151,6 @@ public abstract class AbstractRequestInterceptor implements HandlerInterceptor { } } - /** *

从请求中获取请求的包体

* @@ -168,6 +174,5 @@ public abstract class AbstractRequestInterceptor implements HandlerInterceptor { log.error(exception.getMessage(), exception); } return Constant.EMPTY_STRING; - } } diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenApp.java b/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenApp.java new file mode 100644 index 0000000000000000000000000000000000000000..1dcd3e07c6158dee9f3dee4b1b504ef044cce7d9 --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenApp.java @@ -0,0 +1,34 @@ +package cn.hamm.airpower.open; + +/** + *

开放应用实体接口

+ * + * @author Hamm.cn + * @apiNote 请确保你的应用实体类实现了此接口 + */ +public interface IOpenApp { + /** + *

获取应用的AppKey

+ */ + String getAppKey(); + + /** + *

获取应用的AppSecret

+ */ + String getAppSecret(); + + /** + *

获取应用的加密算法

+ */ + Integer getArithmetic(); + + /** + *

获取应用的私钥

+ */ + String getPrivateKey(); + + /** + *

获取应用的公钥

+ */ + String getPublicKey(); +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenAppService.java b/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenAppService.java new file mode 100644 index 0000000000000000000000000000000000000000..65f08349a222aacb39c646e740403de6e8eb8489 --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenAppService.java @@ -0,0 +1,17 @@ +package cn.hamm.airpower.open; + +/** + *

开放应用的Service接口

+ * + * @author Hamm.cn + * @apiNote 请确保你的开放应用的Service实现了此接口 + */ +public interface IOpenAppService { + /** + *

通过应用的AppKey查一个应用

+ * + * @param appKey AppKey + * @return 应用 + */ + IOpenApp getByAppKey(String appKey); +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenLogService.java b/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenLogService.java new file mode 100644 index 0000000000000000000000000000000000000000..1de0a18211db150f27729595873bbce33735644a --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/IOpenLogService.java @@ -0,0 +1,27 @@ +package cn.hamm.airpower.open; + +/** + *

开放应用请求日志接口

+ * + * @author Hamm.cn + * @apiNote 请确保你的应用请求日志Service实现了此接口,否则将无法记录请求日志 + */ +public interface IOpenLogService { + /** + *

添加一个请求日志

+ * + * @param openApp 开放应用 + * @param url 请求地址 + * @param requestBody 请求体 + * @return 请求日志ID + */ + Long addRequest(IOpenApp openApp, String url, String requestBody); + + /** + *

更新请求日志

+ * + * @param openLogId 请求日志ID + * @param responseBody 响应体 + */ + void updateResponse(Long openLogId, String responseBody); +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/OpenApi.java b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenApi.java new file mode 100644 index 0000000000000000000000000000000000000000..bca968ba591ba1bcf8d51928aafdef5a1cf20b23 --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenApi.java @@ -0,0 +1,15 @@ +package cn.hamm.airpower.open; + +import java.lang.annotation.*; + +/** + *

OpenApi

+ * + * @author Hamm.cn + */ +@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +public @interface OpenApi { +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/OpenApiAspect.java b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenApiAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..6f6690ef3e5aabbbe51821dceb748db3c38b9e8a --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenApiAspect.java @@ -0,0 +1,129 @@ +package cn.hamm.airpower.open; + +import cn.hamm.airpower.enums.ServiceError; +import cn.hamm.airpower.exception.ServiceException; +import cn.hamm.airpower.model.Json; +import cn.hamm.airpower.util.Utils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.lang.reflect.Method; +import java.util.Objects; + +/** + *

OpenApi切面

+ * + * @author Hamm.cn + */ +@Aspect +@Component +public class OpenApiAspect { + @Autowired(required = false) + S openAppService; + + @Autowired(required = false) + LS openLogService; + + @SuppressWarnings("EmptyMethod") + @Pointcut("@annotation(cn.hamm.airpower.open.OpenApi)") + public void pointCut() { + + } + + /** + *

开放API

+ */ + @Around("pointCut()") + public Object openApi(@NotNull ProceedingJoinPoint proceedingJoinPoint) throws Throwable { + Object[] args = proceedingJoinPoint.getArgs(); + Signature signature = proceedingJoinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + OpenApi openApi = method.getAnnotation(OpenApi.class); + ServiceError.API_SERVICE_UNSUPPORTED.whenNull(openApi); + Long openLogId = null; + String response = ""; + if (args.length != 1) { + throw new ServiceException("OpenApi必须接收一个参数"); + } + if (!(args[0] instanceof OpenRequest openRequest)) { + throw new ServiceException("OpenApi必须接收一个OpenRequest参数"); + } + try { + ServiceError.INVALID_APP_KEY.when(!StringUtils.hasText(openRequest.getAppKey())); + ServiceError.SERVICE_ERROR.whenNull(openAppService, "注入OpenAppService失败"); + IOpenApp openApp = openAppService.getByAppKey(openRequest.getAppKey()); + ServiceError.INVALID_APP_KEY.whenNull(openApp); + openRequest.setOpenApp(openApp); + Object object = proceedingJoinPoint.proceed(); + openLogId = addOpenLog(openRequest.getOpenApp(), Utils.getRequest().getRequestURI(), openRequest.decodeContent()); + openRequest.checkSignature(); + if (object instanceof Json json) { + // 日志记录原始数据 + response = Json.toString(json); + updateLogResponse(openLogId, response); + // 如果是Json 需要将 Json.data 对输出的数据进行加密 + json.setData(OpenResponse.encodeResponse(openRequest.getOpenApp(), json.getData())); + } + updateLogResponse(openLogId, response); + return object; + } catch (ServiceException serviceException) { + response = Json.toString(Json.create().setCode(serviceException.getCode()).setMessage(serviceException.getMessage())); + updateLogResponse(openLogId, response); + throw serviceException; + } catch (Exception exception) { + updateExceptionResponse(openLogId, exception); + throw exception; + } + } + + /** + *

添加日志

+ * + * @param openApp OpenApp + * @param url 请求URL + * @param requestBody 请求数据 + * @return 日志ID + */ + private @Nullable Long addOpenLog(IOpenApp openApp, String url, String requestBody) { + if (Objects.nonNull(openLogService)) { + return openLogService.addRequest(openApp, url, requestBody); + } + return null; + } + + /** + *

更新日志返回数据

+ * + * @param openLogId 日志ID + * @param responseBody 返回值 + */ + private void updateLogResponse(Long openLogId, String responseBody) { + if (Objects.isNull(openLogId) || Objects.isNull(openLogService)) { + return; + } + openLogService.updateResponse(openLogId, responseBody); + } + + /** + * +

更新日志异常

+ * + * @param openLogId 日志ID + * @param exception 异常 + */ + private void updateExceptionResponse(Long openLogId, Exception exception) { + if (Objects.isNull(openLogId)) { + return; + } + updateLogResponse(openLogId, Json.toString(Json.create().setMessage(exception.getMessage()))); + } +} \ No newline at end of file diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/OpenArithmeticType.java b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenArithmeticType.java new file mode 100644 index 0000000000000000000000000000000000000000..b16c5d29f1dfa68295588a70944fb98ec429705e --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenArithmeticType.java @@ -0,0 +1,32 @@ +package cn.hamm.airpower.open; + +import cn.hamm.airpower.interfaces.IDictionary; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + *

开放应用加密方式

+ * + * @author Hamm + */ +@AllArgsConstructor +@Getter +public enum OpenArithmeticType implements IDictionary { + /** + *

AES算法

+ */ + AES(1, "AES"), + + /** + *

RSA算法

+ */ + RSA(2, "RSA"), + + /** + *

不加密

+ */ + NO(3, "NO"); + + private final int key; + private final String label; +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/OpenBaseModel.java b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenBaseModel.java new file mode 100644 index 0000000000000000000000000000000000000000..c0a9952b3984392544b7ad34f192b1d0da2ec420 --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenBaseModel.java @@ -0,0 +1,12 @@ +package cn.hamm.airpower.open; + +import cn.hamm.airpower.root.RootModel; + +/** + *

OpenApi数据模型基类

+ * + * @author Hamm.cn + */ +public class OpenBaseModel> extends RootModel { + +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/OpenRequest.java b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..0a775bd5370bb94866b6feaee65fbf142d9924df --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenRequest.java @@ -0,0 +1,133 @@ +package cn.hamm.airpower.open; + +import cn.hamm.airpower.config.Constant; +import cn.hamm.airpower.enums.ServiceError; +import cn.hamm.airpower.exception.ServiceException; +import cn.hamm.airpower.model.Json; +import cn.hamm.airpower.root.RootModel; +import cn.hamm.airpower.util.Utils; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; + +/** + *

OpenApi请求体

+ * + * @author Hamm.cn + */ +@Slf4j +@Setter +public class OpenRequest { + /** + *

防重放缓存前缀

+ */ + private static final String NONCE_CACHE_PREFIX = "NONCE_"; + + /** + *

防重放时长

+ */ + private static final int NONCE_CACHE_SECOND = 60; + + /** + *

AppKey

+ */ + @NotBlank(message = "AppKey不能为空") + @Getter + private String appKey; + + /** + *

版本号

+ */ + @NotNull(message = "版本号不能为空") + private int version; + + /** + *

请求毫秒时间戳

+ */ + @NotNull(message = "请求毫秒时间戳不能为空") + private long timestamp; + + /** + *

加密后的业务数据

+ */ + @NotNull(message = "业务数据包体不能为空") + private String content; + + /** + *

签名字符串

+ */ + @NotNull(message = "签名字符串不能为空") + private String signature; + + /** + *

请求随机串不能为空

+ */ + @NotNull(message = "请求随机串不能为空") + private String nonce; + + /** + *

当前请求的应用

+ */ + @Getter + private IOpenApp openApp; + + /** + *

签名验证结果

+ * + * @apiNote 无需手动调用 + */ + public final void checkSignature() { + String source = this.openApp.getAppSecret() + this.appKey + this.version + this.timestamp + this.nonce + this.content; + ServiceError.SIGNATURE_INVALID.whenNotEquals(this.signature, DigestUtils.sha1Hex(source)); + Object savedNonce = Utils.getRedisUtil().get(NONCE_CACHE_PREFIX + this.nonce); + ServiceError.REPEAT_REQUEST.whenNotNull(savedNonce); + Utils.getRedisUtil().set(NONCE_CACHE_PREFIX + this.nonce, 1, NONCE_CACHE_SECOND); + ServiceError.TIMESTAMP_INVALID.when( + this.timestamp > System.currentTimeMillis() + NONCE_CACHE_SECOND * Constant.MILLISECONDS_PER_SECOND || + this.timestamp < System.currentTimeMillis() - NONCE_CACHE_SECOND * Constant.MILLISECONDS_PER_SECOND + ); + } + + /** + *

强转请求数据到指定的类对象

+ * + * @param clazz 业务数据对象类型 + */ + public final > T parse(Class clazz) { + try { + return Json.parse(decodeContent(), clazz); + } catch (Exception e) { + ServiceError.JSON_DECODE_FAIL.show(); + throw new ServiceException(e); + } + } + + /** + *

解密请求数据

+ * + * @return 请求数据 + */ + public final String decodeContent() { + String request = this.content; + OpenArithmeticType appArithmeticType = Utils.getDictionaryUtil().getDictionary( + OpenArithmeticType.class, this.openApp.getArithmetic() + ); + try { + switch (appArithmeticType) { + case AES: + request = Utils.getAesUtil().setKey(this.openApp.getAppSecret()).decrypt(request); + break; + case RSA: + request = Utils.getRsaUtil().setPrivateKey(openApp.getPrivateKey()).privateKeyDecrypt(request); + break; + default: + } + } catch (Exception e) { + ServiceError.DECRYPT_DATA_FAIL.show(); + } + return request; + } +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/open/OpenResponse.java b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..d8c9fc999ff3df1e0e9129c7aca39e3be6b17d65 --- /dev/null +++ b/airpower-core/src/main/java/cn/hamm/airpower/open/OpenResponse.java @@ -0,0 +1,51 @@ +package cn.hamm.airpower.open; + +import cn.hamm.airpower.enums.ServiceError; +import cn.hamm.airpower.exception.ServiceException; +import cn.hamm.airpower.model.Json; +import cn.hamm.airpower.util.Utils; + +import java.util.Objects; + +/** + *

开放接口的响应对象

+ * + * @author Hamm.cn + */ +public class OpenResponse { + /** + *

加密响应数据

+ * + * @param openApp 应用 + * @param data 数据 + * @return 加密后的数据 + */ + public static String encodeResponse(A openApp, Object data) { + String response = null; + if (Objects.isNull(data)) { + // 数据负载为空 直接返回 + return response; + } + response = Json.toString(data); + OpenArithmeticType appArithmeticType = Utils.getDictionaryUtil().getDictionary( + OpenArithmeticType.class, openApp.getArithmetic() + ); + try { + switch (appArithmeticType) { + case AES: + response = Utils.getAesUtil().setKey(openApp.getAppSecret()).encrypt(response); + break; + case RSA: + response = Utils.getRsaUtil().setPrivateKey(openApp.getPrivateKey()).publicKeyEncrypt(response); + break; + case NO: + break; + default: + throw new ServiceException(ServiceError.ENCRYPT_DATA_FAIL, "不支持的加密算法"); + } + } catch (Exception e) { + ServiceError.ENCRYPT_DATA_FAIL.show(); + } + return response; + } +} diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/AccessUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/AccessUtil.java index 9d6f0cfee8e1d85bb0d4764df5a533454344c0ae..0c9404c2738f225f79f62b5dff2fb45dfbd03f30 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/AccessUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/AccessUtil.java @@ -28,7 +28,6 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; - /** *

权限处理助手

* diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/AesUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/AesUtil.java index 63e0ba584bda70e476decde87bcf2a9744bfc77b..0399344b2fc33d4d6132fd916ba7a5c879e1357f 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/AesUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/AesUtil.java @@ -1,6 +1,5 @@ package cn.hamm.airpower.util; - import cn.hamm.airpower.exception.ServiceException; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/CookieUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/CookieUtil.java index 900cf59300fbe584c20c0662fff6bcb48dc83b40..5c0f556848948fa63d608d1d57cc59728d7645b6 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/CookieUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/CookieUtil.java @@ -13,7 +13,6 @@ import org.springframework.stereotype.Component; */ @Component public class CookieUtil { - /** *

获取一个Cookie

* diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/DictionaryUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/DictionaryUtil.java index 0eb1e7c308d75a7fd69d888609ab72183134755a..deef87bec0e7311205e076056ccde63290f89163 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/DictionaryUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/DictionaryUtil.java @@ -22,7 +22,6 @@ import java.util.function.Function; @Slf4j @Component public class DictionaryUtil { - /** *

查字典

* diff --git a/airpower-core/src/main/java/cn/hamm/airpower/util/ReflectUtil.java b/airpower-core/src/main/java/cn/hamm/airpower/util/ReflectUtil.java index 9687390da3b5ccbca8f7d36dea119e213773267c..79854da0511c680df17e638a1fb879b03cb7f0b7 100644 --- a/airpower-core/src/main/java/cn/hamm/airpower/util/ReflectUtil.java +++ b/airpower-core/src/main/java/cn/hamm/airpower/util/ReflectUtil.java @@ -32,7 +32,6 @@ import java.util.*; @Slf4j @Component public class ReflectUtil { - /** *

获取对象指定属性的值

* diff --git a/pom.xml b/pom.xml index 219ddf3fd27620a1cd2ae6a3db7688ecd76606c6..578951a87a3f983204d80fef5fa7562c7b9f0f1c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,11 +4,11 @@ 4.0.0 cn.hamm airpower - 2.0.1 + 2.0.2 airpower AirPower is a fast backend development tool based on SpringBoot3 and JPA. - 2.0.1 + 2.0.2 UTF-8 UTF-8 UTF-8