系列文章目录 《SpringBoot整合SpringSecurity实现权限控制(一):实现原理》 《SpringBoot整合SpringSecurity实现权限控制(二):权限数据基本模型设计》 《SpringBoot整合SpringSecurity实现权限控制(三):前端动态装载路由与菜单》
一、前言
角色是基于业务管理需求而预先在系统中设定好的固定标签,每个角色需对应明确的系统权限,其所拥有的系统权限一般不会随意更改,并且角色也不会随着用户的被添加和被移除而进行改变,相较于用户管理而言更加稳定。
- 本文将实现角色管理的增删改查
二、后端实现
2.1 创建角色实体类
@ApiModel(value = "角色表")
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@TableName("sys_role")
public class SysRole implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String roleCode;
private String roleName;
private String description;
@TableLogic
private Boolean enabled;
private Timestamp createTime;
@Builder.Default
private Timestamp updateTime = Timestamp.valueOf(LocalDateTime.now());
}
2.1 添加角色Mapper接口
@Mapper
public interface SysRoleMapper extends BaseMapper<SysRole> {
}
2.3 实现角色增删改查服务
public interface SysRoleService {
SysRole create(SysRole role);
SysRole delete(SysRole role);
SysRole update(SysRole role);
SysRole findByRoleCode(String roleCode);
SysRole findByRoleName(String roleName);
List<SysRole> findAll();
List<SysRole> list( RoleQueryDto roleQueryDto);
}
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class SysRoleServiceImpl implements SysRoleService {
private final SysRoleMapper sysRoleMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public SysRole create(SysRole role) {
if (findByRoleCode(role.getRoleCode()) != null || findByRoleCode(role.getRoleName()) != null) {
throw new RuntimeException("该角色已存在,不得重复添加!!");
}
if (sysRoleMapper.insert(role) > 0) {
return role;
}
throw new RuntimeException("增加角色信息失败");
}
@Override
@Transactional(rollbackFor = Exception.class)
public SysRole delete(SysRole role) {
QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(SysRole::getRoleCode, role.getRoleCode());
if (sysRoleMapper.delete(queryWrapper) > 0) {
return role;
}
throw new RuntimeException("删除角色信息失败");
}
@Override
@Transactional(rollbackFor = Exception.class)
public SysRole update(SysRole role) {
if (sysRoleMapper.updateById(role) > 0) {
return role;
}
throw new RuntimeException("修改角色信息失败");
}
@Override
public SysRole findByRoleCode(String roleCode) {
QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(SysRole::getRoleCode, roleCode);
return sysRoleMapper.selectOne(queryWrapper);
}
@Override
public SysRole findByRoleName(String roleName) {
QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
queryWrapper.lambda().eq(SysRole::getRoleName, roleName);
return sysRoleMapper.selectOne(queryWrapper);
}
@Override
public List<SysRole> findAll() {
QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
return sysRoleMapper.selectList(queryWrapper);
}
@Override
public List<SysRole> list(RoleQueryDto roleQueryDto) {
QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
if (!StringUtils.isEmpty(roleQueryDto.getRoleName())) {
queryWrapper.lambda().like(SysRole::getRoleName, roleQueryDto.getRoleName());
}
if (!StringUtils.isEmpty(roleQueryDto.getCreateTimeStart())
&& !StringUtils.isEmpty(roleQueryDto.getCreateTimeEnd())) {
queryWrapper.lambda().between(SysRole::getCreateTime,
new Timestamp(roleQueryDto.getCreateTimeStart()),
new Timestamp(roleQueryDto.getCreateTimeEnd()));
}
return sysRoleMapper.selectList(queryWrapper);
}
}
2.4 编写Controller层
- 共实现以下6个后台接口
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/api/role")
@Api(tags = "角色信息接口")
public class SysRoleController {
private final SysRoleService sysRoleService;
@ApiOperation("根据条件查询角色信息")
@PostMapping("/list")
public Object getRoleList(@RequestBody RoleQueryDto roleQueryDto) {
return sysRoleService.list(roleQueryDto);
}
@ApiOperation("根据id获取单个角色信息")
@GetMapping("{id}")
public ResponseEntity<Object> getRoleById(@PathVariable Long id) {
return ResponseEntity.ok(sysRoleService.findById(id));
}
@ApiOperation("根据角色编码获取单个角色信息")
@GetMapping("/roleCode/{roleCode}")
public ResponseEntity<Object> getRoleByRoleCode(@PathVariable String roleCode) {
return ResponseEntity.ok(sysRoleService.findByRoleCode(roleCode));
}
@ApiOperation("获取所有角色信息")
@GetMapping()
public ResponseEntity<Object> getAllRole() {
return ResponseEntity.ok(sysRoleService.findAll());
}
@ApiOperation("保存角色信息")
@PostMapping
public ResponseEntity<Object> saveRole(@RequestBody SysRole role) {
if (role.getId() != null) {
return ResponseEntity.ok(sysRoleService.update(role));
} else {
return ResponseEntity.ok(sysRoleService.create(role));
}
}
@ApiOperation("删除角色信息")
@DeleteMapping
public ResponseEntity<Object> deleteRole(@RequestBody Set<Long> ids) {
return ResponseEntity.ok(sysRoleService.delete(ids));
}
}
三、前端实现
3.1 添加角色api访问接口
import request from '@/utils/request'
export function getAllRole() {
return request({
url: '/api/role',
method: 'get'
})
}
export function getRole(id) {
return request({
url: '/api/role/' + id,
method: 'get'
})
}
export function saveRole(data) {
return request({
url: '/api/role',
method: 'post',
data
})
}
export function deleteRole(ids) {
return request({
url: '/api/role',
method: 'delete',
data: ids
})
}
export function getRoleList(params) {
return request({
url: '/api/role/list',
method: 'post',
data: JSON.stringify(params)
})
}
3.2 编写前端页面
- 通过角色名与创建起始与结束时间查询角色,并用卡片的形式进行显示。
- 通过点击“新增”按钮,跳出表单,输入角色信息后保存角色。
- 通过点击角色卡片上的“编辑”按钮,对原有角色信息进行更新。
- 通过点击角色卡片上的“删除”按钮,删除角色信息,删除前要有提示。
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<!-- 搜索 -->
<el-input
v-model="roleName"
size="small"
clearable
placeholder="输入角色名称搜索"
style="width: 200px"
class="filter-item"
@keyup.enter.native="doQuery"
/>
<el-date-picker
v-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-button
class="filter-item"
size="mini"
type="success"
icon="el-icon-search"
@click="doQuery"
>搜索</el-button>
<el-button
class="filter-item"
size="mini"
type="primary"
icon="el-icon-circle-plus-outline"
@click="doAdd"
>新增</el-button>
</div>
<!-- 表单渲染 -->
<el-dialog
append-to-body
:close-on-click-modal="false"
:before-close="doBeforeClose"
:visible.sync="showDialog"
width="520px"
>
<el-form
ref="form"
:inline="true"
:model="form"
:rules="rules"
size="small"
label-width="80px"
>
<el-form-item label="角色编码" prop="roleCode">
<el-input v-model="form.roleCode" style="width: 380px" />
</el-form-item>
<el-form-item label="角色名称" prop="roleName">
<el-input v-model="form.roleName" style="width: 380px" />
</el-form-item>
<el-form-item label="描述信息" prop="description">
<el-input
v-model="form.description"
style="width: 380px"
rows="5"
type="textarea"
/>
</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(form)"
>确认</el-button>
</div>
</el-dialog>
<el-row>
<el-col
v-for="item in roles"
:key="item.id"
:span="5"
style="margin-bottom: 10px"
:offset="1"
>
<el-card>
<div slot="header" class="clearfix">
<i class="el-icon-user" /><span style="margin-left: 5px">{{ item.roleName }}</span>
<div style="display: inline-block; float: right; cursor: pointer" @click="doEdit(item.id)">
<i class="el-icon-edit-outline" style="margin-left: 15px" />
</div>
</div>
<div>
<ul class="role-info">
<li>
<div class="role-left">描述信息:{{ item.description }}</div>
</li>
<li>
<div class="role-left">
创建时间:{{ parseTime(item.createTime) }}
</div>
</li>
</ul>
</div>
<div style="display: inline-block; float: right; cursor: pointer" @click="doDelete(item.id)">
<i class="el-icon-delete" style="margin-left: 15px" />
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { parseTime } from '@/utils/index'
import { getRoleList, getRole, saveRole, deleteRole } from '@/api/role'
export default {
name: 'Role',
data() {
return {
showDialog: false,
loading: false,
formLoading: true,
form: {},
roles: [],
roleName: '',
createTime: null,
rules: {
roleCode: [
{ required: true, message: '请输入角色编码', trigger: 'blur' }
],
roleName: [
{ required: true, message: '请输入角色名称', trigger: 'blur' }
]
}
}
},
created() {
},
methods: {
parseTime,
doQuery() {
var param = { roleName: this.roleName }
if (this.createTime != null) {
param.createTimeStart = Date.parse(this.createTime[0])
param.createTimeEnd = Date.parse(this.createTime[1])
}
getRoleList(param).then(res => {
if (res) {
this.roles = res
}
})
},
doAdd() {
this.showDialog = true
this.formLoading = false
this.form = {}
},
doEdit(id) {
this.showDialog = true
getRole(id).then(res => {
if (res) {
this.form = res
this.formLoading = false
}
})
},
doCancel() {
this.showDialog = false
this.formLoading = true
this.form = {}
},
doSubmit(role) {
this.$refs.form.validate(valid => {
if (valid) {
this.formLoading = true
saveRole(role).then(res => {
if (res) {
this.showDialog = false
this.$notify({
title: '保存成功',
type: 'success',
duration: 2500
})
this.doQuery()
}
}).catch(() => {
this.formLoading = false
})
}
})
},
doDelete(id) {
this.$confirm(`确认删除此条数据?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() =>
deleteRole([id]).then(res => {
if (res) {
this.$notify({
title: '删除成功',
type: 'success',
duration: 2500
})
this.doQuery()
}
})
).catch(() => {
})
},
doBeforeClose() {
this.showDialog = true
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss">
.role-span {
font-weight: bold;
color: #303133;
font-size: 15px;
}
.role-info {
margin-top: 0;
padding-top: 0;
padding-left: 0;
list-style: none;
li {
border-bottom: 1px solid #f0f3f4;
padding: 11px 0;
font-size: 12px;
}
.role-left {
color: rgb(148, 137, 137);
overflow: hidden;
white-space: nowrap;
text-align: left;
text-overflow: ellipsis;
}
}
</style>
<style rel="stylesheet/scss" lang="scss" scoped>
::v-deep .el-input-number .el-input__inner {
text-align: left;
}
::v-deep .vue-treeselect__multi-value {
margin-bottom: 0;
}
::v-deep .vue-treeselect__multi-value-item {
border: 0;
padding: 0;
}
</style>
四、效果演示
六、源码
|