java后台通用权限管理系统(springboot)

2023-05-16

推荐:Java秒杀系统优化(高性能高并发)(Java秒杀系统优化(高性能高并发)_Garry1115的博客-CSDN博客)

说明:这是本人正在使用的一款通用权限管理系统。

来源:通过对网上优秀开源项目组件的合并与重构实现自身需求和功能。

技术架构:Springboot2.x + Shiro + MyBatis Plus + Layui

整个项目(初级版)的功能包括:用户管理、角色管理、菜单管理、字典管理、参数设置、通知公告、操作日志、登录日志、服务监控、资源分类等

高级版的功能在初级版之上会增加:部门管理、岗位管理、在线用户、定时任务、代码生成、系统接口、邮件管理、短信管理等

数据库表设计:

初级版数据库表:用户表、角色表、菜单表、用户角色表、角色菜单表、字典数据表、配置信息表、通知公告表、操作日志表、登陆日志表等。

高级版新增数据库表:新增部门表、岗位表、用户岗位表、角色部门表、短信配置模板、短信发送日志、邮件配置模板、邮件发送日志、定时任务管理、定时任务日志表等。

项目结构:

realm类

package com.xiaofeng.shiro.realm;

import com.google.common.collect.Sets;
import com.xiaofeng.shiro.entity.SysUser;
import com.xiaofeng.shiro.service.ISysLoginService;
import com.xiaofeng.shiro.service.ISysMenuService;
import com.xiaofeng.shiro.service.ISysRoleService;
import com.xiaofeng.shiro.util.ShiroUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * @author xiaofeng
 * @version V1.0
 * @title: UserRealm
 * @package: com.xiaofeng.share.shiro
 * @description: 自定义Realm 处理登录 权限
 * @date 2019/7/4 9:44
 */
public class UserRealm extends AuthorizingRealm {
    private static final Logger log = LoggerFactory.getLogger(UserRealm.class);

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysLoginService loginService;

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        SysUser user = ShiroUtils.getSysUser();
        // 角色列表
        Set<String> roles = Sets.newHashSet();
        // 功能列表
        Set<String> menus = Sets.newHashSet();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            info.addRole("admin");
            info.addStringPermission("*:*:*");
        } else {
            roles = roleService.selectRoleKeys(user.getId().longValue());
            menus = menuService.selectPermssionByUserId(user.getId().longValue());
            // 角色加入AuthorizationInfo认证对象
            info.setRoles(roles);
            // 权限加入AuthorizationInfo认证对象
            info.setStringPermissions(menus);
        }
        return info;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        String password = "";
        if (upToken.getPassword() != null) {
            password = new String(upToken.getPassword());
        }

        SysUser user = null;
        try {
            user = loginService.login(username, password);
        } catch (Exception e) {
            log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
            throw new AuthenticationException(e.getMessage(), e);
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
        return info;
    }

    /**
     * 清理缓存权限
     */
    public void clearCachedAuthorizationInfo() {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}

废话不多说,直接上效果图:

后台主页:

用户管理模块:

角色管理模块:

菜单管理模块:

操作日志模块:

用户模块Controller:

package com.xiaofeng.shiro.controller;


import cn.afterturn.easypoi.entity.vo.NormalExcelConstants;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.view.PoiBaseView;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Maps;
import com.xiaofeng.shiro.aspectj.annotation.Log;
import com.xiaofeng.shiro.common.response.AjaxResult;
import com.xiaofeng.shiro.common.response.TableDataInfo;
import com.xiaofeng.shiro.constant.UserConstants;
import com.xiaofeng.shiro.entity.SysRole;
import com.xiaofeng.shiro.entity.SysUser;
import com.xiaofeng.shiro.enums.LogType;
import com.xiaofeng.shiro.service.ISysRoleService;
import com.xiaofeng.shiro.service.ISysUserService;
import com.xiaofeng.shiro.service.impl.SysPasswordService;
import com.xiaofeng.shiro.util.DateUtil;
import com.xiaofeng.shiro.util.ShiroUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 用户信息表 前端控制器
 * </p>
 *
 * @author xiaofeng
 * @since 2019-07-03
 */
@Controller
@RequestMapping("/system/user")
public class SysUserController extends BaseController {
    private String prefix = "system/user";

    @Autowired
    private ISysUserService userService;
    @Autowired
    private ISysRoleService roleService;
    @Autowired
    private SysPasswordService passwordService;

    @RequiresPermissions("system:user:view")
    @GetMapping()
    public String user() {
        return prefix + "/user";
    }

