ycl-common/pom.xml
@@ -43,7 +43,10 @@ <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-core</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> </project> ycl-common/src/main/java/annotation/Excel.java
File was renamed from ycl-server/src/main/java/com/ycl/annotation/Excel.java @@ -1,8 +1,8 @@ package com.ycl.annotation; package annotation; import com.ycl.utils.poi.ExcelHandlerAdapter; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.IndexedColors; import utils.poi.ExcelHandlerAdapter; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; ycl-common/src/main/java/annotation/Excels.java
File was renamed from ycl-server/src/main/java/com/ycl/annotation/Excels.java @@ -1,4 +1,4 @@ package com.ycl.annotation; package annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; ycl-common/src/main/java/config/PlatformConfig.java
New file @@ -0,0 +1,122 @@ package config; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * 读取项目相关配置 * * @author platform */ @Component @ConfigurationProperties(prefix = "platform") public class PlatformConfig { /** 项目名称 */ private String name; /** 版本 */ private String version; /** 版权年份 */ private String copyrightYear; /** 上传路径 */ private static String profile; /** 获取地址开关 */ private static boolean addressEnabled; /** 验证码类型 */ private static String captchaType; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getCopyrightYear() { return copyrightYear; } public void setCopyrightYear(String copyrightYear) { this.copyrightYear = copyrightYear; } public static String getProfile() { return profile; } public void setProfile(String profile) { PlatformConfig.profile = profile; } public static boolean isAddressEnabled() { return addressEnabled; } public void setAddressEnabled(boolean addressEnabled) { PlatformConfig.addressEnabled = addressEnabled; } public static String getCaptchaType() { return captchaType; } public void setCaptchaType(String captchaType) { PlatformConfig.captchaType = captchaType; } /** * 获取导入上传路径 */ public static String getImportPath() { return getProfile() + "/import"; } /** * 获取头像上传路径 */ public static String getAvatarPath() { return getProfile() + "/avatar"; } /** * 获取下载路径 */ public static String getDownloadPath() { return getProfile() + "/download/"; } /** * 获取上传路径 */ public static String getUploadPath() { return getProfile() + "/upload"; } } ycl-common/src/main/java/exception/DemoModeException.java
New file @@ -0,0 +1,15 @@ package exception; /** * 演示模式异常 * * @author ruoyi */ public class DemoModeException extends RuntimeException { private static final long serialVersionUID = 1L; public DemoModeException() { } } ycl-common/src/main/java/exception/GlobalException.java
New file @@ -0,0 +1,58 @@ package exception; /** * 全局异常 * * @author ruoyi */ public class GlobalException extends RuntimeException { private static final long serialVersionUID = 1L; /** * 错误提示 */ private String message; /** * 错误明细,内部调试错误 * * 和 {@link CommonResult#getDetailMessage()} 一致的设计 */ private String detailMessage; /** * 空构造方法,避免反序列化问题 */ public GlobalException() { } public GlobalException(String message) { this.message = message; } public String getDetailMessage() { return detailMessage; } public GlobalException setDetailMessage(String detailMessage) { this.detailMessage = detailMessage; return this; } @Override public String getMessage() { return message; } public GlobalException setMessage(String message) { this.message = message; return this; } } ycl-common/src/main/java/exception/ServiceException.java
New file @@ -0,0 +1,74 @@ package exception; /** * 业务异常 * * @author ruoyi */ public final class ServiceException extends RuntimeException { private static final long serialVersionUID = 1L; /** * 错误码 */ private Integer code; /** * 错误提示 */ private String message; /** * 错误明细,内部调试错误 * * 和 {@link CommonResult#getDetailMessage()} 一致的设计 */ private String detailMessage; /** * 空构造方法,避免反序列化问题 */ public ServiceException() { } public ServiceException(String message) { this.message = message; } public ServiceException(String message, Integer code) { this.message = message; this.code = code; } public String getDetailMessage() { return detailMessage; } @Override public String getMessage() { return message; } public Integer getCode() { return code; } public ServiceException setMessage(String message) { this.message = message; return this; } public ServiceException setDetailMessage(String detailMessage) { this.detailMessage = detailMessage; return this; } } ycl-common/src/main/java/exception/UtilException.java
New file @@ -0,0 +1,26 @@ package exception; /** * 工具类异常 * * @author ruoyi */ public class UtilException extends RuntimeException { private static final long serialVersionUID = 8247610319171014183L; public UtilException(Throwable e) { super(e.getMessage(), e); } public UtilException(String message) { super(message); } public UtilException(String message, Throwable throwable) { super(message, throwable); } } ycl-common/src/main/java/exception/base/BaseException.java
New file @@ -0,0 +1,97 @@ package exception.base; import utils.MessageUtils; import utils.StringUtils; /** * 基础异常 * * @author ruoyi */ public class BaseException extends RuntimeException { private static final long serialVersionUID = 1L; /** * 所属模块 */ private String module; /** * 错误码 */ private String code; /** * 错误码对应的参数 */ private Object[] args; /** * 错误消息 */ private String defaultMessage; public BaseException(String module, String code, Object[] args, String defaultMessage) { this.module = module; this.code = code; this.args = args; this.defaultMessage = defaultMessage; } public BaseException(String module, String code, Object[] args) { this(module, code, args, null); } public BaseException(String module, String defaultMessage) { this(module, null, null, defaultMessage); } public BaseException(String code, Object[] args) { this(null, code, args, null); } public BaseException(String defaultMessage) { this(null, null, null, defaultMessage); } @Override public String getMessage() { String message = null; if (!StringUtils.isEmpty(code)) { message = MessageUtils.message(code, args); } if (message == null) { message = defaultMessage; } return message; } public String getModule() { return module; } public String getCode() { return code; } public Object[] getArgs() { return args; } public String getDefaultMessage() { return defaultMessage; } } ycl-common/src/main/java/exception/file/FileException.java
New file @@ -0,0 +1,19 @@ package exception.file; import exception.base.BaseException; /** * 文件信息异常类 * * @author ruoyi */ public class FileException extends BaseException { private static final long serialVersionUID = 1L; public FileException(String code, Object[] args) { super("file", code, args, null); } } ycl-common/src/main/java/exception/file/FileNameLengthLimitExceededException.java
New file @@ -0,0 +1,16 @@ package exception.file; /** * 文件名称超长限制异常类 * * @author ruoyi */ public class FileNameLengthLimitExceededException extends FileException { private static final long serialVersionUID = 1L; public FileNameLengthLimitExceededException(int defaultFileNameLength) { super("upload.filename.exceed.length", new Object[] { defaultFileNameLength }); } } ycl-common/src/main/java/exception/file/FileSizeLimitExceededException.java
New file @@ -0,0 +1,16 @@ package exception.file; /** * 文件名大小限制异常类 * * @author ruoyi */ public class FileSizeLimitExceededException extends FileException { private static final long serialVersionUID = 1L; public FileSizeLimitExceededException(long defaultMaxSize) { super("upload.exceed.maxSize", new Object[] { defaultMaxSize }); } } ycl-common/src/main/java/exception/file/FileUploadException.java
New file @@ -0,0 +1,61 @@ package exception.file; import java.io.PrintStream; import java.io.PrintWriter; /** * 文件上传异常类 * * @author ruoyi */ public class FileUploadException extends Exception { private static final long serialVersionUID = 1L; private final Throwable cause; public FileUploadException() { this(null, null); } public FileUploadException(final String msg) { this(msg, null); } public FileUploadException(String msg, Throwable cause) { super(msg); this.cause = cause; } @Override public void printStackTrace(PrintStream stream) { super.printStackTrace(stream); if (cause != null) { stream.println("Caused by:"); cause.printStackTrace(stream); } } @Override public void printStackTrace(PrintWriter writer) { super.printStackTrace(writer); if (cause != null) { writer.println("Caused by:"); cause.printStackTrace(writer); } } @Override public Throwable getCause() { return cause; } } ycl-common/src/main/java/exception/file/InvalidExtensionException.java
New file @@ -0,0 +1,80 @@ package exception.file; import java.util.Arrays; /** * 文件上传 误异常类 * * @author ruoyi */ public class InvalidExtensionException extends FileUploadException { private static final long serialVersionUID = 1L; private String[] allowedExtension; private String extension; private String filename; public InvalidExtensionException(String[] allowedExtension, String extension, String filename) { super("文件[" + filename + "]后缀[" + extension + "]不正确,请上传" + Arrays.toString(allowedExtension) + "格式"); this.allowedExtension = allowedExtension; this.extension = extension; this.filename = filename; } public String[] getAllowedExtension() { return allowedExtension; } public String getExtension() { return extension; } public String getFilename() { return filename; } public static class InvalidImageExtensionException extends InvalidExtensionException { private static final long serialVersionUID = 1L; public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename) { super(allowedExtension, extension, filename); } } public static class InvalidFlashExtensionException extends InvalidExtensionException { private static final long serialVersionUID = 1L; public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename) { super(allowedExtension, extension, filename); } } public static class InvalidMediaExtensionException extends InvalidExtensionException { private static final long serialVersionUID = 1L; public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename) { super(allowedExtension, extension, filename); } } public static class InvalidVideoExtensionException extends InvalidExtensionException { private static final long serialVersionUID = 1L; public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename) { super(allowedExtension, extension, filename); } } } ycl-common/src/main/java/exception/job/TaskException.java
New file @@ -0,0 +1,34 @@ package exception.job; /** * 计划策略异常 * * @author ruoyi */ public class TaskException extends Exception { private static final long serialVersionUID = 1L; private Code code; public TaskException(String msg, Code code) { this(msg, code, null); } public TaskException(String msg, Code code, Exception nestedEx) { super(msg, nestedEx); this.code = code; } public Code getCode() { return code; } public enum Code { TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE } } ycl-common/src/main/java/exception/user/BlackListException.java
New file @@ -0,0 +1,16 @@ package exception.user; /** * 黑名单IP异常类 * * @author ruoyi */ public class BlackListException extends UserException { private static final long serialVersionUID = 1L; public BlackListException() { super("login.blocked", null); } } ycl-common/src/main/java/exception/user/CaptchaException.java
New file @@ -0,0 +1,16 @@ package exception.user; /** * 验证码错误异常类 * * @author ruoyi */ public class CaptchaException extends UserException { private static final long serialVersionUID = 1L; public CaptchaException() { super("user.jcaptcha.error", null); } } ycl-common/src/main/java/exception/user/CaptchaExpireException.java
New file @@ -0,0 +1,16 @@ package exception.user; /** * 验证码失效异常类 * * @author ruoyi */ public class CaptchaExpireException extends UserException { private static final long serialVersionUID = 1L; public CaptchaExpireException() { super("user.jcaptcha.expire", null); } } ycl-common/src/main/java/exception/user/UserException.java
New file @@ -0,0 +1,18 @@ package exception.user; import exception.base.BaseException; /** * 用户信息异常类 * * @author ruoyi */ public class UserException extends BaseException { private static final long serialVersionUID = 1L; public UserException(String code, Object[] args) { super("user", code, args, null); } } ycl-common/src/main/java/exception/user/UserNotExistsException.java
New file @@ -0,0 +1,16 @@ package exception.user; /** * 用户不存在异常类 * * @author ruoyi */ public class UserNotExistsException extends UserException { private static final long serialVersionUID = 1L; public UserNotExistsException() { super("user.not.exists", null); } } ycl-common/src/main/java/exception/user/UserPasswordNotMatchException.java
New file @@ -0,0 +1,16 @@ package exception.user; /** * 用户密码不正确或不符合规范异常类 * * @author ruoyi */ public class UserPasswordNotMatchException extends UserException { private static final long serialVersionUID = 1L; public UserPasswordNotMatchException() { super("user.password.not.match", null); } } ycl-common/src/main/java/exception/user/UserPasswordRetryLimitExceedException.java
New file @@ -0,0 +1,16 @@ package exception.user; /** * 用户错误最大次数异常类 * * @author ruoyi */ public class UserPasswordRetryLimitExceedException extends UserException { private static final long serialVersionUID = 1L; public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime) { super("user.password.retry.limit.exceed", new Object[] { retryLimitCount, lockTime }); } } ycl-common/src/main/java/pojo/AjaxResult.java
New file @@ -0,0 +1,217 @@ package pojo; import constant.HttpStatus; import utils.StringUtils; import java.util.HashMap; import java.util.Objects; /** * 操作消息提醒 * * @author ruoyi */ public class AjaxResult extends HashMap<String, Object> { private static final long serialVersionUID = 1L; /** 状态码 */ public static final String CODE_TAG = "code"; /** 返回内容 */ public static final String MSG_TAG = "msg"; /** 数据对象 */ public static final String DATA_TAG = "data"; /** * 初始化一个新创建的 pojo.AjaxResult 对象,使其表示一个空消息。 */ public AjaxResult() { } /** * 初始化一个新创建的 pojo.AjaxResult 对象 * * @param code 状态码 * @param msg 返回内容 */ public AjaxResult(int code, String msg) { super.put(CODE_TAG, code); super.put(MSG_TAG, msg); } /** * 初始化一个新创建的 pojo.AjaxResult 对象 * * @param code 状态码 * @param msg 返回内容 * @param data 数据对象 */ public AjaxResult(int code, String msg, Object data) { super.put(CODE_TAG, code); super.put(MSG_TAG, msg); if (StringUtils.isNotNull(data)) { super.put(DATA_TAG, data); } } /** * 返回成功消息 * * @return 成功消息 */ public static AjaxResult success() { return AjaxResult.success("操作成功"); } /** * 返回成功数据 * * @return 成功消息 */ public static AjaxResult success(Object data) { return AjaxResult.success("操作成功", data); } /** * 返回成功消息 * * @param msg 返回内容 * @return 成功消息 */ public static AjaxResult success(String msg) { return AjaxResult.success(msg, null); } /** * 返回成功消息 * * @param msg 返回内容 * @param data 数据对象 * @return 成功消息 */ public static AjaxResult success(String msg, Object data) { return new AjaxResult(HttpStatus.SUCCESS, msg, data); } /** * 返回警告消息 * * @param msg 返回内容 * @return 警告消息 */ public static AjaxResult warn(String msg) { return AjaxResult.warn(msg, null); } /** * 返回警告消息 * * @param msg 返回内容 * @param data 数据对象 * @return 警告消息 */ public static AjaxResult warn(String msg, Object data) { return new AjaxResult(HttpStatus.WARN, msg, data); } /** * 返回错误消息 * * @return 错误消息 */ public static AjaxResult error() { return AjaxResult.error("操作失败"); } /** * 返回错误消息 * * @param msg 返回内容 * @return 错误消息 */ public static AjaxResult error(String msg) { return AjaxResult.error(msg, null); } /** * 返回错误消息 * * @param msg 返回内容 * @param data 数据对象 * @return 错误消息 */ public static AjaxResult error(String msg, Object data) { return new AjaxResult(HttpStatus.ERROR, msg, data); } /** * 返回错误消息 * * @param code 状态码 * @param msg 返回内容 * @return 错误消息 */ public static AjaxResult error(int code, String msg) { return new AjaxResult(code, msg, null); } /** * 是否为成功消息 * * @return 结果 */ public boolean isSuccess() { return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG)); } /** * 是否为警告消息 * * @return 结果 */ public boolean isWarn() { return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG)); } /** * 是否为错误消息 * * @return 结果 */ public boolean isError() { return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG)); } /** * 方便链式调用 * * @param key 键 * @param value 值 * @return 数据对象 */ @Override public AjaxResult put(String key, Object value) { super.put(key, value); return this; } } ycl-common/src/main/java/pojo/BaseEntity.java
New file @@ -0,0 +1,119 @@ package pojo; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * Entity基类 * * @author ruoyi */ public class BaseEntity implements Serializable { private static final long serialVersionUID = 1L; /** 搜索值 */ @JsonIgnore private String searchValue; /** 创建者 */ private String createBy; /** 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; /** 更新者 */ private String updateBy; /** 更新时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; /** 备注 */ private String remark; /** 请求参数 */ @JsonInclude(JsonInclude.Include.NON_EMPTY) private Map<String, Object> params; public String getSearchValue() { return searchValue; } public void setSearchValue(String searchValue) { this.searchValue = searchValue; } public String getCreateBy() { return createBy; } public void setCreateBy(String createBy) { this.createBy = createBy; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getUpdateBy() { return updateBy; } public void setUpdateBy(String updateBy) { this.updateBy = updateBy; } public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public Map<String, Object> getParams() { if (params == null) { params = new HashMap<>(); } return params; } public void setParams(Map<String, Object> params) { this.params = params; } } ycl-common/src/main/java/pojo/SysDictData.java
New file @@ -0,0 +1,167 @@ package pojo; import constant.UserConstants; import jakarta.validation.constraints.NotBlank; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import javax.validation.constraints.Size; /** * 字典数据表 sys_dict_data * * @author ruoyi */ public class SysDictData extends BaseEntity { private static final long serialVersionUID = 1L; /** 字典编码 */ private Long dictCode; /** 字典排序 */ private Long dictSort; /** 字典标签 */ private String dictLabel; /** 字典键值 */ private String dictValue; /** 字典类型 */ private String dictType; /** 样式属性(其他样式扩展) */ private String cssClass; /** 表格字典样式 */ private String listClass; /** 是否默认(Y是 N否) */ private String isDefault; /** 状态(0正常 1停用) */ private String status; public Long getDictCode() { return dictCode; } public void setDictCode(Long dictCode) { this.dictCode = dictCode; } public Long getDictSort() { return dictSort; } public void setDictSort(Long dictSort) { this.dictSort = dictSort; } @NotBlank(message = "字典标签不能为空") @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符") public String getDictLabel() { return dictLabel; } public void setDictLabel(String dictLabel) { this.dictLabel = dictLabel; } @NotBlank(message = "字典键值不能为空") @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符") public String getDictValue() { return dictValue; } public void setDictValue(String dictValue) { this.dictValue = dictValue; } @NotBlank(message = "字典类型不能为空") @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符") public String getDictType() { return dictType; } public void setDictType(String dictType) { this.dictType = dictType; } @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符") public String getCssClass() { return cssClass; } public void setCssClass(String cssClass) { this.cssClass = cssClass; } public String getListClass() { return listClass; } public void setListClass(String listClass) { this.listClass = listClass; } public boolean getDefault() { return UserConstants.YES.equals(this.isDefault); } public String getIsDefault() { return isDefault; } public void setIsDefault(String isDefault) { this.isDefault = isDefault; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) .append("dictCode", getDictCode()) .append("dictSort", getDictSort()) .append("dictLabel", getDictLabel()) .append("dictValue", getDictValue()) .append("dictType", getDictType()) .append("cssClass", getCssClass()) .append("listClass", getListClass()) .append("isDefault", getIsDefault()) .append("status", getStatus()) .append("createBy", getCreateBy()) .append("createTime", getCreateTime()) .append("updateBy", getUpdateBy()) .append("updateTime", getUpdateTime()) .append("remark", getRemark()) .toString(); } } ycl-common/src/main/java/utils/DictUtils.java
New file @@ -0,0 +1,186 @@ package utils; import com.alibaba.fastjson2.JSONArray; import constant.CacheConstants; import pojo.SysDictData; import utils.redis.RedisCache; import java.util.Collection; import java.util.List; /** * 字典工具类 * * @author ruoyi */ public class DictUtils { /** * 分隔符 */ public static final String SEPARATOR = ","; /** * 设置字典缓存 * * @param key 参数键 * @param dictDatas 字典数据列表 */ public static void setDictCache(String key, List<SysDictData> dictDatas) { SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas); } /** * 获取字典缓存 * * @param key 参数键 * @return dictDatas 字典数据列表 */ public static List<SysDictData> getDictCache(String key) { JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key)); if (StringUtils.isNotNull(arrayCache)) { return arrayCache.toList(SysDictData.class); } return null; } /** * 根据字典类型和字典值获取字典标签 * * @param dictType 字典类型 * @param dictValue 字典值 * @return 字典标签 */ public static String getDictLabel(String dictType, String dictValue) { return getDictLabel(dictType, dictValue, SEPARATOR); } /** * 根据字典类型和字典标签获取字典值 * * @param dictType 字典类型 * @param dictLabel 字典标签 * @return 字典值 */ public static String getDictValue(String dictType, String dictLabel) { return getDictValue(dictType, dictLabel, SEPARATOR); } /** * 根据字典类型和字典值获取字典标签 * * @param dictType 字典类型 * @param dictValue 字典值 * @param separator 分隔符 * @return 字典标签 */ public static String getDictLabel(String dictType, String dictValue, String separator) { StringBuilder propertyString = new StringBuilder(); List<SysDictData> datas = getDictCache(dictType); if (StringUtils.isNotNull(datas)) { if (StringUtils.containsAny(separator, dictValue)) { for (SysDictData dict : datas) { for (String value : dictValue.split(separator)) { if (value.equals(dict.getDictValue())) { propertyString.append(dict.getDictLabel()).append(separator); break; } } } } else { for (SysDictData dict : datas) { if (dictValue.equals(dict.getDictValue())) { return dict.getDictLabel(); } } } } return StringUtils.stripEnd(propertyString.toString(), separator); } /** * 根据字典类型和字典标签获取字典值 * * @param dictType 字典类型 * @param dictLabel 字典标签 * @param separator 分隔符 * @return 字典值 */ public static String getDictValue(String dictType, String dictLabel, String separator) { StringBuilder propertyString = new StringBuilder(); List<SysDictData> datas = getDictCache(dictType); if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) { for (SysDictData dict : datas) { for (String label : dictLabel.split(separator)) { if (label.equals(dict.getDictLabel())) { propertyString.append(dict.getDictValue()).append(separator); break; } } } } else { for (SysDictData dict : datas) { if (dictLabel.equals(dict.getDictLabel())) { return dict.getDictValue(); } } } return StringUtils.stripEnd(propertyString.toString(), separator); } /** * 删除指定字典缓存 * * @param key 字典键 */ public static void removeDictCache(String key) { SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key)); } /** * 清空字典缓存 */ public static void clearDictCache() { Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*"); SpringUtils.getBean(RedisCache.class).deleteObject(keys); } /** * 设置cache key * * @param configKey 参数键 * @return 缓存键key */ public static String getCacheKey(String configKey) { return CacheConstants.SYS_DICT_KEY + configKey; } } ycl-common/src/main/java/utils/MessageUtils.java
New file @@ -0,0 +1,25 @@ package utils; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; /** * 获取i18n资源文件 * * @author ruoyi */ public class MessageUtils { /** * 根据消息键和参数 获取消息 委托给spring messageSource * * @param code 消息键 * @param args 参数 * @return 获取国际化翻译值 */ public static String message(String code, Object... args) { MessageSource messageSource = SpringUtils.getBean(MessageSource.class); return messageSource.getMessage(code, args, LocaleContextHolder.getLocale()); } } ycl-common/src/main/java/utils/SpringUtils.java
New file @@ -0,0 +1,157 @@ package utils; import org.springframework.aop.framework.AopContext; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * spring工具类 方便在非spring管理环境中获取bean * * @author ruoyi */ @Component public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware { /** Spring应用上下文环境 */ private static ConfigurableListableBeanFactory beanFactory; private static ApplicationContext applicationContext; @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { SpringUtils.beanFactory = beanFactory; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringUtils.applicationContext = applicationContext; } /** * 获取对象 * * @param name * @return Object 一个以所给名字注册的bean的实例 * @throws BeansException * */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) throws BeansException { return (T) beanFactory.getBean(name); } /** * 获取类型为requiredType的对象 * * @param clz * @return * @throws BeansException * */ public static <T> T getBean(Class<T> clz) throws BeansException { T result = (T) beanFactory.getBean(clz); return result; } /** * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true * * @param name * @return boolean */ public static boolean containsBean(String name) { return beanFactory.containsBean(name); } /** * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) * * @param name * @return boolean * @throws NoSuchBeanDefinitionException * */ public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { return beanFactory.isSingleton(name); } /** * @param name * @return Class 注册对象的类型 * @throws NoSuchBeanDefinitionException * */ public static Class<?> getType(String name) throws NoSuchBeanDefinitionException { return beanFactory.getType(name); } /** * 如果给定的bean名字在bean定义中有别名,则返回这些别名 * * @param name * @return * @throws NoSuchBeanDefinitionException * */ public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { return beanFactory.getAliases(name); } /** * 获取aop代理对象 * * @param invoker * @return */ @SuppressWarnings("unchecked") public static <T> T getAopProxy(T invoker) { return (T) AopContext.currentProxy(); } /** * 获取当前的环境配置,无配置返回null * * @return 当前的环境配置 */ public static String[] getActiveProfiles() { return applicationContext.getEnvironment().getActiveProfiles(); } /** * 获取当前的环境配置,当有多个环境配置时,只获取第一个 * * @return 当前的环境配置 */ public static String getActiveProfile() { final String[] activeProfiles = getActiveProfiles(); return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; } /** * 获取配置文件中的值 * * @param key 配置文件的key * @return 当前的配置文件的值 * */ public static String getRequiredProperty(String key) { return applicationContext.getEnvironment().getRequiredProperty(key); } } ycl-common/src/main/java/utils/file/FileTypeUtils.java
New file @@ -0,0 +1,77 @@ package utils.file; import org.apache.commons.lang3.StringUtils; import java.io.File; /** * 文件类型工具类 * * @author ruoyi */ public class FileTypeUtils { /** * 获取文件类型 * <p> * 例如: ruoyi.txt, 返回: txt * * @param file 文件名 * @return 后缀(不含".") */ public static String getFileType(File file) { if (null == file) { return StringUtils.EMPTY; } return getFileType(file.getName()); } /** * 获取文件类型 * <p> * 例如: ruoyi.txt, 返回: txt * * @param fileName 文件名 * @return 后缀(不含".") */ public static String getFileType(String fileName) { int separatorIndex = fileName.lastIndexOf("."); if (separatorIndex < 0) { return ""; } return fileName.substring(separatorIndex + 1).toLowerCase(); } /** * 获取文件类型 * * @param photoByte 文件字节码 * @return 后缀(不含".") */ public static String getFileExtendName(byte[] photoByte) { String strFileExtendName = "JPG"; if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) { strFileExtendName = "GIF"; } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) { strFileExtendName = "JPG"; } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) { strFileExtendName = "BMP"; } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) { strFileExtendName = "PNG"; } return strFileExtendName; } } ycl-common/src/main/java/utils/file/FileUploadUtils.java
New file @@ -0,0 +1,233 @@ package utils.file; import config.PlatformConfig; import constant.Constants; import exception.file.FileNameLengthLimitExceededException; import exception.file.FileSizeLimitExceededException; import exception.file.InvalidExtensionException; import org.apache.commons.io.FilenameUtils; import org.springframework.web.multipart.MultipartFile; import utils.DateUtils; import utils.StringUtils; import utils.uuid.Seq; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.util.Objects; /** * 文件上传工具类 * * @author ruoyi */ public class FileUploadUtils { /** * 默认大小 50M */ public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024; /** * 默认的文件名最大长度 100 */ public static final int DEFAULT_FILE_NAME_LENGTH = 100; /** * 默认上传的地址 */ private static String defaultBaseDir = PlatformConfig.getProfile(); public static void setDefaultBaseDir(String defaultBaseDir) { FileUploadUtils.defaultBaseDir = defaultBaseDir; } public static String getDefaultBaseDir() { return defaultBaseDir; } /** * 以默认配置进行文件上传 * * @param file 上传的文件 * @return 文件名称 * @throws Exception */ public static final String upload(MultipartFile file) throws IOException { try { return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 根据文件路径上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @return 文件名称 * @throws IOException */ public static final String upload(String baseDir, MultipartFile file) throws IOException { try { return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); } catch (Exception e) { throw new IOException(e.getMessage(), e); } } /** * 文件上传 * * @param baseDir 相对应用的基目录 * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 * @throws IOException 比如读写文件出错时 * @throws InvalidExtensionException 文件校验异常 */ public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length(); if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } assertAllowed(file, allowedExtension); String fileName = extractFilename(file); String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath(); file.transferTo(Paths.get(absPath)); return getPathFileName(baseDir, fileName); } /** * 编码文件名 */ public static final String extractFilename(MultipartFile file) { return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(), FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file)); } public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException { File desc = new File(uploadDir + File.separator + fileName); if (!desc.exists()) { if (!desc.getParentFile().exists()) { desc.getParentFile().mkdirs(); } } return desc; } public static final String getPathFileName(String uploadDir, String fileName) throws IOException { int dirLastIndex = PlatformConfig.getProfile().length() + 1; String currentDir = StringUtils.substring(uploadDir, dirLastIndex); return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; } /** * 文件大小校验 * * @param file 上传的文件 * @return * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws InvalidExtensionException */ public static final void assertAllowed(MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, InvalidExtensionException { long size = file.getSize(); if (size > DEFAULT_MAX_SIZE) { throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); } String fileName = file.getOriginalFilename(); String extension = getExtension(file); if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) { if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) { throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, fileName); } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) { throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, fileName); } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) { throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, fileName); } else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) { throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, fileName); } else { throw new InvalidExtensionException(allowedExtension, extension, fileName); } } } /** * 判断MIME类型是否是允许的MIME类型 * * @param extension * @param allowedExtension * @return */ public static final boolean isAllowedExtension(String extension, String[] allowedExtension) { for (String str : allowedExtension) { if (str.equalsIgnoreCase(extension)) { return true; } } return false; } /** * 获取文件名的后缀 * * @param file 表单文件 * @return 后缀名 */ public static final String getExtension(MultipartFile file) { String extension = FilenameUtils.getExtension(file.getOriginalFilename()); if (StringUtils.isEmpty(extension)) { extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType())); } return extension; } } ycl-common/src/main/java/utils/file/FileUtils.java
New file @@ -0,0 +1,286 @@ package utils.file; import config.PlatformConfig; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.ArrayUtils; import utils.DateUtils; import utils.StringUtils; import utils.uuid.IdUtils; import java.io.*; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; /** * 文件处理工具类 * * @author ruoyi */ public class FileUtils { public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; /** * 输出指定文件的byte数组 * * @param filePath 文件路径 * @param os 输出流 * @return */ public static void writeBytes(String filePath, OutputStream os) throws IOException { FileInputStream fis = null; try { File file = new File(filePath); if (!file.exists()) { throw new FileNotFoundException(filePath); } fis = new FileInputStream(file); byte[] b = new byte[1024]; int length; while ((length = fis.read(b)) > 0) { os.write(b, 0, length); } } catch (IOException e) { throw e; } finally { IOUtils.close(os); IOUtils.close(fis); } } /** * 写数据到文件中 * * @param data 数据 * @return 目标文件 * @throws IOException IO异常 */ public static String writeImportBytes(byte[] data) throws IOException { return writeBytes(data, PlatformConfig.getImportPath()); } /** * 写数据到文件中 * * @param data 数据 * @param uploadDir 目标文件 * @return 目标文件 * @throws IOException IO异常 */ public static String writeBytes(byte[] data, String uploadDir) throws IOException { FileOutputStream fos = null; String pathName = ""; try { String extension = getFileExtendName(data); pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName); fos = new FileOutputStream(file); fos.write(data); } finally { IOUtils.close(fos); } return FileUploadUtils.getPathFileName(uploadDir, pathName); } /** * 删除文件 * * @param filePath 文件 * @return */ public static boolean deleteFile(String filePath) { boolean flag = false; File file = new File(filePath); // 路径为文件且不为空则进行删除 if (file.isFile() && file.exists()) { flag = file.delete(); } return flag; } /** * 文件名称验证 * * @param filename 文件名称 * @return true 正常 false 非法 */ public static boolean isValidFilename(String filename) { return filename.matches(FILENAME_PATTERN); } /** * 检查文件是否可下载 * * @param resource 需要下载的文件 * @return true 正常 false 非法 */ public static boolean checkAllowDownload(String resource) { // 禁止目录上跳级别 if (StringUtils.contains(resource, "..")) { return false; } // 检查允许下载的文件规则 if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) { return true; } // 不在允许下载的文件规则 return false; } /** * 下载文件名重新编码 * * @param request 请求对象 * @param fileName 文件名 * @return 编码后的文件名 */ public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException { final String agent = request.getHeader("USER-AGENT"); String filename = fileName; if (agent.contains("MSIE")) { // IE浏览器 filename = URLEncoder.encode(filename, "utf-8"); filename = filename.replace("+", " "); } else if (agent.contains("Firefox")) { // 火狐浏览器 filename = new String(fileName.getBytes(), "ISO8859-1"); } else if (agent.contains("Chrome")) { // google浏览器 filename = URLEncoder.encode(filename, "utf-8"); } else { // 其它浏览器 filename = URLEncoder.encode(filename, "utf-8"); } return filename; } /** * 下载文件名重新编码 * * @param response 响应对象 * @param realFileName 真实文件名 */ public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException { String percentEncodedFileName = percentEncode(realFileName); StringBuilder contentDispositionValue = new StringBuilder(); contentDispositionValue.append("attachment; filename=") .append(percentEncodedFileName) .append(";") .append("filename*=") .append("utf-8''") .append(percentEncodedFileName); response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); response.setHeader("Content-disposition", contentDispositionValue.toString()); response.setHeader("download-filename", percentEncodedFileName); } /** * 百分号编码工具方法 * * @param s 需要百分号编码的字符串 * @return 百分号编码后的字符串 */ public static String percentEncode(String s) throws UnsupportedEncodingException { String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); return encode.replaceAll("\\+", "%20"); } /** * 获取图像后缀 * * @param photoByte 图像数据 * @return 后缀名 */ public static String getFileExtendName(byte[] photoByte) { String strFileExtendName = "jpg"; if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) { strFileExtendName = "gif"; } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) { strFileExtendName = "jpg"; } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) { strFileExtendName = "bmp"; } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) { strFileExtendName = "png"; } return strFileExtendName; } /** * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png * * @param fileName 路径名称 * @return 没有文件路径的名称 */ public static String getName(String fileName) { if (fileName == null) { return null; } int lastUnixPos = fileName.lastIndexOf('/'); int lastWindowsPos = fileName.lastIndexOf('\\'); int index = Math.max(lastUnixPos, lastWindowsPos); return fileName.substring(index + 1); } /** * 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi * * @param fileName 路径名称 * @return 没有文件路径和后缀的名称 */ public static String getNameNotSuffix(String fileName) { if (fileName == null) { return null; } String baseName = FilenameUtils.getBaseName(fileName); return baseName; } } ycl-common/src/main/java/utils/file/ImageUtils.java
New file @@ -0,0 +1,99 @@ package utils.file; import config.PlatformConfig; import constant.Constants; import org.apache.poi.util.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import utils.StringUtils; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.Arrays; /** * 图片处理工具类 * * @author ruoyi */ public class ImageUtils { private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); public static byte[] getImage(String imagePath) { InputStream is = getFile(imagePath); try { return IOUtils.toByteArray(is); } catch (Exception e) { log.error("图片加载异常 {}", e); return null; } finally { IOUtils.closeQuietly(is); } } public static InputStream getFile(String imagePath) { try { byte[] result = readFile(imagePath); result = Arrays.copyOf(result, result.length); return new ByteArrayInputStream(result); } catch (Exception e) { log.error("获取图片异常 {}", e); } return null; } /** * 读取文件为字节数据 * * @param url 地址 * @return 字节数据 */ public static byte[] readFile(String url) { InputStream in = null; try { if (url.startsWith("http")) { // 网络地址 URL urlObj = new URL(url); URLConnection urlConnection = urlObj.openConnection(); urlConnection.setConnectTimeout(30 * 1000); urlConnection.setReadTimeout(60 * 1000); urlConnection.setDoInput(true); in = urlConnection.getInputStream(); } else { // 本机地址 String localPath = PlatformConfig.getProfile(); String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX); in = new FileInputStream(downloadPath); } return IOUtils.toByteArray(in); } catch (Exception e) { log.error("获取文件路径异常 {}", e); return null; } finally { IOUtils.closeQuietly(in); } } } ycl-common/src/main/java/utils/file/MimeTypeUtils.java
New file @@ -0,0 +1,59 @@ package utils.file; /** * 媒体类型工具类 * * @author ruoyi */ public class MimeTypeUtils { public static final String IMAGE_PNG = "image/png"; public static final String IMAGE_JPG = "image/jpg"; public static final String IMAGE_JPEG = "image/jpeg"; public static final String IMAGE_BMP = "image/bmp"; public static final String IMAGE_GIF = "image/gif"; public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" }; public static final String[] FLASH_EXTENSION = { "swf", "flv" }; public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", "asf", "rm", "rmvb" }; public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" }; public static final String[] DEFAULT_ALLOWED_EXTENSION = { // 图片 "bmp", "gif", "jpg", "jpeg", "png", // word excel powerpoint "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", // 压缩文件 "rar", "zip", "gz", "bz2", // 视频格式 "mp4", "avi", "rmvb", "pdf" }; public static String getExtension(String prefix) { switch (prefix) { case IMAGE_PNG: return "png"; case IMAGE_JPG: return "jpg"; case IMAGE_JPEG: return "jpeg"; case IMAGE_BMP: return "bmp"; case IMAGE_GIF: return "gif"; default: return ""; } } } ycl-common/src/main/java/utils/poi/ExcelHandlerAdapter.java
New file @@ -0,0 +1,24 @@ package utils.poi; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Workbook; /** * Excel数据格式处理适配器 * * @author ruoyi */ public interface ExcelHandlerAdapter { /** * 格式化 * * @param value 单元格数据值 * @param args excel注解args参数组 * @param cell 单元格对象 * @param wb 工作簿对象 * * @return 处理后的值 */ Object format(Object value, String[] args, Cell cell, Workbook wb); } ycl-common/src/main/java/utils/poi/ExcelUtil.java
New file @@ -0,0 +1,1713 @@ package utils.poi; import annotation.Excel; import annotation.Excels; import config.PlatformConfig; import exception.UtilException; import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.usermodel.*; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pojo.AjaxResult; import utils.DateUtils; import utils.DictUtils; import utils.StringUtils; import utils.file.FileTypeUtils; import utils.file.FileUtils; import utils.file.ImageUtils; import utils.reflect.ReflectUtils; import utils.text.Convert; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.math.BigDecimal; import java.text.DecimalFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; /** * Excel相关处理 * * @author ruoyi */ public class ExcelUtil<T> { private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); public static final String FORMULA_REGEX_STR = "=|-|\\+|@"; public static final String[] FORMULA_STR = { "=", "-", "+", "@" }; /** * 用于dictType属性数据存储,避免重复查缓存 */ public Map<String, String> sysDictMap = new HashMap<String, String>(); /** * Excel sheet最大行数,默认65536 */ public static final int sheetSize = 65536; /** * 工作表名称 */ private String sheetName; /** * 导出类型(EXPORT:导出数据;IMPORT:导入模板) */ private Excel.Type type; /** * 工作薄对象 */ private Workbook wb; /** * 工作表对象 */ private Sheet sheet; /** * 样式列表 */ private Map<String, CellStyle> styles; /** * 导入导出数据列表 */ private List<T> list; /** * 注解列表 */ private List<Object[]> fields; /** * 当前行号 */ private int rownum; /** * 标题 */ private String title; /** * 最大高度 */ private short maxHeight; /** * 合并后最后行数 */ private int subMergedLastRowNum = 0; /** * 合并后开始行数 */ private int subMergedFirstRowNum = 1; /** * 对象的子列表方法 */ private Method subMethod; /** * 对象的子列表属性 */ private List<Field> subFields; /** * 统计列表 */ private Map<Integer, Double> statistics = new HashMap<Integer, Double>(); /** * 数字格式 */ private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); /** * 实体对象 */ public Class<T> clazz; /** * 需要排除列属性 */ public String[] excludeFields; public ExcelUtil(Class<T> clazz) { this.clazz = clazz; } /** * 隐藏Excel中列属性 * * @param fields 列属性名 示例[单个"name"/多个"id","name"] * @throws Exception */ public void hideColumn(String... fields) { this.excludeFields = fields; } public void init(List<T> list, String sheetName, String title, Excel.Type type) { if (list == null) { list = new ArrayList<T>(); } this.list = list; this.sheetName = sheetName; this.type = type; this.title = title; createExcelField(); createWorkbook(); createTitle(); createSubHead(); } /** * 创建excel第一行标题 */ public void createTitle() { if (StringUtils.isNotEmpty(title)) { subMergedFirstRowNum++; subMergedLastRowNum++; int titleLastCol = this.fields.size() - 1; if (isSubList()) { titleLastCol = titleLastCol + subFields.size() - 1; } Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0); titleRow.setHeightInPoints(30); Cell titleCell = titleRow.createCell(0); titleCell.setCellStyle(styles.get("title")); titleCell.setCellValue(title); sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); } } /** * 创建对象的子列表名称 */ public void createSubHead() { if (isSubList()) { subMergedFirstRowNum++; subMergedLastRowNum++; Row subRow = sheet.createRow(rownum); int excelNum = 0; for (Object[] objects : fields) { Excel attr = (Excel) objects[1]; Cell headCell1 = subRow.createCell(excelNum); headCell1.setCellValue(attr.name()); headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); excelNum++; } int headFirstRow = excelNum - 1; int headLastRow = headFirstRow + subFields.size() - 1; if (headLastRow > headFirstRow) { sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); } rownum++; } } /** * 对excel表单默认第一个索引名转换成list * * @param is 输入流 * @return 转换后集合 */ public List<T> importExcel(InputStream is) { List<T> list = null; try { list = importExcel(is, 0); } catch (Exception e) { log.error("导入Excel异常{}", e.getMessage()); throw new UtilException(e.getMessage()); } finally { IOUtils.closeQuietly(is); } return list; } /** * 对excel表单默认第一个索引名转换成list * * @param is 输入流 * @param titleNum 标题占用行数 * @return 转换后集合 */ public List<T> importExcel(InputStream is, int titleNum) throws Exception { return importExcel(StringUtils.EMPTY, is, titleNum); } /** * 对excel表单指定表格索引名转换成list * * @param sheetName 表格索引名 * @param titleNum 标题占用行数 * @param is 输入流 * @return 转换后集合 */ public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception { this.type = Excel.Type.IMPORT; this.wb = WorkbookFactory.create(is); List<T> list = new ArrayList<T>(); // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0); if (sheet == null) { throw new IOException("文件sheet不存在"); } boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook); Map<String, PictureData> pictures; if (isXSSFWorkbook) { pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb); } else { pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb); } // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1 int rows = sheet.getLastRowNum(); if (rows > 0) { // 定义一个map用于存放excel列的序号和field. Map<String, Integer> cellMap = new HashMap<String, Integer>(); // 获取表头 Row heard = sheet.getRow(titleNum); for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) { Cell cell = heard.getCell(i); if (StringUtils.isNotNull(cell)) { String value = this.getCellValue(heard, i).toString(); cellMap.put(value, i); } else { cellMap.put(null, i); } } // 有数据时才处理 得到类的所有field. List<Object[]> fields = this.getFields(); Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>(); for (Object[] objects : fields) { Excel attr = (Excel) objects[1]; Integer column = cellMap.get(attr.name()); if (column != null) { fieldsMap.put(column, objects); } } for (int i = titleNum + 1; i <= rows; i++) { // 从第2行开始取数据,默认第一行是表头. Row row = sheet.getRow(i); // 判断当前行是否是空行 if (isRowEmpty(row)) { continue; } T entity = null; for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet()) { Object val = this.getCellValue(row, entry.getKey()); // 如果不存在实例则新建. entity = (entity == null ? clazz.newInstance() : entity); // 从map中得到对应列的field. Field field = (Field) entry.getValue()[0]; Excel attr = (Excel) entry.getValue()[1]; // 取得类型,并根据对象类型设置值. Class<?> fieldType = field.getType(); if (String.class == fieldType) { String s = Convert.toStr(val); if (StringUtils.endsWith(s, ".0")) { val = StringUtils.substringBefore(s, ".0"); } else { String dateFormat = field.getAnnotation(Excel.class).dateFormat(); if (StringUtils.isNotEmpty(dateFormat)) { val = parseDateToStr(dateFormat, val); } else { val = Convert.toStr(val); } } } else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) { val = Convert.toInt(val); } else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) { val = Convert.toLong(val); } else if (Double.TYPE == fieldType || Double.class == fieldType) { val = Convert.toDouble(val); } else if (Float.TYPE == fieldType || Float.class == fieldType) { val = Convert.toFloat(val); } else if (BigDecimal.class == fieldType) { val = Convert.toBigDecimal(val); } else if (Date.class == fieldType) { if (val instanceof String) { val = DateUtils.parseDate(val); } else if (val instanceof Double) { val = DateUtil.getJavaDate((Double) val); } } else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) { val = Convert.toBool(val, false); } if (StringUtils.isNotNull(fieldType)) { String propertyName = field.getName(); if (StringUtils.isNotEmpty(attr.targetAttr())) { propertyName = field.getName() + "." + attr.targetAttr(); } if (StringUtils.isNotEmpty(attr.readConverterExp())) { val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); } else if (StringUtils.isNotEmpty(attr.dictType())) { val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); } else if (!attr.handler().equals(ExcelHandlerAdapter.class)) { val = dataFormatHandlerAdapter(val, attr, null); } else if (Excel.ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures)) { PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey()); if (image == null) { val = ""; } else { byte[] data = image.getData(); val = FileUtils.writeImportBytes(data); } } ReflectUtils.invokeSetter(entity, propertyName, val); } } list.add(entity); } } return list; } /** * 对list数据源将其里面的数据导入到excel表单 * * @param list 导出数据集合 * @param sheetName 工作表的名称 * @return 结果 */ public AjaxResult exportExcel(List<T> list, String sheetName) { return exportExcel(list, sheetName, StringUtils.EMPTY); } /** * 对list数据源将其里面的数据导入到excel表单 * * @param list 导出数据集合 * @param sheetName 工作表的名称 * @param title 标题 * @return 结果 */ public AjaxResult exportExcel(List<T> list, String sheetName, String title) { this.init(list, sheetName, title, Excel.Type.EXPORT); return exportExcel(); } /** * 对list数据源将其里面的数据导入到excel表单 * * @param response 返回数据 * @param list 导出数据集合 * @param sheetName 工作表的名称 * @return 结果 */ public void exportExcel(HttpServletResponse response, List<T> list, String sheetName) { exportExcel(response, list, sheetName, StringUtils.EMPTY); } /** * 对list数据源将其里面的数据导入到excel表单 * * @param response 返回数据 * @param list 导出数据集合 * @param sheetName 工作表的名称 * @param title 标题 * @return 结果 */ public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title) { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); this.init(list, sheetName, title, Excel.Type.EXPORT); exportExcel(response); } /** * 对list数据源将其里面的数据导入到excel表单 * * @param sheetName 工作表的名称 * @return 结果 */ public AjaxResult importTemplateExcel(String sheetName) { return importTemplateExcel(sheetName, StringUtils.EMPTY); } /** * 对list数据源将其里面的数据导入到excel表单 * * @param sheetName 工作表的名称 * @param title 标题 * @return 结果 */ public AjaxResult importTemplateExcel(String sheetName, String title) { this.init(null, sheetName, title, Excel.Type.IMPORT); return exportExcel(); } /** * 对list数据源将其里面的数据导入到excel表单 * * @param sheetName 工作表的名称 * @return 结果 */ public void importTemplateExcel(HttpServletResponse response, String sheetName) { importTemplateExcel(response, sheetName, StringUtils.EMPTY); } /** * 对list数据源将其里面的数据导入到excel表单 * * @param sheetName 工作表的名称 * @param title 标题 * @return 结果 */ public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) { response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); this.init(null, sheetName, title, Excel.Type.IMPORT); exportExcel(response); } /** * 对list数据源将其里面的数据导入到excel表单 * * @return 结果 */ public void exportExcel(HttpServletResponse response) { try { writeSheet(); wb.write(response.getOutputStream()); } catch (Exception e) { log.error("导出Excel异常{}", e.getMessage()); } finally { IOUtils.closeQuietly(wb); } } /** * 对list数据源将其里面的数据导入到excel表单 * * @return 结果 */ public AjaxResult exportExcel() { OutputStream out = null; try { writeSheet(); String filename = encodingFilename(sheetName); out = new FileOutputStream(getAbsoluteFile(filename)); wb.write(out); return AjaxResult.success(filename); } catch (Exception e) { log.error("导出Excel异常{}", e.getMessage()); throw new UtilException("导出Excel失败,请联系网站管理员!"); } finally { IOUtils.closeQuietly(wb); IOUtils.closeQuietly(out); } } /** * 创建写入数据到Sheet */ public void writeSheet() { // 取出一共有多少个sheet. int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize)); for (int index = 0; index < sheetNo; index++) { createSheet(sheetNo, index); // 产生一行 Row row = sheet.createRow(rownum); int column = 0; // 写入各个字段的列头名称 for (Object[] os : fields) { Field field = (Field) os[0]; Excel excel = (Excel) os[1]; if (Collection.class.isAssignableFrom(field.getType())) { for (Field subField : subFields) { Excel subExcel = subField.getAnnotation(Excel.class); this.createHeadCell(subExcel, row, column++); } } else { this.createHeadCell(excel, row, column++); } } if (Excel.Type.EXPORT.equals(type)) { fillExcelData(index, row); addStatisticsRow(); } } } /** * 填充excel数据 * * @param index 序号 * @param row 单元格行 */ @SuppressWarnings("unchecked") public void fillExcelData(int index, Row row) { int startNo = index * sheetSize; int endNo = Math.min(startNo + sheetSize, list.size()); int rowNo = (1 + rownum) - startNo; for (int i = startNo; i < endNo; i++) { rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; row = sheet.createRow(rowNo); // 得到导出对象. T vo = (T) list.get(i); Collection<?> subList = null; if (isSubList()) { if (isSubListValue(vo)) { subList = getListCellValue(vo); subMergedLastRowNum = subMergedLastRowNum + subList.size(); } else { subMergedFirstRowNum++; subMergedLastRowNum++; } } int column = 0; for (Object[] os : fields) { Field field = (Field) os[0]; Excel excel = (Excel) os[1]; if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) { boolean subFirst = false; for (Object obj : subList) { if (subFirst) { rowNo++; row = sheet.createRow(rowNo); } List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class); int subIndex = 0; for (Field subField : subFields) { if (subField.isAnnotationPresent(Excel.class)) { subField.setAccessible(true); Excel attr = subField.getAnnotation(Excel.class); this.addCell(attr, row, (T) obj, subField, column + subIndex); } subIndex++; } subFirst = true; } this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size(); } else { this.addCell(excel, row, vo, field, column++); } } } } /** * 创建表格样式 * * @param wb 工作薄对象 * @return 样式列表 */ private Map<String, CellStyle> createStyles(Workbook wb) { // 写入各条记录,每条记录对应excel表中的一行 Map<String, CellStyle> styles = new HashMap<String, CellStyle>(); CellStyle style = wb.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); Font titleFont = wb.createFont(); titleFont.setFontName("Arial"); titleFont.setFontHeightInPoints((short) 16); titleFont.setBold(true); style.setFont(titleFont); styles.put("title", style); style = wb.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setBorderRight(BorderStyle.THIN); style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBorderLeft(BorderStyle.THIN); style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBorderTop(BorderStyle.THIN); style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBorderBottom(BorderStyle.THIN); style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); Font dataFont = wb.createFont(); dataFont.setFontName("Arial"); dataFont.setFontHeightInPoints((short) 10); style.setFont(dataFont); styles.put("data", style); style = wb.createCellStyle(); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); Font totalFont = wb.createFont(); totalFont.setFontName("Arial"); totalFont.setFontHeightInPoints((short) 10); style.setFont(totalFont); styles.put("total", style); styles.putAll(annotationHeaderStyles(wb, styles)); styles.putAll(annotationDataStyles(wb)); return styles; } /** * 根据Excel注解创建表格头样式 * * @param wb 工作薄对象 * @return 自定义样式列表 */ private Map<String, CellStyle> annotationHeaderStyles(Workbook wb, Map<String, CellStyle> styles) { Map<String, CellStyle> headerStyles = new HashMap<String, CellStyle>(); for (Object[] os : fields) { Excel excel = (Excel) os[1]; String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor()); if (!headerStyles.containsKey(key)) { CellStyle style = wb.createCellStyle(); style.cloneStyleFrom(styles.get("data")); style.setAlignment(HorizontalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setFillForegroundColor(excel.headerBackgroundColor().index); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); Font headerFont = wb.createFont(); headerFont.setFontName("Arial"); headerFont.setFontHeightInPoints((short) 10); headerFont.setBold(true); headerFont.setColor(excel.headerColor().index); style.setFont(headerFont); headerStyles.put(key, style); } } return headerStyles; } /** * 根据Excel注解创建表格列样式 * * @param wb 工作薄对象 * @return 自定义样式列表 */ private Map<String, CellStyle> annotationDataStyles(Workbook wb) { Map<String, CellStyle> styles = new HashMap<String, CellStyle>(); for (Object[] os : fields) { Excel excel = (Excel) os[1]; String key = StringUtils.format("data_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor()); if (!styles.containsKey(key)) { CellStyle style = wb.createCellStyle(); style.setAlignment(excel.align()); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setBorderRight(BorderStyle.THIN); style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBorderLeft(BorderStyle.THIN); style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBorderTop(BorderStyle.THIN); style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBorderBottom(BorderStyle.THIN); style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); style.setFillForegroundColor(excel.backgroundColor().getIndex()); Font dataFont = wb.createFont(); dataFont.setFontName("Arial"); dataFont.setFontHeightInPoints((short) 10); dataFont.setColor(excel.color().index); style.setFont(dataFont); styles.put(key, style); } } return styles; } /** * 创建单元格 */ public Cell createHeadCell(Excel attr, Row row, int column) { // 创建列 Cell cell = row.createCell(column); // 写入列信息 cell.setCellValue(attr.name()); setDataValidation(attr, row, column); cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); if (isSubList()) { // 填充默认样式,防止合并单元格样式失效 sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); if (attr.needMerge()) { sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); } } return cell; } /** * 设置单元格信息 * * @param value 单元格值 * @param attr 注解相关 * @param cell 单元格信息 */ public void setCellVo(Object value, Excel attr, Cell cell) { if (Excel.ColumnType.STRING == attr.cellType()) { String cellValue = Convert.toStr(value); // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。 if (StringUtils.startsWithAny(cellValue, FORMULA_STR)) { cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0"); } if (value instanceof Collection && StringUtils.equals("[]", cellValue)) { cellValue = StringUtils.EMPTY; } cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix()); } else if (Excel.ColumnType.NUMERIC == attr.cellType()) { if (StringUtils.isNotNull(value)) { cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); } } else if (Excel.ColumnType.IMAGE == attr.cellType()) { ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1); String imagePath = Convert.toStr(value); if (StringUtils.isNotEmpty(imagePath)) { byte[] data = ImageUtils.getImage(imagePath); getDrawingPatriarch(cell.getSheet()).createPicture(anchor, cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); } } } /** * 获取画布 */ public static Drawing<?> getDrawingPatriarch(Sheet sheet) { if (sheet.getDrawingPatriarch() == null) { sheet.createDrawingPatriarch(); } return sheet.getDrawingPatriarch(); } /** * 获取图片类型,设置图片插入类型 */ public int getImageType(byte[] value) { String type = FileTypeUtils.getFileExtendName(value); if ("JPG".equalsIgnoreCase(type)) { return Workbook.PICTURE_TYPE_JPEG; } else if ("PNG".equalsIgnoreCase(type)) { return Workbook.PICTURE_TYPE_PNG; } return Workbook.PICTURE_TYPE_JPEG; } /** * 创建表格样式 */ public void setDataValidation(Excel attr, Row row, int column) { if (attr.name().indexOf("注:") >= 0) { sheet.setColumnWidth(column, 6000); } else { // 设置列宽 sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); } if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0) { if (attr.combo().length > 15 || StringUtils.join(attr.combo()).length() > 255) { // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到 setXSSFValidationWithHidden(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); } else { // 提示信息或只能选择不能输入的列内容. setPromptOrValidation(sheet, attr.combo(), attr.prompt(), 1, 100, column, column); } } } /** * 添加单元格 */ public Cell addCell(Excel attr, Row row, T vo, Field field, int column) { Cell cell = null; try { // 设置行高 row.setHeight(maxHeight); // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. if (attr.isExport()) { // 创建cell cell = row.createCell(column); if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) { CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); sheet.addMergedRegion(cellAddress); } cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor()))); // 用于读取对象中的属性 Object value = getTargetValue(vo, field, attr); String dateFormat = attr.dateFormat(); String readConverterExp = attr.readConverterExp(); String separator = attr.separator(); String dictType = attr.dictType(); if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) { cell.setCellValue(parseDateToStr(dateFormat, value)); } else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) { cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); } else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) { if (!sysDictMap.containsKey(dictType + value)) { String lable = convertDictByExp(Convert.toStr(value), dictType, separator); sysDictMap.put(dictType + value, lable); } cell.setCellValue(sysDictMap.get(dictType + value)); } else if (value instanceof BigDecimal && -1 != attr.scale()) { cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue()); } else if (!attr.handler().equals(ExcelHandlerAdapter.class)) { cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell)); } else { // 设置列类型 setCellVo(value, attr, cell); } addStatisticsData(column, Convert.toStr(value), attr); } } catch (Exception e) { log.error("导出Excel失败{}", e); } return cell; } /** * 设置 POI XSSFSheet 单元格提示或选择框 * * @param sheet 表单 * @param textlist 下拉框显示的内容 * @param promptContent 提示内容 * @param firstRow 开始行 * @param endRow 结束行 * @param firstCol 开始列 * @param endCol 结束列 */ public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol) { DataValidationHelper helper = sheet.getDataValidationHelper(); DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1"); CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); DataValidation dataValidation = helper.createValidation(constraint, regions); if (StringUtils.isNotEmpty(promptContent)) { // 如果设置了提示信息则鼠标放上去提示 dataValidation.createPromptBox("", promptContent); dataValidation.setShowPromptBox(true); } // 处理Excel兼容性问题 if (dataValidation instanceof XSSFDataValidation) { dataValidation.setSuppressDropDownArrow(true); dataValidation.setShowErrorBox(true); } else { dataValidation.setSuppressDropDownArrow(false); } sheet.addValidationData(dataValidation); } /** * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框). * * @param sheet 要设置的sheet. * @param textlist 下拉框显示的内容 * @param promptContent 提示内容 * @param firstRow 开始行 * @param endRow 结束行 * @param firstCol 开始列 * @param endCol 结束列 */ public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol) { String hideSheetName = "combo_" + firstCol + "_" + endCol; Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据 for (int i = 0; i < textlist.length; i++) { hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]); } // 创建名称,可被其他单元格引用 Name name = wb.createName(); name.setNameName(hideSheetName + "_data"); name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length); DataValidationHelper helper = sheet.getDataValidationHelper(); // 加载下拉列表内容 DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data"); // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); // 数据有效性对象 DataValidation dataValidation = helper.createValidation(constraint, regions); if (StringUtils.isNotEmpty(promptContent)) { // 如果设置了提示信息则鼠标放上去提示 dataValidation.createPromptBox("", promptContent); dataValidation.setShowPromptBox(true); } // 处理Excel兼容性问题 if (dataValidation instanceof XSSFDataValidation) { dataValidation.setSuppressDropDownArrow(true); dataValidation.setShowErrorBox(true); } else { dataValidation.setSuppressDropDownArrow(false); } sheet.addValidationData(dataValidation); // 设置hiddenSheet隐藏 wb.setSheetHidden(wb.getSheetIndex(hideSheet), true); } /** * 解析导出值 0=男,1=女,2=未知 * * @param propertyValue 参数值 * @param converterExp 翻译注解 * @param separator 分隔符 * @return 解析后值 */ public static String convertByExp(String propertyValue, String converterExp, String separator) { StringBuilder propertyString = new StringBuilder(); String[] convertSource = converterExp.split(","); for (String item : convertSource) { String[] itemArray = item.split("="); if (StringUtils.containsAny(propertyValue, separator)) { for (String value : propertyValue.split(separator)) { if (itemArray[0].equals(value)) { propertyString.append(itemArray[1] + separator); break; } } } else { if (itemArray[0].equals(propertyValue)) { return itemArray[1]; } } } return StringUtils.stripEnd(propertyString.toString(), separator); } /** * 反向解析值 男=0,女=1,未知=2 * * @param propertyValue 参数值 * @param converterExp 翻译注解 * @param separator 分隔符 * @return 解析后值 */ public static String reverseByExp(String propertyValue, String converterExp, String separator) { StringBuilder propertyString = new StringBuilder(); String[] convertSource = converterExp.split(","); for (String item : convertSource) { String[] itemArray = item.split("="); if (StringUtils.containsAny(propertyValue, separator)) { for (String value : propertyValue.split(separator)) { if (itemArray[1].equals(value)) { propertyString.append(itemArray[0] + separator); break; } } } else { if (itemArray[1].equals(propertyValue)) { return itemArray[0]; } } } return StringUtils.stripEnd(propertyString.toString(), separator); } /** * 解析字典值 * * @param dictValue 字典值 * @param dictType 字典类型 * @param separator 分隔符 * @return 字典标签 */ public static String convertDictByExp(String dictValue, String dictType, String separator) { return DictUtils.getDictLabel(dictType, dictValue, separator); } /** * 反向解析值字典值 * * @param dictLabel 字典标签 * @param dictType 字典类型 * @param separator 分隔符 * @return 字典值 */ public static String reverseDictByExp(String dictLabel, String dictType, String separator) { return DictUtils.getDictValue(dictType, dictLabel, separator); } /** * 数据处理器 * * @param value 数据值 * @param excel 数据注解 * @return */ public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell) { try { Object instance = excel.handler().newInstance(); Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class }); value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb); } catch (Exception e) { log.error("不能格式化数据 " + excel.handler(), e.getMessage()); } return Convert.toStr(value); } /** * 合计统计信息 */ private void addStatisticsData(Integer index, String text, Excel entity) { if (entity != null && entity.isStatistics()) { Double temp = 0D; if (!statistics.containsKey(index)) { statistics.put(index, temp); } try { temp = Double.valueOf(text); } catch (NumberFormatException e) { } statistics.put(index, statistics.get(index) + temp); } } /** * 创建统计行 */ public void addStatisticsRow() { if (statistics.size() > 0) { Row row = sheet.createRow(sheet.getLastRowNum() + 1); Set<Integer> keys = statistics.keySet(); Cell cell = row.createCell(0); cell.setCellStyle(styles.get("total")); cell.setCellValue("合计"); for (Integer key : keys) { cell = row.createCell(key); cell.setCellStyle(styles.get("total")); cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); } statistics.clear(); } } /** * 编码文件名 */ public String encodingFilename(String filename) { filename = UUID.randomUUID() + "_" + filename + ".xlsx"; return filename; } /** * 获取下载路径 * * @param filename 文件名称 */ public String getAbsoluteFile(String filename) { String downloadPath = PlatformConfig.getDownloadPath() + filename; File desc = new File(downloadPath); if (!desc.getParentFile().exists()) { desc.getParentFile().mkdirs(); } return downloadPath; } /** * 获取bean中的属性值 * * @param vo 实体对象 * @param field 字段 * @param excel 注解 * @return 最终的属性值 * @throws Exception */ private Object getTargetValue(T vo, Field field, Excel excel) throws Exception { Object o = field.get(vo); if (StringUtils.isNotEmpty(excel.targetAttr())) { String target = excel.targetAttr(); if (target.contains(".")) { String[] targets = target.split("[.]"); for (String name : targets) { o = getValue(o, name); } } else { o = getValue(o, target); } } return o; } /** * 以类的属性的get方法方法形式获取值 * * @param o * @param name * @return value * @throws Exception */ private Object getValue(Object o, String name) throws Exception { if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) { Class<?> clazz = o.getClass(); Field field = clazz.getDeclaredField(name); field.setAccessible(true); o = field.get(o); } return o; } /** * 得到所有定义字段 */ private void createExcelField() { this.fields = getFields(); this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); this.maxHeight = getRowHeight(); } /** * 获取字段注解信息 */ public List<Object[]> getFields() { List<Object[]> fields = new ArrayList<Object[]>(); List<Field> tempFields = new ArrayList<>(); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); for (Field field : tempFields) { if (!ArrayUtils.contains(this.excludeFields, field.getName())) { // 单注解 if (field.isAnnotationPresent(Excel.class)) { Excel attr = field.getAnnotation(Excel.class); if (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type)) { field.setAccessible(true); fields.add(new Object[] { field, attr }); } if (Collection.class.isAssignableFrom(field.getType())) { subMethod = getSubMethod(field.getName(), clazz); ParameterizedType pt = (ParameterizedType) field.getGenericType(); Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0]; this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class); } } // 多注解 if (field.isAnnotationPresent(Excels.class)) { Excels attrs = field.getAnnotation(Excels.class); Excel[] excels = attrs.value(); for (Excel attr : excels) { if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) && (attr != null && (attr.type() == Excel.Type.ALL || attr.type() == type))) { field.setAccessible(true); fields.add(new Object[] { field, attr }); } } } } } return fields; } /** * 根据注解获取最大行高 */ public short getRowHeight() { double maxHeight = 0; for (Object[] os : this.fields) { Excel excel = (Excel) os[1]; maxHeight = Math.max(maxHeight, excel.height()); } return (short) (maxHeight * 20); } /** * 创建一个工作簿 */ public void createWorkbook() { this.wb = new SXSSFWorkbook(500); this.sheet = wb.createSheet(); wb.setSheetName(0, sheetName); this.styles = createStyles(wb); } /** * 创建工作表 * * @param sheetNo sheet数量 * @param index 序号 */ public void createSheet(int sheetNo, int index) { // 设置工作表的名称. if (sheetNo > 1 && index > 0) { this.sheet = wb.createSheet(); this.createTitle(); wb.setSheetName(index, sheetName + index); } } /** * 获取单元格值 * * @param row 获取的行 * @param column 获取单元格列号 * @return 单元格值 */ public Object getCellValue(Row row, int column) { if (row == null) { return row; } Object val = ""; try { Cell cell = row.getCell(column); if (StringUtils.isNotNull(cell)) { if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) { val = cell.getNumericCellValue(); if (DateUtil.isCellDateFormatted(cell)) { val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 } else { if ((Double) val % 1 != 0) { val = new BigDecimal(val.toString()); } else { val = new DecimalFormat("0").format(val); } } } else if (cell.getCellType() == CellType.STRING) { val = cell.getStringCellValue(); } else if (cell.getCellType() == CellType.BOOLEAN) { val = cell.getBooleanCellValue(); } else if (cell.getCellType() == CellType.ERROR) { val = cell.getErrorCellValue(); } } } catch (Exception e) { return val; } return val; } /** * 判断是否是空行 * * @param row 判断的行 * @return */ private boolean isRowEmpty(Row row) { if (row == null) { return true; } for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) { Cell cell = row.getCell(i); if (cell != null && cell.getCellType() != CellType.BLANK) { return false; } } return true; } /** * 获取Excel2003图片 * * @param sheet 当前sheet对象 * @param workbook 工作簿对象 * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData */ public static Map<String, PictureData> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook) { Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>(); List<HSSFPictureData> pictures = workbook.getAllPictures(); if (!pictures.isEmpty()) { for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) { HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor(); if (shape instanceof HSSFPicture) { HSSFPicture pic = (HSSFPicture) shape; int pictureIndex = pic.getPictureIndex() - 1; HSSFPictureData picData = pictures.get(pictureIndex); String picIndex = anchor.getRow1() + "_" + anchor.getCol1(); sheetIndexPicMap.put(picIndex, picData); } } return sheetIndexPicMap; } else { return sheetIndexPicMap; } } /** * 获取Excel2007图片 * * @param sheet 当前sheet对象 * @param workbook 工作簿对象 * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData */ public static Map<String, PictureData> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook) { Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>(); for (POIXMLDocumentPart dr : sheet.getRelations()) { if (dr instanceof XSSFDrawing) { XSSFDrawing drawing = (XSSFDrawing) dr; List<XSSFShape> shapes = drawing.getShapes(); for (XSSFShape shape : shapes) { if (shape instanceof XSSFPicture) { XSSFPicture pic = (XSSFPicture) shape; XSSFClientAnchor anchor = pic.getPreferredSize(); CTMarker ctMarker = anchor.getFrom(); String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); sheetIndexPicMap.put(picIndex, pic.getPictureData()); } } } } return sheetIndexPicMap; } /** * 格式化不同类型的日期对象 * * @param dateFormat 日期格式 * @param val 被格式化的日期对象 * @return 格式化后的日期字符 */ public String parseDateToStr(String dateFormat, Object val) { if (val == null) { return ""; } String str; if (val instanceof Date) { str = DateUtils.parseDateToStr(dateFormat, (Date) val); } else if (val instanceof LocalDateTime) { str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val)); } else if (val instanceof LocalDate) { str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val)); } else { str = val.toString(); } return str; } /** * 是否有对象的子列表 */ public boolean isSubList() { return StringUtils.isNotNull(subFields) && subFields.size() > 0; } /** * 是否有对象的子列表,集合不为空 */ public boolean isSubListValue(T vo) { return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0; } /** * 获取集合的值 */ public Collection<?> getListCellValue(Object obj) { Object value; try { value = subMethod.invoke(obj, new Object[] {}); } catch (Exception e) { return new ArrayList<Object>(); } return (Collection<?>) value; } /** * 获取对象的子列表方法 * * @param name 名称 * @param pojoClass 类对象 * @return 子列表方法 */ public Method getSubMethod(String name, Class<?> pojoClass) { StringBuffer getMethodName = new StringBuffer("get"); getMethodName.append(name.substring(0, 1).toUpperCase()); getMethodName.append(name.substring(1)); Method method = null; try { method = pojoClass.getMethod(getMethodName.toString(), new Class[] {}); } catch (Exception e) { log.error("获取对象异常{}", e.getMessage()); } return method; } } ycl-common/src/main/java/utils/redis/RedisCache.java
New file @@ -0,0 +1,265 @@ package utils.redis; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.BoundSetOperations; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import java.util.*; import java.util.concurrent.TimeUnit; /** * spring redis 工具类 * * @author ruoyi **/ @SuppressWarnings(value = { "unchecked", "rawtypes" }) @Component public class RedisCache { @Autowired public RedisTemplate redisTemplate; /** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 */ public <T> void setCacheObject(final String key, final T value) { redisTemplate.opsForValue().set(key, value); } /** * 缓存基本的对象,Integer、String、实体类等 * * @param key 缓存的键值 * @param value 缓存的值 * @param timeout 时间 * @param timeUnit 时间颗粒度 */ public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, timeout, timeUnit); } /** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @return true=设置成功;false=设置失败 */ public boolean expire(final String key, final long timeout) { return expire(key, timeout, TimeUnit.SECONDS); } /** * 设置有效时间 * * @param key Redis键 * @param timeout 超时时间 * @param unit 时间单位 * @return true=设置成功;false=设置失败 */ public boolean expire(final String key, final long timeout, final TimeUnit unit) { return redisTemplate.expire(key, timeout, unit); } /** * 获取有效时间 * * @param key Redis键 * @return 有效时间 */ public long getExpire(final String key) { return redisTemplate.getExpire(key); } /** * 判断 key是否存在 * * @param key 键 * @return true 存在 false不存在 */ public Boolean hasKey(String key) { return redisTemplate.hasKey(key); } /** * 获得缓存的基本对象。 * * @param key 缓存键值 * @return 缓存键值对应的数据 */ public <T> T getCacheObject(final String key) { ValueOperations<String, T> operation = redisTemplate.opsForValue(); return operation.get(key); } /** * 删除单个对象 * * @param key */ public boolean deleteObject(final String key) { return redisTemplate.delete(key); } /** * 删除集合对象 * * @param collection 多个对象 * @return */ public boolean deleteObject(final Collection collection) { return redisTemplate.delete(collection) > 0; } /** * 缓存List数据 * * @param key 缓存的键值 * @param dataList 待缓存的List数据 * @return 缓存的对象 */ public <T> long setCacheList(final String key, final List<T> dataList) { Long count = redisTemplate.opsForList().rightPushAll(key, dataList); return count == null ? 0 : count; } /** * 获得缓存的list对象 * * @param key 缓存的键值 * @return 缓存键值对应的数据 */ public <T> List<T> getCacheList(final String key) { return redisTemplate.opsForList().range(key, 0, -1); } /** * 缓存Set * * @param key 缓存键值 * @param dataSet 缓存的数据 * @return 缓存数据的对象 */ public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) { BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key); Iterator<T> it = dataSet.iterator(); while (it.hasNext()) { setOperation.add(it.next()); } return setOperation; } /** * 获得缓存的set * * @param key * @return */ public <T> Set<T> getCacheSet(final String key) { return redisTemplate.opsForSet().members(key); } /** * 缓存Map * * @param key * @param dataMap */ public <T> void setCacheMap(final String key, final Map<String, T> dataMap) { if (dataMap != null) { redisTemplate.opsForHash().putAll(key, dataMap); } } /** * 获得缓存的Map * * @param key * @return */ public <T> Map<String, T> getCacheMap(final String key) { return redisTemplate.opsForHash().entries(key); } /** * 往Hash中存入数据 * * @param key Redis键 * @param hKey Hash键 * @param value 值 */ public <T> void setCacheMapValue(final String key, final String hKey, final T value) { redisTemplate.opsForHash().put(key, hKey, value); } /** * 获取Hash中的数据 * * @param key Redis键 * @param hKey Hash键 * @return Hash中的对象 */ public <T> T getCacheMapValue(final String key, final String hKey) { HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash(); return opsForHash.get(key, hKey); } /** * 获取多个Hash中的数据 * * @param key Redis键 * @param hKeys Hash键集合 * @return Hash对象集合 */ public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) { return redisTemplate.opsForHash().multiGet(key, hKeys); } /** * 删除Hash中的某条数据 * * @param key Redis键 * @param hKey Hash键 * @return 是否成功 */ public boolean deleteCacheMapValue(final String key, final String hKey) { return redisTemplate.opsForHash().delete(key, hKey) > 0; } /** * 获得缓存的基本对象列表 * * @param pattern 字符串前缀 * @return 对象列表 */ public Collection<String> keys(final String pattern) { return redisTemplate.keys(pattern); } } ycl-common/src/main/java/utils/reflect/ReflectUtils.java
New file @@ -0,0 +1,406 @@ package utils.reflect; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.poi.ss.usermodel.DateUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import utils.DateUtils; import utils.text.Convert; import java.lang.reflect.*; import java.util.Date; /** * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. * * @author ruoyi */ @SuppressWarnings("rawtypes") public class ReflectUtils { private static final String SETTER_PREFIX = "set"; private static final String GETTER_PREFIX = "get"; private static final String CGLIB_CLASS_SEPARATOR = "$$"; private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class); /** * 调用Getter方法. * 支持多级,如:对象名.对象名.方法 */ @SuppressWarnings("unchecked") public static <E> E invokeGetter(Object obj, String propertyName) { Object object = obj; for (String name : StringUtils.split(propertyName, ".")) { String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); } return (E) object; } /** * 调用Setter方法, 仅匹配方法名。 * 支持多级,如:对象名.对象名.方法 */ public static <E> void invokeSetter(Object obj, String propertyName, E value) { Object object = obj; String[] names = StringUtils.split(propertyName, "."); for (int i = 0; i < names.length; i++) { if (i < names.length - 1) { String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); } else { String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); invokeMethodByName(object, setterMethodName, new Object[] { value }); } } } /** * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数. */ @SuppressWarnings("unchecked") public static <E> E getFieldValue(final Object obj, final String fieldName) { Field field = getAccessibleField(obj, fieldName); if (field == null) { logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); return null; } E result = null; try { result = (E) field.get(obj); } catch (IllegalAccessException e) { logger.error("不可能抛出的异常{}", e.getMessage()); } return result; } /** * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数. */ public static <E> void setFieldValue(final Object obj, final String fieldName, final E value) { Field field = getAccessibleField(obj, fieldName); if (field == null) { // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 "); return; } try { field.set(obj, value); } catch (IllegalAccessException e) { logger.error("不可能抛出的异常: {}", e.getMessage()); } } /** * 直接调用对象方法, 无视private/protected修饰符. * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用. * 同时匹配方法名+参数类型, */ @SuppressWarnings("unchecked") public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes, final Object[] args) { if (obj == null || methodName == null) { return null; } Method method = getAccessibleMethod(obj, methodName, parameterTypes); if (method == null) { logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); return null; } try { return (E) method.invoke(obj, args); } catch (Exception e) { String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; throw convertReflectionExceptionToUnchecked(msg, e); } } /** * 直接调用对象方法, 无视private/protected修饰符, * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. * 只匹配函数名,如果有多个同名函数调用第一个。 */ @SuppressWarnings("unchecked") public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args) { Method method = getAccessibleMethodByName(obj, methodName, args.length); if (method == null) { // 如果为空不报错,直接返回空。 logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 "); return null; } try { // 类型转换(将参数数据类型转换为目标方法参数类型) Class<?>[] cs = method.getParameterTypes(); for (int i = 0; i < cs.length; i++) { if (args[i] != null && !args[i].getClass().equals(cs[i])) { if (cs[i] == String.class) { args[i] = Convert.toStr(args[i]); if (StringUtils.endsWith((String) args[i], ".0")) { args[i] = StringUtils.substringBefore((String) args[i], ".0"); } } else if (cs[i] == Integer.class) { args[i] = Convert.toInt(args[i]); } else if (cs[i] == Long.class) { args[i] = Convert.toLong(args[i]); } else if (cs[i] == Double.class) { args[i] = Convert.toDouble(args[i]); } else if (cs[i] == Float.class) { args[i] = Convert.toFloat(args[i]); } else if (cs[i] == Date.class) { if (args[i] instanceof String) { args[i] = DateUtils.parseDate(args[i]); } else { args[i] = DateUtil.getJavaDate((Double) args[i]); } } else if (cs[i] == boolean.class || cs[i] == Boolean.class) { args[i] = Convert.toBool(args[i]); } } } return (E) method.invoke(obj, args); } catch (Exception e) { String msg = "method: " + method + ", obj: " + obj + ", args: " + args + ""; throw convertReflectionExceptionToUnchecked(msg, e); } } /** * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问. * 如向上转型到Object仍无法找到, 返回null. */ public static Field getAccessibleField(final Object obj, final String fieldName) { // 为空不报错。直接返回 null if (obj == null) { return null; } Validate.notBlank(fieldName, "fieldName can't be blank"); for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { try { Field field = superClass.getDeclaredField(fieldName); makeAccessible(field); return field; } catch (NoSuchFieldException e) { continue; } } return null; } /** * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. * 如向上转型到Object仍无法找到, 返回null. * 匹配函数名+参数类型。 * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) */ public static Method getAccessibleMethod(final Object obj, final String methodName, final Class<?>... parameterTypes) { // 为空不报错。直接返回 null if (obj == null) { return null; } Validate.notBlank(methodName, "methodName can't be blank"); for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { try { Method method = searchType.getDeclaredMethod(methodName, parameterTypes); makeAccessible(method); return method; } catch (NoSuchMethodException e) { continue; } } return null; } /** * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. * 如向上转型到Object仍无法找到, 返回null. * 只匹配函数名。 * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) */ public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum) { // 为空不报错。直接返回 null if (obj == null) { return null; } Validate.notBlank(methodName, "methodName can't be blank"); for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { Method[] methods = searchType.getDeclaredMethods(); for (Method method : methods) { if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum) { makeAccessible(method); return method; } } } return null; } /** * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ public static void makeAccessible(Method method) { if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) { method.setAccessible(true); } } /** * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ public static void makeAccessible(Field field) { if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) { field.setAccessible(true); } } /** * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处 * 如无法找到, 返回Object.class. */ @SuppressWarnings("unchecked") public static <T> Class<T> getClassGenricType(final Class clazz) { return getClassGenricType(clazz, 0); } /** * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. * 如无法找到, 返回Object.class. */ public static Class getClassGenricType(final Class clazz, final int index) { Type genType = clazz.getGenericSuperclass(); if (!(genType instanceof ParameterizedType)) { logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType"); return Object.class; } Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); if (index >= params.length || index < 0) { logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length); return Object.class; } if (!(params[index] instanceof Class)) { logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); return Object.class; } return (Class) params[index]; } public static Class<?> getUserClass(Object instance) { if (instance == null) { throw new RuntimeException("Instance must not be null"); } Class clazz = instance.getClass(); if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { Class<?> superClass = clazz.getSuperclass(); if (superClass != null && !Object.class.equals(superClass)) { return superClass; } } return clazz; } /** * 将反射时的checked exception转换为unchecked exception. */ public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e) { if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException || e instanceof NoSuchMethodException) { return new IllegalArgumentException(msg, e); } else if (e instanceof InvocationTargetException) { return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException()); } return new RuntimeException(msg, e); } } ycl-common/src/main/java/utils/uuid/IdUtils.java
New file @@ -0,0 +1,49 @@ package utils.uuid; /** * ID生成器工具类 * * @author ruoyi */ public class IdUtils { /** * 获取随机UUID * * @return 随机UUID */ public static String randomUUID() { return UUID.randomUUID().toString(); } /** * 简化的UUID,去掉了横线 * * @return 简化的UUID,去掉了横线 */ public static String simpleUUID() { return UUID.randomUUID().toString(true); } /** * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID * * @return 随机UUID */ public static String fastUUID() { return UUID.fastUUID().toString(); } /** * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID * * @return 简化的UUID,去掉了横线 */ public static String fastSimpleUUID() { return UUID.fastUUID().toString(true); } } ycl-common/src/main/java/utils/uuid/Seq.java
New file @@ -0,0 +1,87 @@ package utils.uuid; import utils.DateUtils; import utils.StringUtils; import java.util.concurrent.atomic.AtomicInteger; /** * @author ruoyi 序列生成类 */ public class Seq { // 通用序列类型 public static final String commSeqType = "COMMON"; // 上传序列类型 public static final String uploadSeqType = "UPLOAD"; // 通用接口序列数 private static AtomicInteger commSeq = new AtomicInteger(1); // 上传接口序列数 private static AtomicInteger uploadSeq = new AtomicInteger(1); // 机器标识 private static final String machineCode = "A"; /** * 获取通用序列号 * * @return 序列值 */ public static String getId() { return getId(commSeqType); } /** * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串 * * @return 序列值 */ public static String getId(String type) { AtomicInteger atomicInt = commSeq; if (uploadSeqType.equals(type)) { atomicInt = uploadSeq; } return getId(atomicInt, 3); } /** * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串 * * @param atomicInt 序列数 * @param length 数值长度 * @return 序列值 */ public static String getId(AtomicInteger atomicInt, int length) { String result = DateUtils.dateTimeNow(); result += machineCode; result += getSeq(atomicInt, length); return result; } /** * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数 * * @return 序列值 */ private synchronized static String getSeq(AtomicInteger atomicInt, int length) { // 先取值再+1 int value = atomicInt.getAndIncrement(); // 如果更新后值>=10 的 (length)幂次方则重置为1 int maxSeq = (int) Math.pow(10, length); if (atomicInt.get() >= maxSeq) { atomicInt.set(1); } // 转字符串,用0左补齐 return StringUtils.padl(value, length); } } ycl-common/src/main/java/utils/uuid/UUID.java
New file @@ -0,0 +1,485 @@ package utils.uuid; import exception.UtilException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; /** * 提供通用唯一识别码(universally unique identifier)(UUID)实现 * * @author ruoyi */ public final class UUID implements java.io.Serializable, Comparable<UUID> { private static final long serialVersionUID = -1185015143654744140L; /** * SecureRandom 的单例 * */ private static class Holder { static final SecureRandom numberGenerator = getSecureRandom(); } /** 此UUID的最高64有效位 */ private final long mostSigBits; /** 此UUID的最低64有效位 */ private final long leastSigBits; /** * 私有构造 * * @param data 数据 */ private UUID(byte[] data) { long msb = 0; long lsb = 0; assert data.length == 16 : "data must be 16 bytes in length"; for (int i = 0; i < 8; i++) { msb = (msb << 8) | (data[i] & 0xff); } for (int i = 8; i < 16; i++) { lsb = (lsb << 8) | (data[i] & 0xff); } this.mostSigBits = msb; this.leastSigBits = lsb; } /** * 使用指定的数据构造新的 UUID。 * * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位 * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位 */ public UUID(long mostSigBits, long leastSigBits) { this.mostSigBits = mostSigBits; this.leastSigBits = leastSigBits; } /** * 获取类型 4(伪随机生成的)UUID 的静态工厂。 * * @return 随机生成的 {@code UUID} */ public static UUID fastUUID() { return randomUUID(false); } /** * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 * * @return 随机生成的 {@code UUID} */ public static UUID randomUUID() { return randomUUID(true); } /** * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 * * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能 * @return 随机生成的 {@code UUID} */ public static UUID randomUUID(boolean isSecure) { final Random ng = isSecure ? Holder.numberGenerator : getRandom(); byte[] randomBytes = new byte[16]; ng.nextBytes(randomBytes); randomBytes[6] &= 0x0f; /* clear version */ randomBytes[6] |= 0x40; /* set to version 4 */ randomBytes[8] &= 0x3f; /* clear variant */ randomBytes[8] |= 0x80; /* set to IETF variant */ return new UUID(randomBytes); } /** * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。 * * @param name 用于构造 UUID 的字节数组。 * * @return 根据指定数组生成的 {@code UUID} */ public static UUID nameUUIDFromBytes(byte[] name) { MessageDigest md; try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException nsae) { throw new InternalError("MD5 not supported"); } byte[] md5Bytes = md.digest(name); md5Bytes[6] &= 0x0f; /* clear version */ md5Bytes[6] |= 0x30; /* set to version 3 */ md5Bytes[8] &= 0x3f; /* clear variant */ md5Bytes[8] |= 0x80; /* set to IETF variant */ return new UUID(md5Bytes); } /** * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。 * * @param name 指定 {@code UUID} 字符串 * @return 具有指定值的 {@code UUID} * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常 * */ public static UUID fromString(String name) { String[] components = name.split("-"); if (components.length != 5) { throw new IllegalArgumentException("Invalid UUID string: " + name); } for (int i = 0; i < 5; i++) { components[i] = "0x" + components[i]; } long mostSigBits = Long.decode(components[0]).longValue(); mostSigBits <<= 16; mostSigBits |= Long.decode(components[1]).longValue(); mostSigBits <<= 16; mostSigBits |= Long.decode(components[2]).longValue(); long leastSigBits = Long.decode(components[3]).longValue(); leastSigBits <<= 48; leastSigBits |= Long.decode(components[4]).longValue(); return new UUID(mostSigBits, leastSigBits); } /** * 返回此 UUID 的 128 位值中的最低有效 64 位。 * * @return 此 UUID 的 128 位值中的最低有效 64 位。 */ public long getLeastSignificantBits() { return leastSigBits; } /** * 返回此 UUID 的 128 位值中的最高有效 64 位。 * * @return 此 UUID 的 128 位值中最高有效 64 位。 */ public long getMostSignificantBits() { return mostSigBits; } /** * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。 * <p> * 版本号具有以下含意: * <ul> * <li>1 基于时间的 UUID * <li>2 DCE 安全 UUID * <li>3 基于名称的 UUID * <li>4 随机生成的 UUID * </ul> * * @return 此 {@code UUID} 的版本号 */ public int version() { // Version is bits masked by 0x000000000000F000 in MS long return (int) ((mostSigBits >> 12) & 0x0f); } /** * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。 * <p> * 变体号具有以下含意: * <ul> * <li>0 为 NCS 向后兼容保留 * <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF RFC 4122</a>(Leach-Salz), 用于此类 * <li>6 保留,微软向后兼容 * <li>7 保留供以后定义使用 * </ul> * * @return 此 {@code UUID} 相关联的变体号 */ public int variant() { // This field is composed of a varying number of bits. // 0 - - Reserved for NCS backward compatibility // 1 0 - The IETF aka Leach-Salz variant (used by this class) // 1 1 0 Reserved, Microsoft backward compatibility // 1 1 1 Reserved for future definition. return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63)); } /** * 与此 UUID 相关联的时间戳值。 * * <p> * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br> * 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。 * * <p> * 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br> * 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 * * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。 */ public long timestamp() throws UnsupportedOperationException { checkTimeBase(); return (mostSigBits & 0x0FFFL) << 48// | ((mostSigBits >> 16) & 0x0FFFFL) << 32// | mostSigBits >>> 32; } /** * 与此 UUID 相关联的时钟序列值。 * * <p> * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。 * <p> * {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出 * UnsupportedOperationException。 * * @return 此 {@code UUID} 的时钟序列 * * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 */ public int clockSequence() throws UnsupportedOperationException { checkTimeBase(); return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); } /** * 与此 UUID 相关的节点值。 * * <p> * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。 * <p> * 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br> * 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 * * @return 此 {@code UUID} 的节点值 * * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 */ public long node() throws UnsupportedOperationException { checkTimeBase(); return leastSigBits & 0x0000FFFFFFFFFFFFL; } /** * 返回此{@code UUID} 的字符串表现形式。 * * <p> * UUID 的字符串表示形式由此 BNF 描述: * * <pre> * {@code * UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node> * time_low = 4*<hexOctet> * time_mid = 2*<hexOctet> * time_high_and_version = 2*<hexOctet> * variant_and_sequence = 2*<hexOctet> * node = 6*<hexOctet> * hexOctet = <hexDigit><hexDigit> * hexDigit = [0-9a-fA-F] * } * </pre> * * </blockquote> * * @return 此{@code UUID} 的字符串表现形式 * @see #toString(boolean) */ @Override public String toString() { return toString(false); } /** * 返回此{@code UUID} 的字符串表现形式。 * * <p> * UUID 的字符串表示形式由此 BNF 描述: * * <pre> * {@code * UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node> * time_low = 4*<hexOctet> * time_mid = 2*<hexOctet> * time_high_and_version = 2*<hexOctet> * variant_and_sequence = 2*<hexOctet> * node = 6*<hexOctet> * hexOctet = <hexDigit><hexDigit> * hexDigit = [0-9a-fA-F] * } * </pre> * * </blockquote> * * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串 * @return 此{@code UUID} 的字符串表现形式 */ public String toString(boolean isSimple) { final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36); // time_low builder.append(digits(mostSigBits >> 32, 8)); if (!isSimple) { builder.append('-'); } // time_mid builder.append(digits(mostSigBits >> 16, 4)); if (!isSimple) { builder.append('-'); } // time_high_and_version builder.append(digits(mostSigBits, 4)); if (!isSimple) { builder.append('-'); } // variant_and_sequence builder.append(digits(leastSigBits >> 48, 4)); if (!isSimple) { builder.append('-'); } // node builder.append(digits(leastSigBits, 12)); return builder.toString(); } /** * 返回此 UUID 的哈希码。 * * @return UUID 的哈希码值。 */ @Override public int hashCode() { long hilo = mostSigBits ^ leastSigBits; return ((int) (hilo >> 32)) ^ (int) hilo; } /** * 将此对象与指定对象比较。 * <p> * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。 * * @param obj 要与之比较的对象 * * @return 如果对象相同,则返回 {@code true};否则返回 {@code false} */ @Override public boolean equals(Object obj) { if ((null == obj) || (obj.getClass() != UUID.class)) { return false; } UUID id = (UUID) obj; return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits); } // Comparison Operations /** * 将此 UUID 与指定的 UUID 比较。 * * <p> * 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。 * * @param val 与此 UUID 比较的 UUID * * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。 * */ @Override public int compareTo(UUID val) { // The ordering is intentionally set up so that the UUIDs // can simply be numerically compared as two numbers return (this.mostSigBits < val.mostSigBits ? -1 : // (this.mostSigBits > val.mostSigBits ? 1 : // (this.leastSigBits < val.leastSigBits ? -1 : // (this.leastSigBits > val.leastSigBits ? 1 : // 0)))); } // ------------------------------------------------------------------------------------------------------------------- // Private method start /** * 返回指定数字对应的hex值 * * @param val 值 * @param digits 位 * @return 值 */ private static String digits(long val, int digits) { long hi = 1L << (digits * 4); return Long.toHexString(hi | (val & (hi - 1))).substring(1); } /** * 检查是否为time-based版本UUID */ private void checkTimeBase() { if (version() != 1) { throw new UnsupportedOperationException("Not a time-based UUID"); } } /** * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG) * * @return {@link SecureRandom} */ public static SecureRandom getSecureRandom() { try { return SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { throw new UtilException(e); } } /** * 获取随机数生成器对象<br> * ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。 * * @return {@link ThreadLocalRandom} */ public static ThreadLocalRandom getRandom() { return ThreadLocalRandom.current(); } } ycl-generator/src/main/resources/vm/java/controller.java.vm
@@ -21,6 +21,7 @@ import com.ycl.common.utils.poi.ExcelUtil; #if($table.crud || $table.sub) import com.ycl.common.core.page.TableDataInfo; import pojo.AjaxResult; #elseif($table.tree) #end ycl-pojo/src/main/java/com/ycl/platform/entity/TMonitor.java
New file @@ -0,0 +1,461 @@ package com.ycl.platform.entity; import annotation.Excel; import com.fasterxml.jackson.annotation.JsonFormat; import com.ycl.system.entity.BaseEntity; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import java.util.Date; /** * 设备资产对象 t_monitor * * @author ruoyi * @date 2024-03-04 */ public class TMonitor extends BaseEntity { private static final long serialVersionUID = 1L; /** $column.columnComment */ private Long id; /** 设备编码 */ @Excel(name = "设备编码") private String serialNumber; /** 设备名称 */ @Excel(name = "设备名称") private String name; /** 监控点位类型 [1.一类视频监控点;2.二类视频监控点;3.三类视频监控点;4.公安内部视频监控点;9.其他点位;] */ @Excel(name = "监控点位类型 [1.一类视频监控点;2.二类视频监控点;3.三类视频监控点;4.公安内部视频监控点;9.其他点位;]") private Long siteType; /** 摄像机Mac地址 */ @Excel(name = "摄像机Mac地址") private String macAddr; /** 摄像机IPV4或IPV6地址 */ @Excel(name = "摄像机IPV4或IPV6地址") private String ip; /** 摄像机功能类型[1.视频监控;2.车辆识别;3.人员识别;] 数据格式[填入多个值并以/隔开。例如 1/2] */ @Excel(name = "摄像机功能类型[1.视频监控;2.车辆识别;3.人员识别;] 数据格式[填入多个值并以/隔开。例如 1/2]") private String cameraFunType; /** 设备经度,至少保留六位小数 */ @Excel(name = "设备经度,至少保留六位小数") private String longitude; /** 设备维度,至少保留六位小数 */ @Excel(name = "设备维度,至少保留六位小数") private String latitude; /** 摄像机采集区域参考字典表,数据多选以/隔开 */ @Excel(name = "摄像机采集区域参考字典表,数据多选以/隔开") private String cameraCaptureArea; /** 设备状态 1/2 可用/不可用 */ @Excel(name = "设备状态 1/2 可用/不可用") private Long onState; /** 行政区域 */ @Excel(name = "行政区域") private String civilCode; /** 是否集成设备,0/1 不是/是 */ @Excel(name = "是否集成设备,0/1 不是/是") private Long integratedDevice; /** 摄像机品牌 [1.海康威视;2.大华;3.天地伟业;4.科达;5.安讯士;6.博世;7.亚安;8.英飞拓;9.宇视;10.海信;11.中星电子;12.明景;13.联想;14.中兴;15.索尼;16.三星;99.其它; */ @Excel(name = "摄像机品牌 [1.海康威视;2.大华;3.天地伟业;4.科达;5.安讯士;6.博世;7.亚安;8.英飞拓;9.宇视;10.海信;11.中星电子;12.明景;13.联想;14.中兴;15.索尼;16.三星;99.其它;") private Long cameraBrand; /** 安装地址 */ @Excel(name = "安装地址") private String address; /** 联网属性 0/1 已联网/未联网 */ @Excel(name = "联网属性 0/1 已联网/未联网") private Long netWorking; /** 所属辖区公安机关 */ @Excel(name = "所属辖区公安机关") private String publicSecurity; /** 安装时间 yyyy-MM-dd HH:mm:ss */ @JsonFormat(pattern = "yyyy-MM-dd") @Excel(name = "安装时间 yyyy-MM-dd HH:mm:ss", width = 30, dateFormat = "yyyy-MM-dd") private Date installedTime; /** 管理单位 */ @Excel(name = "管理单位") private String managementUnit; /** 管理单位联系方式 */ @Excel(name = "管理单位联系方式") private String muContactInfo; /** 录象保存天数 0 - 2147483647 */ @Excel(name = "录象保存天数 0 - 2147483647") private Long storageDays; /** 监视方位 [1.东;2.西;3.南;4.北;5.东南;6.东北;7.西南;8.西北;9.全向;] */ @Excel(name = "监视方位 [1.东;2.西;3.南;4.北;5.东南;6.东北;7.西南;8.西北;9.全向;]") private Long monitorAzimuth; /** 摄像机场景预设照片URL */ @Excel(name = "摄像机场景预设照片URL") private String scenePhotoAddr; /** 设备型号 */ @Excel(name = "设备型号") private String model; /** 点位俗称 */ @Excel(name = "点位俗称") private String siteVulgo; /** 摄像机类型 [1.球机;2.半球;3.固定枪机;4.遥控枪机;5.卡口枪机;99.未知; */ @Excel(name = "摄像机类型 [1.球机;2.半球;3.固定枪机;4.遥控枪机;5.卡口枪机;99.未知;") private Long cameraType; /** 补光属性[1.无补光;2.红外补光;3.白光补光;9.其他补光;] */ @Excel(name = "补光属性[1.无补光;2.红外补光;3.白光补光;9.其他补光;] ") private Long cameraLightType; /** 摄像机编码格式 [1.MPEG-4;2.H.264;3.SVAC;4.H.265;] */ @Excel(name = "摄像机编码格式 [1.MPEG-4;2.H.264;3.SVAC;4.H.265;]") private Long encodedFormat; /** 所属部门/行业 取值范围(多选) : [1.公安机关;2.环保部门;3.文博部门;4.医疗部门;5.旅游管理;6.新闻广电;7.食品医药监督管理部门;8.教育管理部门;9.检察院;10.法院;11.金融部门;12.交通部门;13.住房和城乡建设部门;14.水利部门;15.林业部门;16.安全生产监督部门;17.市政市容委;18.国土局;] 数据格式[填入多个值并以/隔开。例如 1/2] */ @Excel(name = "所属部门/行业 取值范围(多选) : [1.公安机关;2.环保部门;3.文博部门;4.医疗部门;5.旅游管理;6.新闻广电;7.食品医药监督管理部门;8.教育管理部门;9.检察院;10.法院;11.金融部门;12.交通部门;13.住房和城乡建设部门;14.水利部门;15.林业部门;16.安全生产监督部门;17.市政市容委;18.国土局;] 数据格式[填入多个值并以/隔开。例如 1/2]") private String cameraDept; /** 行业编码 [00.社会治安路面接入;01.社会治安社区接入;02.社会治安内部接入;03.社会治安其他接入;04.交通路面接入;05.交通卡口接入;06.交通内部接入;07.交通其他接入;08.城市管理接入;09.卫生环保接入;10.商检海关接入;11.教育部门接入;] */ @Excel(name = "行业编码 [00.社会治安路面接入;01.社会治安社区接入;02.社会治安内部接入;03.社会治安其他接入;04.交通路面接入;05.交通卡口接入;06.交通内部接入;07.交通其他接入;08.城市管理接入;09.卫生环保接入;10.商检海关接入;11.教育部门接入;]") private String hybm; /** 类型编码 : [131.摄像机编码;132.网络摄像机编码;] */ @Excel(name = "类型编码 : [131.摄像机编码;132.网络摄像机编码;]") private Long lxbm; public void setId(Long id) { this.id = id; } public Long getId() { return id; } public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; } public String getSerialNumber() { return serialNumber; } public void setName(String name) { this.name = name; } public String getName() { return name; } public void setSiteType(Long siteType) { this.siteType = siteType; } public Long getSiteType() { return siteType; } public void setMacAddr(String macAddr) { this.macAddr = macAddr; } public String getMacAddr() { return macAddr; } public void setIp(String ip) { this.ip = ip; } public String getIp() { return ip; } public void setCameraFunType(String cameraFunType) { this.cameraFunType = cameraFunType; } public String getCameraFunType() { return cameraFunType; } public void setLongitude(String longitude) { this.longitude = longitude; } public String getLongitude() { return longitude; } public void setLatitude(String latitude) { this.latitude = latitude; } public String getLatitude() { return latitude; } public void setCameraCaptureArea(String cameraCaptureArea) { this.cameraCaptureArea = cameraCaptureArea; } public String getCameraCaptureArea() { return cameraCaptureArea; } public void setOnState(Long onState) { this.onState = onState; } public Long getOnState() { return onState; } public void setCivilCode(String civilCode) { this.civilCode = civilCode; } public String getCivilCode() { return civilCode; } public void setIntegratedDevice(Long integratedDevice) { this.integratedDevice = integratedDevice; } public Long getIntegratedDevice() { return integratedDevice; } public void setCameraBrand(Long cameraBrand) { this.cameraBrand = cameraBrand; } public Long getCameraBrand() { return cameraBrand; } public void setAddress(String address) { this.address = address; } public String getAddress() { return address; } public void setNetWorking(Long netWorking) { this.netWorking = netWorking; } public Long getNetWorking() { return netWorking; } public void setPublicSecurity(String publicSecurity) { this.publicSecurity = publicSecurity; } public String getPublicSecurity() { return publicSecurity; } public void setInstalledTime(Date installedTime) { this.installedTime = installedTime; } public Date getInstalledTime() { return installedTime; } public void setManagementUnit(String managementUnit) { this.managementUnit = managementUnit; } public String getManagementUnit() { return managementUnit; } public void setMuContactInfo(String muContactInfo) { this.muContactInfo = muContactInfo; } public String getMuContactInfo() { return muContactInfo; } public void setStorageDays(Long storageDays) { this.storageDays = storageDays; } public Long getStorageDays() { return storageDays; } public void setMonitorAzimuth(Long monitorAzimuth) { this.monitorAzimuth = monitorAzimuth; } public Long getMonitorAzimuth() { return monitorAzimuth; } public void setScenePhotoAddr(String scenePhotoAddr) { this.scenePhotoAddr = scenePhotoAddr; } public String getScenePhotoAddr() { return scenePhotoAddr; } public void setModel(String model) { this.model = model; } public String getModel() { return model; } public void setSiteVulgo(String siteVulgo) { this.siteVulgo = siteVulgo; } public String getSiteVulgo() { return siteVulgo; } public void setCameraType(Long cameraType) { this.cameraType = cameraType; } public Long getCameraType() { return cameraType; } public void setCameraLightType(Long cameraLightType) { this.cameraLightType = cameraLightType; } public Long getCameraLightType() { return cameraLightType; } public void setEncodedFormat(Long encodedFormat) { this.encodedFormat = encodedFormat; } public Long getEncodedFormat() { return encodedFormat; } public void setCameraDept(String cameraDept) { this.cameraDept = cameraDept; } public String getCameraDept() { return cameraDept; } public void setHybm(String hybm) { this.hybm = hybm; } public String getHybm() { return hybm; } public void setLxbm(Long lxbm) { this.lxbm = lxbm; } public Long getLxbm() { return lxbm; } @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) .append("id", getId()) .append("serialNumber", getSerialNumber()) .append("name", getName()) .append("siteType", getSiteType()) .append("macAddr", getMacAddr()) .append("ip", getIp()) .append("cameraFunType", getCameraFunType()) .append("longitude", getLongitude()) .append("latitude", getLatitude()) .append("cameraCaptureArea", getCameraCaptureArea()) .append("onState", getOnState()) .append("civilCode", getCivilCode()) .append("integratedDevice", getIntegratedDevice()) .append("cameraBrand", getCameraBrand()) .append("address", getAddress()) .append("netWorking", getNetWorking()) .append("publicSecurity", getPublicSecurity()) .append("installedTime", getInstalledTime()) .append("managementUnit", getManagementUnit()) .append("muContactInfo", getMuContactInfo()) .append("storageDays", getStorageDays()) .append("monitorAzimuth", getMonitorAzimuth()) .append("scenePhotoAddr", getScenePhotoAddr()) .append("model", getModel()) .append("siteVulgo", getSiteVulgo()) .append("cameraType", getCameraType()) .append("cameraLightType", getCameraLightType()) .append("encodedFormat", getEncodedFormat()) .append("cameraDept", getCameraDept()) .append("hybm", getHybm()) .append("lxbm", getLxbm()) .toString(); } } ycl-pojo/src/main/java/com/ycl/system/AjaxResult.java
@@ -26,14 +26,14 @@ public static final String DATA_TAG = "data"; /** * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 * 初始化一个新创建的 pojo.AjaxResult 对象,使其表示一个空消息。 */ public AjaxResult() { } /** * 初始化一个新创建的 AjaxResult 对象 * 初始化一个新创建的 pojo.AjaxResult 对象 * * @param code 状态码 * @param msg 返回内容 @@ -45,7 +45,7 @@ } /** * 初始化一个新创建的 AjaxResult 对象 * 初始化一个新创建的 pojo.AjaxResult 对象 * * @param code 状态码 * @param msg 返回内容 ycl-server/src/main/java/com/ycl/platform/controller/TMonitorController.java
New file @@ -0,0 +1,98 @@ package com.ycl.platform.controller; import annotation.Log; import com.ycl.platform.entity.TMonitor; import com.ycl.platform.service.ITMonitorService; import com.ycl.system.AjaxResult; import com.ycl.system.controller.BaseController; import com.ycl.system.page.TableDataInfo; import com.ycl.utils.poi.ExcelUtil; import enumeration.BusinessType; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import java.util.List; /** * 设备资产Controller * * @author ruoyi * @date 2024-03-04 */ @RestController @RequestMapping("/system/monitor") public class TMonitorController extends BaseController { @Autowired private ITMonitorService tMonitorService; /** * 查询设备资产列表 */ @PreAuthorize("@ss.hasPermi('system:monitor:list')") @GetMapping("/list") public TableDataInfo list(TMonitor tMonitor) { startPage(); List<TMonitor> list = tMonitorService.selectTMonitorList(tMonitor); return getDataTable(list); } /** * 导出设备资产列表 */ @PreAuthorize("@ss.hasPermi('system:monitor:export')") @Log(title = "设备资产", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(HttpServletResponse response, TMonitor tMonitor) { List<TMonitor> list = tMonitorService.selectTMonitorList(tMonitor); ExcelUtil<TMonitor> util = new ExcelUtil<TMonitor>(TMonitor.class); util.exportExcel(response, list, "设备资产数据"); } /** * 获取设备资产详细信息 */ @PreAuthorize("@ss.hasPermi('system:monitor:query')") @GetMapping(value = "/{id}") public AjaxResult getInfo(@PathVariable("id") Long id) { return success(tMonitorService.selectTMonitorById(id)); } /** * 新增设备资产 */ @PreAuthorize("@ss.hasPermi('system:monitor:add')") @Log(title = "设备资产", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@RequestBody TMonitor tMonitor) { return toAjax(tMonitorService.insertTMonitor(tMonitor)); } /** * 修改设备资产 */ @PreAuthorize("@ss.hasPermi('system:monitor:edit')") @Log(title = "设备资产", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@RequestBody TMonitor tMonitor) { return toAjax(tMonitorService.updateTMonitor(tMonitor)); } /** * 删除设备资产 */ @PreAuthorize("@ss.hasPermi('system:monitor:remove')") @Log(title = "设备资产", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") public AjaxResult remove(@PathVariable Long[] ids) { return toAjax(tMonitorService.deleteTMonitorByIds(ids)); } } ycl-server/src/main/java/com/ycl/platform/mapper/TMonitorMapper.java
New file @@ -0,0 +1,62 @@ package com.ycl.platform.mapper; import com.ycl.platform.entity.TMonitor; import java.util.List; /** * 设备资产Mapper接口 * * @author ruoyi * @date 2024-03-04 */ public interface TMonitorMapper { /** * 查询设备资产 * * @param id 设备资产主键 * @return 设备资产 */ public TMonitor selectTMonitorById(Long id); /** * 查询设备资产列表 * * @param tMonitor 设备资产 * @return 设备资产集合 */ public List<TMonitor> selectTMonitorList(TMonitor tMonitor); /** * 新增设备资产 * * @param tMonitor 设备资产 * @return 结果 */ public int insertTMonitor(TMonitor tMonitor); /** * 修改设备资产 * * @param tMonitor 设备资产 * @return 结果 */ public int updateTMonitor(TMonitor tMonitor); /** * 删除设备资产 * * @param id 设备资产主键 * @return 结果 */ public int deleteTMonitorById(Long id); /** * 批量删除设备资产 * * @param ids 需要删除的数据主键集合 * @return 结果 */ public int deleteTMonitorByIds(Long[] ids); } ycl-server/src/main/java/com/ycl/platform/service/ITMonitorService.java
New file @@ -0,0 +1,62 @@ package com.ycl.platform.service; import com.ycl.platform.entity.TMonitor; import java.util.List; /** * 设备资产Service接口 * * @author ruoyi * @date 2024-03-04 */ public interface ITMonitorService { /** * 查询设备资产 * * @param id 设备资产主键 * @return 设备资产 */ public TMonitor selectTMonitorById(Long id); /** * 查询设备资产列表 * * @param tMonitor 设备资产 * @return 设备资产集合 */ public List<TMonitor> selectTMonitorList(TMonitor tMonitor); /** * 新增设备资产 * * @param tMonitor 设备资产 * @return 结果 */ public int insertTMonitor(TMonitor tMonitor); /** * 修改设备资产 * * @param tMonitor 设备资产 * @return 结果 */ public int updateTMonitor(TMonitor tMonitor); /** * 批量删除设备资产 * * @param ids 需要删除的设备资产主键集合 * @return 结果 */ public int deleteTMonitorByIds(Long[] ids); /** * 删除设备资产信息 * * @param id 设备资产主键 * @return 结果 */ public int deleteTMonitorById(Long id); } ycl-server/src/main/java/com/ycl/platform/service/impl/TMonitorServiceImpl.java
New file @@ -0,0 +1,94 @@ package com.ycl.platform.service.impl; import com.ycl.platform.entity.TMonitor; import com.ycl.platform.mapper.TMonitorMapper; import com.ycl.platform.service.ITMonitorService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; /** * 设备资产Service业务层处理 * * @author ruoyi * @date 2024-03-04 */ @Service public class TMonitorServiceImpl implements ITMonitorService { @Autowired private TMonitorMapper tMonitorMapper; /** * 查询设备资产 * * @param id 设备资产主键 * @return 设备资产 */ @Override public TMonitor selectTMonitorById(Long id) { return tMonitorMapper.selectTMonitorById(id); } /** * 查询设备资产列表 * * @param tMonitor 设备资产 * @return 设备资产 */ @Override public List<TMonitor> selectTMonitorList(TMonitor tMonitor) { return tMonitorMapper.selectTMonitorList(tMonitor); } /** * 新增设备资产 * * @param tMonitor 设备资产 * @return 结果 */ @Override public int insertTMonitor(TMonitor tMonitor) { return tMonitorMapper.insertTMonitor(tMonitor); } /** * 修改设备资产 * * @param tMonitor 设备资产 * @return 结果 */ @Override public int updateTMonitor(TMonitor tMonitor) { return tMonitorMapper.updateTMonitor(tMonitor); } /** * 批量删除设备资产 * * @param ids 需要删除的设备资产主键 * @return 结果 */ @Override public int deleteTMonitorByIds(Long[] ids) { return tMonitorMapper.deleteTMonitorByIds(ids); } /** * 删除设备资产信息 * * @param id 设备资产主键 * @return 结果 */ @Override public int deleteTMonitorById(Long id) { return tMonitorMapper.deleteTMonitorById(id); } } ycl-server/src/main/java/com/ycl/utils/poi/ExcelUtil.java
@@ -1,7 +1,7 @@ package com.ycl.utils.poi; import com.ycl.annotation.Excel; import com.ycl.annotation.Excels; import annotation.Excel; import annotation.Excels; import com.ycl.config.PlatformConfig; import com.ycl.exception.UtilException; import com.ycl.system.AjaxResult; ycl-server/src/main/resources/mapper/zgyw/TMonitorMapper.xml
New file @@ -0,0 +1,201 @@ <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.ycl.platform.mapper.TMonitorMapper"> <resultMap type="com.ycl.platform.entity.TMonitor" id="TMonitorResult"> <result property="id" column="id" /> <result property="serialNumber" column="serial_number" /> <result property="name" column="name" /> <result property="siteType" column="site_type" /> <result property="macAddr" column="mac_addr" /> <result property="ip" column="ip" /> <result property="cameraFunType" column="camera_fun_type" /> <result property="longitude" column="longitude" /> <result property="latitude" column="latitude" /> <result property="cameraCaptureArea" column="camera_capture_area" /> <result property="onState" column="on_state" /> <result property="civilCode" column="civil_code" /> <result property="integratedDevice" column="integrated_device" /> <result property="cameraBrand" column="camera_brand" /> <result property="address" column="address" /> <result property="netWorking" column="net_working" /> <result property="publicSecurity" column="public_security" /> <result property="installedTime" column="installed_time" /> <result property="managementUnit" column="management_unit" /> <result property="muContactInfo" column="mu_contact_info" /> <result property="storageDays" column="storage_days" /> <result property="monitorAzimuth" column="monitor_azimuth" /> <result property="scenePhotoAddr" column="scene_photo_addr" /> <result property="model" column="model" /> <result property="siteVulgo" column="site_vulgo" /> <result property="cameraType" column="camera_type" /> <result property="cameraLightType" column="camera_light_type" /> <result property="encodedFormat" column="encoded_format" /> <result property="cameraDept" column="camera_dept" /> <result property="hybm" column="hybm" /> <result property="lxbm" column="lxbm" /> </resultMap> <sql id="selectTMonitorVo"> select id, serial_number, name, site_type, mac_addr, ip, camera_fun_type, longitude, latitude, camera_capture_area, on_state, civil_code, integrated_device, camera_brand, address, net_working, public_security, installed_time, management_unit, mu_contact_info, storage_days, monitor_azimuth, scene_photo_addr, model, site_vulgo, camera_type, camera_light_type, encoded_format, camera_dept, hybm, lxbm from t_monitor </sql> <select id="selectTMonitorList" parameterType="com.ycl.platform.entity.TMonitor" resultMap="TMonitorResult"> <include refid="selectTMonitorVo"/> <where> <if test="serialNumber != null and serialNumber != ''"> and serial_number = #{serialNumber}</if> <if test="name != null and name != ''"> and name like concat('%', #{name}, '%')</if> <if test="siteType != null "> and site_type = #{siteType}</if> <if test="macAddr != null and macAddr != ''"> and mac_addr = #{macAddr}</if> <if test="ip != null and ip != ''"> and ip = #{ip}</if> <if test="cameraFunType != null and cameraFunType != ''"> and camera_fun_type = #{cameraFunType}</if> <if test="longitude != null and longitude != ''"> and longitude = #{longitude}</if> <if test="latitude != null and latitude != ''"> and latitude = #{latitude}</if> <if test="cameraCaptureArea != null and cameraCaptureArea != ''"> and camera_capture_area = #{cameraCaptureArea}</if> <if test="onState != null "> and on_state = #{onState}</if> <if test="civilCode != null and civilCode != ''"> and civil_code = #{civilCode}</if> <if test="integratedDevice != null "> and integrated_device = #{integratedDevice}</if> <if test="cameraBrand != null "> and camera_brand = #{cameraBrand}</if> <if test="address != null and address != ''"> and address = #{address}</if> <if test="netWorking != null "> and net_working = #{netWorking}</if> <if test="publicSecurity != null and publicSecurity != ''"> and public_security = #{publicSecurity}</if> <if test="installedTime != null "> and installed_time = #{installedTime}</if> <if test="managementUnit != null and managementUnit != ''"> and management_unit = #{managementUnit}</if> <if test="muContactInfo != null and muContactInfo != ''"> and mu_contact_info = #{muContactInfo}</if> <if test="storageDays != null "> and storage_days = #{storageDays}</if> <if test="monitorAzimuth != null "> and monitor_azimuth = #{monitorAzimuth}</if> <if test="scenePhotoAddr != null and scenePhotoAddr != ''"> and scene_photo_addr = #{scenePhotoAddr}</if> <if test="model != null and model != ''"> and model = #{model}</if> <if test="siteVulgo != null and siteVulgo != ''"> and site_vulgo = #{siteVulgo}</if> <if test="cameraType != null "> and camera_type = #{cameraType}</if> <if test="cameraLightType != null "> and camera_light_type = #{cameraLightType}</if> <if test="encodedFormat != null "> and encoded_format = #{encodedFormat}</if> <if test="cameraDept != null and cameraDept != ''"> and camera_dept = #{cameraDept}</if> <if test="hybm != null and hybm != ''"> and hybm = #{hybm}</if> <if test="lxbm != null "> and lxbm = #{lxbm}</if> </where> </select> <select id="selectTMonitorById" parameterType="Long" resultMap="TMonitorResult"> <include refid="selectTMonitorVo"/> where id = #{id} </select> <insert id="insertTMonitor" parameterType="com.ycl.platform.entity.TMonitor" useGeneratedKeys="true" keyProperty="id"> insert into t_monitor <trim prefix="(" suffix=")" suffixOverrides=","> <if test="serialNumber != null and serialNumber != ''">serial_number,</if> <if test="name != null and name != ''">name,</if> <if test="siteType != null">site_type,</if> <if test="macAddr != null and macAddr != ''">mac_addr,</if> <if test="ip != null and ip != ''">ip,</if> <if test="cameraFunType != null and cameraFunType != ''">camera_fun_type,</if> <if test="longitude != null and longitude != ''">longitude,</if> <if test="latitude != null and latitude != ''">latitude,</if> <if test="cameraCaptureArea != null and cameraCaptureArea != ''">camera_capture_area,</if> <if test="onState != null">on_state,</if> <if test="civilCode != null and civilCode != ''">civil_code,</if> <if test="integratedDevice != null">integrated_device,</if> <if test="cameraBrand != null">camera_brand,</if> <if test="address != null">address,</if> <if test="netWorking != null">net_working,</if> <if test="publicSecurity != null">public_security,</if> <if test="installedTime != null">installed_time,</if> <if test="managementUnit != null">management_unit,</if> <if test="muContactInfo != null">mu_contact_info,</if> <if test="storageDays != null">storage_days,</if> <if test="monitorAzimuth != null">monitor_azimuth,</if> <if test="scenePhotoAddr != null">scene_photo_addr,</if> <if test="model != null">model,</if> <if test="siteVulgo != null">site_vulgo,</if> <if test="cameraType != null">camera_type,</if> <if test="cameraLightType != null">camera_light_type,</if> <if test="encodedFormat != null">encoded_format,</if> <if test="cameraDept != null">camera_dept,</if> <if test="hybm != null">hybm,</if> <if test="lxbm != null">lxbm,</if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="serialNumber != null and serialNumber != ''">#{serialNumber},</if> <if test="name != null and name != ''">#{name},</if> <if test="siteType != null">#{siteType},</if> <if test="macAddr != null and macAddr != ''">#{macAddr},</if> <if test="ip != null and ip != ''">#{ip},</if> <if test="cameraFunType != null and cameraFunType != ''">#{cameraFunType},</if> <if test="longitude != null and longitude != ''">#{longitude},</if> <if test="latitude != null and latitude != ''">#{latitude},</if> <if test="cameraCaptureArea != null and cameraCaptureArea != ''">#{cameraCaptureArea},</if> <if test="onState != null">#{onState},</if> <if test="civilCode != null and civilCode != ''">#{civilCode},</if> <if test="integratedDevice != null">#{integratedDevice},</if> <if test="cameraBrand != null">#{cameraBrand},</if> <if test="address != null">#{address},</if> <if test="netWorking != null">#{netWorking},</if> <if test="publicSecurity != null">#{publicSecurity},</if> <if test="installedTime != null">#{installedTime},</if> <if test="managementUnit != null">#{managementUnit},</if> <if test="muContactInfo != null">#{muContactInfo},</if> <if test="storageDays != null">#{storageDays},</if> <if test="monitorAzimuth != null">#{monitorAzimuth},</if> <if test="scenePhotoAddr != null">#{scenePhotoAddr},</if> <if test="model != null">#{model},</if> <if test="siteVulgo != null">#{siteVulgo},</if> <if test="cameraType != null">#{cameraType},</if> <if test="cameraLightType != null">#{cameraLightType},</if> <if test="encodedFormat != null">#{encodedFormat},</if> <if test="cameraDept != null">#{cameraDept},</if> <if test="hybm != null">#{hybm},</if> <if test="lxbm != null">#{lxbm},</if> </trim> </insert> <update id="updateTMonitor" parameterType="com.ycl.platform.entity.TMonitor"> update t_monitor <trim prefix="SET" suffixOverrides=","> <if test="serialNumber != null and serialNumber != ''">serial_number = #{serialNumber},</if> <if test="name != null and name != ''">name = #{name},</if> <if test="siteType != null">site_type = #{siteType},</if> <if test="macAddr != null and macAddr != ''">mac_addr = #{macAddr},</if> <if test="ip != null and ip != ''">ip = #{ip},</if> <if test="cameraFunType != null and cameraFunType != ''">camera_fun_type = #{cameraFunType},</if> <if test="longitude != null and longitude != ''">longitude = #{longitude},</if> <if test="latitude != null and latitude != ''">latitude = #{latitude},</if> <if test="cameraCaptureArea != null and cameraCaptureArea != ''">camera_capture_area = #{cameraCaptureArea},</if> <if test="onState != null">on_state = #{onState},</if> <if test="civilCode != null and civilCode != ''">civil_code = #{civilCode},</if> <if test="integratedDevice != null">integrated_device = #{integratedDevice},</if> <if test="cameraBrand != null">camera_brand = #{cameraBrand},</if> <if test="address != null">address = #{address},</if> <if test="netWorking != null">net_working = #{netWorking},</if> <if test="publicSecurity != null">public_security = #{publicSecurity},</if> <if test="installedTime != null">installed_time = #{installedTime},</if> <if test="managementUnit != null">management_unit = #{managementUnit},</if> <if test="muContactInfo != null">mu_contact_info = #{muContactInfo},</if> <if test="storageDays != null">storage_days = #{storageDays},</if> <if test="monitorAzimuth != null">monitor_azimuth = #{monitorAzimuth},</if> <if test="scenePhotoAddr != null">scene_photo_addr = #{scenePhotoAddr},</if> <if test="model != null">model = #{model},</if> <if test="siteVulgo != null">site_vulgo = #{siteVulgo},</if> <if test="cameraType != null">camera_type = #{cameraType},</if> <if test="cameraLightType != null">camera_light_type = #{cameraLightType},</if> <if test="encodedFormat != null">encoded_format = #{encodedFormat},</if> <if test="cameraDept != null">camera_dept = #{cameraDept},</if> <if test="hybm != null">hybm = #{hybm},</if> <if test="lxbm != null">lxbm = #{lxbm},</if> </trim> where id = #{id} </update> <delete id="deleteTMonitorById" parameterType="Long"> delete from t_monitor where id = #{id} </delete> <delete id="deleteTMonitorByIds" parameterType="String"> delete from t_monitor where id in <foreach item="id" collection="array" open="(" separator="," close=")"> #{id} </foreach> </delete> </mapper>