1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > SpringBoot整合SpringSecurity实现权限控制(五):用户管理

SpringBoot整合SpringSecurity实现权限控制(五):用户管理

时间:2023-04-10 15:20:52

相关推荐

SpringBoot整合SpringSecurity实现权限控制(五):用户管理

系列文章目录

《SpringBoot整合SpringSecurity实现权限控制(一):实现原理》

《SpringBoot整合SpringSecurity实现权限控制(二):权限数据基本模型设计》

《SpringBoot整合SpringSecurity实现权限控制(三):前端动态装载路由与菜单》

《SpringBoot整合SpringSecurity实现权限控制(四):角色管理》


本文目录

一、前言二、后端实现2.1 创建用户实体类2.2 创建用户角色实体类2.3 添加用户与用户角色Mapper接口2.4 实现用户的增删改查服务2.5 编写Controller层 三、前端实现3.1 添加用户api访问接口3.2 编写前端页面 四、效果演示五、源码

一、前言

系统的使用者称为用户,仅可在被赋予的权限范围之内操作系统。

管理员是一种特殊的用户,拥有系统操作的最高权限。

本文将实现用户的管理功能,重点实现用户的角色分配。

– 用户的新增(自助注册)可参考以下文章:《手把手教你通过SpringBoot实现邮箱注册码验证》 实现效果如下:

二、后端实现

2.1 创建用户实体类

该实体类对应用户表,记录用户的基础信息。

/*** 用户表** @author zhuhuix* @date -04-03*/@ApiModel(value = "用户信息")@Data@SuperBuilder@NoArgsConstructor@AllArgsConstructor@TableName("sys_user")public class SysUser implements Serializable {@TableId(value = "id", type = IdType.AUTO)private Long id;private String userName;@JsonIgnoreprivate String password;private String nickName;/*** 性别 0-未知 1-male,2-female*/private Integer gender;/*** 头像地址*/private String avatarUrl;private String country;private String province;private String city;@Emailprivate String email;private String phone;private String remarks;@TableLogicprivate Boolean enabled;private Timestamp lastPasswordResetTime;private Timestamp createTime;@Builder.Defaultprivate Timestamp updateTime = Timestamp.valueOf(LocalDateTime.now());}

2.2 创建用户角色实体类

该实体类对应用户角色表,记录用户对应的角色信息(一个角户可对应多个角色)。

/*** 用户角色表** @author zhuhuix* @date -09-29*/@ApiModel(value = "用户角色信息")@Data@SuperBuilder@NoArgsConstructor@AllArgsConstructor@TableName("sys_user_role")public class SysUserRole {@TableId(value = "id", type = IdType.AUTO)private Long id;private Long userId;private Long roleId;private Timestamp createTime;}

2.3 添加用户与用户角色Mapper接口

通过该Mapper接口可操作用户实体与用户角色实体

/*** 用户DAO接口** @author zhuhuix* @date -07-19*/@Mapperpublic interface SysUserMapper extends BaseMapper<SysUser> {/*** 查询用户角色* @param userId 用户id* @return 角色信息*/@Select("select r.id,r.role_code,r.role_name,r.description,r.enabled,r.create_time,r.update_time " +"from sys_role r " +"INNER JOIN sys_user_role ur ON r.id=ur.role_id where ur.user_id=#{userId} ")List<SysRole> selectUserRoles(Long userId);/*** 查询用户权限* @param userId 用户id* @return 权限信息*/@Select("SELECT m.id, m.`path`, m.`name`, m.`component`, m.`icon`, m.`cache`, m.`hidden`, m.`redirect`, m.p_id " +"FROM " +"sys_menu m " +"INNER JOIN sys_permission p ON p.menu_id = m.id " +"INNER JOIN sys_user_role ur ON ur.role_id = p.role_id " +"INNER JOIN sys_user u ON u.id = ur.user_id " +"INNER JOIN sys_role r ON r.id = ur.role_id where ur.user_id=#{userId}"+" and m.enabled=1 " +" order by m.sort ")List<PermissionDto> selectUserPermission(Long userId);}