    @Log(title = "用户查询", logType = LogType.SELECT)
    @RequiresPermissions("system:user:list")
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(SysUser user) {
        IPage<SysUser> page = getPage();
        userService.pageList(page, user);
        return getDataTable(page.getRecords(), page.getSize());
    }

    @Log(title = "用户管理", logType = LogType.EXPORT)
    @RequiresPermissions("system:user:export")
    @GetMapping("/export")
    public void export(SysUser user, HttpServletRequest request, HttpServletResponse response) {
        List<SysUser> list = userService.list(user);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        String title = "用户信息";
        Map<String, Object> map = Maps.newHashMap();
        ExportParams params = new ExportParams(title, title, ExcelType.HSSF);
        map.put(NormalExcelConstants.DATA_LIST, list);
        map.put(NormalExcelConstants.CLASS, SysUser.class);
        map.put(NormalExcelConstants.PARAMS, params);
        map.put("fileName", DateUtil.getNowDateTime());
        PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
    }

    /**
     * 新增用户
     */
    @GetMapping("/add")
    public String add(ModelMap mmap) {
        List<SysRole> roleList = roleService.list(new LambdaQueryWrapper<SysRole>().eq(SysRole::getDelFlag, 0));
        mmap.put("roles", roleList);
        return prefix + "/add";
    }

    /**
     * 新增保存用户
     */
    @RequiresPermissions("system:user:add")
    @Log(title = "用户管理", logType = LogType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(SysUser user) {
        if (user.getId() != null && SysUser.isAdmin(ShiroUtils.getSysUser().getUserType())) {
            return error("不允许修改超级管理员用户");
        }
        String nameUnique = userService.checkLoginNameUnique(user.getUserName());
        if (UserConstants.USER_NAME_NOT_UNIQUE.equals(nameUnique)) {
            return error("保存用户'" + user.getUserName() + "'失败,登录账号已存在");
        }
        user.setSalt(ShiroUtils.randomSalt());
        user.setPassword(passwordService.encryptPassword(user.getUserName(), user.getPassword(), user.getSalt()));
        user.setCreateBy(ShiroUtils.getLoginName());
        user.setCreateTime(DateUtil.getNowTimestamp());
        return toAjax(userService.insertUser(user));
    }

    /**
     * 修改用户
     */
    @GetMapping("/edit/{userId}")
    public String edit(@PathVariable("userId") Long userId, ModelMap mmap) {
        mmap.put("user", userService.getById(userId));
        mmap.put("roles", roleService.selectRolesByUserId(userId));
        return prefix + "/edit";
    }

    /**
     * 修改保存用户
     */
    @RequiresPermissions("system:user:edit")
    @Log(title = "用户管理", logType = LogType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(SysUser user) {
        if (user.getId() != null && SysUser.isAdmin(ShiroUtils.getSysUser().getUserType())) {
            return error("不允许修改超级管理员用户");
        }
        user.setUpdateBy(ShiroUtils.getLoginName());
        return toAjax(userService.updateUser(user));
    }


    @RequiresPermissions("system:user:resetPwd")
    @Log(title = "重置密码", logType = LogType.UPDATE)
    @GetMapping("/resetPwd/{userId}")
    public String resetPwd(@PathVariable("userId") Long userId, ModelMap mmap) {
        mmap.put("user", userService.getById(userId));
        return prefix + "/resetPwd";
    }

    @RequiresPermissions("system:user:resetPwd")
    @Log(title = "重置密码", logType = LogType.UPDATE)
    @PostMapping("/resetPwd")
    @ResponseBody
    public AjaxResult resetPwdSave(SysUser user) {
        user.setSalt(ShiroUtils.randomSalt());
        user.setPassword(passwordService.encryptPassword(user.getUserName(), user.getPassword(), user.getSalt()));
        return toAjax(userService.updateById(user));
    }

    @RequiresPermissions("system:user:remove")
    @Log(title = "用户管理", logType = LogType.DELETE)
    @PostMapping("/remove")
    @ResponseBody
    public AjaxResult remove(String ids) {
        try {
            if (StringUtils.isNoneBlank(ids)) {
                String[] split = ids.split(",");
                return toAjax(userService.batchDeleteUser(Arrays.asList(split)));
            }
        } catch (Exception e) {
            return error(e.getMessage());
        }
        return error();
    }


    /**
     * 校验用户名
     */
    @PostMapping("/checkLoginNameUnique")
    @ResponseBody
    public String checkLoginNameUnique(SysUser user) {
        String nameUnique = userService.checkLoginNameUnique(user.getUserName());
        return nameUnique;
    }

    /**
     * 校验手机号码
     */
    @PostMapping("/checkPhoneUnique")
    @ResponseBody
    public String checkPhoneUnique(SysUser user) {
        String phoneUnique = userService.checkPhoneUnique(user);
        return phoneUnique;
    }

    /**
     * 校验email邮箱
     */
    @PostMapping("/checkEmailUnique")
    @ResponseBody
    public String checkEmailUnique(SysUser user) {
        return userService.checkEmailUnique(user);
    }

    /**
     * 用户状态修改
     */
    @Log(title = "用户管理", logType = LogType.UPDATE)
    @RequiresPermissions("system:user:edit")
    @PostMapping("/changeStatus")
    @ResponseBody
    public AjaxResult changeStatus(SysUser user) {
        if (SysUser.isAdmin(ShiroUtils.getSysUser().getUserType())) {
            return error("不允许修改超级管理员用户");
        }
        return toAjax(userService.updateUser(user));
    }
}

用户模块service实现:

package com.xiaofeng.shiro.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaofeng.shiro.constant.Constants;
import com.xiaofeng.shiro.constant.UserConstants;
import com.xiaofeng.shiro.entity.SysRole;
import com.xiaofeng.shiro.entity.SysUser;
import com.xiaofeng.shiro.entity.SysUserRole;
import com.xiaofeng.shiro.mapper.SysRoleMapper;
import com.xiaofeng.shiro.mapper.SysUserMapper;
import com.xiaofeng.shiro.mapper.SysUserRoleMapper;
import com.xiaofeng.shiro.service.ISysUserRoleService;
import com.xiaofeng.shiro.service.ISysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author xiaofeng
 * @since 2019-07-03
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    SysRoleMapper sysRoleMapper;
    @Autowired
    ISysUserRoleService userRoleService;

    @Override
    public IPage<SysUser> pageList(IPage<SysUser> iPage, SysUser user) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<SysUser>();
        queryWrapper
                .like(StringUtils.isNoneBlank(user.getUserName()), SysUser::getUserName, user.getUserName())
                .like(StringUtils.isNoneBlank(user.getTelephone()), SysUser::getTelephone, user.getTelephone())
                .ge(user.getParams().get(Constants.START_TIME) != null && StringUtils.isNoneBlank(user.getParams().get(Constants.START_TIME).toString()), SysUser::getCreateTime, user.getParams().get(Constants.START_TIME))
                .le(user.getParams().get(Constants.END_TIME) != null && StringUtils.isNoneBlank(user.getParams().get(Constants.END_TIME).toString()), SysUser::getCreateTime, user.getParams().get(Constants.END_TIME));
        page(iPage, queryWrapper);
        return iPage;
    }

