Commit 0a6078610b4b3abd237fb2d6d7f3127b555ab0bb
1 parent
fc8eac54
common 包,基础组件
Showing
14 changed files
with
641 additions
and
0 deletions
src/main/java/cn/iocoder/dashboard/common/exception/ErrorCode.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.exception; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.exception.enums.ServiceErrorCodeRange; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 错误码对象 | |
| 8 | + * | |
| 9 | + * 全局错误码,占用 [0, 999],参见 {@link GlobalException} | |
| 10 | + * 业务异常错误码,占用 [1 000 000 000, +∞),参见 {@link ServiceErrorCodeRange} | |
| 11 | + * | |
| 12 | + * TODO 错误码设计成对象的原因,为未来的 i18 国际化做准备 | |
| 13 | + */ | |
| 14 | +@Data | |
| 15 | +public class ErrorCode { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 错误码 | |
| 19 | + */ | |
| 20 | + private final Integer code; | |
| 21 | + /** | |
| 22 | + * 错误提示 | |
| 23 | + */ | |
| 24 | + private final String message; | |
| 25 | + | |
| 26 | + public ErrorCode(Integer code, String message) { | |
| 27 | + this.code = code; | |
| 28 | + this.message = message; | |
| 29 | + } | |
| 30 | + | |
| 31 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/exception/GlobalException.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.exception; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.EqualsAndHashCode; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 全局异常 Exception | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +@EqualsAndHashCode(callSuper = true) | |
| 12 | +public class GlobalException extends RuntimeException { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 全局错误码 | |
| 16 | + * | |
| 17 | + * @see GlobalErrorCodeConstants | |
| 18 | + */ | |
| 19 | + private Integer code; | |
| 20 | + /** | |
| 21 | + * 错误提示 | |
| 22 | + */ | |
| 23 | + private String message; | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 空构造方法,避免反序列化问题 | |
| 27 | + */ | |
| 28 | + public GlobalException() { | |
| 29 | + } | |
| 30 | + | |
| 31 | + public GlobalException(ErrorCode errorCode) { | |
| 32 | + this.code = errorCode.getCode(); | |
| 33 | + this.message = errorCode.getMessage(); | |
| 34 | + } | |
| 35 | + | |
| 36 | + public GlobalException(Integer code, String message) { | |
| 37 | + this.code = code; | |
| 38 | + this.message = message; | |
| 39 | + } | |
| 40 | + | |
| 41 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/exception/ServiceException.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.exception; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.exception.enums.ServiceErrorCodeRange; | |
| 4 | +import lombok.Data; | |
| 5 | +import lombok.EqualsAndHashCode; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * 业务逻辑异常 Exception | |
| 9 | + */ | |
| 10 | +@Data | |
| 11 | +@EqualsAndHashCode(callSuper = true) | |
| 12 | +public final class ServiceException extends RuntimeException { | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 业务错误码 | |
| 16 | + * | |
| 17 | + * @see ServiceErrorCodeRange | |
| 18 | + */ | |
| 19 | + private Integer code; | |
| 20 | + /** | |
| 21 | + * 错误提示 | |
| 22 | + */ | |
| 23 | + private String message; | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 空构造方法,避免反序列化问题 | |
| 27 | + */ | |
| 28 | + public ServiceException() { | |
| 29 | + } | |
| 30 | + | |
| 31 | + public ServiceException(ErrorCode errorCode) { | |
| 32 | + this.code = errorCode.getCode(); | |
| 33 | + this.message = errorCode.getMessage(); | |
| 34 | + } | |
| 35 | + | |
| 36 | + public ServiceException(Integer code, String message) { | |
| 37 | + this.code = code; | |
| 38 | + this.message = message; | |
| 39 | + } | |
| 40 | + | |
| 41 | + public Integer getCode() { | |
| 42 | + return code; | |
| 43 | + } | |
| 44 | + | |
| 45 | + public ServiceException setCode(Integer code) { | |
| 46 | + this.code = code; | |
| 47 | + return this; | |
| 48 | + } | |
| 49 | + | |
| 50 | + public String getMessage() { | |
| 51 | + return message; | |
| 52 | + } | |
| 53 | + | |
| 54 | + public ServiceException setMessage(String message) { | |
| 55 | + this.message = message; | |
| 56 | + return this; | |
| 57 | + } | |
| 58 | + | |
| 59 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/exception/enums/GlobalErrorCodeConstants.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.exception.enums; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.exception.ErrorCode; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 全局错误码枚举 | |
| 7 | + * 0-999 系统异常编码保留 | |
| 8 | + * | |
| 9 | + * 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status | |
| 10 | + * 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的 | |
| 11 | + * 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。 | |
| 12 | + * | |
| 13 | + * @author 芋道源码 | |
| 14 | + */ | |
| 15 | +public interface GlobalErrorCodeConstants { | |
| 16 | + | |
| 17 | + ErrorCode SUCCESS = new ErrorCode(0, "成功"); | |
| 18 | + | |
| 19 | + // ========== 客户端错误段 ========== | |
| 20 | + | |
| 21 | + ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确"); | |
| 22 | + ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录"); | |
| 23 | + ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限"); | |
| 24 | + ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到"); | |
| 25 | + ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确"); | |
| 26 | + | |
| 27 | + // ========== 服务端错误段 ========== | |
| 28 | + | |
| 29 | + ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常"); | |
| 30 | + | |
| 31 | + ErrorCode UNKNOWN = new ErrorCode(999, "未知错误"); | |
| 32 | + | |
| 33 | + static boolean isMatch(Integer code) { | |
| 34 | + return code != null | |
| 35 | + && code >= SUCCESS.getCode() && code <= UNKNOWN.getCode(); | |
| 36 | + } | |
| 37 | + | |
| 38 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/exception/enums/ServiceErrorCodeRange.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.exception.enums; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 业务异常的错误码区间,解决:解决各模块错误码定义,避免重复,在此只声明不做实际使用 | |
| 5 | + * | |
| 6 | + * 一共 10 位,分成四段 | |
| 7 | + * | |
| 8 | + * 第一段,1 位,类型 | |
| 9 | + * 1 - 业务级别异常 | |
| 10 | + * x - 预留 | |
| 11 | + * 第二段,3 位,系统类型 | |
| 12 | + * 001 - 用户系统 | |
| 13 | + * 002 - 商品系统 | |
| 14 | + * 003 - 订单系统 | |
| 15 | + * 004 - 支付系统 | |
| 16 | + * 005 - 优惠劵系统 | |
| 17 | + * ... - ... | |
| 18 | + * 第三段,3 位,模块 | |
| 19 | + * 不限制规则。 | |
| 20 | + * 一般建议,每个系统里面,可能有多个模块,可以再去做分段。以用户系统为例子: | |
| 21 | + * 001 - OAuth2 模块 | |
| 22 | + * 002 - User 模块 | |
| 23 | + * 003 - MobileCode 模块 | |
| 24 | + * 第四段,3 位,错误码 | |
| 25 | + * 不限制规则。 | |
| 26 | + * 一般建议,每个模块自增。 | |
| 27 | + * | |
| 28 | + * @author 芋道源码 | |
| 29 | + */ | |
| 30 | +public class ServiceErrorCodeRange { | |
| 31 | + | |
| 32 | + // 模块 system 错误码区间 [1-000-001-000 ~ 1-000-002-000] | |
| 33 | + | |
| 34 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/exception/util/ServiceExceptionUtil.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.exception.util; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.exception.ErrorCode; | |
| 4 | +import cn.iocoder.dashboard.common.exception.ServiceException; | |
| 5 | +import org.slf4j.Logger; | |
| 6 | +import org.slf4j.LoggerFactory; | |
| 7 | + | |
| 8 | +import java.util.Map; | |
| 9 | +import java.util.concurrent.ConcurrentHashMap; | |
| 10 | +import java.util.concurrent.ConcurrentMap; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * {@link ServiceException} 工具类 | |
| 14 | + * | |
| 15 | + * 目的在于,格式化异常信息提示。 | |
| 16 | + * 考虑到 String.format 在参数不正确时会报错,因此使用 {} 作为占位符,并使用 {@link #doFormat(int, String, Object...)} 方法来格式化 | |
| 17 | + * | |
| 18 | + * 因为 {@link #MESSAGES} 里面默认是没有异常信息提示的模板的,所以需要使用方自己初始化进去。目前想到的有几种方式: | |
| 19 | + * | |
| 20 | + * 1. 异常提示信息,写在枚举类中,例如说,cn.iocoder.oceans.user.api.constants.ErrorCodeEnum 类 + ServiceExceptionConfiguration | |
| 21 | + * 2. 异常提示信息,写在 .properties 等等配置文件 | |
| 22 | + * 3. 异常提示信息,写在 Apollo 等等配置中心中,从而实现可动态刷新 | |
| 23 | + * 4. 异常提示信息,存储在 db 等等数据库中,从而实现可动态刷新 | |
| 24 | + */ | |
| 25 | +public class ServiceExceptionUtil { | |
| 26 | + | |
| 27 | + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceExceptionUtil.class); | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 错误码提示模板 | |
| 31 | + */ | |
| 32 | + private static final ConcurrentMap<Integer, String> MESSAGES = new ConcurrentHashMap<>(); | |
| 33 | + | |
| 34 | + public static void putAll(Map<Integer, String> messages) { | |
| 35 | + ServiceExceptionUtil.MESSAGES.putAll(messages); | |
| 36 | + } | |
| 37 | + | |
| 38 | + public static void put(Integer code, String message) { | |
| 39 | + ServiceExceptionUtil.MESSAGES.put(code, message); | |
| 40 | + } | |
| 41 | + | |
| 42 | + public static void delete(Integer code, String message) { | |
| 43 | + ServiceExceptionUtil.MESSAGES.remove(code, message); | |
| 44 | + } | |
| 45 | + | |
| 46 | + // ========== 和 ServiceException 的集成 ========== | |
| 47 | + | |
| 48 | + public static ServiceException exception(ErrorCode errorCode) { | |
| 49 | + String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMessage()); | |
| 50 | + return exception0(errorCode.getCode(), messagePattern); | |
| 51 | + } | |
| 52 | + | |
| 53 | + public static ServiceException exception(ErrorCode errorCode, Object... params) { | |
| 54 | + String messagePattern = MESSAGES.getOrDefault(errorCode.getCode(), errorCode.getMessage()); | |
| 55 | + return exception0(errorCode.getCode(), messagePattern, params); | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** | |
| 59 | + * 创建指定编号的 ServiceException 的异常 | |
| 60 | + * | |
| 61 | + * @param code 编号 | |
| 62 | + * @return 异常 | |
| 63 | + */ | |
| 64 | + public static ServiceException exception(Integer code) { | |
| 65 | + return exception0(code, MESSAGES.get(code)); | |
| 66 | + } | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * 创建指定编号的 ServiceException 的异常 | |
| 70 | + * | |
| 71 | + * @param code 编号 | |
| 72 | + * @param params 消息提示的占位符对应的参数 | |
| 73 | + * @return 异常 | |
| 74 | + */ | |
| 75 | + public static ServiceException exception(Integer code, Object... params) { | |
| 76 | + return exception0(code, MESSAGES.get(code), params); | |
| 77 | + } | |
| 78 | + | |
| 79 | + public static ServiceException exception0(Integer code, String messagePattern, Object... params) { | |
| 80 | + String message = doFormat(code, messagePattern, params); | |
| 81 | + return new ServiceException(code, message); | |
| 82 | + } | |
| 83 | + | |
| 84 | + // ========== 格式化方法 ========== | |
| 85 | + | |
| 86 | + /** | |
| 87 | + * 将错误编号对应的消息使用 params 进行格式化。 | |
| 88 | + * | |
| 89 | + * @param code 错误编号 | |
| 90 | + * @param messagePattern 消息模版 | |
| 91 | + * @param params 参数 | |
| 92 | + * @return 格式化后的提示 | |
| 93 | + */ | |
| 94 | + private static String doFormat(int code, String messagePattern, Object... params) { | |
| 95 | + StringBuilder sbuf = new StringBuilder(messagePattern.length() + 50); | |
| 96 | + int i = 0; | |
| 97 | + int j; | |
| 98 | + int l; | |
| 99 | + for (l = 0; l < params.length; l++) { | |
| 100 | + j = messagePattern.indexOf("{}", i); | |
| 101 | + if (j == -1) { | |
| 102 | + LOGGER.error("[doFormat][参数过多:错误码({})|错误内容({})|参数({})", code, messagePattern, params); | |
| 103 | + if (i == 0) { | |
| 104 | + return messagePattern; | |
| 105 | + } else { | |
| 106 | + sbuf.append(messagePattern.substring(i, messagePattern.length())); | |
| 107 | + return sbuf.toString(); | |
| 108 | + } | |
| 109 | + } else { | |
| 110 | + sbuf.append(messagePattern.substring(i, j)); | |
| 111 | + sbuf.append(params[l]); | |
| 112 | + i = j + 2; | |
| 113 | + } | |
| 114 | + } | |
| 115 | + if (messagePattern.indexOf("{}", i) != -1) { | |
| 116 | + LOGGER.error("[doFormat][参数过少:错误码({})|错误内容({})|参数({})", code, messagePattern, params); | |
| 117 | + } | |
| 118 | + sbuf.append(messagePattern.substring(i, messagePattern.length())); | |
| 119 | + return sbuf.toString(); | |
| 120 | + } | |
| 121 | + | |
| 122 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/package-info.java
0 → 100644
src/main/java/cn/iocoder/dashboard/common/pojo/CommonResult.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.pojo; | |
| 2 | + | |
| 3 | +import cn.iocoder.dashboard.common.exception.ErrorCode; | |
| 4 | +import cn.iocoder.dashboard.common.exception.GlobalException; | |
| 5 | +import cn.iocoder.dashboard.common.exception.ServiceException; | |
| 6 | +import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants; | |
| 7 | +import com.alibaba.fastjson.annotation.JSONField; | |
| 8 | +import lombok.Data; | |
| 9 | +import org.springframework.util.Assert; | |
| 10 | + | |
| 11 | +import java.io.Serializable; | |
| 12 | + | |
| 13 | +/** | |
| 14 | + * 通用返回 | |
| 15 | + * | |
| 16 | + * @param <T> 数据泛型 | |
| 17 | + */ | |
| 18 | +@Data | |
| 19 | +public final class CommonResult<T> implements Serializable { | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 错误码 | |
| 23 | + * | |
| 24 | + * @see ErrorCode#getCode() | |
| 25 | + */ | |
| 26 | + private Integer code; | |
| 27 | + /** | |
| 28 | + * 返回数据 | |
| 29 | + */ | |
| 30 | + private T data; | |
| 31 | + /** | |
| 32 | + * 错误提示,用户可阅读 | |
| 33 | + * | |
| 34 | + * @see ErrorCode#getMessage() () | |
| 35 | + */ | |
| 36 | + private String msg; | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 将传入的 result 对象,转换成另外一个泛型结果的对象 | |
| 40 | + * | |
| 41 | + * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。 | |
| 42 | + * | |
| 43 | + * @param result 传入的 result 对象 | |
| 44 | + * @param <T> 返回的泛型 | |
| 45 | + * @return 新的 CommonResult 对象 | |
| 46 | + */ | |
| 47 | + public static <T> CommonResult<T> error(CommonResult<?> result) { | |
| 48 | + return error(result.getCode(), result.getMsg()); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public static <T> CommonResult<T> error(Integer code, String message) { | |
| 52 | + Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code), "code 必须是错误的!"); | |
| 53 | + CommonResult<T> result = new CommonResult<>(); | |
| 54 | + result.code = code; | |
| 55 | + result.msg = message; | |
| 56 | + return result; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public static <T> CommonResult<T> error(ErrorCode errorCode) { | |
| 60 | + return error(errorCode.getCode(), errorCode.getMessage()); | |
| 61 | + } | |
| 62 | + | |
| 63 | + public static <T> CommonResult<T> success(T data) { | |
| 64 | + CommonResult<T> result = new CommonResult<>(); | |
| 65 | + result.code = GlobalErrorCodeConstants.SUCCESS.getCode(); | |
| 66 | + result.data = data; | |
| 67 | + result.msg = ""; | |
| 68 | + return result; | |
| 69 | + } | |
| 70 | + | |
| 71 | + @JSONField(serialize = false) // 避免序列化 | |
| 72 | + public boolean isSuccess() { | |
| 73 | + return GlobalErrorCodeConstants.SUCCESS.getCode().equals(code); | |
| 74 | + } | |
| 75 | + | |
| 76 | + @JSONField(serialize = false) // 避免序列化 | |
| 77 | + public boolean isError() { | |
| 78 | + return !isSuccess(); | |
| 79 | + } | |
| 80 | + | |
| 81 | + // ========= 和 Exception 异常体系集成 ========= | |
| 82 | + | |
| 83 | + /** | |
| 84 | + * 判断是否有异常。如果有,则抛出 {@link GlobalException} 或 {@link ServiceException} 异常 | |
| 85 | + */ | |
| 86 | + public void checkError() throws GlobalException, ServiceException { | |
| 87 | + if (isSuccess()) { | |
| 88 | + return; | |
| 89 | + } | |
| 90 | + // 全局异常 | |
| 91 | + if (GlobalErrorCodeConstants.isMatch(code)) { | |
| 92 | + throw new GlobalException(code, msg); | |
| 93 | + } | |
| 94 | + // 业务异常 | |
| 95 | + throw new ServiceException(code, msg); | |
| 96 | + } | |
| 97 | + | |
| 98 | + public static <T> CommonResult<T> error(ServiceException serviceException) { | |
| 99 | + return error(serviceException.getCode(), serviceException.getMessage()); | |
| 100 | + } | |
| 101 | + | |
| 102 | + public static <T> CommonResult<T> error(GlobalException globalException) { | |
| 103 | + return error(globalException.getCode(), globalException.getMessage()); | |
| 104 | + } | |
| 105 | + | |
| 106 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/pojo/PageParam.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.pojo; | |
| 2 | + | |
| 3 | +import io.swagger.annotations.ApiModel; | |
| 4 | +import io.swagger.annotations.ApiModelProperty; | |
| 5 | +import lombok.Data; | |
| 6 | +import org.hibernate.validator.constraints.Range; | |
| 7 | + | |
| 8 | +import javax.validation.constraints.Min; | |
| 9 | +import javax.validation.constraints.NotNull; | |
| 10 | +import java.io.Serializable; | |
| 11 | + | |
| 12 | +@ApiModel("分页参数") | |
| 13 | +@Data | |
| 14 | +public class PageParam implements Serializable { | |
| 15 | + | |
| 16 | + @ApiModelProperty(value = "页码,从 1 开始", required = true,example = "1") | |
| 17 | + @NotNull(message = "页码不能为空") | |
| 18 | + @Min(value = 1, message = "页码最小值为 1") | |
| 19 | + private Integer pageNo; | |
| 20 | + | |
| 21 | + @ApiModelProperty(value = "每页条数,最大值为 100", required = true, example = "10") | |
| 22 | + @NotNull(message = "每页条数不能为空") | |
| 23 | + @Range(min = 1, max = 100, message = "条数范围为 [1, 100]") | |
| 24 | + private Integer pageSize; | |
| 25 | + | |
| 26 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/pojo/PageResult.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.pojo; | |
| 2 | + | |
| 3 | +import io.swagger.annotations.ApiModel; | |
| 4 | +import io.swagger.annotations.ApiModelProperty; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +import java.io.Serializable; | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 10 | +@ApiModel("分页结果") | |
| 11 | +@Data | |
| 12 | +public final class PageResult<T> implements Serializable { | |
| 13 | + | |
| 14 | + @ApiModelProperty(value = "数据", required = true) | |
| 15 | + private List<T> list; | |
| 16 | + | |
| 17 | + @ApiModelProperty(value = "总量", required = true) | |
| 18 | + private Long total; | |
| 19 | + | |
| 20 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/common/pojo/SortingField.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.common.pojo; | |
| 2 | + | |
| 3 | +import java.io.Serializable; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 排序字段 DTO | |
| 7 | + * | |
| 8 | + * 类名加了 ing 的原因是,避免和 ES SortField 重名。 | |
| 9 | + */ | |
| 10 | +public class SortingField implements Serializable { | |
| 11 | + | |
| 12 | + /** | |
| 13 | + * 顺序 - 升序 | |
| 14 | + */ | |
| 15 | + public static final String ORDER_ASC = "asc"; | |
| 16 | + /** | |
| 17 | + * 顺序 - 降序 | |
| 18 | + */ | |
| 19 | + public static final String ORDER_DESC = "desc"; | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 字段 | |
| 23 | + */ | |
| 24 | + private String field; | |
| 25 | + /** | |
| 26 | + * 顺序 | |
| 27 | + */ | |
| 28 | + private String order; | |
| 29 | + | |
| 30 | + // 空构造方法,解决反序列化 | |
| 31 | + public SortingField() { | |
| 32 | + } | |
| 33 | + | |
| 34 | + public SortingField(String field, String order) { | |
| 35 | + this.field = field; | |
| 36 | + this.order = order; | |
| 37 | + } | |
| 38 | + | |
| 39 | + public String getField() { | |
| 40 | + return field; | |
| 41 | + } | |
| 42 | + | |
| 43 | + public SortingField setField(String field) { | |
| 44 | + this.field = field; | |
| 45 | + return this; | |
| 46 | + } | |
| 47 | + | |
| 48 | + public String getOrder() { | |
| 49 | + return order; | |
| 50 | + } | |
| 51 | + | |
| 52 | + public SortingField setOrder(String order) { | |
| 53 | + this.order = order; | |
| 54 | + return this; | |
| 55 | + } | |
| 56 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/util/collection/CollectionUtils.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.util.collection; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollectionUtil; | |
| 4 | + | |
| 5 | +import java.util.*; | |
| 6 | +import java.util.function.Function; | |
| 7 | +import java.util.stream.Collectors; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * Collection 工具类 | |
| 11 | + * | |
| 12 | + * @author 芋道源码 | |
| 13 | + */ | |
| 14 | +public class CollectionUtils { | |
| 15 | + | |
| 16 | + public static <T> Set<T> asSet(T... objs) { | |
| 17 | + return new HashSet<>(Arrays.asList(objs)); | |
| 18 | + } | |
| 19 | + | |
| 20 | + public static <T, U> List<U> convertList(List<T> from, Function<T, U> func) { | |
| 21 | + return from.stream().map(func).collect(Collectors.toList()); | |
| 22 | + } | |
| 23 | + | |
| 24 | + public static <T, U> Set<U> convertSet(List<T> from, Function<T, U> func) { | |
| 25 | + return from.stream().map(func).collect(Collectors.toSet()); | |
| 26 | + } | |
| 27 | + | |
| 28 | + public static <T, K> Map<K, T> convertMap(List<T> from, Function<T, K> keyFunc) { | |
| 29 | + return from.stream().collect(Collectors.toMap(keyFunc, item -> item)); | |
| 30 | + } | |
| 31 | + | |
| 32 | + public static <T, K, V> Map<K, V> convertMap(List<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { | |
| 33 | + return from.stream().collect(Collectors.toMap(keyFunc, valueFunc)); | |
| 34 | + } | |
| 35 | + | |
| 36 | + public static <T, K> Map<K, List<T>> convertMultiMap(List<T> from, Function<T, K> keyFunc) { | |
| 37 | + return from.stream().collect(Collectors.groupingBy(keyFunc, | |
| 38 | + Collectors.mapping(t -> t, Collectors.toList()))); | |
| 39 | + } | |
| 40 | + | |
| 41 | + public static <T, K, V> Map<K, List<V>> convertMultiMap(List<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { | |
| 42 | + return from.stream().collect(Collectors.groupingBy(keyFunc, | |
| 43 | + Collectors.mapping(valueFunc, Collectors.toList()))); | |
| 44 | + } | |
| 45 | + | |
| 46 | + // 暂时没想好名字,先以 2 结尾噶 | |
| 47 | + public static <T, K, V> Map<K, Set<V>> convertMultiMap2(List<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) { | |
| 48 | + return from.stream().collect(Collectors.groupingBy(keyFunc, Collectors.mapping(valueFunc, Collectors.toSet()))); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public static boolean containsAny(Collection<?> source, Collection<?> candidates) { | |
| 52 | + return org.springframework.util.CollectionUtils.containsAny(source, candidates); | |
| 53 | + } | |
| 54 | + | |
| 55 | + public static <T> T getFirst(List<T> from) { | |
| 56 | + return !CollectionUtil.isEmpty(from) ? from.get(0) : null; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public static <T> void addIfNotNull(Collection<T> coll, T item) { | |
| 60 | + if (item == null) { | |
| 61 | + return; | |
| 62 | + } | |
| 63 | + coll.add(item); | |
| 64 | + } | |
| 65 | + | |
| 66 | +} | ... | ... |
src/main/java/cn/iocoder/dashboard/util/collection/MapUtils.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.util.collection; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollectionUtil; | |
| 4 | +import com.google.common.collect.Multimap; | |
| 5 | + | |
| 6 | +import java.util.ArrayList; | |
| 7 | +import java.util.Collection; | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * Map 工具类 | |
| 12 | + * | |
| 13 | + * @author 芋道源码 | |
| 14 | + */ | |
| 15 | +public class MapUtils { | |
| 16 | + | |
| 17 | + public static <K, V> List<V> getList(Multimap<K, V> multimap, Collection<K> keys) { | |
| 18 | + List<V> result = new ArrayList<>(); | |
| 19 | + keys.forEach(k -> { | |
| 20 | + Collection<V> values = multimap.get(k); | |
| 21 | + if (CollectionUtil.isEmpty(values)) { | |
| 22 | + return; | |
| 23 | + } | |
| 24 | + result.addAll(values); | |
| 25 | + }); | |
| 26 | + return result; | |
| 27 | + } | |
| 28 | + | |
| 29 | +} | ... | ... |