/*** 用户角色DAO接口** @author zhuhuix* @date -09-29*/@Mapperpublic interface SysUserRoleMapper extends BaseMapper<SysUserRole> {}

2.4 实现用户的增删改查服务

/*** 用户管理服务接口** @author zhuhuix* @date -04-03*/public interface SysUserService {/*** 增加用户** @param user 待新增的用户* @return 增加成功的用户*/SysUser create(SysUser user);/*** 删除用户** @param user 待删除的用户* @return 删除成功的用户*/SysUser delete(SysUser user);/*** 修改用户** @param user 待修改的用户* @return 修改成功的用户*/SysUser update(SysUser user);/*** 根据id查找用户** @param id 用户id* @return 用户信息*/SysUser findById(Long id);/*** 根据userName查找用户** @param userName 用户帐号* @return 用户帐号对应的用户*/SysUser findByUserName(String userName);/*** 判断注册使用的邮箱是否存在** @param email 邮箱号* @return 是否找到*/boolean registerEmailExist(String email);/*** 获取用户信息** @return 用户信息*/UserDetails getUserInfo();/*** 修改用户头像** @param file 文件* @return json*/Map<String, String> updateAvatar(MultipartFile file);/*** 获取用户角色信息** @param userId 用户id* @return 角色信息*/List<SysRole> getUserRoles(Long userId);/*** 保存用户角色** @param userId 用户id* @param roleIds 角色id列表* @return 是否成功*/Boolean saveUserRoles(Long userId,Set<Long> roleIds);/*** 获取用户权限信息** @param userId 用户id* @return 权限信息*/List<PermissionDto> getUserPermission(Long userId);/*** 根据条件查询用户信息** @param sysUserQueryDto 查询条件* @return 用户列表*/List<SysUser> list(SysUserQueryDto sysUserQueryDto);/*** 批量删除用户** @param ids 待删除的用户id列表* @return 是否成功*/Boolean delete(Set<Long> ids);}

/*** 用户管理服务实现类** @author zhuhuix* @date -04-03*/@Slf4j@Service@RequiredArgsConstructor@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)public class SysUserServiceImpl implements SysUserService {private final SysUserMapper sysUserMapper;private final SysUserRoleMapper sysUserRoleMapper;private final UploadFileTool uploadFileTool;@Override@Transactional(rollbackFor = Exception.class)public SysUser create(SysUser user) {if (sysUserMapper.insert(user) > 0) {return user;}throw new RuntimeException("增加用户信息失败");}@Override@Transactional(rollbackFor = Exception.class)public SysUser delete(SysUser user) {QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(SysUser::getUserName, user.getUserName());if (sysUserMapper.delete(queryWrapper) > 0) {return user;}throw new RuntimeException("删除用户信息失败");}@Override@Transactional(rollbackFor = Exception.class)public SysUser update(SysUser user) {if (sysUserMapper.updateById(user) > 0) {return user;}throw new RuntimeException("更新用户信息失败");}@Overridepublic SysUser findById(Long id) {return sysUserMapper.selectById(id);}@Overridepublic SysUser findByUserName(String userName) {return sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUserName, userName));}@Overridepublic boolean registerEmailExist(String email) {QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(SysUser::getEmail, email);return sysUserMapper.selectOne(queryWrapper) != null;}@Overridepublic UserDetails getUserInfo() {UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class);return userDetailsService.loadUserByUsername(getCurrentLoginUserName());}@Override@Transactional(rollbackFor = Exception.class)public Map<String, String> updateAvatar(MultipartFile file) {SysUser sysUser = findByUserName(getCurrentLoginUserName());UploadFile uploadFile = uploadFileTool.upload(sysUser.getUserName(), file.getOriginalFilename(), file);sysUser.setAvatarUrl(uploadFile.getType() + File.separator + uploadFile.getFileName());update(sysUser);return new HashMap<String, String>(1) {{put("avatar", uploadFile.getFileName());}};}@Overridepublic List<PermissionDto> getUserPermission(Long userId) {return sysUserMapper.selectUserPermission(userId);}@Overridepublic List<SysRole> getUserRoles(Long userId) {return sysUserMapper.selectUserRoles(userId);}@Override@Transactional(rollbackFor = Exception.class)public Boolean saveUserRoles(Long userId, Set<Long> roleIds) {// 首先清除该用户原有的角色信息QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(SysUserRole::getUserId, userId);sysUserRoleMapper.delete(queryWrapper);// 再进行添加for (Long roleId : roleIds) {SysUserRole sysUserRole = new SysUserRole();sysUserRole.setUserId(userId);sysUserRole.setRoleId(roleId);sysUserRole.setCreateTime(Timestamp.valueOf(LocalDateTime.now()));sysUserRoleMapper.insert(sysUserRole);}return true;}private String getCurrentLoginUserName() {final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();if (authentication == null) {throw new RuntimeException("登录状态已过期");}if (authentication.getPrincipal() instanceof UserDetails) {UserDetails userDetails = (UserDetails) authentication.getPrincipal();return (userDetails.getUsername());}throw new RuntimeException("找不到当前登录的信息");}@Overridepublic List<SysUser> list(SysUserQueryDto sysUserQueryDto) {QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();if (!StringUtils.isEmpty(sysUserQueryDto.getUserName())) {queryWrapper.lambda().like(SysUser::getUserName, sysUserQueryDto.getUserName()).or().like(SysUser::getNickName, sysUserQueryDto.getUserName());}if (!StringUtils.isEmpty(sysUserQueryDto.getCreateTimeStart())&& !StringUtils.isEmpty(sysUserQueryDto.getCreateTimeEnd())) {queryWrapper.and(wrapper -> wrapper.lambda().between(SysUser::getCreateTime,new Timestamp(sysUserQueryDto.getCreateTimeStart()),new Timestamp(sysUserQueryDto.getCreateTimeEnd())));}return sysUserMapper.selectList(queryWrapper);}@Override@Transactional(rollbackFor = Exception.class)public Boolean delete(Set<Long> ids) {if (sysUserMapper.deleteBatchIds(ids) > 0) {return true;}throw new RuntimeException("删除用户信息失败");}}

2.5 编写Controller层

共实现以下9个后台接口

/*** api用户信息** @author zhuhuix* @date -08-16*/@Slf4j@RestController@AllArgsConstructor@RequestMapping("/api/user")@Api(tags = "用户信息接口")public class SysUserController {private final SysUserService sysUserService;@ApiOperation("获取当前登录用户信息")@GetMapping()public ResponseEntity<Object> getUserInfo() {return ResponseEntity.ok(sysUserService.getUserInfo());}@ApiOperation("根据id获取用户信息")@GetMapping("/{id}")public ResponseEntity<Object> getUserInfo(@PathVariable Long id) {return ResponseEntity.ok(sysUserService.findById(id));}@ApiOperation("更新用户信息")@PostMapping()public ResponseEntity<Object> saveUser(@RequestBody SysUser user) {return ResponseEntity.ok(sysUserService.update(user));}@PreAuthorize("hasAuthority('user:updateAvatar')")@ApiOperation("修改用户头像")@PostMapping(value = "/updateAvatar")public ResponseEntity<Object> updateAvatar(@RequestParam MultipartFile avatar) {return ResponseEntity.ok(sysUserService.updateAvatar(avatar));}@ApiOperation("根据条件查询用户列表")@PostMapping("/list")public ResponseEntity<Object> getSysUserList(@RequestBody SysUserQueryDto sysUserQueryDto) {return ResponseEntity.ok(sysUserService.list(sysUserQueryDto));}@ApiOperation("批量删除用户")@DeleteMappingpublic ResponseEntity<Object> deleteUsers(@RequestBody Set<Long> ids) {return ResponseEntity.ok(sysUserService.delete(ids));}@ApiOperation("获取用户角色")@GetMapping("/roles/{userId}")public ResponseEntity<Object> getUserRoles(@PathVariable Long userId) {return ResponseEntity.ok(sysUserService.getUserRoles(userId));}@ApiOperation("保存用户角色")@PostMapping("/roles/{userId}")public ResponseEntity<Object> saveUserRoles(@PathVariable Long userId, @RequestBody Set<Long> ids) {return ResponseEntity.ok(sysUserService.saveUserRoles(userId, ids));}@ApiOperation("获取用户权限")@GetMapping("/permission/{userId}")public ResponseEntity<Object> getUserPermission(@PathVariable Long userId) {return ResponseEntity.ok(sysUserService.getUserPermission(userId));}}

三、前端实现

3.1 添加用户api访问接口

import request from '@/utils/request'// 登录export function login(data) {return request({url: '/api/auth/login',method: 'post',data})}// 注销export function logout() {return request({url: '/api/auth/logout',method: 'delete'})}// 获取当前登录用户信息export function getInfo() {return request({url: '/api/user',method: 'get'})}// 根据用户id获取用户信息export function getInfoById(id) {return request({url: '/api/user/' + id,method: 'get'})}// 保存并更新用户export function saveUser(data) {return request({url: '/api/user',method: 'post',data})}// 根据用户id列表批量删除用户export function deleteUser(ids) {return request({url: '/api/user',method: 'delete',data: ids})}// 根据条件查询获取用户列表export function getUserList(params) {return request({url: '/api/user/list',method: 'post',data: JSON.stringify(params)})}// 根据用户id获取用户权限export function getUserPermission(userId) {return request({url: '/api/user/permission/' + userId,method: 'get'})}// 获取用户角色export function getUserRoles(userId) {return request({url: '/api/user/roles/' + userId,method: 'get'})}// 分配用户角色export function saveUserRoles(userId, roleIds) {return request({url: '/api/user/roles/' + userId,method: 'post',data: roleIds})}

3.2 编写前端页面

我们需要编写一个完整的页面:

通过登录账号或用户名,注册起始与结束时间查询用户,并以列表的形式进行显示。

通过点击“分配角色”按钮,跳出表单,选取角色信息给用户进行角色分配。

在列表上选取用户(可多选),点击“删除”按钮,删除选取的用户,删除前要有提示。

前端关键源码如下:

– src/user/index.vue

<template><div class="app-container"><!--工具栏--><div class="head-container"><!-- 搜索 --><el-inputv-model="userName"size="small"clearableplaceholder="输入账号或用户名称搜索"style="width: 200px"class="filter-item"@keyup.enter.native="doQuery"/><el-date-pickerv-model="createTime":default-time="['00:00:00', '23:59:59']"type="daterange"range-separator=":"size="small"class="date-item"value-format="yyyy-MM-dd HH:mm:ss"start-placeholder="开始日期"end-placeholder="结束日期"/><el-buttonclass="filter-item"size="mini"type="success"icon="el-icon-search"@click="doQuery">搜索</el-button><el-buttonclass="filter-item"size="mini"type="danger"icon="el-icon-circle-plus-outline":disabled="selections.length===0"@click="doDelete">删除</el-button></div><el-row><!--角色分配表单--><el-dialog append-to-body :close-on-click-modal="false" :visible.sync="showDialog" title="角色分配" width="600px"><el-form ref="form" :inline="true" :model="form" size="small" label-width="76px"><el-form-item label="登录账号" prop="userName"><el-input v-model="form.userName" :disabled="true" /></el-form-item><el-form-item label="昵称" prop="nickName"><el-input v-model="form.nickName" :disabled="true" /></el-form-item><el-form-item style="margin-bottom: 0;" label="角色" prop="userRoles"><el-selectv-model="userRoles"style="width: 455px"multiplefilterableplaceholder="请选择"@remove-tag="deleteTag"@change="changeRole"><el-optionv-for="item in roles":key="item.roleCode":label="item.roleName":value="item.id"/></el-select></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button type="text" @click="doCancel">取消</el-button><el-button :loading="formLoading" type="primary" @click="doSubmit">确认</el-button></div></el-dialog><el-tabs v-model="activeName" type="border-card"><el-tab-pane label="用户列表" name="userList"><el-table ref="table" v-loading="loading" :data="users" style="width: 100%; font-size: 12px;" @selection-change="selectionChangeHandler"><el-table-column type="selection" width="55" /><el-table-column :show-overflow-tooltip="true" width="150" prop="userName" label="登录账号" /><el-table-column :show-overflow-tooltip="true" width="150" prop="nickName" label="用户昵称" /><el-table-column prop="gender" width="60" label="性别"><template slot-scope="scope"><el-tag v-if="scope.row.gender===1" type="success">男</el-tag><el-tag v-if="scope.row.gender===2" type="warning">女</el-tag><el-tag v-if="scope.row.gender===0" type="info">未知</el-tag></template></el-table-column><el-table-column :show-overflow-tooltip="true" prop="phone" width="150" label="电话" /><el-table-column :show-overflow-tooltip="true" prop="city" label="所在地区"><template slot-scope="scope"><span>{{scope.row.province }} {{scope.row.city }} {{scope.row.country }}</span></template></el-table-column><el-table-column :show-overflow-tooltip="true" prop="avatarUrl" width="80" label="头像"><template slot-scope="scope"><img:src="scope.row.avatarUrl? baseApi + '/file/' + scope.row.avatarUrl: Avatar"class="avatar"></template></el-table-column><el-table-column :show-overflow-tooltip="true" prop="createTime" width="155" label="注册日期"><template slot-scope="scope"><span>{{parseTime(scope.row.createTime) }}</span></template></el-table-column><el-table-columnlabel="操作"width="160"align="center"fixed="right"><template slot-scope="scope"><el-button size="mini" type="text" round @click="doAssignRole(scope.row.id)">分配角色</el-button></template></el-table-column></el-table></el-tab-pane></el-tabs></el-row></div></template><script>import {mapGetters } from 'vuex'import Avatar from '@/assets/images/avatar.png'import {parseTime } from '@/utils/index'import {getUserList, deleteUser, getInfoById, getUserRoles, saveUserRoles } from '@/api/user'import {getRoleList } from '@/api/role'export default {name: 'User',data() {return {Avatar: Avatar,activeName: 'userList',showDialog: false,loading: false,formLoading: true,form: {},users: [],selections: [],userName: '',createTime: null,roles: [],userRoles: []}},computed: {...mapGetters(['baseApi'])},created() {},methods: {parseTime,doQuery() {this.users = []var param = {userName: this.userName }if (this.createTime != null) {param.createTimeStart = Date.parse(this.createTime[0])param.createTimeEnd = Date.parse(this.createTime[1])}getUserList(param).then(res => {if (res) {this.users = res}})},doDelete() {const ids = []this.selections.forEach((res) => {ids.push(res.id)})this.$confirm(`确认删除这些用户吗?`, '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() =>deleteUser(ids).then(res => {if (res) {this.$notify({title: '删除成功',type: 'success',duration: 2500})this.doQuery()}})).catch(() => {})},// 选择改变selectionChangeHandler(val) {this.selections = val},doAssignRole(id) {this.form = {}this.userRoles = []this.roles = []this.showDialog = truethis.formLoading = truegetInfoById(id).then((res) => {this.form = {id: res.id, userName: res.userName, nickName: res.nickName, gender: res.gender, phone: res.phone }var param = {}getRoleList(param).then(res => {if (res) {this.roles = res}getUserRoles(id).then((res) => {if (res) {res.forEach(role => {this.userRoles.push(role.id)})}this.formLoading = false})})})},doCancel() {this.showDialog = falsethis.form = {}},doSubmit() {this.formLoading = truesaveUserRoles(this.form.id, this.userRoles).then(() => {this.showDialog = falsethis.$notify({title: '保存成功',type: 'success',duration: 2500})})},deleteTag(value) {this.userRoles.forEach(function(data, index) {if (data.id === value) {this.userRoles.splice(index, value)}})},changeRole(value) {// console.log(this.userRoles)}}}</script><style rel="stylesheet/scss" lang="scss">.avatar {width: 32px;height: 32px;border-radius: 50%;}</style><style rel="stylesheet/scss" lang="scss" scoped>::v-deep .el-input-number .el-input__inner {text-align: left;}</style>

四、效果演示

五、源码

前端

/zhuhuix/startup-frontend

/zhuhuix/startup-frontend后端

/zhuhuix/startup-backend

/zhuhuix/startup-backend

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。