    /**
     * 不分页查询
     *
     * @param user
     * @return
     */
    @Override
    public List<SysUser> list(SysUser user) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<SysUser>();
        queryWrapper
                .like(StringUtils.isNoneBlank(user.getUserName()), SysUser::getUserName, user.getUserName())
                .like(StringUtils.isNoneBlank(user.getTelephone()), SysUser::getTelephone, user.getTelephone())
                .like(StringUtils.isNoneBlank(user.getSearchValue()), SysUser::getUserName, user.getSearchValue())
                .like(StringUtils.isNoneBlank(user.getSearchValue()), SysUser::getTelephone, user.getSearchValue())
                .ge(user.getParams().get(Constants.START_TIME) != null && StringUtils.isNoneBlank(user.getParams().get(Constants.START_TIME).toString()), SysUser::getCreateTime, user.getParams().get(Constants.START_TIME))
                .le(user.getParams().get(Constants.END_TIME) != null && StringUtils.isNoneBlank(user.getParams().get(Constants.END_TIME).toString()), SysUser::getCreateTime, user.getParams().get(Constants.END_TIME));
        List<SysUser> list = list(queryWrapper);
        return list;
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param loginName 登录名称
     * @return 结果
     */
    @Override
    public String checkLoginNameUnique(String loginName) {
        int count = count(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, loginName));
        return count > 0 ? UserConstants.USER_NAME_NOT_UNIQUE : UserConstants.USER_NAME_UNIQUE;
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public String checkPhoneUnique(SysUser user) {
        Long userId = user.getId() == null ? -1L : user.getId();
        SysUser sysUser = getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getTelephone, user.getTelephone()));
        String s = sysUser != null && !userId.equals(sysUser.getId()) ? UserConstants.USER_NAME_NOT_UNIQUE : UserConstants.USER_NAME_UNIQUE;
        return s;
    }

    /**
     * 校验email是否唯一
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public String checkEmailUnique(SysUser user) {
        Long userId = user.getId() == null ? -1L : user.getId();
        SysUser sysUser = getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getEmail, user.getEmail()));
        String s = sysUser != null && !userId.equals(sysUser.getId()) ? UserConstants.USER_NAME_NOT_UNIQUE : UserConstants.USER_NAME_UNIQUE;
        return s;
    }

    @Override
    public List<SysUser> selectAllocatedList(SysUser user) {
        return sysUserMapper.selectAllocatedList(user);
    }

    @Override
    public List<SysUser> selectUnallocatedList(SysUser user) {
        return sysUserMapper.selectUnallocatedList(user);
    }

    /**
     * 新增保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int insertUser(SysUser user) {
        // 新增用户信息
        int rows = sysUserMapper.insert(user);
        // 新增用户与角色管理
        insertUserRole(user);
        return rows;
    }

    /**
     * 修改保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUser(SysUser user) {
        // 删除用户与角色关联
        sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, user.getId()));
        // 新增用户与角色管理
        insertUserRole(user);
        boolean b = updateById(user);
        return b ? 1 : 0;
    }

    /**
     * 查询用户所属角色组
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    public String selectUserRoleGroup(Long userId) {
        List<SysRole> sysRoles = sysRoleMapper.selectRolesByUserId(userId);
        StringBuffer idsStr = new StringBuffer();
        for (SysRole role : sysRoles) {
            idsStr.append(role.getRoleName()).append(",");
        }
        if (StringUtils.isNotEmpty(idsStr.toString())) {
            return idsStr.substring(0, idsStr.length() - 1);
        }
        return idsStr.toString();
    }

    /**
     * 查询用户所属岗位组
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    public String selectUserPostGroup(Long userId) {

        return "";
    }

    /**
     * 删除
     *
     * @param userId
     * @return
     */
    @Override
    public int deleteUser(Long userId) {
        //删除用户角色关联
        sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
        //删除用户信息
        boolean b = removeById(userId);
        return b ? 1 : 0;
    }

    /**
     * 批量删除
     *
     * @param userId
     * @return
     */
    @Override
    public int batchDeleteUser(Collection<? extends Serializable> userId) {
        //删除用户角色关联
        sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, userId));
        //删除用户
        boolean b = removeByIds(userId);
        return b ? 1 : 0;
    }

    /**
     * 新增用户角色信息
     *
     * @param user 用户对象
     */
    public void insertUserRole(SysUser user) {
        Long[] roles = user.getRoleIds();
        if (roles != null) {
            // 新增用户与角色管理
            List<SysUserRole> list = new ArrayList<SysUserRole>();
            for (Long roleId : roles) {
                SysUserRole ur = new SysUserRole();
                ur.setUserId(user.getId());
                ur.setRoleId(roleId.intValue());
                list.add(ur);
            }
            if (list.size() > 0) {
                userRoleService.saveBatch(list);
            }
        }
    }

}

Shiro权限:

package com.xiaofeng.share.shiro;

import com.google.common.collect.Sets;
import com.xiaofeng.share.entity.SysUser;
import com.xiaofeng.share.service.ISysLoginService;
import com.xiaofeng.share.service.ISysMenuService;
import com.xiaofeng.share.service.ISysRoleService;
import com.xiaofeng.share.util.ShiroUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * @author xiaofeng
 * @version V1.0
 * @title: UserRealm
 * @package: com.xiaofeng.share.shiro
 * @description: 自定义Realm 处理登录 权限
 * @date 2019/7/4 9:44
 */
public class UserRealm extends AuthorizingRealm {
    private static final Logger log = LoggerFactory.getLogger(UserRealm.class);

    @Autowired
    private ISysMenuService menuService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysLoginService loginService;

    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        SysUser user = ShiroUtils.getSysUser();
        // 角色列表
        Set<String> roles = Sets.newHashSet();
        // 功能列表
        Set<String> menus = Sets.newHashSet();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 管理员拥有所有权限
        if (user.isAdmin()) {
            info.addRole("admin");
            info.addStringPermission("*:*:*");
        } else {
            roles = roleService.selectRoleKeys(user.getId().longValue());
            menus = menuService.selectPermssionByUserId(user.getId().longValue());
            // 角色加入AuthorizationInfo认证对象
            info.setRoles(roles);
            // 权限加入AuthorizationInfo认证对象
            info.setStringPermissions(menus);
        }
        return info;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        String password = "";
        if (upToken.getPassword() != null) {
            password = new String(upToken.getPassword());
        }

        SysUser user = null;
        try {
            user = loginService.login(username, password);
        } catch (Exception e) {
            log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
            throw new AuthenticationException(e.getMessage(), e);
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
        return info;
    }

    /**
     * 清理缓存权限
     */
    public void clearCachedAuthorizationInfo() {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}

核心配置文件:

更新日志:

多环境配置:

多数据源配置(动态数据源):

--------------------------------------------------------------20190926----------------------------------------------------------------------

2019年9月26,今天主要更新了2个功能模块:代码生成工具、在线会话数统计、同一个用户多设备登录限制(默认踢出前一个),sftp文件上传配置修复(用于图片上传),邮件发送配置更新等。

更新日志:

代码生成工具:

采用velocity模板工具生成代码

CodeGenerateController

package com.xiaofeng.sys.controller.tool;

import com.xiaofeng.sys.common.TableDataInfo;
import com.xiaofeng.sys.controller.BaseController;
import com.xiaofeng.sys.entity.generate.TableInfo;
import com.xiaofeng.sys.service.IGenerateService;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @author xiaofeng
 * @version V1.0
 * @title: CodeGenerateController
 * @package: com.xiaofeng.code.generate.controller
 * @description: 代码生成 操作处理
 * @date 2019/9/20 13:47
 */
@Controller
@RequestMapping("/tool/gen")
public class CodeGenerateController extends BaseController {
    private String prefix = "tool/gen";

    @Autowired
    private IGenerateService generateService;

    @RequiresPermissions("tool:gen:view")
    @GetMapping()
    public String gen() {
        return prefix + "/gen";
    }

    @GetMapping("/test")
    public String test() {
        return "test";
    }

    @RequiresPermissions("tool:gen:list")
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(TableInfo tableInfo) {
        List<TableInfo> list = generateService.selectTableList(tableInfo);
        return getDataTable(list);
    }

    /**
     * 生成代码
     */
    @RequiresPermissions("tool:gen:code")
    @GetMapping("/genCode/{tableName}")
    public void genCode(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException {
        byte[] data = generateService.generatorCode(tableName);
        genCode(response, data);
    }

    /**
     * 批量生成代码
     */
    @RequiresPermissions("tool:gen:code")
    @GetMapping("/batchGenCode")
    @ResponseBody
    public void batchGenCode(HttpServletResponse response, String tables) throws IOException {
        if (StringUtils.isBlank(tables)) {
            return;
        }
        String[] tableNames = tables.split(",");
        byte[] data = generateService.generatorCode(tableNames);
        genCode(response, data);
    }

    /**
     * 生成zip文件
     *
     * @param response
     * @param data
     * @throws IOException
     */
    private void genCode(HttpServletResponse response, byte[] data) throws IOException {
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"xiaofeng-code-generate.zip\"");
        response.addHeader("Content-Length", "" + data.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(data, response.getOutputStream());
    }
}

在线会话统计:

采用shiro session存储用户会话信息,会话信息存在系统session中,退出即销毁

OnlineSessionFilter(在线session过滤器


package com.xiaofeng.sys.shiro;

import com.xiaofeng.sys.common.constant.ShiroConstants;
import com.xiaofeng.sys.common.enums.OnlineStatus;
import com.xiaofeng.sys.entity.SysUser;
import com.xiaofeng.sys.util.ShiroUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/**
 * @author xiaofeng
 * @version V1.0
 * @title: OnlineSessionFilter
 * @package: com.xiaofeng.sys.shiro
 * @description: 在线session过滤器
 * @date 2019/9/26 16:00
 */
public class OnlineSessionFilter extends AccessControlFilter {

    /**
     * 强制退出后重定向的地址
     */
    private String forceLogoutUrl;

    private SessionDAO sessionDAO;

    public String getForceLogoutUrl() {
        return forceLogoutUrl;
    }

    public void setForceLogoutUrl(String forceLogoutUrl) {
        this.forceLogoutUrl = forceLogoutUrl;
    }

    public void setSessionDAO(SessionDAO sessionDAO) {
        this.sessionDAO = sessionDAO;
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws Exception {
        Subject subject = getSubject(request, response);
        if (subject == null || subject.getSession() == null) {
            return true;
        }
        Session session = sessionDAO.readSession(subject.getSession().getId());
        if (session != null && session instanceof OnlineSession) {
            OnlineSession onlineSession = (OnlineSession) session;
            request.setAttribute(ShiroConstants.ONLINE_SESSION, onlineSession);
            // 把user id设置进去
            //boolean isGuest = onlineSession.getUserId() == null  ;
            if (onlineSession.getUserId() == null) {
                SysUser user = ShiroUtils.getSysUser();
                if (user != null) {
                    onlineSession.setUserId(user.getUserId().longValue());
                    onlineSession.setLoginName(user.getLoginName());
                    onlineSession.setAvatar(user.getAvatar());
                    onlineSession.markAttributeChanged();
                }
            }
            if (onlineSession.getStatus() == OnlineStatus.off_line) {
                return false;
            }
        }
        return true;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Subject subject = getSubject(request, response);
        if (subject != null) {
            subject.logout();
        }
        saveRequestAndRedirectToLogin(request, response);
        return true;
    }

    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        WebUtils.issueRedirect(request, response, getForceLogoutUrl());
    }

}

SFTP上传配置:

在线用户统计

代码生成

文件管理主要包括:文件上传、文件编辑、文件下载、文件删除,后续会增加文件预览等功能。

文件上传到自主服务器linux目录,通过nginx配置反向代理映射处理,采用sftp协议实现上传、下载、删除等功能。

效果如下:

点击上传(将文件上传到服务器)

点击下载(将文件下载到本地)

由于篇幅有限,无法粘贴所有核心代码。

初级版download:java web基础权限系统 (resourcecode.cn)

高级版download:springboot完整版权限系统 (resourcecode.cn)

qq:193459197

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java后台通用权限管理系统(springboot) 的相关文章

  • 解决Ubuntu虚拟机NAT不能上网的几种方法

    vmware安装ubuntu虚拟机后 xff0c 网络经常抽风 也不知道具体是什么原因导致的 有时候开机就不能上网 xff0c 有时候 xff0c 是突然不能上网 这个时候 xff0c 尝试重启虚拟机后者电脑 xff0c 看看能否解决 或者
  • 显示https不安全的原因及解决办法

    很多人在部署了https证书之后 xff0c 有的时候仍然会出现https 不安全 的提示 xff0c 这就比较纳闷了 明明说部署了https证书会受到浏览器的信任的 xff0c 怎么还会出现这种情况 xff1f 安信SSL帮大家分析一下原
  • 小程序input输入限制小数位数

    小程序input组件本身没有自带这个校验属性 xff0c 但有一个maxlength属性 xff0c 可以通过是否输入了小数点来动态计算设置maxlength的方法达到限制输入的目的 保留一位小数 lt view class 61 34 l
  • js数组对象去重

    removeID span class token operator 61 span span class token punctuation span arr span class token punctuation span span
  • 解决echarts刷新不重绘

    切换筛选条件重新查询时候Echart不重新绘制 需要绘制之前初始化Echart echarts span class token punctuation span span class token function init span sp
  • 判断是否有值,0也是有值的情况

    span class token operator span span class token function isNaN span span class token punctuation span span class token f
  • 基于高德地图SDK进行搜索

    高德地图SDK使用地址http lbs amap com 地图设置 define GDMAPKEY 64 34 key 34 import 34 ViewController h 34 import lt MapKit MapKit h g
  • Microsoft Visual C++ Build Tools.exe安装包损坏

    Python3安装支持库的过程中经常会遇到 Microsoft Visual C 14 0 is required 此时就需要安装Visual C build tools生成工具 在运行build tool安装时 提示安装包损坏 翻墙也无效
  • debian图形界面安装

    安装GNOME中文桌面环境 安装基本的X系统 apt get install x window system core 安装GNOME桌面环境 apt get install gnome 到现在为止 xff0c 我们已成功安装完成gnome
  • Qt 调试时 程序异常结束

    在调试时 xff0c 关闭窗口 xff0c 应用程序输出窗口提示 Qt 调试时 程序异常结束 21 20 48 程序异常结束 21 20 48 The process was ended forcefully 21 20 48 G proj
  • c#webservice的简单示例

    是webservice 就概念上来说 xff0c 可能比较复杂 xff0c 不过我们可以有个宏观的了解 xff1a webservice就是个对外的接口 xff0c 里面有 函数可供外部客户调用 xff08 注意 xff1a 里面同样有客户
  • 实现常规厂家&品牌&型号业务对接物联网平台(snack3加json赋能)

    前言 之前介绍过通过snack3快速对接物模型 xff0c 不知道大家还有没有影响 记得还留了一个作业给大家想想 xff0c 就是这么兼容多型号 多版本 xff0c 这次就来跟大家分享下这么集成多型号 一 物模型文件调整 上次是利用snac
  • 组合OSS服务实现打包业务文件zip下载

    前言 实现文件打包成zip下载 xff0c 支持zip包含目录 文件 废话不多说 xff0c 直接上码 一 设计思路 后端组织文件 xff0c 打包成zip上传到OSS存储返回文件名称给前端前端根据返回的文件名称 xff08 url xff
  • Spring Boot + Disruptor = 王炸!!

    01 背景 工作中遇到项目使用Disruptor做消息队列 对你没看错 不是Kafka 也不是rabbitmq Disruptor有个最大的优点就是快 还有一点它是开源的哦 下面做个简单的记录 02 Disruptor介绍 Disrupto
  • Dbeaver连接ES问题一站解决

    前言 最近几天一直做ES的TPS测试 xff0c 每次看数据ES的数据都在嫌麻烦 xff08 在postman指定索引通过url请求查看数据 xff09 最后决定还是整整Dbeaver连接ES 一 当前境况 1 ES版本比较老 xff0c
  • Dbeaver连接TDengine时序数据库

    前言 还是结合上一阶段的工作 xff0c 为TPS满足合同里的要求 xff0c 预研数据库切换为TDengine 所以查看数据的工具我得能连上去看 xff0c 习惯了Dbeaver xff0c 所以先把Dbeaver整的能连接使用 一 Db
  • idea+ApifoxUploader+Apifox真是内外双修,香

    前言 最近部门为整合后端组 前端组 测试组 需求组 产品组等组之间的工作流程 xff0c 旨在提高协调与高效 xff0c 其中之一就是希望开发组 xff08 后端 前端 xff09 开发的接口能及时更新 xff0c 测试组能做接口测试 xf
  • SpringBoot3+最新MybatisPlus+Mysql与TDengine双数据源

    前言 昨天写的idea 43 Apifox uploader插件 43 apifox新年第一天上班就上榜了 xff0c 真是不错 今天来补一篇 xff0c 本来应该是在前一篇之前发的 实际上就是最新的springBoot集成最新的mybat
  • 业务平台扩展支持TDengine时序数据库方案

    1 场景与架构 1 1业务架构 这里涉及项目隐私 xff0c 架构图不方便公开 大致情况就是 xff1a 应用层的园区畅行 生态宜居 安全守护是我方要交付的系统 平台层的物联网感知中台是我方平台 1 2数据架构 从数据架构看 xff0c 园
  • 物联网平台+业务平台基本架构设计与优化想法

    前言 目前的交付底座有点老 xff0c 而且集成的有点杂 xff0c 计划是要升级下 xff0c 先说想法 xff0c 看领导做不做 1 业务平台定位 我们的愿景 xff1a 通过物联平台赋能 xff0c 让数据产生价值 为客户提供可视化的

随机推荐

  • Qt 正则表达式匹配失败的一个原因

    在Qt中做正则表达式时 xff0c 遇到一个很坑爹的问题 xff0c 还是经验不足导致 在正则表达式中 xff0c 有很多需要元字符 xff0c 是需要使用普通字符加转义符号搭配使用的 比如 w xff0c s 对于这类字符 xff0c 在
  • C++对象模型(整理)

    C 43 43 对象模型 1 何为C 43 43 对象模型 xff1f C 43 43 对象模型可以概括为以下2部分 xff1a 语言中直接支持面向对象程序设计的部分 面向对象程序设计部分 xff1a 如构造函数 析构函数 虚函数 继承 x
  • MybatisPlus多表查询之零sql编写实现

    1 前言 年初节奏还没有快起来 xff0c 适合做做技术前瞻 xff0c 无论是对个人还是团队都是好事 真要说分享 xff0c 其实感觉也没啥好分享的 xff0c 就像接手新项目一样 xff0c 代码都是自己看 xff0c 别人讲的再多 x
  • 物联网设备流水入库TDengine改造方案

    1 存储机制改造 针对提出的流水查询需求 xff0c 结合设备上报数据讨论后 xff0c 初步定以下几种方案 1 1 ES gt TDengine 1 ES入库有延时 2 ES没有提供数据监听API xff08 不能主动监听 xff0c 实
  • SpringBoot3集成Kafka优雅实现信息消费发送

    前言 首先 xff0c 你的JDK是否已经是8 43 了呢 xff1f 其次 xff0c 你是否已经用上SpringBoot3了呢 xff1f 最后 xff0c 这次分享的是SpringBoot3下的kafka发信息与消费信息 一 场景说明
  • SpringBoot3集成TDengine自适应裂变存储

    前言 首先很遗憾的告诉大家 xff0c 今天这篇分享要关注才可以看了 原因是穷啊 xff0c 现在基本都是要人民币玩家了 xff0c 就比如chatGPT copilot xff0c 这些AI虽然都是可以很好的辅助编码 xff0c 但是都是
  • Github Copilot编码神剑

    前言 今天跟大家分享的其实是现在比较火的Github copilot xff0c 另外 xff0c 就是分享下它的优雅使用 其实知道用这个以后 xff0c 瑟瑟发抖 xff0c 感觉就要失业了 不过真正用过后 xff0c 其实发现这要完全取
  • 一个基于缓存的业务链路日志记录设计方案

    前言 一个简单的全接口日志设计文档 xff0c 先分享设计文档 xff0c 后面分享核心设计代码 1 对外接口设计原则 1 1 基本原则 对外接口要遵守的基本原则 xff1a 1 开闭原则 2 依赖倒置原则 3 单一职责原则 4 接口隔离原
  • 基于缓存的统一请求日志实现

    前言 昨天说的会分享方案的具体实现 xff0c 今天就来分享想核心代码吧 一 思路 我们用的是springboot组服务 xff0c 每个链路通过http请求 所以要实现全链路的日志记录 xff0c 也都是围绕sprinboot做的处理 这
  • SpringBoot集成ChatGPT实现AI聊天

    前言 ChatGPT已经组件放开了 xff0c 现在都可以基于它写插件了 但是说实话我还真没想到可以用它干嘛 xff0c 也许可以用它结合文字语音开发一个老人小孩需要的智能的说话陪伴啥的 今天我就先分享下SpringBoot结合ChatGP
  • activemq 延时队列以及不生效问题

    最近在做的项目中有一个业务涉及到了订单的有效期的问题 xff08 即订单达到一定的时间未支付完成就让该订单失效 xff09 xff0c 于是就想到了延时队列的方式 xff0c 由于项目采用的是activemq xff0c 所以就写了个act
  • elasticsearch的分布式架构原理

    对于全文检索 xff0c lucene是目前最流行的搜索库 以前我们都需要学习使用lucene 基于lucene做相关的开发 xff0c 学习倒排索引的原理 xff0c 而现在 xff0c 我们可以直接使用现成的搜索框架了 xff0c 因为
  • vscode设置代理

    1 通过命令行方式设置 参考 xff1a https liliyuanshangcaoyisuiyikurongyehuoshaobujinchunfengchuiyousheng com 2021 vscode socks5 proxy
  • springboot oa 办公系统,springboot权限系统

    springboot oa 自动化办公系统 43 springboot 完整权限管理系统合二为一 xff01 办公自动化 xff08 OA xff09 是面向组织的日常运作和管理 xff0c 员工及管理者使用频率最高的应用系统 xff0c
  • linux下的shell运算(加、减、乘、除)

    关注微信公众号 虾米聊吧 获取所有资料干货 xff0c 每天更新技术干货 xff0c 一起交流一起学习 i 61 j 43 k 等价于 i 61 96 expr j 43 k 96 i 61 j k 等价于 i 61 96 expr j k
  • 仿QQ聊天程序(java)

    简易版qq聊天 xff1a qq聊天 简易版 resourcecode cn 推荐java最新聊天项目 xff08 java仿微信聊天 xff09 java 简单仿微信聊天 springboot Garry1115的博客 CSDN博客 sp
  • yum出错Error: Cannot find a valid baseurl for repo: base

    关注微信公众号 虾米聊吧 xff0c 每天更新一篇技术文章 xff0c 文章内容涵盖架构师成长必经之路应掌握的技术 xff0c 一起学习 xff0c 一起交流 最近在安装mysql的rpm包时 xff0c 出现了一个问题 xff0c 当使用
  • java web简单权限管理设计

    注 xff1a 由于该项目比较老 xff0c 所以没有采用maven管理 xff0c 建议下载java后台通用权限管理系统 springboot xff09 xff0c 对学习和使用会更有帮助 最近在做一个网站类型项目 xff0c 主要负责
  • C/C++ 开发神器 CLion 使用入门

    关注微信公众号 虾米聊吧 xff0c 每天分享知识干货 xff0c 和博主一起打卡 xff0c 进步 CLion是Jetbrains公司旗下新推出的一款专为开发C C 43 43 所设计的跨平台IDE xff0c 它是以IntelliJ为基
  • java后台通用权限管理系统(springboot)

    推荐 xff1a Java秒杀系统优化 高性能高并发 xff08 Java秒杀系统优化 高性能高并发 Garry1115的博客 CSDN博客 xff09 说明 xff1a 这是本人正在使用的一款通用权限管理系统 来源 xff1a 通过对网上