From 0be0f6881508a4834a2665916193a052e5413813 Mon Sep 17 00:00:00 2001 From: RuoYi Date: Thu, 10 Jan 2019 19:06:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=94=A8=E6=88=B7=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/monitor/SysJobController.java | 2 +- .../monitor/SysJobLogController.java | 2 +- .../monitor/SysLogininforController.java | 2 +- .../monitor/SysOperlogController.java | 2 +- .../system/SysConfigController.java | 2 +- .../system/SysDictDataController.java | 2 +- .../system/SysDictTypeController.java | 2 +- .../controller/system/SysPostController.java | 2 +- .../controller/system/SysRoleController.java | 2 +- .../controller/system/SysUserController.java | 26 +- .../main/resources/static/ruoyi/css/ry-ui.css | 53 +- .../main/resources/static/ruoyi/js/ry-ui.js | 64 ++- .../resources/templates/system/user/edit.html | 2 +- .../resources/templates/system/user/user.html | 18 + .../com/ruoyi/common/annotation/Excel.java | 23 +- .../ruoyi/common/reflect/ReflectUtils.java | 406 ++++++++++++++ .../com/ruoyi/common/utils/ExcelUtil.java | 513 ++++++++++++------ .../java/com/ruoyi/system/domain/SysUser.java | 5 + .../ruoyi/system/service/ISysUserService.java | 8 + .../service/impl/SysUserServiceImpl.java | 116 +++- 20 files changed, 1043 insertions(+), 209 deletions(-) create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/reflect/ReflectUtils.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysJobController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysJobController.java index c5797387..973a3067 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysJobController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysJobController.java @@ -59,7 +59,7 @@ public class SysJobController extends BaseController { List list = jobService.selectJobList(job); ExcelUtil util = new ExcelUtil(SysJob.class); - return util.exportExcel(list, "job"); + return util.exportExcel(list, "定时任务"); } @Log(title = "定时任务", businessType = BusinessType.DELETE) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysJobLogController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysJobLogController.java index a91daacd..5c2cfc1d 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysJobLogController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysJobLogController.java @@ -58,7 +58,7 @@ public class SysJobLogController extends BaseController { List list = jobLogService.selectJobLogList(jobLog); ExcelUtil util = new ExcelUtil(SysJobLog.class); - return util.exportExcel(list, "jobLog"); + return util.exportExcel(list, "调度日志"); } @Log(title = "调度日志", businessType = BusinessType.DELETE) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java index ed77e4ef..13f3102f 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java @@ -56,7 +56,7 @@ public class SysLogininforController extends BaseController { List list = logininforService.selectLogininforList(logininfor); ExcelUtil util = new ExcelUtil(SysLogininfor.class); - return util.exportExcel(list, "logininfor"); + return util.exportExcel(list, "登陆日志"); } @RequiresPermissions("monitor:logininfor:remove") diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java index d481cb86..c0cdbf9e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java @@ -58,7 +58,7 @@ public class SysOperlogController extends BaseController { List list = operLogService.selectOperLogList(operLog); ExcelUtil util = new ExcelUtil(SysOperLog.class); - return util.exportExcel(list, "operLog"); + return util.exportExcel(list, "操作日志"); } @RequiresPermissions("monitor:operlog:remove") diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java index efe6ef2f..962fcf08 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java @@ -62,7 +62,7 @@ public class SysConfigController extends BaseController { List list = configService.selectConfigList(config); ExcelUtil util = new ExcelUtil(SysConfig.class); - return util.exportExcel(list, "config"); + return util.exportExcel(list, "参数数据"); } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java index 66c10a59..de60f4a5 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java @@ -59,7 +59,7 @@ public class SysDictDataController extends BaseController { List list = dictDataService.selectDictDataList(dictData); ExcelUtil util = new ExcelUtil(SysDictData.class); - return util.exportExcel(list, "dictData"); + return util.exportExcel(list, "字典数据"); } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java index d7009695..f0e082a5 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java @@ -60,7 +60,7 @@ public class SysDictTypeController extends BaseController List list = dictTypeService.selectDictTypeList(dictType); ExcelUtil util = new ExcelUtil(SysDictType.class); - return util.exportExcel(list, "dictType"); + return util.exportExcel(list, "字典类型"); } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java index 55a72a6f..f921464a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java @@ -59,7 +59,7 @@ public class SysPostController extends BaseController { List list = postService.selectPostList(post); ExcelUtil util = new ExcelUtil(SysPost.class); - return util.exportExcel(list, "post"); + return util.exportExcel(list, "岗位数据"); } @RequiresPermissions("system:post:remove") diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java index 3450ef64..51d03816 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java @@ -60,7 +60,7 @@ public class SysRoleController extends BaseController { List list = roleService.selectRoleList(role); ExcelUtil util = new ExcelUtil(SysRole.class); - return util.exportExcel(list, "role"); + return util.exportExcel(list, "角色数据"); } /** diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java index af13355a..391e4ea5 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.base.AjaxResult; import com.ruoyi.common.enums.BusinessType; @@ -19,11 +20,11 @@ import com.ruoyi.common.utils.ExcelUtil; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.shiro.service.SysPasswordService; import com.ruoyi.framework.util.ShiroUtils; +import com.ruoyi.framework.web.base.BaseController; import com.ruoyi.system.domain.SysUser; import com.ruoyi.system.service.ISysPostService; import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysUserService; -import com.ruoyi.framework.web.base.BaseController; /** * 用户信息 @@ -73,7 +74,28 @@ public class SysUserController extends BaseController { List list = userService.selectUserList(user); ExcelUtil util = new ExcelUtil(SysUser.class); - return util.exportExcel(list, "user"); + return util.exportExcel(list, "用户数据"); + } + + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @RequiresPermissions("system:user:import") + @PostMapping("/importData") + @ResponseBody + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + { + ExcelUtil util = new ExcelUtil(SysUser.class); + List userList = util.importExcel(file.getInputStream()); + String message = userService.importUser(userList, updateSupport); + return AjaxResult.success(message); + } + + @RequiresPermissions("system:user:view") + @GetMapping("/importTemplate") + @ResponseBody + public AjaxResult importTemplate() + { + ExcelUtil util = new ExcelUtil(SysUser.class); + return util.importTemplateExcel("用户数据"); } /** diff --git a/ruoyi-admin/src/main/resources/static/ruoyi/css/ry-ui.css b/ruoyi-admin/src/main/resources/static/ruoyi/css/ry-ui.css index 73f1b986..c9f8c97f 100644 --- a/ruoyi-admin/src/main/resources/static/ruoyi/css/ry-ui.css +++ b/ruoyi-admin/src/main/resources/static/ruoyi/css/ry-ui.css @@ -3,7 +3,42 @@ * Copyright (c) 2018 ruoyi */ -/** 用户管理 样式布局 */ +/** 基础通用 **/ +.pt5 { + padding-top: 5px; +} +.pr5 { + padding-right: 5px; +} +.pb5 { + padding-bottom: 5px; +} +.mt10 { + margin-top: 10px; +} +.mr10 { + margin-right: 10px; +} +.mb10 { + margin-bottom: 10px; +} +.ml0 { + margin-left: 10px; +} +.mt20 { + margin-top: 20px; +} +.mr20 { + margin-right: 20px; +} +.mb20 { + margin-bottom: 20px; +} +.ml20 { + margin-left: 20px; +} + +/** 用户管理 样式布局 **/ .box { position: relative; border-radius: 3px; @@ -91,7 +126,7 @@ margin: 5px 0 5px -25px } -/** select2 样式修改 */ +/** select2 样式修改 **/ .select2-container--default .select2-selection--multiple .select2-selection__choice { background-color: #1AB394; border-color: #1AB394; @@ -112,7 +147,7 @@ padding-right: 10px } -/** 表单验证 样式布局 */ +/** 表单验证 样式布局 **/ label.error { position: absolute; right: 18px; @@ -143,7 +178,7 @@ label.error { max-width: none; } -/** 复选框&单选框 */ +/** 复选框&单选框 **/ .check-box,.radio-box { display: inline-block; box-sizing: border-box; @@ -160,7 +195,7 @@ label.error { left: 0 } -/* iCheck */ +/** iCheck **/ .icheckbox-blue,.iradio-blue { display: block; margin: 0; @@ -214,7 +249,7 @@ label.error { background-position: -180px 0 } -/** 遮罩层 */ +/** 遮罩层 **/ .loaderbox { display: inline-block; min-width: 125px; @@ -281,7 +316,7 @@ label.error { } } -/** 表单查询条件 */ +/** 表单查询条件 **/ ul { margin: 0; padding: 0; @@ -409,7 +444,7 @@ label { cursor: pointer; } -/** 表格查询数据 */ +/** 表格查询数据 **/ .table-striped { min-height: 75%; } @@ -437,7 +472,7 @@ label { border: 1px solid #ddd!important } -/** 首页样式 */ +/** 首页样式 **/ .ax_close_max { position: fixed; top: 5px; diff --git a/ruoyi-admin/src/main/resources/static/ruoyi/js/ry-ui.js b/ruoyi-admin/src/main/resources/static/ruoyi/js/ry-ui.js index d47f1c20..05ddd5d3 100644 --- a/ruoyi-admin/src/main/resources/static/ruoyi/js/ry-ui.js +++ b/ruoyi-admin/src/main/resources/static/ruoyi/js/ry-ui.js @@ -92,7 +92,7 @@ } $("#bootstrap-table").bootstrapTable('refresh', params); }, - // 下载-默认第一个form + // 导出数据 exportExcel: function(formId) { var currentId = $.common.isEmpty(formId) ? $('form').attr('id') : formId; $.modal.loading("正在导出数据,请稍后..."); @@ -105,6 +105,64 @@ $.modal.closeLoading(); }); }, + // 下载模板 + importTemplate: function() { + $.get($.table._option.importTemplateUrl, function(result) { + if (result.code == web_status.SUCCESS) { + window.location.href = ctx + "common/download?fileName=" + result.msg + "&delete=" + true; + } else { + $.modal.alertError(result.msg); + } + }); + }, + // 导入数据 + importExcel: function(formId) { + var currentId = $.common.isEmpty(formId) ? 'importForm' : formId; + $.form.reset(currentId); + layer.open({ + type: 1, + area: ['400px'], + fix: false, + //不固定 + maxmin: true, + shade: 0.3, + title: '导入' + $.table._option.modalName + '数据', + content: $('#' + currentId), + btn: [' 导入', ' 取消'], + // 弹层外区域关闭 + shadeClose: true, + btn1: function(index, layero){ + var file = layero.find('#file').val(); + if (file == '' || (!$.common.endWith(file, '.xls') && !$.common.endWith(file, '.xlsx'))){ + $.modal.msgWarning("请选择后缀为 “xls”或“xlsx”的文件。"); + return false; + } + var index = layer.load(2, {shade: false}); + var url = prefix + "/importData"; + var formData = new FormData(); + formData.append("file", $('#file')[0].files[0]); + formData.append("updateSupport", $("input[name='updateSupport']").is(':checked')); + $.ajax({ + url: url, + data: formData, + cache: false, + contentType: false, + processData: false, + type: 'POST', + success: function (result) { + if (result.code == web_status.SUCCESS) { + $.modal.closeAll(); + $.modal.alertSuccess(result.msg); + $.table.refresh(); + } else { + layer.close(index); + $.modal.alertError(result.msg); + } + } + }); + } + }); + }, // 刷新表格 refresh: function() { $("#bootstrap-table").bootstrapTable('refresh', { @@ -288,6 +346,10 @@ var index = parent.layer.getFrameIndex(window.name); parent.layer.close(index); }, + // 关闭全部窗体 + closeAll: function () { + layer.closeAll(); + }, // 确认窗体 confirm: function (content, callBack) { layer.confirm(content, { diff --git a/ruoyi-admin/src/main/resources/templates/system/user/edit.html b/ruoyi-admin/src/main/resources/templates/system/user/edit.html index 75c4012e..42e17fcd 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/edit.html @@ -184,7 +184,7 @@ /*用户管理-修改-选择部门树*/ function selectDeptTree() { - var deptId = $("#treeId").val(); + var deptId = $.common.isEmpty($("#treeId").val()) ? "100" : $("#treeId").val(); var url = ctx + "system/dept/selectDeptTree/" + deptId; var options = { title: '选择部门', diff --git a/ruoyi-admin/src/main/resources/templates/system/user/user.html b/ruoyi-admin/src/main/resources/templates/system/user/user.html index 49e0b929..c443c78d 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/user.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/user.html @@ -73,6 +73,9 @@ 删除 + + 导入 + 导出 @@ -83,6 +86,7 @@ +
@@ -106,6 +110,8 @@ updateUrl: prefix + "/edit/{id}", removeUrl: prefix + "/remove", exportUrl: prefix + "/export", + importUrl: prefix + "/importData", + importTemplateUrl: prefix + "/importTemplate", sortName: "createTime", sortOrder: "desc", modalName: "用户", @@ -214,4 +220,16 @@ } + \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java index 7a925a16..0cd77d21 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java @@ -37,7 +37,7 @@ public @interface Excel /** * 导出时在excel中每个列的宽 单位为字符 */ - public double width() default 20; + public double width() default 16; /** * 文字后缀,如% 90 变成90% @@ -68,4 +68,25 @@ public @interface Excel * 另一个类中的属性名称,支持多级获取,以小数点隔开 */ public String targetAttr() default ""; + + /** + * 字段类型( 1:仅导出;2:仅导入) + */ + Type type() default Type.EXPORT; + + public enum Type + { + EXPORT(1), IMPORT(2); + private final int value; + + Type(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } } \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/reflect/ReflectUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/reflect/ReflectUtils.java new file mode 100644 index 00000000..40205d97 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/reflect/ReflectUtils.java @@ -0,0 +1,406 @@ +package com.ruoyi.common.reflect; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Date; +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 com.ruoyi.common.support.Convert; +import com.ruoyi.common.utils.DateUtils; + +/** + * 反射工具类. 提供调用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 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 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 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 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 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 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]); + } + } + } + } + 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 Class 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); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ExcelUtil.java index 38f0790e..2f3976ee 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ExcelUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ExcelUtil.java @@ -7,7 +7,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.text.SimpleDateFormat; +import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -15,30 +15,32 @@ import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.poi.hssf.usermodel.DVConstraint; -import org.apache.poi.hssf.usermodel.HSSFCell; -import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFDataValidation; +import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFFont; -import org.apache.poi.hssf.usermodel.HSSFRow; -import org.apache.poi.hssf.usermodel.HSSFSheet; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.util.HSSFColor.HSSFColorPredefined; import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.annotation.Excel.Type; import com.ruoyi.common.base.AjaxResult; import com.ruoyi.common.config.Global; import com.ruoyi.common.exception.BusinessException; +import com.ruoyi.common.reflect.ReflectUtils; /** * Excel相关处理 @@ -49,6 +51,44 @@ public class ExcelUtil { private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + private List fields; + + /** + * 实体对象 + */ public Class clazz; public ExcelUtil(Class clazz) @@ -56,15 +96,28 @@ public class ExcelUtil this.clazz = clazz; } + public void init(List list, String sheetName, Type type) + { + if (list == null) + { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + createExcelField(); + createWorkbook(); + } + /** * 对excel表单默认第一个索引名转换成list * * @param input 输入流 * @return 转换后集合 */ - public List importExcel(InputStream input) throws Exception + public List importExcel(InputStream is) throws Exception { - return importExcel(StringUtils.EMPTY, input); + return importExcel(StringUtils.EMPTY, is); } /** @@ -74,21 +127,20 @@ public class ExcelUtil * @param input 输入流 * @return 转换后集合 */ - public List importExcel(String sheetName, InputStream input) throws Exception + public List importExcel(String sheetName, InputStream is) throws Exception { + this.wb = new XSSFWorkbook(is); List list = new ArrayList(); - - Workbook workbook = WorkbookFactory.create(input); Sheet sheet = null; if (StringUtils.isNotEmpty(sheetName)) { // 如果指定sheet名,则取指定sheet中的内容. - sheet = workbook.getSheet(sheetName); + sheet = wb.getSheet(sheetName); } else { // 如果传入的sheet名不存在则默认指向第1个sheet. - sheet = workbook.getSheetAt(0); + sheet = wb.getSheetAt(0); } if (sheet == null) @@ -123,88 +175,77 @@ public class ExcelUtil Row row = sheet.getRow(i); int cellNum = serialNum; T entity = null; - for (int j = 0; j < cellNum; j++) + for (int column = 0; column < cellNum; column++) { - Cell cell = row.getCell(j); - if (cell == null) - { - continue; - } - else - { - // 先设置Cell的类型,然后就可以把纯数字作为String类型读进来了 - row.getCell(j).setCellType(CellType.STRING); - cell = row.getCell(j); - } - - String c = cell.getStringCellValue(); - if (StringUtils.isEmpty(c)) - { - continue; - } + Object val = this.getCellValue(row, column); // 如果不存在实例则新建. entity = (entity == null ? clazz.newInstance() : entity); // 从map中得到对应列的field. - Field field = fieldsMap.get(j + 1); + Field field = fieldsMap.get(column + 1); // 取得类型,并根据对象类型设置值. Class fieldType = field.getType(); if (String.class == fieldType) { - field.set(entity, String.valueOf(c)); + String s = String.valueOf(val.toString()); + if (StringUtils.endsWith(s, ".0")) + { + val = StringUtils.substringBefore(s, ".0"); + } + else + { + val = String.valueOf(val.toString()); + } } else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) { - field.set(entity, Integer.parseInt(c)); + val = Double.valueOf(val.toString()).intValue(); } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) { - field.set(entity, Long.valueOf(c)); + val = Double.valueOf(val.toString()).longValue(); } - else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) - { - field.set(entity, Float.valueOf(c)); - } - else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) + else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) { - field.set(entity, Short.valueOf(c)); + val = Double.valueOf(val.toString()); } - else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) + else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) { - field.set(entity, Double.valueOf(c)); + val = Float.valueOf(val.toString()); } - else if (Character.TYPE == fieldType) + else if (Date.class == fieldType) { - if ((c != null) && (c.length() > 0)) + if (val instanceof String) + { + val = DateUtils.parseDate(val); + } + else if (val instanceof Double) { - field.set(entity, Character.valueOf(c.charAt(0))); + val = DateUtil.getJavaDate((Double) val); } } - else if (java.util.Date.class == fieldType) + if (StringUtils.isNotNull(fieldType)) { - if (cell.getCellTypeEnum() == CellType.NUMERIC) + Excel attr = field.getAnnotation(Excel.class); + if (StringUtils.isNotEmpty(attr.targetAttr())) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - cell.setCellValue(sdf.format(cell.getNumericCellValue())); - c = sdf.format(cell.getNumericCellValue()); + + ReflectUtils.invokeSetter(entity, field.getName() + "." + attr.targetAttr(), val); + } + else if (StringUtils.isNotEmpty(attr.readConverterExp())) + { + String value = reverseByExp(String.valueOf(val), attr.readConverterExp()); + ReflectUtils.invokeSetter(entity, field.getName() + "." + attr.targetAttr(), value); } else { - c = cell.getStringCellValue(); + ReflectUtils.invokeSetter(entity, field.getName(), val); } } - else if (java.math.BigDecimal.class == fieldType) - { - c = cell.getStringCellValue(); - } - } - if (entity != null) - { - list.add(entity); } + list.add(entity); } } - return list; } @@ -216,47 +257,42 @@ public class ExcelUtil * @return 结果 */ public AjaxResult exportExcel(List list, String sheetName) + { + this.init(list, sheetName, Type.EXPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param sheetName 工作表的名称 + * @return 结果 + */ + public AjaxResult importTemplateExcel(String sheetName) + { + this.init(null, sheetName, Type.IMPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public AjaxResult exportExcel() { OutputStream out = null; - HSSFWorkbook workbook = null; try { - // 得到所有定义字段 - Field[] allFields = clazz.getDeclaredFields(); - List fields = new ArrayList(); - // 得到所有field并存放到一个list中. - for (Field field : allFields) - { - if (field.isAnnotationPresent(Excel.class)) - { - fields.add(field); - } - } - - // 产生工作薄对象 - workbook = new HSSFWorkbook(); - // excel2003中每个sheet中最多有65536行 - int sheetSize = 65536; // 取出一共有多少个sheet. double sheetNo = Math.ceil(list.size() / sheetSize); for (int index = 0; index <= sheetNo; index++) { - // 产生工作表对象 - HSSFSheet sheet = workbook.createSheet(); - if (sheetNo == 0) - { - workbook.setSheetName(index, sheetName); - } - else - { - // 设置工作表的名称. - workbook.setSheetName(index, sheetName + index); - } - HSSFRow row; - HSSFCell cell; // 产生单元格 + createSheet(sheetNo, index); + Cell cell = null; // 产生单元格 // 产生一行 - row = sheet.createRow(0); + Row row = sheet.createRow(0); // 写入各个字段的列头名称 for (int i = 0; i < fields.size(); i++) { @@ -266,12 +302,12 @@ public class ExcelUtil cell = row.createCell(i); // 设置列中写入内容为String类型 cell.setCellType(CellType.STRING); - HSSFCellStyle cellStyle = workbook.createCellStyle(); + CellStyle cellStyle = wb.createCellStyle(); cellStyle.setAlignment(HorizontalAlignment.CENTER); cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); if (attr.name().indexOf("注:") >= 0) { - HSSFFont font = workbook.createFont(); + Font font = wb.createFont(); font.setColor(HSSFFont.COLOR_RED); cellStyle.setFont(font); cellStyle.setFillForegroundColor(HSSFColorPredefined.YELLOW.getIndex()); @@ -279,7 +315,7 @@ public class ExcelUtil } else { - HSSFFont font = workbook.createFont(); + Font font = wb.createFont(); // 粗体显示 font.setBold(true); // 选择需要用到的字体格式 @@ -309,72 +345,14 @@ public class ExcelUtil setHSSFValidation(sheet, attr.combo(), 1, 100, i, i); } } - - int startNo = index * sheetSize; - int endNo = Math.min(startNo + sheetSize, list.size()); - // 写入各条记录,每条记录对应excel表中的一行 - HSSFCellStyle cs = workbook.createCellStyle(); - cs.setAlignment(HorizontalAlignment.CENTER); - cs.setVerticalAlignment(VerticalAlignment.CENTER); - for (int i = startNo; i < endNo; i++) + if (Type.EXPORT.equals(type)) { - row = sheet.createRow(i + 1 - startNo); - // 得到导出对象. - T vo = (T) list.get(i); - for (int j = 0; j < fields.size(); j++) - { - // 获得field. - Field field = fields.get(j); - // 设置实体类私有属性可访问 - field.setAccessible(true); - Excel attr = field.getAnnotation(Excel.class); - try - { - // 设置行高 - row.setHeight((short) (attr.height() * 20)); - // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. - if (attr.isExport()) - { - // 创建cell - cell = row.createCell(j); - cell.setCellStyle(cs); - if (vo == null) - { - // 如果数据存在就填入,不存在填入空格. - cell.setCellValue(""); - continue; - } - - // 用于读取对象中的属性 - Object value = getTargetValue(vo, field, attr); - String dateFormat = attr.dateFormat(); - String readConverterExp = attr.readConverterExp(); - if (StringUtils.isNotEmpty(dateFormat)) - { - cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); - } - else if (StringUtils.isNotEmpty(readConverterExp)) - { - cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp)); - } - else - { - cell.setCellType(CellType.STRING); - // 如果数据存在就填入,不存在填入空格. - cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); - } - } - } - catch (Exception e) - { - log.error("导出Excel失败{}", e.getMessage()); - } - } + fillExcelData(index, row, cell); } } String filename = encodingFilename(sheetName); out = new FileOutputStream(getAbsoluteFile(filename)); - workbook.write(out); + wb.write(out); return AjaxResult.success(filename); } catch (Exception e) @@ -384,11 +362,11 @@ public class ExcelUtil } finally { - if (workbook != null) + if (wb != null) { try { - workbook.close(); + wb.close(); } catch (IOException e1) { @@ -409,6 +387,78 @@ public class ExcelUtil } } + /** + * 填充excel数据 + * + * @param index 序号 + * @param row 单元格行 + * @param cell 类型单元格 + */ + public void fillExcelData(int index, Row row, Cell cell) + { + int startNo = index * sheetSize; + int endNo = Math.min(startNo + sheetSize, list.size()); + // 写入各条记录,每条记录对应excel表中的一行 + CellStyle cs = wb.createCellStyle(); + cs.setAlignment(HorizontalAlignment.CENTER); + cs.setVerticalAlignment(VerticalAlignment.CENTER); + for (int i = startNo; i < endNo; i++) + { + row = sheet.createRow(i + 1 - startNo); + // 得到导出对象. + T vo = (T) list.get(i); + for (int j = 0; j < fields.size(); j++) + { + // 获得field. + Field field = fields.get(j); + // 设置实体类私有属性可访问 + field.setAccessible(true); + Excel attr = field.getAnnotation(Excel.class); + try + { + // 设置行高 + row.setHeight((short) (attr.height() * 20)); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) + { + // 创建cell + cell = row.createCell(j); + cell.setCellStyle(cs); + if (vo == null) + { + // 如果数据存在就填入,不存在填入空格. + cell.setCellValue(""); + continue; + } + + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + if (StringUtils.isNotEmpty(dateFormat)) + { + cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); + } + else if (StringUtils.isNotEmpty(readConverterExp)) + { + cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp)); + } + else + { + cell.setCellType(CellType.STRING); + // 如果数据存在就填入,不存在填入空格. + cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); + } + } + } + catch (Exception e) + { + log.error("导出Excel失败{}", e.getMessage()); + } + } + } + } + /** * 设置单元格上提示 * @@ -421,8 +471,8 @@ public class ExcelUtil * @param endCol 结束列 * @return 设置好的sheet. */ - public static HSSFSheet setHSSFPrompt(HSSFSheet sheet, String promptTitle, String promptContent, int firstRow, - int endRow, int firstCol, int endCol) + public static Sheet setHSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, + int firstCol, int endCol) { // 构造constraint对象 DVConstraint constraint = DVConstraint.createCustomFormulaConstraint("DD1"); @@ -446,8 +496,8 @@ public class ExcelUtil * @param endCol 结束列 * @return 设置好的sheet. */ - public static HSSFSheet setHSSFValidation(HSSFSheet sheet, String[] textlist, int firstRow, int endRow, - int firstCol, int endCol) + public static Sheet setHSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, + int endCol) { // 加载下拉列表内容 DVConstraint constraint = DVConstraint.createExplicitListConstraint(textlist); @@ -488,12 +538,41 @@ public class ExcelUtil return propertyValue; } + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @return 解析后值 + * @throws Exception + */ + public static String reverseByExp(String propertyValue, String converterExp) throws Exception + { + try + { + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (itemArray[1].equals(propertyValue)) + { + return itemArray[0]; + } + } + } + catch (Exception e) + { + throw e; + } + return propertyValue; + } + /** * 编码文件名 */ public String encodingFilename(String filename) { - filename = UUID.randomUUID().toString() + "_" + filename + ".xls"; + filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; return filename; } @@ -563,4 +642,110 @@ public class ExcelUtil } return o; } + + /** + * 得到所有定义字段 + */ + private void createExcelField() + { + this.fields = new ArrayList(); + Field[] allFields = clazz.getDeclaredFields(); + // 得到所有field并存放到一个list中. + for (Field field : allFields) + { + if (field.isAnnotationPresent(Excel.class)) + { + fields.add(field); + } + } + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() + { + this.wb = new SXSSFWorkbook(500); + } + + /** + * 创建工作表 + * + * @param sheetName,指定Sheet名称 + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(double sheetNo, int index) + { + this.sheet = wb.createSheet(); + // 设置工作表的名称. + if (sheetNo == 0) + { + wb.setSheetName(index, sheetName); + } + else + { + 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 (cell != null) + { + if (cell.getCellTypeEnum() == CellType.NUMERIC) + { + val = cell.getNumericCellValue(); + if (HSSFDateUtil.isCellDateFormatted(cell)) + { + val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 + } + else + { + if ((Double) val % 1 > 0) + { + val = new DecimalFormat("0.00").format(val); + } + else + { + val = new DecimalFormat("0").format(val); + } + } + } + else if (cell.getCellTypeEnum() == CellType.STRING) + { + val = cell.getStringCellValue(); + } + else if (cell.getCellTypeEnum() == CellType.BOOLEAN) + { + val = cell.getBooleanCellValue(); + } + else if (cell.getCellTypeEnum() == CellType.ERROR) + { + val = cell.getErrorCellValue(); + } + + } + } + catch (Exception e) + { + return val; + } + return val; + } } \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java index bca493a8..22a666a2 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java @@ -244,6 +244,10 @@ public class SysUser extends BaseEntity public SysDept getDept() { + if (dept == null) + { + dept = new SysDept(); + } return dept; } @@ -304,6 +308,7 @@ public class SysUser extends BaseEntity .append("updateBy", getUpdateBy()) .append("updateTime", getUpdateTime()) .append("remark", getRemark()) + .append("dept", getDept()) .toString(); } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index bdff6ee2..c4e63ea5 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -138,4 +138,12 @@ public interface ISysUserService * @return 结果 */ public String selectUserPostGroup(Long userId); + + /** + * 导入用户数据 + * + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @return 结果 + */ + public String importUser(List userList, Boolean isUpdateSupport); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 09a9f0a3..9051a0db 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -2,6 +2,8 @@ package com.ruoyi.system.service.impl; import java.util.ArrayList; import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.common.annotation.DataScope; @@ -29,6 +31,8 @@ import com.ruoyi.system.service.ISysUserService; @Service public class SysUserServiceImpl implements ISysUserService { + private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class); + @Autowired private SysUserMapper userMapper; @@ -212,18 +216,22 @@ public class SysUserServiceImpl implements ISysUserService */ public void insertUserRole(SysUser user) { - // 新增用户与角色管理 - List list = new ArrayList(); - for (Long roleId : user.getRoleIds()) + Long[] roles = user.getRoleIds(); + if (StringUtils.isNotNull(roles)) { - SysUserRole ur = new SysUserRole(); - ur.setUserId(user.getUserId()); - ur.setRoleId(roleId); - list.add(ur); - } - if (list.size() > 0) - { - userRoleMapper.batchUserRole(list); + // 新增用户与角色管理 + List list = new ArrayList(); + for (Long roleId : roles) + { + SysUserRole ur = new SysUserRole(); + ur.setUserId(user.getUserId()); + ur.setRoleId(roleId); + list.add(ur); + } + if (list.size() > 0) + { + userRoleMapper.batchUserRole(list); + } } } @@ -234,18 +242,22 @@ public class SysUserServiceImpl implements ISysUserService */ public void insertUserPost(SysUser user) { - // 新增用户与岗位管理 - List list = new ArrayList(); - for (Long postId : user.getPostIds()) + Long[] posts = user.getPostIds(); + if (StringUtils.isNotNull(posts)) { - SysUserPost up = new SysUserPost(); - up.setUserId(user.getUserId()); - up.setPostId(postId); - list.add(up); - } - if (list.size() > 0) - { - userPostMapper.batchUserPost(list); + // 新增用户与岗位管理 + List list = new ArrayList(); + for (Long postId : posts) + { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + list.add(up); + } + if (list.size() > 0) + { + userPostMapper.batchUserPost(list); + } } } @@ -345,4 +357,64 @@ public class SysUserServiceImpl implements ISysUserService } return idsStr.toString(); } + + /** + * 导入用户数据 + * + * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 + * @return 结果 + */ + public String importUser(List userList, Boolean isUpdateSupport) + { + if (StringUtils.isNull(userList) || userList.size() == 0) + { + throw new BusinessException("导入用户数据不能为空!"); + } + int successNum = 0; + int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + for (SysUser user : userList) + { + try + { + // 验证是否存在这个用户 + SysUser u = userMapper.selectUserByLoginName(user.getLoginName()); + if (StringUtils.isNull(u)) + { + this.insertUser(user); + successNum++; + successMsg.append("
" + successNum + "、账号 " + user.getLoginName() + " 导入成功"); + } + else if (isUpdateSupport) + { + this.updateUser(user); + successNum++; + successMsg.append("
" + successNum + "、账号 " + user.getLoginName() + " 更新成功"); + } + else + { + failureNum++; + failureMsg.append("
" + failureNum + "、账号 " + user.getLoginName() + " 已存在"); + } + } + catch (Exception e) + { + failureNum++; + String msg = "
" + failureNum + "、账号 " + user.getLoginName() + " 导入失败:"; + failureMsg.append(msg + e.getMessage()); + log.error(msg, e); + } + } + if (failureNum > 0) + { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new BusinessException(failureMsg.toString()); + } + else + { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } }