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

x33g5p2x  于2021-12-30 转载在 Spring  
字(11.4k)|赞(0)|评价(0)|浏览(301)

系列文章目录
《SpringBoot整合SpringSecurity实现权限控制(一):实现原理》
《SpringBoot整合SpringSecurity实现权限控制(二):权限数据基本模型设计》
《SpringBoot整合SpringSecurity实现权限控制(三):前端动态装载路由与菜单》

一、前言

角色是基于业务管理需求而预先在系统中设定好的固定标签,每个角色需对应明确的系统权限,其所拥有的系统权限一般不会随意更改,并且角色也不会随着用户的被添加和被移除而进行改变,相较于用户管理而言更加稳定。

  • 本文将实现角色管理的增删改查

二、后端实现

2.1 创建角色实体类

/** * 角色表 * * @author zhuhuix * @date 2021-09-03 */
@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接口

/** * 角色DAO接口 * * @author zhuhuix * @date 2021-09-13 */
@Mapper
public interface SysRoleMapper extends BaseMapper<SysRole> {
}

2.3 实现角色增删改查服务

/** * 角色信息接口 * * @author zhuhuix * @date 2021-09-13 */
public interface SysRoleService {

    /** * 增加角色 * * @param role 待新增的角色 * @return 增加成功的角色 */
    SysRole create(SysRole role);

    /** * 删除角色 * * @param role 待删除的角色 * @return 已删除的角色 */
    SysRole delete(SysRole role);

    /** * 修改角色 * * @param role 待修改的角色 * @return 修改成功的角色 */
    SysRole update(SysRole role);

    /** * 根据角色代码查找角色 * * @param roleCode 角色代码 * @return 增加成功的角色 */
    SysRole findByRoleCode(String roleCode);

    /** * 根据角色名称查找角色 * * @param roleName 角色代码 * @return 增加成功的角色 */
    SysRole findByRoleName(String roleName);

    /** * 获取全部角色信息 * @return 角色列表 */
    List<SysRole> findAll();

	/** * 根据条件查询角色 * @param roleQueryDto 查询条件 * @return 角色列表 */
    List<SysRole> list( RoleQueryDto roleQueryDto);

}
/** * 角色服务实现类 * * @author zhuhuix * @date 2021-09-13 */
@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个后台接口

/** * 角色信息api * * @author zhuhuix * @date 2021-09-13 */
@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访问接口

  • src/api/role.js
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 编写前端页面

  • 我们需要编写一个完整的页面:
  1. 通过角色名与创建起始与结束时间查询角色,并用卡片的形式进行显示。
  2. 通过点击“新增”按钮,跳出表单,输入角色信息后保存角色。
  3. 通过点击角色卡片上的“编辑”按钮,对原有角色信息进行更新。
  4. 通过点击角色卡片上的“删除”按钮,删除角色信息,删除前要有提示。

<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>

四、效果演示

六、源码

相关文章