queryWrapperByCode = new LambdaQueryWrapper<>();
+ queryWrapperByCode.eq(SysMenu::getCode, code)
+ .eq(SysMenu::getIsDelete, YesOrNoState.NO.getState());
+
+ if (isExcludeSelf) {
+ queryWrapperByName.ne(SysMenu::getId, id);
+ queryWrapperByCode.ne(SysMenu::getId, id);
+ }
+ int countByName = this.count(queryWrapperByName);
+ int countByCode = this.count(queryWrapperByCode);
+
+ if (countByName >= 1) {
+ throw new CustomException("菜单名称重复,请检查name参数");
+ }
+ if (countByCode >= 1) {
+ throw new CustomException("菜单编码重复,请检查code参数");
+ }
+ }
+ /**
+ * 创建pids的值
+ *
+ * 如果pid是0顶级节点,pids就是 [0],
+ *
+ * 如果pid不是顶级节点,pids就是 pid菜单的pids + [pid] + ,
+ */
+ private String createNewPids(Long pid) {
+ if (pid.equals(0L)) {
+ return "[" + 0 + "]"
+ + ",";
+ } else {
+ //获取父菜单
+ SysMenu parentMenu = this.getById(pid);
+ return parentMenu.getPids()
+ + "[" + pid + "]"
+ + ",";
+ }
+ }
+
+ /**
+ * 根据菜单ID删除菜单
+ *
+ * @param id
+ * @return
+ */
+ @Transactional
+ public boolean del(Long id, String deleteReason){
+ log.info("SysMenuService - del - id:{}", id);
+
+ //级联删除子节点
+ List childIdList = this.getChildIdListById(id);
+ childIdList.add(id);
+ LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>();
+ updateWrapper.in(SysMenu::getId, childIdList)
+ .set(SysMenu::getIsDelete, YesOrNoState.YES.getState())
+ .set(SysMenu::getDeleteBy, SecurityUtil.getUserId())
+ .set(SysMenu::getDeleteTime, new Date())
+ .set(SysMenu::getDeleteReason, deleteReason);
+ boolean flag = this.update(updateWrapper);
+
+ // 删除角色菜单引用
+ sysRoleMenuService.deleteRoleMenuListByMenuIdList(childIdList);
+
+ return flag;
+ }
+
+ /**
+ * 根据节点id获取所有子节点id集合
+ */
+ private List getChildIdListById(Long id) {
+ List childIdList = CollectionUtil.newArrayList();
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.like(SysMenu::getPids, "[" + id + "]");
+ this.list(queryWrapper).forEach(sysMenu -> childIdList.add(sysMenu.getId()));
+ return childIdList;
+ }
+
+ /**
+ * 查询菜单列表
+ * @param sysMenu
+ * @return
+ */
+ public List queryList(SysMenu sysMenu) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysMenu::getIsDelete, YesOrNoState.NO.getState());
+ //根据菜单名称模糊查询
+ if (StringUtils.isNotEmpty(sysMenu.getName())) {
+ queryWrapper.like(SysMenu::getName, sysMenu.getName());
+ }
+ //根据排序升序排列,序号越小越在前
+ queryWrapper.orderByAsc(SysMenu::getIntCode);
+ List sysMenuList = this.list(queryWrapper);
+ return sysMenuList;
+ }
+
+ public List findAll(){
+ log.info("SysMenuService - findAll userid:{}", SecurityUtil.getUserId());
+
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysMenu::getIsDelete, YesOrNoState.NO.getState()).orderByAsc(SysMenu::getIntCode);
+
+ return this.list(queryWrapper);
+ }
+
+ /**
+ * 查出并组装树形结构
+ * @param list 所有节点菜单
+ * @param pid 父级id
+ * @return
+ */
+ public List buildMenuTree(List list, Long pid){
+ //组装数据
+ List collect = list.stream().filter(sysMenu -> {
+ return pid.equals(sysMenu.getPid());
+ }).map(sysMenu -> {
+ sysMenu.setChildren(getChildren(sysMenu, list));
+ return sysMenu;
+ }).collect(Collectors.toList());
+ return collect;
+ }
+
+ /**
+ * 在所有列表中查询当前项的子项
+ * @param o 当前节点
+ * @param all 所有数据
+ */
+ private List getChildren(SysMenu o, List all){
+ List children = all.stream().filter((sysMenu) -> {
+ return o.getId().equals(sysMenu.getPid());
+ }).map(sysMenu -> {
+ sysMenu.setChildren(getChildren(sysMenu, all));
+ return sysMenu;
+ }).collect(Collectors.toList());
+ return children;
+ }
+
+ /**
+ * 获取系统菜单树,用于新增,编辑时选择上级节点
+ * @return
+ */
+ public List tree() {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysMenu::getIsDelete, YesOrNoState.NO.getState());
+ List allMenu = list(queryWrapper);
+ allMenu = this.buildMenuTree(allMenu, 0L);
+ return allMenu;
+ }
+
+ /**
+ * 获取系统菜单树,用于给角色授权时选择
+ */
+ public List treeForGrant() {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysMenu::getIsDelete, YesOrNoState.NO.getState());
+ //如果是超级管理员给角色授权菜单时可选择所有菜单
+ if (SecurityUtil.getLoginUser().ifAdmin()) {
+ // 不加任何判断条件
+ } else {
+ //非超级管理员则获取自己拥有的菜单,分配给人员,防止越级授权
+ Long userId = SecurityUtil.getUserId();
+ List roleIdList = sysUserRoleService.getUserRoleIdList(userId);
+ if (ObjectUtil.isNotEmpty(roleIdList)) {
+ List menuIdList = sysRoleMenuService.getRoleMenuIdList(roleIdList);
+ if (ObjectUtil.isNotEmpty(menuIdList)) {
+ queryWrapper.in(SysMenu::getId, menuIdList);
+ } else {
+ //如果角色的菜单为空,则查不到菜单
+ return CollectionUtil.newArrayList();
+ }
+ } else {
+ //如果角色为空,则根本没菜单
+ return CollectionUtil.newArrayList();
+ }
+ }
+ queryWrapper.orderByAsc(SysMenu::getIntCode);
+ List allMenu = list(queryWrapper);
+ allMenu = this.buildMenuTree(allMenu, 0L);
+ return allMenu;
+ }
+
+ /**
+ * 将SysMenu格式菜单转换为LoginMenuTreeNode菜单
+ */
+ public List convertSysMenuToLoginMenu(List sysMenuList) {
+ List antDesignMenuTreeNodeList = CollectionUtil.newArrayList();
+ sysMenuList.forEach(sysMenu -> {
+ if(sysMenu.getType() != MenuTypeEnum.BTN.getCode()) {
+ LoginMenuTreeNode loginMenuTreeNode = new LoginMenuTreeNode();
+ loginMenuTreeNode.setComponent(sysMenu.getComponent());
+ loginMenuTreeNode.setId(sysMenu.getId());
+ loginMenuTreeNode.setName(sysMenu.getCode());
+ loginMenuTreeNode.setPath(sysMenu.getRouter());
+ loginMenuTreeNode.setPid(sysMenu.getPid());
+ LoginMenuTreeNode.Meta mateItem = new LoginMenuTreeNode().new Meta();
+ mateItem.setTitle(sysMenu.getName());
+ //是否可见
+ mateItem.setShow(YesOrNoState.YES.getState() == sysMenu.getVisible());
+ loginMenuTreeNode.setMeta(mateItem);
+ antDesignMenuTreeNodeList.add(loginMenuTreeNode);
+ }
+ });
+ return antDesignMenuTreeNodeList;
+ }
+}
diff --git a/src/main/java/com/org/system/service/SysOperLogService.java b/src/main/java/com/org/system/service/SysOperLogService.java
new file mode 100644
index 0000000..8539db4
--- /dev/null
+++ b/src/main/java/com/org/system/service/SysOperLogService.java
@@ -0,0 +1,23 @@
+package com.org.system.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.org.system.entity.SysOperLog;
+import com.org.system.mapper.SysOperLogMapper;
+import com.org.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Slf4j
+@Service
+public class SysOperLogService extends ServiceImpl {
+ public List queryList(SysOperLog sysOperLog) {
+ log.info("SysOperLogService - queryList sysOperLog:{}", sysOperLog);
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ if(StringUtils.isNotEmpty(sysOperLog.getTitle())) queryWrapper.like(SysOperLog::getTitle, sysOperLog.getTitle());
+
+ return list(queryWrapper);
+ }
+}
diff --git a/src/main/java/com/org/system/service/SysRoleMenuService.java b/src/main/java/com/org/system/service/SysRoleMenuService.java
new file mode 100644
index 0000000..ffa45d4
--- /dev/null
+++ b/src/main/java/com/org/system/service/SysRoleMenuService.java
@@ -0,0 +1,64 @@
+package com.org.system.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.org.system.entity.SysMenu;
+import com.org.system.entity.SysRoleMenu;
+import com.org.system.mapper.SysRoleMenuMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class SysRoleMenuService extends ServiceImpl {
+
+ public List getRoleMenuIdList(List roleIdList) {
+ if(ObjectUtil.isNotEmpty(roleIdList)) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.in(SysRoleMenu::getRoleId, roleIdList);
+ return this.list(queryWrapper).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
+ }
+ return CollectionUtil.newArrayList();
+ }
+
+ public void grantMenu(Long roleId, List grantMenuIdList) {
+ //删除所拥有菜单
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysRoleMenu::getRoleId, roleId);
+ this.remove(queryWrapper);
+ //授权菜单
+ grantMenuIdList.forEach(menuId -> {
+ SysRoleMenu sysRoleMenu = new SysRoleMenu();
+ sysRoleMenu.setRoleId(roleId);
+ sysRoleMenu.setMenuId(menuId);
+ this.save(sysRoleMenu);
+ });
+ }
+
+ public void deleteRoleMenuListByMenuIdList(List menuIdList) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.in(SysRoleMenu::getMenuId, menuIdList);
+ this.remove(queryWrapper);
+ }
+
+ public void deleteRoleMenuListByRoleId(Long roleId) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysRoleMenu::getRoleId, roleId);
+ this.remove(queryWrapper);
+ }
+
+ /**
+ * 根据角色ID获取菜单
+ * @param roleId
+ * @return
+ */
+ public List findMenuListByRoleId(Long roleId) {
+ return baseMapper.findMenuListByRoleId(roleId);
+
+ }
+}
diff --git a/src/main/java/com/org/system/service/SysRoleService.java b/src/main/java/com/org/system/service/SysRoleService.java
new file mode 100644
index 0000000..e544077
--- /dev/null
+++ b/src/main/java/com/org/system/service/SysRoleService.java
@@ -0,0 +1,178 @@
+package com.org.system.service;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.org.system.entity.SysRole;
+import com.org.system.enums.YesOrNoState;
+import com.org.system.mapper.SysRoleMapper;
+import com.org.utils.SecurityUtil;
+import com.org.utils.StringUtils;
+import com.org.utils.exception.CustomException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@Service
+public class SysRoleService extends ServiceImpl {
+
+ @Autowired
+ private SysRoleMenuService sysRoleMenuService;
+
+ @Autowired
+ private SysUserRoleService sysUserRoleService;
+
+ /**
+ * 新增或修改
+ *
+ * @param sysRole
+ * @return
+ */
+ public boolean saveOrUpdate(SysRole sysRole){
+ log.info("SysRoleService - saveOrUpdate sysRole:{}", sysRole);
+
+ if(StringUtils.isNull(sysRole.getId())){
+ //校验参数,检查是否存在相同的名称和编码
+ checkParam(sysRole, false);
+ // 新增
+ sysRole.setParentId(sysRole.getParentId() == null ? -1 : sysRole.getParentId());
+ sysRole.setCreateBy(SecurityUtil.getUserId());
+ sysRole.setCreateTime(new Date());
+ sysRole.setIsDelete(YesOrNoState.NO.getState());
+ log.info("SysRoleService - saveOrUpdate save sysRole:{}", sysRole);
+
+ return save(sysRole);
+ } else {
+ //校验参数,检查是否存在相同的名称和编码
+ checkParam(sysRole, true);
+ // 修改
+ SysRole sysRoleOld = querySysRole(sysRole.getId());
+
+ sysRoleOld.setName(sysRole.getName());
+ sysRoleOld.setCode(sysRole.getCode());
+ sysRoleOld.setSort(sysRole.getSort());
+
+ sysRoleOld.setOrgCode(sysRole.getOrgCode());
+ sysRoleOld.setParentId(sysRole.getParentId());
+ sysRoleOld.setUpdateBy(SecurityUtil.getUserId());
+ sysRoleOld.setUpdateTime(new Date());
+ log.info("SysRoleService - saveOrUpdate update sysRole:{}", sysRoleOld);
+
+ return updateById(sysRoleOld);
+ }
+ }
+
+ /**
+ * 校验参数,检查是否存在相同的名称
+ */
+ private void checkParam(SysRole sysRole, boolean isExcludeSelf) {
+ Long id = sysRole.getId();
+ String name = sysRole.getName();
+ String code = sysRole.getCode();
+
+ LambdaQueryWrapper queryWrapperByName = new LambdaQueryWrapper<>();
+ queryWrapperByName.eq(SysRole::getName, name)
+ .eq(SysRole::getIsDelete, YesOrNoState.NO.getState());
+
+ LambdaQueryWrapper queryWrapperByCode = new LambdaQueryWrapper<>();
+ queryWrapperByCode.eq(SysRole::getCode, code)
+ .eq(SysRole::getIsDelete, YesOrNoState.NO.getState());
+
+ //是否排除自己,如果排除自己则不查询自己的id
+ if (isExcludeSelf) {
+ queryWrapperByName.ne(SysRole::getId, id);
+ queryWrapperByCode.ne(SysRole::getId, id);
+ }
+ int countByName = this.count(queryWrapperByName);
+ int countByCode = this.count(queryWrapperByCode);
+
+ if (countByName >= 1) {
+ throw new CustomException("角色名称重复,请检查name参数");
+ }
+ if (countByCode >= 1) {
+ throw new CustomException("角色编码重复,请检查code参数");
+ }
+ }
+
+ /**
+ * 获取系统角色
+ */
+ private SysRole querySysRole(Long id) {
+ SysRole sysRole = this.getById(id);
+ if (ObjectUtil.isNull(sysRole)) {
+ throw new CustomException("角色不存在");
+ }
+ return sysRole;
+ }
+
+ /**
+ * 删除
+ */
+ @Transactional
+ public boolean del(Long id){
+ SysRole sysRole = querySysRole(id);
+
+ // 删除角色菜单引用
+ sysRoleMenuService.deleteRoleMenuListByRoleId(sysRole.getId());
+ // 删除用户角色引用
+ sysUserRoleService.delByRoleId(sysRole.getId());
+
+ sysRole.setIsDelete(YesOrNoState.YES.getState());
+ sysRole.setDeleteBy(SecurityUtil.getUserId());
+ sysRole.setDeleteTime(new Date());
+
+ return updateById(sysRole);
+ }
+
+ /**
+ * 查询角色
+ *
+ * @param sysRole
+ * @return
+ */
+ public List findList(SysRole sysRole){
+ log.info("SysRoleService - findList - sysRole:{}", sysRole);
+
+ if(sysRole.getParentId() == null) sysRole.setParentId(-1L);
+
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysRole::getParentId, sysRole.getParentId())
+ .eq(SysRole::getIsDelete, YesOrNoState.NO.getState());
+
+ if(StringUtils.isNotEmpty(sysRole.getName())) queryWrapper.like(SysRole::getName, sysRole.getName());
+ if(StringUtils.isNotNull(sysRole.getOrgCode())) queryWrapper.eq(SysRole::getOrgCode, sysRole.getOrgCode());
+
+ return list(queryWrapper);
+ }
+
+ /**
+ * 查询所有角色信息
+ * @return
+ */
+ public List findAll(){
+ log.info("SysRoleService - findAll - userId:{}", SecurityUtil.getUserId());
+
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysRole::getIsDelete, YesOrNoState.NO.getState());
+
+ return list(queryWrapper);
+ }
+
+ public List ownMenu(Long id) {
+ SysRole sysRole = querySysRole(id);
+ return sysRoleMenuService.getRoleMenuIdList(CollectionUtil.newArrayList(sysRole.getId()));
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void grantMenu(Long id, List grantMenuIdList) {
+ this.querySysRole(id);
+ sysRoleMenuService.grantMenu(id, grantMenuIdList);
+ }
+
+}
diff --git a/src/main/java/com/org/system/service/SysUserRoleService.java b/src/main/java/com/org/system/service/SysUserRoleService.java
new file mode 100644
index 0000000..6ac59c3
--- /dev/null
+++ b/src/main/java/com/org/system/service/SysUserRoleService.java
@@ -0,0 +1,157 @@
+package com.org.system.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.org.system.entity.SysRole;
+import com.org.system.entity.SysUser;
+import com.org.system.entity.SysUserRole;
+import com.org.system.mapper.SysUserRoleMapper;
+import com.org.utils.StringUtils;
+import com.org.utils.exception.CustomException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class SysUserRoleService extends ServiceImpl {
+
+ /**
+ * 新能用户角色
+ *
+ * @param userId
+ * @param roleIdList
+ * @return
+ */
+ @Transactional
+ public boolean save(Long userId, List roleIdList){
+ log.info("SysUserRoleService - save userId:{}", userId);
+ log.info("SysUserRoleService - save roleIdList:{}", roleIdList);
+
+ if(StringUtils.isNull(userId)) throw new CustomException("用户ID不能为空");
+ if(StringUtils.isNull(roleIdList) || roleIdList.size() == 0) throw new CustomException("角色ID不能为空");
+
+ List sysUserRoleList = new ArrayList<>();
+ for (Long roleId : roleIdList) {
+ if(StringUtils.isNull(roleId)) continue;
+
+ sysUserRoleList.add(new SysUserRole().setUserId(userId).setRoleId(roleId));
+ }
+
+ return saveBatch(sysUserRoleList);
+ }
+
+ /**
+ * 根据用户ID删除
+ *
+ * @param userId
+ * @return
+ */
+ public boolean delByUserId(Long userId){
+ log.info("SysUserRoleService - delByUserId userId:{}", userId);
+
+ if(StringUtils.isNull(userId)) throw new CustomException("用户ID不能为空");
+
+ return baseMapper.delByUserId(userId) > 0;
+ }
+
+ /**
+ * 根据角色ID删除
+ *
+ * @param roleId
+ * @return
+ */
+ public boolean delByRoleId(Long roleId){
+ log.info("SysUserRoleService - delByRoleId roleId:{}", roleId);
+
+ if(StringUtils.isNull(roleId)) throw new CustomException("角色ID不能为空");
+
+ return baseMapper.delByRoleId(roleId) > 0;
+ }
+
+ /**
+ * 根据用户ID和角色ID删除
+ *
+ * @param userId
+ * @param roleIdList
+ * @return
+ */
+ @Transactional
+ public boolean delByUserIdAndRoleId(Long userId, List roleIdList){
+ log.info("SysUserRoleService - delByUserIdAndRoleId userId:{}", userId);
+ log.info("SysUserRoleService - delByUserIdAndRoleId roleIdList:{}", roleIdList);
+
+ if(StringUtils.isNull(userId)) throw new CustomException("用户ID不能为空");
+ if(StringUtils.isNull(roleIdList) || roleIdList.size() == 0) throw new CustomException("角色ID不能为空");
+
+ for (Long roleId : roleIdList) {
+ baseMapper.delByUserIdAndRoleId(userId, roleId);
+ }
+
+ return true;
+ }
+
+ /**
+ * 根据角色ID获取用户
+ *
+ * @param roleId
+ * @return
+ */
+ public List findUserListByRoleId(Long roleId){
+ log.info("SysUserRoleService - findUserListByRoleId roleId:{}", roleId);
+
+ if(StringUtils.isNull(roleId)) return new ArrayList<>();
+
+ return baseMapper.findUserListByRoleId(roleId);
+ }
+
+ /**
+ * 根据用户ID获取角色
+ *
+ * @param userid
+ * @return
+ */
+ public List findRoleListByUserId(Long userid){
+ log.info("SysUserRoleService - findRoleListByUserId roleId:{}", userid);
+
+ if(StringUtils.isNull(userid)) return new ArrayList<>();
+
+ return baseMapper.findRoleListByUserId(userid);
+ }
+
+ /* 2021-08-28 新增方法*/
+
+ public List getUserRoleIdList(Long userId) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysUserRole::getUserId, userId);
+
+ return this.list(queryWrapper).stream().map(SysUserRole::getRoleId).collect(Collectors.toList());
+ }
+
+ public void grantRole(Long userId, List grantRoleIdList) {
+ //删除所拥有角色
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysUserRole::getUserId, userId);
+ this.remove(queryWrapper);
+ //授权角色
+ grantRoleIdList.forEach(roleId -> {
+ SysUserRole sysUserRole = new SysUserRole();
+ sysUserRole.setUserId(userId);
+ sysUserRole.setRoleId(roleId);
+ this.save(sysUserRole);
+ });
+ }
+
+ public SysUserRole getByUserIdAndRoleCode(Long userId, String roleCode) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysUserRole::getUserId, userId);
+ queryWrapper.inSql(SysUserRole::getRoleId, "select id from sys_role where is_delete = 0 and code = '" + roleCode + "'");
+ queryWrapper.last("limit 1");
+ return this.getOne(queryWrapper);
+ }
+
+}
diff --git a/src/main/java/com/org/system/service/SysUserService.java b/src/main/java/com/org/system/service/SysUserService.java
new file mode 100644
index 0000000..6764a60
--- /dev/null
+++ b/src/main/java/com/org/system/service/SysUserService.java
@@ -0,0 +1,234 @@
+package com.org.system.service;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.org.system.config.security.Md5PasswordEncoder;
+import com.org.system.entity.SysUser;
+import com.org.system.enums.YesOrNoState;
+import com.org.system.mapper.SysUserMapper;
+import com.org.utils.SecurityUtil;
+import com.org.utils.SpringUtil;
+import com.org.utils.StringUtils;
+import com.org.utils.exception.CustomException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@Service
+public class SysUserService extends ServiceImpl {
+
+ @Autowired
+ private SysUserRoleService sysUserRoleService;
+
+ /**
+ * 新增或修改系统用户
+ *
+ * @param sysUser
+ * @return
+ */
+ public boolean saveOrUpdate(SysUser sysUser){
+ log.info("SysUserService - saveOrUpdate sysUser:{}", sysUser);
+
+ if(StringUtils.isNull(sysUser.getId())){
+ // 新增
+ checkParam(sysUser, false);
+
+ sysUser.setSalt(DigestUtil.md5Hex(sysUser.getUserName()));
+
+ Md5PasswordEncoder md5PasswordEncoder = Md5PasswordEncoder.getInstance();
+ md5PasswordEncoder.setSalt(sysUser.getSalt());
+ sysUser.setPassword(md5PasswordEncoder.encode(sysUser.getPassword()));
+
+ sysUser.setStatus(1);
+ sysUser.setCreateBy(SecurityUtil.getUserId());
+ sysUser.setCreateTime(new Date());
+ sysUser.setIsDelete(YesOrNoState.NO.getState());
+ log.info("SysUserService - saveOrUpdate save sysUser:{}", sysUser);
+
+ return save(sysUser);
+ } else {
+ // 修改
+ checkParam(sysUser, true);
+
+ SysUser sysUserOld = getById(sysUser.getId());
+ if(StringUtils.isNull(sysUserOld) || StringUtils.isNull(sysUserOld.getId()))
+ throw new CustomException("未找到要修改的用户");
+
+ // 禁止修改的内容
+ sysUser.setSalt(null);
+ sysUser.setPassword(null);
+ sysUser.setWxOpenId(null);
+
+ sysUser.setUpdateBy(SecurityUtil.getUserId());
+ sysUser.setUpdateTime(new Date());
+ log.info("SysUserService - saveOrUpdate update sysUser:{}", sysUser);
+
+ return updateById(sysUser);
+ }
+ }
+
+ /**
+ * 校验参数,检查是否存在相同的账号
+ */
+ private void checkParam(SysUser sysUser, boolean isExcludeSelf) {
+ Long id = sysUser.getId();
+ String userName = sysUser.getUserName();
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysUser::getUserName, userName)
+ .eq(SysUser::getIsDelete, YesOrNoState.NO.getState());
+ //是否排除自己,如果是则查询条件排除自己id
+ if (isExcludeSelf) {
+ queryWrapper.ne(SysUser::getId, id);
+ }
+ int countByAccount = this.count(queryWrapper);
+ //大于等于1个则表示重复
+ if (countByAccount >= 1) {
+ throw new CustomException("用户名:" + sysUser.getUserName() + "已存在");
+ }
+ }
+
+ /**
+ * 根据用户ID删除用户
+ *
+ * @param idList
+ * @param deleteReason
+ * @return
+ */
+ public boolean del(List idList, String deleteReason){
+ log.info("SysUserService - del idList:{}", idList);
+ log.info("SysUserService - del deleteReason:{}", deleteReason);
+
+ if(StringUtils.isNull(idList) || idList.size() == 0) return true;
+
+ List sysUserList = new ArrayList<>();
+ for (Long id : idList) {
+ SysUser sysUser = getById(id);
+
+ if(StringUtils.isNull(sysUser) || StringUtils.isNull(sysUser.getId())) continue;
+
+ // 删除用户角色引用
+ SpringUtil.getBean(SysUserRoleService.class).delByUserId(sysUser.getId());
+
+ sysUser.setIsDelete(YesOrNoState.YES.getState());
+ sysUser.setDeleteBy(SecurityUtil.getUserId());
+ sysUser.setDeleteTime(new Date());
+ sysUser.setDeleteReason(deleteReason);
+ log.info("SysUserService - del sysUser:{}", sysUser);
+
+ sysUserList.add(sysUser);
+ }
+
+ return updateBatchById(sysUserList);
+ }
+
+ /**
+ * 系统用户查询
+ *
+ * @param sysUser
+ * @return
+ */
+ public List findList(SysUser sysUser){
+ log.info("SysUserService - findList sysUser:{}", sysUser);
+
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(SysUser::getIsDelete, YesOrNoState.NO.getState());
+
+ if(StringUtils.isNotEmpty(sysUser.getName())) queryWrapper.like(SysUser::getName, sysUser.getName());
+ if(StringUtils.isNotEmpty(sysUser.getUserName())) queryWrapper.like(SysUser::getUserName, sysUser.getUserName());
+ if(StringUtils.isNotEmpty(sysUser.getPhone())) queryWrapper.like(SysUser::getPhone, sysUser.getPhone());
+
+ return list(queryWrapper);
+ }
+
+ /**
+ * 根据登录名查询系统用户
+ *
+ * @param userName
+ * @return
+ */
+ public SysUser findByUserName(String userName){
+ log.info("SysUserService - findByUserName userName:{}", userName);
+ return baseMapper.findByUserName(userName);
+ }
+
+ /**
+ * 根据登录名或电话查询系统用户
+ *
+ * @param userName
+ * @return
+ */
+ public SysUser findByUserNameOrPhone(String userName) {
+ log.info("SysUserService - findByUserNameOrPhone userName:{}", userName);
+ return baseMapper.findByUserNameOrPhone(userName);
+ }
+
+ /**
+ * 获取系统用户
+ */
+ private SysUser querySysUser(Long id) {
+ SysUser sysUser = this.getById(id);
+ if (ObjectUtil.isNull(sysUser)) {
+ throw new CustomException("用户不存在");
+ }
+ return sysUser;
+ }
+
+ public List ownRole(Long id) {
+ SysUser sysUser = this.querySysUser(id);
+ return sysUserRoleService.getUserRoleIdList(sysUser.getId());
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public void grantRole(Long id, List grantRoleIdList) {
+ this.querySysUser(id);
+ sysUserRoleService.grantRole(id, grantRoleIdList);
+ }
+
+ // 重置密码
+ @Transactional
+ public boolean resetPwd(Long id) {
+ // 修改用户密码
+ SysUser sysUser = this.getById(id);
+ if (ObjectUtil.isNull(sysUser)) {
+ throw new CustomException("未查询到用户信息");
+ }
+ sysUser.setSalt(DigestUtil.md5Hex(sysUser.getUserName()));
+
+ Md5PasswordEncoder md5PasswordEncoder = Md5PasswordEncoder.getInstance();
+ md5PasswordEncoder.setSalt(sysUser.getSalt());
+ sysUser.setPassword(md5PasswordEncoder.encode(SysUser.DEFAULT_PASSWORD));
+ return updateById(sysUser);
+ }
+
+ // 修改密码
+ @Transactional
+ public boolean changePwd(String oldPassword, String password) {
+ // 修改用户密码
+ SysUser sysUser = this.getById(SecurityUtil.getUserId());
+ if (ObjectUtil.isNull(sysUser)) {
+ throw new CustomException("未查询到用户信息");
+ }
+
+ Md5PasswordEncoder.getInstance().setSalt(sysUser.getSalt());
+ if(!Md5PasswordEncoder.getInstance().matches(oldPassword, sysUser.getPassword())){
+ throw new CustomException("原密码不正确!");
+ }
+
+ Md5PasswordEncoder md5PasswordEncoder = Md5PasswordEncoder.getInstance();
+ md5PasswordEncoder.setSalt(sysUser.getSalt());
+ sysUser.setPassword(md5PasswordEncoder.encode(password));
+
+ sysUser.setUpdateBy(sysUser.getId());
+ sysUser.setUpdateTime(new Date());
+
+ return updateById(sysUser);
+ }
+}
diff --git a/src/main/java/com/org/system/service/TokenService.java b/src/main/java/com/org/system/service/TokenService.java
new file mode 100644
index 0000000..8a99943
--- /dev/null
+++ b/src/main/java/com/org/system/service/TokenService.java
@@ -0,0 +1,190 @@
+package com.org.system.service;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.extra.servlet.ServletUtil;
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentUtil;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.org.system.entity.LoginUser;
+import com.org.system.config.redis.RedisCache;
+import com.org.utils.Constants;
+import com.org.utils.HttpServletUtil;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/** token验证处理 **/
+@Service
+public class TokenService
+{
+ // 令牌自定义标识
+ @Value("${token.header}")
+ private String header;
+
+ // 令牌秘钥
+ @Value("${token.secret}")
+ private String secret;
+
+ // 令牌有效期(默认30分钟)
+ @Value("${token.expireTime}")
+ private int expireTime;
+
+ protected static final long MILLIS_SECOND = 1000;
+
+ protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
+
+ private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
+
+ @Autowired
+ private RedisCache redisCache;
+
+ /**
+ * 获取用户身份信息
+ *
+ * @return 用户信息
+ */
+ public LoginUser getLoginUser(HttpServletRequest request) {
+ // 获取请求携带的令牌
+ String token = getToken(request);
+ if (StringUtils.isNotEmpty(token)) {
+ Claims claims = parseToken(token);
+ // 解析对应的权限以及用户信息
+ String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
+ String userKey = getTokenKey(uuid);
+ LoginUser user = redisCache.getCacheObject(userKey);
+ return user;
+ }
+ return null;
+ }
+
+ /**
+ * 设置用户身份信息
+ */
+ public void setLoginUser(LoginUser loginUser) {
+ if (null != loginUser && StringUtils.isNotEmpty(loginUser.getToken())) refreshToken(loginUser);
+ }
+
+ /**
+ * 删除用户身份信息
+ */
+ public void delLoginUser(String token) {
+ if (StringUtils.isNotEmpty(token)) {
+ String userKey = getTokenKey(token);
+ redisCache.deleteObject(userKey);
+ }
+ }
+
+ /**
+ * 创建令牌
+ *
+ * @param loginUser 用户信息
+ * @return 令牌
+ */
+ public String createToken(LoginUser loginUser) {
+ String token = IdUtil.fastUUID();
+ loginUser.setToken(token);
+ setUserAgent(loginUser);
+ refreshToken(loginUser);
+
+ Map claims = new HashMap<>();
+ claims.put(Constants.LOGIN_USER_KEY, token);
+ return createToken(claims);
+ }
+
+ /**
+ * 验证令牌有效期,相差不足20分钟,自动刷新缓存
+ *
+ * @param loginUser
+ * @return 令牌
+ */
+ public void verifyToken(LoginUser loginUser) {
+ long expireTime = loginUser.getExpireTime();
+ long currentTime = System.currentTimeMillis();
+ if (expireTime - currentTime <= MILLIS_MINUTE_TEN) refreshToken(loginUser);
+ }
+
+ /**
+ * 刷新令牌有效期
+ *
+ * @param loginUser 登录信息
+ */
+ public void refreshToken(LoginUser loginUser) {
+ loginUser.setLoginTime(System.currentTimeMillis());
+ loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
+ // 根据uuid将loginUser缓存
+ String userKey = getTokenKey(loginUser.getToken());
+ redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
+ }
+
+ /**
+ * 设置用户代理信息
+ *
+ * @param loginUser 登录信息
+ */
+ public void setUserAgent(LoginUser loginUser) {
+ UserAgent userAgent = UserAgentUtil.parse(HttpServletUtil.getRequest().getHeader("User-Agent"));
+ String ip = ServletUtil.getClientIP(HttpServletUtil.getRequest(), "");
+ loginUser.setIpaddr(ip);
+ loginUser.setLoginLocation("");
+ loginUser.setBrowser(userAgent.getBrowser().getName());
+ loginUser.setOs(userAgent.getOs().getName());
+ }
+
+ /**
+ * 从数据声明生成令牌
+ *
+ * @param claims 数据声明
+ * @return 令牌
+ */
+ private String createToken(Map claims) {
+ String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
+ return token;
+ }
+
+ /**
+ * 从令牌中获取数据声明
+ *
+ * @param token 令牌
+ * @return 数据声明
+ */
+ private Claims parseToken(String token) {
+ return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
+ }
+
+ /**
+ * 从令牌中获取用户名
+ *
+ * @param token 令牌
+ * @return 用户名
+ */
+ public String getUsernameFromToken(String token) {
+ Claims claims = parseToken(token);
+ return claims.getSubject();
+ }
+
+ /**
+ * 获取请求token
+ *
+ * @param request
+ * @return token
+ */
+ private String getToken(HttpServletRequest request) {
+ String token = request.getHeader(header);
+ if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) {
+ token = token.replace(Constants.TOKEN_PREFIX, "");
+ }
+ return token;
+ }
+
+ private String getTokenKey(String uuid) {
+ return Constants.LOGIN_TOKEN_KEY + uuid;
+ }
+}
diff --git a/src/main/java/com/org/ueditor/controller/UeditorContorller.java b/src/main/java/com/org/ueditor/controller/UeditorContorller.java
new file mode 100644
index 0000000..b85e12e
--- /dev/null
+++ b/src/main/java/com/org/ueditor/controller/UeditorContorller.java
@@ -0,0 +1,46 @@
+package com.org.ueditor.controller;
+
+import com.org.oss.service.SysOssService;
+import com.org.system.annotation.Log;
+import com.org.system.enums.BusinessType;
+import com.org.ueditor.domain.UeditorConfig;
+import com.org.ueditor.domain.UeditorConfigJson;
+import com.org.utils.AjaxResult;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+@Slf4j
+@RestController
+@RequestMapping("sys/ueditor")
+public class UeditorContorller {
+
+ @Autowired
+ private SysOssService sysOssService;
+
+ @Log(title = "富文本上传", businessType = BusinessType.INSERT)
+ @RequestMapping("/config")
+ public Object ueditorConfig(MultipartFile upfile, String action) throws IOException {
+ log.info("UeditorContorller - ueditorConfig action:{}", action);
+
+ switch (action) {
+ case "config":
+ log.info("UeditorContorller - ueditorConfig get config json");
+ return new UeditorConfigJson();
+ case "uploadimage":
+ log.info("UeditorContorller - ueditorConfig uploadimage");
+
+ AjaxResult upload = sysOssService.upload(upfile, "ueditor", "ueditor");
+
+ String url = upload.get("zoomUrl") != null ? upload.get("zoomUrl").toString() : upload.get("url").toString();
+ url = String.format("%s?width=1024", url);
+ return new UeditorConfig("SUCCESS", url, upfile.getSize(), upfile.getContentType(), upfile.getOriginalFilename(), upfile.getOriginalFilename());
+ }
+ return "请求失败";
+ }
+
+}
diff --git a/src/main/java/com/org/ueditor/domain/UeditorConfig.java b/src/main/java/com/org/ueditor/domain/UeditorConfig.java
new file mode 100644
index 0000000..a30528a
--- /dev/null
+++ b/src/main/java/com/org/ueditor/domain/UeditorConfig.java
@@ -0,0 +1,29 @@
+package com.org.ueditor.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class UeditorConfig {
+
+ /* 状态 */
+ private String state;
+
+ /* 回显路径 */
+ private String url;
+
+ /* 大小 */
+ private long size;
+
+ /* 类型 */
+ private String type;
+
+ /* 文件title */
+ private String title;
+
+ /* 名称 */
+ private String original;
+}
diff --git a/src/main/java/com/org/ueditor/domain/UeditorConfigJson.java b/src/main/java/com/org/ueditor/domain/UeditorConfigJson.java
new file mode 100644
index 0000000..63ab942
--- /dev/null
+++ b/src/main/java/com/org/ueditor/domain/UeditorConfigJson.java
@@ -0,0 +1,140 @@
+package com.org.ueditor.domain;
+
+import lombok.Data;
+
+@Data
+public class UeditorConfigJson {
+
+ /* 上传图片配置项 */
+ /* 执行上传图片的action名称 */
+ private String imageActionName = "uploadimage";
+ /* 提交的图片表单名称 */
+ private String imageFieldName = "upfile";
+ /* 上传大小限制,单位B */
+ private long imageMaxSize = 2048000;
+ /* 上传图片格式显示 */
+ private String[] imageAllowFiles = new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"};
+ /* 是否压缩图片;默认是true */
+ private boolean imageCompressEnable = true;
+ /* 图片压缩最长边限制 */
+ private long imageCompressBorder = 1600;
+ /* 插入的图片浮动方式 */
+ private String imageInsertAlign = "none";
+ /* 图片访问路径前缀 */
+ private String imageUrlPrefix = "";
+ /* 上传保存路径;可以自定义保存路径和文件名格式 */
+ /* {filename} 会替换成原文件名;配置这项需要注意中文乱码问题 */
+ /* {rand:6} 会替换成随机数;后面的数字是随机数的位数 */
+ /* {time} 会替换成时间戳 */
+ /* {yyyy} 会替换成四位年份 */
+ /* {yy} 会替换成两位年份 */
+ /* {mm} 会替换成两位月份 */
+ /* {dd} 会替换成两位日期 */
+ /* {hh} 会替换成两位小时 */
+ /* {ii} 会替换成两位分钟 */
+ /* {ss} 会替换成两位秒 */
+ /* 非法字符 \ : * ? " < > | */
+ /* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */
+ private String imagePathFormat = "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}";
+
+
+ /* 涂鸦图片上传配置项 */
+ /* 执行上传涂鸦的action名称 */
+ private String scrawlActionName = "uploadscrawl";
+ /* 提交的图片表单名称 */
+ private String scrawlFieldName = "upfile";
+ /* 上传保存路径;可以自定义保存路径和文件名格式 */
+ private String scrawlPathFormat = "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}";
+ /* 上传大小限制,单位B */
+ private long scrawlMaxSize = 2048000;
+ /* 图片访问路径前缀 */
+ private String scrawlUrlPrefix = "";
+ private String scrawlInsertAlign = "none";
+
+ /* 截图工具上传 */
+ /* 执行上传截图的action名称 */
+ private String snapscreenActionName = "uploadimage";
+ /* 上传保存路径;可以自定义保存路径和文件名格式 */
+ private String snapscreenPathFormat = "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}";
+ /* 图片访问路径前缀 */
+ private String snapscreenUrlPrefix = "";
+ /* 插入的图片浮动方式 */
+ private String snapscreenInsertAlign = "none";
+
+ /* 抓取远程图片配置 */
+ private String[] catcherLocalDomain = new String[]{"127.0.0.1", "localhost", "img.baidu.com"};
+ /* 执行抓取远程图片的action名称 */
+ private String catcherActionName = "catchimage";
+ /* 提交的图片列表表单名称 */
+ private String catcherFieldName = "source";
+ /* 上传保存路径;可以自定义保存路径和文件名格式 */
+ private String catcherPathFormat = "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}";
+ /* 图片访问路径前缀 */
+ private String catcherUrlPrefix = "";
+ /* 上传大小限制,单位B */
+ private long catcherMaxSize = 2048000;
+ /* 抓取图片格式显示 */
+ private String[] catcherAllowFiles = new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"};
+
+ /* 上传视频配置 */
+ /* 执行上传视频的action名称 */
+ private String videoActionName = "uploadvideo";
+ /* 提交的视频表单名称 */
+ private String videoFieldName = "upfile";
+ /* 上传保存路径;可以自定义保存路径和文件名格式 */
+ private String videoPathFormat = "/ueditor/jsp/upload/video/{yyyy}{mm}{dd}/{time}{rand:6}";
+ /* 视频访问路径前缀 */
+ private String videoUrlPrefix = "";
+ /* 上传大小限制,单位B,默认100MB */
+ private long videoMaxSize = 102400000;
+ /* 上传视频格式显示 */
+ private String[] videoAllowFiles = new String[]{".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
+ ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"};
+
+ /* 上传文件配置 */
+ /* controller里;执行上传视频的action名称 */
+ private String fileActionName = "uploadfile";
+ /* 提交的文件表单名称 */
+ private String fileFieldName = "upfile";
+ /* 上传保存路径;可以自定义保存路径和文件名格式 */
+ private String filePathFormat = "/ueditor/jsp/upload/file/{yyyy}{mm}{dd}/{time}{rand:6}";
+ /* 文件访问路径前缀 */
+ private String fileUrlPrefix = "";
+ /* 上传大小限制,单位B,默认50MB */
+ private long fileMaxSize = 51200000;
+ /* 上传文件格式显示 */
+ private String[] fileAllowFiles = new String[]{ ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".flv", ".swf", ".mkv",
+ ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav",
+ ".mid", ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso", ".doc", ".docx", ".xls", ".xlsx",
+ ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"};
+
+ /* 列出指定目录下的图片 */
+ /* 执行图片管理的action名称 */
+ private String imageManagerActionName = "listimage";
+ /* 指定要列出图片的目录 */
+ private String imageManagerListPath = "/ueditor/jsp/upload/image/";
+ /* 每次列出文件数量 */
+ private long imageManagerListSize = 20;
+ /* 图片访问路径前缀 */
+ private String imageManagerUrlPrefix = "";
+ /* 插入的图片浮动方式 */
+ private String imageManagerInsertAlign = "none";
+ /* 列出的文件类型 */
+ private String[] imageManagerAllowFiles = new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp"};
+
+ /* 列出指定目录下的文件 */
+ /* 执行文件管理的action名称 */
+ private String fileManagerActionName = "listfile";
+ /* 指定要列出文件的目录 */
+ private String fileManagerListPath = "/ueditor/jsp/upload/file/";
+ /* 文件访问路径前缀 */
+ private String fileManagerUrlPrefix = "";
+ /* 每次列出文件数量 */
+ private long fileManagerListSize = 20;
+ /* 列出的文件类型 */
+ private String[] fileManagerAllowFiles = new String[]{".png", ".jpg", ".jpeg", ".gif", ".bmp", ".flv", ".swf",
+ ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg", ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3",
+ ".wav", ".mid", ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso", ".doc", ".docx", ".xls",
+ ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"};
+
+}
diff --git a/src/main/java/com/org/utils/AjaxResult.java b/src/main/java/com/org/utils/AjaxResult.java
new file mode 100644
index 0000000..a64e5ce
--- /dev/null
+++ b/src/main/java/com/org/utils/AjaxResult.java
@@ -0,0 +1,119 @@
+package com.org.utils;
+
+import org.springframework.http.HttpStatus;
+
+import java.util.HashMap;
+
+/** 操作消息提醒 **/
+public class AjaxResult extends HashMap {
+ 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";
+
+ /** 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息 **/
+ public AjaxResult() { }
+
+ /**
+ * 初始化一个新创建的 AjaxResult 对象
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ */
+ public AjaxResult(int code, String msg){
+ super.put(CODE_TAG, code);
+ super.put(MSG_TAG, msg);
+ }
+
+ /**
+ * 初始化一个新创建的 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 (data != null) 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.OK.value(), 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.INTERNAL_SERVER_ERROR.value(), msg, data); }
+
+ /**
+ * 返回错误消息
+ *
+ * @param code 状态码
+ * @param msg 返回内容
+ * @return 警告消息
+ */
+ public static AjaxResult error(int code, String msg) { return new AjaxResult(code, msg, null); }
+
+ @Override
+ public AjaxResult put(String key, Object value) {
+ super.put(key, value);
+ return this;
+ }
+}
diff --git a/src/main/java/com/org/utils/Constants.java b/src/main/java/com/org/utils/Constants.java
new file mode 100644
index 0000000..f0cd92c
--- /dev/null
+++ b/src/main/java/com/org/utils/Constants.java
@@ -0,0 +1,140 @@
+package com.org.utils;
+
+/** 通用常量信息 **/
+public class Constants
+{
+ /**
+ * UTF-8 字符集
+ */
+ public static final String UTF8 = "UTF-8";
+
+ /**
+ * GBK 字符集
+ */
+ public static final String GBK = "GBK";
+
+ /**
+ * http请求
+ */
+ public static final String HTTP = "http://";
+
+ /**
+ * https请求
+ */
+ public static final String HTTPS = "https://";
+
+ /**
+ * 通用成功标识
+ */
+ public static final String SUCCESS = "0";
+
+ /**
+ * 通用失败标识
+ */
+ public static final String FAIL = "1";
+
+ /**
+ * 登录成功
+ */
+ public static final String LOGIN_SUCCESS = "Success";
+
+ /**
+ * 注销
+ */
+ public static final String LOGOUT = "Logout";
+
+ /**
+ * 登录失败
+ */
+ public static final String LOGIN_FAIL = "Error";
+
+ /**
+ * 验证码 redis key
+ */
+ public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+ /**
+ * 登录用户 redis key
+ */
+ public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
+ /**
+ * 防重提交 redis key
+ */
+ public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
+
+ /**
+ * 验证码有效期(分钟)
+ */
+ public static final Integer CAPTCHA_EXPIRATION = 2;
+
+ /**
+ * 令牌
+ */
+ public static final String TOKEN = "token";
+
+ /**
+ * 令牌前缀
+ */
+ public static final String TOKEN_PREFIX = "Bearer ";
+
+ /**
+ * 令牌前缀
+ */
+ public static final String LOGIN_USER_KEY = "login_user_key";
+
+ /**
+ * 用户ID
+ */
+ public static final String JWT_USERID = "userid";
+
+ /**
+ * 用户名称
+ */
+ public static final String JWT_USERNAME = "sub";
+
+ /**
+ * 用户头像
+ */
+ public static final String JWT_AVATAR = "avatar";
+
+ /**
+ * 创建时间
+ */
+ public static final String JWT_CREATED = "created";
+
+ /**
+ * 用户权限
+ */
+ public static final String JWT_AUTHORITIES = "authorities";
+
+ /**
+ * 参数管理 cache key
+ */
+ public static final String SYS_CONFIG_KEY = "sys_config:";
+
+ /**
+ * 字典管理 cache key
+ */
+ public static final String SYS_DICT_KEY = "sys_dict:";
+
+ /**
+ * 资源映射路径 前缀
+ */
+ public static final String RESOURCE_PREFIX = "/profile";
+
+ /**
+ * app版本管理 cache key
+ */
+ public static final String SYS_APP_VERSION_KEY = "sys_app_version:";
+
+ /**
+ * app版本强制升级版本号 cache key
+ */
+ public static final String SYS_APP_VERSION_FORCE_KEY = "sys_app_version_force:";
+
+ /**
+ * app版本强制升级版本号 cache key
+ */
+ public static final String SYS_APP_VERSION_NOTICE_KEY = "sys_app_version_notice:";
+}
diff --git a/src/main/java/com/org/utils/HttpServletUtil.java b/src/main/java/com/org/utils/HttpServletUtil.java
new file mode 100644
index 0000000..77cd3c7
--- /dev/null
+++ b/src/main/java/com/org/utils/HttpServletUtil.java
@@ -0,0 +1,82 @@
+package com.org.utils;
+
+import cn.hutool.core.convert.Convert;
+import com.org.utils.exception.CustomException;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class HttpServletUtil {
+
+ public static ServletRequestAttributes getServletRequestAttributes(){
+ RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
+
+ if(requestAttributes == null) throw new CustomException("获取 RequestAttributes 异常");
+
+ return (ServletRequestAttributes) requestAttributes;
+ }
+
+ /**
+ * 获取 HttpServletRequest
+ *
+ * @return
+ */
+ public static HttpServletRequest getRequest(){
+ return getServletRequestAttributes().getRequest();
+ }
+
+ /**
+ * 获取 HttpServletResponse
+ *
+ * @return
+ */
+ public static HttpServletResponse getResponse(){
+ return getServletRequestAttributes().getResponse();
+ }
+
+ /**
+ * 获取String参数
+ *
+ * @param name
+ * @return
+ */
+ public static String getParameter(String name) {
+ return getRequest().getParameter(name);
+ }
+
+ /**
+ * 获取String参数
+ *
+ * @param name
+ * @param defaultValue
+ * @return
+ */
+ public static String getParameter(String name, String defaultValue) {
+ return Convert.toStr(getRequest().getParameter(name), defaultValue);
+ }
+
+ /**
+ * 获取Integer参数
+ *
+ * @param name
+ * @return
+ */
+ public static Integer getParameterToInt(String name) {
+ return Convert.toInt(getRequest().getParameter(name));
+ }
+
+ /**
+ * 获取Integer参数
+ *
+ * @param name
+ * @param defaultValue
+ * @return
+ */
+ public static Integer getParameterToInt(String name, Integer defaultValue) {
+ return Convert.toInt(getRequest().getParameter(name), defaultValue);
+ }
+
+}
diff --git a/src/main/java/com/org/utils/ImagePicUtil.java b/src/main/java/com/org/utils/ImagePicUtil.java
new file mode 100644
index 0000000..070f497
--- /dev/null
+++ b/src/main/java/com/org/utils/ImagePicUtil.java
@@ -0,0 +1,113 @@
+package com.org.utils;
+
+import cn.hutool.core.img.ImgUtil;
+import cn.hutool.core.lang.Validator;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+@Slf4j
+public class ImagePicUtil {
+ // 缩放至的宽度
+ public static int zoomWidth = 1024;
+ // 缩略图的宽度
+ public static int thumbnailWidth = 400;
+
+ /**
+ * 图片缩放
+ * @param filePath
+ * @param width
+ * @param fileName
+ * @return
+ */
+ public static MultipartFile getImagePic(String filePath, int width, String fileName){
+ log.info("ImagePicUtil - getImagePic filePath:{}", filePath);
+ log.info("ImagePicUtil - getImagePic width:{}", width);
+ log.info("ImagePicUtil - getImagePic fileName:{}", fileName);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ Image image = ImageIO.read(new File(filePath));
+
+ int image_width = image.getWidth(null);
+ log.info("ImagePicUtil - getImagePic image_width:{}", image_width);
+
+ if(image_width <= width){
+ log.info("ImagePicUtil - getImagePic not scale");
+ return null;
+ }
+
+ float scale = Float.parseFloat(String.valueOf(width)) / Float.parseFloat(String.valueOf(image_width));
+ log.info("ImagePicUtil - getImagePic scale:{}", scale);
+
+ // 等比缩放图片
+ Image scaleImage = ImgUtil.scale(image, scale);
+
+ // Image 转 BufferedImage
+ BufferedImage bufferedImage = new BufferedImage(scaleImage.getWidth(null), scaleImage.getHeight(null), BufferedImage.TYPE_3BYTE_BGR);
+ Graphics g = bufferedImage.getGraphics();
+ g.drawImage(scaleImage, 0, 0, null);
+
+ // 获取文件后缀
+ String suffix = filePath.substring(filePath.lastIndexOf(".")+1);
+
+ //将newImage写入字节数组输出流
+ ImageIO.write( bufferedImage, suffix, baos );
+ } catch (IOException e) {
+ log.error("{}", e);
+ } finally {
+ try {
+ baos.flush();
+ baos.close();
+ } catch (IOException e) {
+ log.error("PDFUtil - imgToPdf error {}", e);
+ }
+ }
+
+ MockMultipartFile mockMultipartFile = new MockMultipartFile(fileName, fileName, "image/jpeg", baos.toByteArray());
+ log.info("ImagePicUtil - getImagePic ok ...");
+
+ return mockMultipartFile;
+ }
+
+ /**
+ * 通过文件路径
+ * @param path
+ * @return true-支持 false-不支持
+ */
+ public static boolean checkImageByPath(String path) {
+ log.info("ImagePicUtil - checkImageByPath path:{}", path);
+ // 文本课件没有封面
+ if (Validator.isEmpty(path)) return true;
+
+ // 获取文件后缀,并且转换小写
+ String suffix = path.substring(path.lastIndexOf(".")+1).toLowerCase();
+ log.info("ImagePicUtil - checkImageByPath suffix:{}", suffix);
+
+ String str = constMap1.get(suffix);
+ log.info("ImagePicUtil - checkImageByPath str:{}", str);
+ if (Validator.isNotEmpty(str)) return true;
+
+ return false;
+ }
+
+ /**
+ * 支持的图片
+ */
+ private static final Map constMap1 = new HashMap() {
+ {
+ put("jpg", "jpg");
+ put("jpeg", "jpeg");
+ put("png", "png");
+ }
+ };
+
+}
diff --git a/src/main/java/com/org/utils/MessageUtil.java b/src/main/java/com/org/utils/MessageUtil.java
new file mode 100644
index 0000000..cf82283
--- /dev/null
+++ b/src/main/java/com/org/utils/MessageUtil.java
@@ -0,0 +1,19 @@
+package com.org.utils;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.i18n.LocaleContextHolder;
+
+/** 获取i18n资源文件 **/
+public class MessageUtil {
+ /**
+ * 根据消息键和参数 获取消息 委托给spring messageSource
+ *
+ * @param code 消息键
+ * @param args 参数
+ * @return 获取国际化翻译值
+ */
+ public static String message(String code, Object... args) {
+ MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
+ return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
+ }
+}
diff --git a/src/main/java/com/org/utils/SecurityUtil.java b/src/main/java/com/org/utils/SecurityUtil.java
new file mode 100644
index 0000000..293b3da
--- /dev/null
+++ b/src/main/java/com/org/utils/SecurityUtil.java
@@ -0,0 +1,53 @@
+package com.org.utils;
+
+import com.org.system.entity.LoginUser;
+import com.org.utils.exception.CustomException;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/** 安全服务工具类 **/
+public class SecurityUtil {
+
+ /** 获取Authentication **/
+ public static Authentication getAuthentication() { return SecurityContextHolder.getContext().getAuthentication(); }
+
+ /**
+ * 当前是否登录
+ *
+ * @return
+ */
+ public static boolean isLogin(){
+ String principal = getAuthentication().getPrincipal().toString();
+ if("anonymousUser".equals(principal)) return false;
+ return true;
+ }
+
+ /** 获取用户 **/
+ public static LoginUser getLoginUser() {
+ try {
+ return (LoginUser) getAuthentication().getPrincipal();
+ } catch (Exception e) {
+ throw new CustomException("获取用户信息异常", HttpStatus.UNAUTHORIZED.value());
+ }
+ }
+
+ /** 获取用户ID **/
+ public static Long getUserId() {
+ try {
+ return getLoginUser().getUser().getId();
+ } catch (Exception e) {
+ throw new CustomException("获取用户账户异常", HttpStatus.UNAUTHORIZED.value());
+ }
+ }
+
+ /** 获取用户账户 **/
+ public static String getUsername() {
+ try {
+ return getLoginUser().getUsername();
+ } catch (Exception e) {
+ throw new CustomException("获取用户账户异常", HttpStatus.UNAUTHORIZED.value());
+ }
+ }
+
+}
diff --git a/src/main/java/com/org/utils/SpringUtil.java b/src/main/java/com/org/utils/SpringUtil.java
new file mode 100644
index 0000000..c780ef8
--- /dev/null
+++ b/src/main/java/com/org/utils/SpringUtil.java
@@ -0,0 +1,111 @@
+package com.org.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 **/
+@Component
+public final class SpringUtil implements BeanFactoryPostProcessor, ApplicationContextAware
+{
+ /** Spring应用上下文环境 */
+ private static ConfigurableListableBeanFactory beanFactory;
+
+ private static ApplicationContext applicationContext;
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { SpringUtil.beanFactory = beanFactory; }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringUtil.applicationContext = applicationContext; }
+
+ /**
+ * 获取对象
+ *
+ * @param name
+ * @return Object 一个以所给名字注册的bean的实例
+ * @throws BeansException
+ *
+ */
+ @SuppressWarnings("unchecked")
+ public static T getBean(String name) throws BeansException { return (T) beanFactory.getBean(name); }
+
+ /**
+ * 获取类型为requiredType的对象
+ *
+ * @param clz
+ * @return
+ * @throws BeansException
+ *
+ */
+ public static T getBean(Class clz) throws BeansException { return (T) beanFactory.getBean(clz); }
+
+ /**
+ * 如果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 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();
+
+ if(activeProfiles == null || activeProfiles.length == 0) return null;
+ return activeProfiles[0];
+ }
+}
diff --git a/src/main/java/com/org/utils/SqlUtil.java b/src/main/java/com/org/utils/SqlUtil.java
new file mode 100644
index 0000000..220efd3
--- /dev/null
+++ b/src/main/java/com/org/utils/SqlUtil.java
@@ -0,0 +1,32 @@
+package com.org.utils;
+
+import com.org.utils.exception.BaseException;
+
+/** sql操作工具类 **/
+public class SqlUtil {
+ /** 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) **/
+ public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
+
+ /**
+ * 检查字符,防止注入绕过
+ *
+ * @param value
+ * @return
+ */
+ public static String escapeOrderBySql(String value) {
+ if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
+ throw new BaseException("参数不符合规范,不能进行查询");
+
+ return value;
+ }
+
+ /**
+ * 验证 order by 语法是否符合规范
+ *
+ * @param value
+ * @return
+ */
+ public static boolean isValidOrderBySql(String value) {
+ return value.matches(SQL_PATTERN);
+ }
+}
diff --git a/src/main/java/com/org/utils/StringUtils.java b/src/main/java/com/org/utils/StringUtils.java
new file mode 100644
index 0000000..f674d6f
--- /dev/null
+++ b/src/main/java/com/org/utils/StringUtils.java
@@ -0,0 +1,370 @@
+package com.org.utils;
+
+import cn.hutool.core.text.StrFormatter;
+
+import java.util.*;
+
+/** 字符串工具类 **/
+public class StringUtils extends org.apache.commons.lang3.StringUtils {
+ /** 空字符串 */
+ private static final String NULLSTR = "";
+
+ /** 下划线 */
+ private static final char SEPARATOR = '_';
+
+ /**
+ * 获取参数不为空值
+ *
+ * @param value defaultValue 要判断的value
+ * @return value 返回值
+ */
+ public static T nvl(T value, T defaultValue) {
+ return value != null ? value : defaultValue;
+ }
+
+ /**
+ * * 判断一个Collection是否为空, 包含List,Set,Queue
+ *
+ * @param coll 要判断的Collection
+ * @return true:为空 false:非空
+ */
+ public static boolean isEmpty(Collection> coll) {
+ return isNull(coll) || coll.isEmpty();
+ }
+
+ /**
+ * * 判断一个Collection是否非空,包含List,Set,Queue
+ *
+ * @param coll 要判断的Collection
+ * @return true:非空 false:空
+ */
+ public static boolean isNotEmpty(Collection> coll) {
+ return !isEmpty(coll);
+ }
+
+ /**
+ * * 判断一个对象数组是否为空
+ *
+ * @param objects 要判断的对象数组
+ ** @return true:为空 false:非空
+ */
+ public static boolean isEmpty(Object[] objects) {
+ return isNull(objects) || (objects.length == 0);
+ }
+
+ /**
+ * * 判断一个对象数组是否非空
+ *
+ * @param objects 要判断的对象数组
+ * @return true:非空 false:空
+ */
+ public static boolean isNotEmpty(Object[] objects) {
+ return !isEmpty(objects);
+ }
+
+ /**
+ * * 判断一个Map是否为空
+ *
+ * @param map 要判断的Map
+ * @return true:为空 false:非空
+ */
+ public static boolean isEmpty(Map, ?> map) {
+ return isNull(map) || map.isEmpty();
+ }
+
+ /**
+ * * 判断一个Map是否为空
+ *
+ * @param map 要判断的Map
+ * @return true:非空 false:空
+ */
+ public static boolean isNotEmpty(Map, ?> map) {
+ return !isEmpty(map);
+ }
+
+ /**
+ * * 判断一个字符串是否为空串
+ *
+ * @param str String
+ * @return true:为空 false:非空
+ */
+ public static boolean isEmpty(String str) {
+ return isNull(str) || NULLSTR.equals(str.trim());
+ }
+
+ /**
+ * * 判断一个字符串是否为非空串
+ *
+ * @param str String
+ * @return true:非空串 false:空串
+ */
+ public static boolean isNotEmpty(String str) {
+ return !isEmpty(str);
+ }
+
+ /**
+ * * 判断一个对象是否为空
+ *
+ * @param object Object
+ * @return true:为空 false:非空
+ */
+ public static boolean isNull(Object object) {
+ return object == null;
+ }
+
+ /**
+ * * 判断一个对象是否非空
+ *
+ * @param object Object
+ * @return true:非空 false:空
+ */
+ public static boolean isNotNull(Object object) {
+ return !isNull(object);
+ }
+
+ /**
+ * * 判断一个对象是否是数组类型(Java基本型别的数组)
+ *
+ * @param object 对象
+ * @return true:是数组 false:不是数组
+ */
+ public static boolean isArray(Object object) {
+ return isNotNull(object) && object.getClass().isArray();
+ }
+
+ /**
+ * 去空格
+ */
+ public static String trim(String str) {
+ return (str == null ? "" : str.trim());
+ }
+
+ /**
+ * 截取字符串
+ *
+ * @param str 字符串
+ * @param start 开始
+ * @return 结果
+ */
+ public static String substring(final String str, int start) {
+ if (str == null) return NULLSTR;
+
+ if (start < 0) start = str.length() + start;
+ if (start < 0) start = 0;
+
+ if (start > str.length()) return NULLSTR;
+
+ return str.substring(start);
+ }
+
+ /**
+ * 截取字符串
+ *
+ * @param str 字符串
+ * @param start 开始
+ * @param end 结束
+ * @return 结果
+ */
+ public static String substring(final String str, int start, int end) {
+ if (str == null) return NULLSTR;
+
+ if (end < 0) end = str.length() + end;
+ if (start < 0) start = str.length() + start;
+
+ if (end > str.length()) end = str.length();
+ if (start > end) return NULLSTR;
+
+ if (start < 0) start = 0;
+ if (end < 0) end = 0;
+
+ return str.substring(start, end);
+ }
+
+ /**
+ * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ *
+ * @param template 文本模板,被替换的部分用 {} 表示
+ * @param params 参数值
+ * @return 格式化后的文本
+ */
+ public static String format(String template, Object... params) {
+ if (isEmpty(params) || isEmpty(template)) return template;
+
+ return StrFormatter.format(template, params);
+ }
+
+ /**
+ * 字符串转set
+ *
+ * @param str 字符串
+ * @param sep 分隔符
+ * @return set集合
+ */
+ public static final Set str2Set(String str, String sep) {
+ return new HashSet(str2List(str, sep, true, false));
+ }
+
+ /**
+ * 字符串转list
+ *
+ * @param str 字符串
+ * @param sep 分隔符
+ * @param filterBlank 过滤纯空白
+ * @param trim 去掉首尾空白
+ * @return list集合
+ */
+ public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) {
+ List list = new ArrayList();
+
+ if (StringUtils.isEmpty(str)) return list;
+
+ // 过滤空白字符串
+ if (filterBlank && StringUtils.isBlank(str)) return list;
+
+ String[] split = str.split(sep);
+ for (String string : split) {
+ if (filterBlank && StringUtils.isBlank(string)) continue;
+
+ if (trim) string = string.trim();
+
+ list.add(string);
+ }
+
+ return list;
+ }
+
+ /**
+ * 下划线转驼峰命名
+ */
+ public static String toUnderScoreCase(String str) {
+ if (str == null) return null;
+
+ StringBuilder sb = new StringBuilder();
+
+ // 前置字符是否大写
+ boolean preCharIsUpperCase = true;
+ // 当前字符是否大写
+ boolean curreCharIsUpperCase = true;
+ // 下一字符是否大写
+ boolean nexteCharIsUpperCase = true;
+
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+
+ if (i > 0) preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
+ else preCharIsUpperCase = false;
+
+ curreCharIsUpperCase = Character.isUpperCase(c);
+
+ if (i < (str.length() - 1)) nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
+
+ if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) sb.append(SEPARATOR);
+ else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) sb.append(SEPARATOR);
+
+ sb.append(Character.toLowerCase(c));
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * 是否包含字符串
+ *
+ * @param str 验证字符串
+ * @param strs 字符串组
+ * @return 包含返回true
+ */
+ public static boolean inStringIgnoreCase(String str, String... strs) {
+ if (str != null && strs != null) {
+ for (String s : strs) {
+ if (str.equalsIgnoreCase(trim(s))) return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
+ *
+ * @param name 转换前的下划线大写方式命名的字符串
+ * @return 转换后的驼峰式命名的字符串
+ */
+ public static String convertToCamelCase(String name) {
+ StringBuilder result = new StringBuilder();
+
+ if (name == null || name.isEmpty()) return "";
+ else if (!name.contains("_")) return name.substring(0, 1).toUpperCase() + name.substring(1);
+
+ // 用下划线将原始字符串分割
+ String[] camels = name.split("_");
+ for (String camel : camels) {
+ // 跳过原始字符串中开头、结尾的下换线或双重下划线
+ if (camel.isEmpty()) continue;
+
+ // 首字母大写
+ result.append(camel.substring(0, 1).toUpperCase());
+ result.append(camel.substring(1).toLowerCase());
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * 驼峰式命名法 例如:user_name->userName
+ */
+ public static String toCamelCase(String s) {
+ if (s == null) return null;
+
+ s = s.toLowerCase();
+
+ StringBuilder sb = new StringBuilder(s.length());
+
+ boolean upperCase = false;
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+
+ if (c == SEPARATOR) {
+ upperCase = true;
+ } else if (upperCase) {
+ sb.append(Character.toUpperCase(c));
+ upperCase = false;
+ } else {
+ sb.append(c);
+ }
+ }
+
+ return sb.toString();
+ }
+
+
+ /**
+ * 获取固定长度的随机数字字符串
+ *
+ * @param strLength
+ * 长度
+ * @return 指定长度的随机数字字符串
+ *
+ */
+ public static String getFixLenNumString(int strLength) {
+ StringBuilder result = new StringBuilder();
+
+ Random random = new Random();
+
+ for (int i = 0; i < strLength; i++) {
+ result.append(random.nextInt(10));
+ }
+
+ return result.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static T cast(Object obj) {
+ return (T) obj;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/org/utils/Threads.java b/src/main/java/com/org/utils/Threads.java
new file mode 100644
index 0000000..98a90e2
--- /dev/null
+++ b/src/main/java/com/org/utils/Threads.java
@@ -0,0 +1,71 @@
+package com.org.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.concurrent.*;
+
+/** 线程相关工具类 **/
+@Slf4j
+public class Threads {
+
+ /** sleep等待,单位为毫秒 **/
+ public static void sleep(long milliseconds) {
+ try {
+ Thread.sleep(milliseconds);
+ } catch (InterruptedException e) {
+ log.error("{}", e);
+ return;
+ }
+ }
+
+ /**
+ * 停止线程池
+ * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
+ * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
+ * 如果仍人超時,則強制退出.
+ * 另对在shutdown时线程本身被调用中断做了处理.
+ */
+ public static void shutdownAndAwaitTermination(ExecutorService pool) {
+ if (pool != null && !pool.isShutdown()) {
+ pool.shutdown();
+ try {
+ if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
+ pool.shutdownNow();
+ if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
+ log.info("Pool did not terminate");
+ }
+ }
+ } catch (InterruptedException ie) {
+ log.error("{}", ie);
+ pool.shutdownNow();
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ /**
+ * 打印线程异常信息
+ */
+ public static void printException(Runnable r, Throwable t) {
+ if (t == null && r instanceof Future>) {
+ try {
+ Future> future = (Future>) r;
+ if (future.isDone()) {
+ future.get();
+ }
+ } catch (CancellationException ce) {
+ log.error("{}", ce);
+ t = ce;
+ } catch (ExecutionException ee) {
+ log.error("{}", ee);
+ t = ee.getCause();
+ } catch (InterruptedException ie) {
+ log.error("{}", ie);
+ Thread.currentThread().interrupt();
+ }
+ }
+ if (t != null) {
+ log.error("{}", t);
+ }
+ }
+}
diff --git a/src/main/java/com/org/utils/core/IdParams.java b/src/main/java/com/org/utils/core/IdParams.java
new file mode 100644
index 0000000..50930f0
--- /dev/null
+++ b/src/main/java/com/org/utils/core/IdParams.java
@@ -0,0 +1,19 @@
+package com.org.utils.core;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Id请求参数对象
+ */
+@Data
+public class IdParams {
+
+ /**
+ * 主键
+ */
+ @NotNull(message = "ID不能为空")
+ private Long id;
+
+}
diff --git a/src/main/java/com/org/utils/core/PageParams.java b/src/main/java/com/org/utils/core/PageParams.java
new file mode 100644
index 0000000..b18e605
--- /dev/null
+++ b/src/main/java/com/org/utils/core/PageParams.java
@@ -0,0 +1,29 @@
+package com.org.utils.core;
+
+import lombok.Data;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 分页参数对象
+ */
+@Data
+public class PageParams {
+
+ /**
+ * 页码,默认为1
+ */
+ @NotNull(message = "页码不能为空")
+ @Min(value = 1, message ="页码不能小于1")
+ private Integer pageNum = 1;
+
+ /**
+ * 分页大小
+ */
+ @NotNull(message = "分页大小不能为空")
+ @Min(value = 1, message = "分页大小不能小于1")
+ @Max(value = 100, message = "分页大小不能大于100")
+ private Integer pageSize = 10;
+}
diff --git a/src/main/java/com/org/utils/exception/BaseException.java b/src/main/java/com/org/utils/exception/BaseException.java
new file mode 100644
index 0000000..edca38e
--- /dev/null
+++ b/src/main/java/com/org/utils/exception/BaseException.java
@@ -0,0 +1,80 @@
+package com.org.utils.exception;
+
+import cn.hutool.core.util.StrUtil;
+import com.org.utils.MessageUtil;
+
+/** 基础异常 **/
+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 (!StrUtil.isEmpty(code)) {
+ message = MessageUtil.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;
+ }
+}
diff --git a/src/main/java/com/org/utils/exception/CustomException.java b/src/main/java/com/org/utils/exception/CustomException.java
new file mode 100644
index 0000000..8e67d62
--- /dev/null
+++ b/src/main/java/com/org/utils/exception/CustomException.java
@@ -0,0 +1,39 @@
+package com.org.utils.exception;
+
+/** 自定义异常 **/
+public class CustomException extends RuntimeException
+{
+ private static final long serialVersionUID = 1L;
+
+ private Integer code;
+
+ private String message;
+
+ public CustomException(String message)
+ {
+ this.message = message;
+ }
+
+ public CustomException(String message, Integer code)
+ {
+ this.message = message;
+ this.code = code;
+ }
+
+ public CustomException(String message, Throwable e)
+ {
+ super(message, e);
+ this.message = message;
+ }
+
+ @Override
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public Integer getCode()
+ {
+ return code;
+ }
+}
diff --git a/src/main/java/com/org/utils/exception/GlobalExceptionHandler.java b/src/main/java/com/org/utils/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..977b47f
--- /dev/null
+++ b/src/main/java/com/org/utils/exception/GlobalExceptionHandler.java
@@ -0,0 +1,88 @@
+package com.org.utils.exception;
+
+import com.org.utils.AjaxResult;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.authentication.AccountExpiredException;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.NoHandlerFoundException;
+
+/** 全局异常处理器 **/
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+ /**
+ * 基础异常
+ */
+ @ExceptionHandler(BaseException.class)
+ public AjaxResult baseException(BaseException e)
+ {
+ return AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 业务异常
+ */
+ @ExceptionHandler(CustomException.class)
+ public AjaxResult businessException(CustomException e) {
+ if (null == e.getCode()) {
+ return AjaxResult.error(e.getMessage());
+ }
+ return AjaxResult.error(e.getCode(), e.getMessage());
+ }
+
+ @ExceptionHandler(NoHandlerFoundException.class)
+ public AjaxResult handlerNoFoundException(Exception e) {
+ log.error(e.getMessage(), e);
+ return AjaxResult.error(HttpStatus.NOT_FOUND.value(), "路径不存在,请检查路径是否正确");
+ }
+
+ @ExceptionHandler(AccessDeniedException.class)
+ public AjaxResult handleAuthorizationException(AccessDeniedException e) {
+ log.error(e.getMessage());
+ return AjaxResult.error(HttpStatus.FORBIDDEN.value(), "没有权限,请联系管理员授权");
+ }
+
+ @ExceptionHandler(AccountExpiredException.class)
+ public AjaxResult handleAccountExpiredException(AccountExpiredException e) {
+ log.error(e.getMessage(), e);
+ return AjaxResult.error(e.getMessage());
+ }
+
+ @ExceptionHandler(UsernameNotFoundException.class)
+ public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e) {
+ log.error(e.getMessage(), e);
+ return AjaxResult.error(e.getMessage());
+ }
+
+ @ExceptionHandler(Exception.class)
+ public AjaxResult handleException(Exception e) {
+ log.error(e.getMessage(), e);
+ return AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 自定义验证异常
+ */
+ @ExceptionHandler(BindException.class)
+ public AjaxResult validatedBindException(BindException e) {
+ log.error(e.getMessage(), e);
+ String message = e.getAllErrors().get(0).getDefaultMessage();
+ return AjaxResult.error(message);
+ }
+
+ /**
+ * 自定义验证异常
+ */
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public Object validExceptionHandler(MethodArgumentNotValidException e) {
+ log.error(e.getMessage(), e);
+ String message = e.getBindingResult().getFieldError().getDefaultMessage();
+ return AjaxResult.error(message);
+ }
+}
diff --git a/src/main/java/com/org/utils/exception/UserException.java b/src/main/java/com/org/utils/exception/UserException.java
new file mode 100644
index 0000000..e4f8039
--- /dev/null
+++ b/src/main/java/com/org/utils/exception/UserException.java
@@ -0,0 +1,11 @@
+package com.org.utils.exception;
+
+/** 用户信息异常类 **/
+public class UserException extends BaseException {
+ private static final long serialVersionUID = 1L;
+
+ public UserException(String code, Object[] args)
+ {
+ super("user", code, args, null);
+ }
+}
diff --git a/src/main/java/com/org/utils/exception/UserPasswordNotMatchException.java b/src/main/java/com/org/utils/exception/UserPasswordNotMatchException.java
new file mode 100644
index 0000000..d82b7fd
--- /dev/null
+++ b/src/main/java/com/org/utils/exception/UserPasswordNotMatchException.java
@@ -0,0 +1,12 @@
+package com.org.utils.exception;
+
+/** 用户密码不正确或不符合规范异常类 **/
+public class UserPasswordNotMatchException extends UserException
+{
+ private static final long serialVersionUID = 1L;
+
+ public UserPasswordNotMatchException()
+ {
+ super("user.password.not.match", null);
+ }
+}
diff --git a/src/main/java/com/org/utils/page/PageDomain.java b/src/main/java/com/org/utils/page/PageDomain.java
new file mode 100644
index 0000000..20e87ef
--- /dev/null
+++ b/src/main/java/com/org/utils/page/PageDomain.java
@@ -0,0 +1,28 @@
+package com.org.utils.page;
+
+
+import com.org.utils.StringUtils;
+import lombok.Data;
+
+/** 分页数据 **/
+@Data
+public class PageDomain {
+ /** 当前记录起始索引 */
+ private Integer pageNum;
+
+ /** 每页显示记录数 */
+ private Integer pageSize;
+
+ /** 排序列 */
+ private String orderByColumn;
+
+ /** 排序的方向desc或者asc */
+ private String isAsc = "asc";
+
+ public String getOrderBy() {
+ if (StringUtils.isEmpty(orderByColumn)) return "";
+
+ return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
+ }
+
+}
diff --git a/src/main/java/com/org/utils/page/TableDataInfo.java b/src/main/java/com/org/utils/page/TableDataInfo.java
new file mode 100644
index 0000000..1b9372b
--- /dev/null
+++ b/src/main/java/com/org/utils/page/TableDataInfo.java
@@ -0,0 +1,47 @@
+package com.org.utils.page;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/** 表格分页数据对象 **/
+@Data
+public class TableDataInfo implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /** 总记录数 **/
+ private long total;
+
+ /** 当前页码 **/
+ private int pageNo;
+
+ /** 列表数据 **/
+ private List> rows;
+
+ /** 消息状态码 **/
+ private int code;
+
+ /** 消息内容 **/
+ private String msg;
+
+ /**
+ * 表格数据对象
+ *
+ */
+ public TableDataInfo() {
+ }
+
+ /**
+ * 分页
+ *
+ * @param list 列表数据
+ * @param total 总记录数
+ */
+ public TableDataInfo(List> list, int total, int pageNo) {
+ this.rows = list;
+ this.total = total;
+ this.pageNo = pageNo;
+ }
+
+}
diff --git a/src/main/java/com/org/utils/page/TableSupport.java b/src/main/java/com/org/utils/page/TableSupport.java
new file mode 100644
index 0000000..71d003e
--- /dev/null
+++ b/src/main/java/com/org/utils/page/TableSupport.java
@@ -0,0 +1,34 @@
+package com.org.utils.page;
+
+import com.org.utils.HttpServletUtil;
+
+/** 表格数据处理 **/
+public class TableSupport {
+ /** 当前记录起始索引 **/
+ public static final String PAGE_NUM = "pageNum";
+
+ /** 每页显示记录数 **/
+ public static final String PAGE_SIZE = "pageSize";
+
+ /** 排序列 **/
+ public static final String ORDER_BY_COLUMN = "orderByColumn";
+
+ /** 排序的方向 "desc" 或者 "asc". **/
+ public static final String IS_ASC = "isAsc";
+
+ /** 封装分页对象 **/
+ public static PageDomain getPageDomain() {
+ PageDomain pageDomain = new PageDomain();
+
+ pageDomain.setPageNum(HttpServletUtil.getParameterToInt(PAGE_NUM));
+ pageDomain.setPageSize(HttpServletUtil.getParameterToInt(PAGE_SIZE));
+ pageDomain.setOrderByColumn(HttpServletUtil.getParameter(ORDER_BY_COLUMN));
+ pageDomain.setIsAsc(HttpServletUtil.getParameter(IS_ASC));
+ return pageDomain;
+ }
+
+ public static PageDomain buildPageRequest()
+ {
+ return getPageDomain();
+ }
+}
diff --git a/src/main/java/com/org/utils/poi/ExcelUtil.java b/src/main/java/com/org/utils/poi/ExcelUtil.java
new file mode 100644
index 0000000..1681ed8
--- /dev/null
+++ b/src/main/java/com/org/utils/poi/ExcelUtil.java
@@ -0,0 +1,977 @@
+package com.org.utils.poi;
+
+import cn.hutool.core.convert.Convert;
+import com.org.system.annotation.Excel;
+import com.org.system.annotation.Excel.ColumnType;
+import com.org.system.annotation.Excel.Type;
+import com.org.system.annotation.Excels;
+import com.org.system.service.SysDataDictionaryItemService;
+import com.org.utils.AjaxResult;
+import com.org.utils.SpringUtil;
+import com.org.utils.StringUtils;
+import com.org.utils.exception.CustomException;
+import com.org.utils.reflect.ReflectUtils;
+import com.org.utils.upload.CommonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+
+import java.io.*;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Excel相关处理
+ *
+ * @author ruoyi
+ */
+@Slf4j
+public class ExcelUtil {
+
+ /**
+ * Excel sheet最大行数,默认65536
+ */
+ public static final int sheetSize = 65536;
+
+ /**
+ * 工作表名称
+ */
+ private String sheetName;
+
+ /**
+ * 导出类型(EXPORT:导出数据;IMPORT:导入模板)
+ */
+ private Type type;
+
+ /**
+ * 工作薄对象
+ */
+ private Workbook wb;
+
+ /**
+ * 工作表对象
+ */
+ private Sheet sheet;
+
+ /**
+ * 样式列表
+ */
+ private Map styles;
+
+ /**
+ * 导入导出数据列表
+ */
+ private List list;
+
+ /**
+ * 注解列表
+ */
+ private List