尚硅谷通用权限管理系统笔记 - 角色管理模块

535 阅读5分钟

角色管理模块

1、前后端分离开发

就是前端请求后端接口,后端响应json格式数据给前端,前端解析json格式数据并展示在网页。

json数据格式:

  • 对象格式

{"username": "陈慢慢", "password" : "huanyuan"}

  • 数组格式

[{"username": "陈慢慢", "password" : "huanyuan"}, {"username": "陈慢慢1", "password" : "huanyuan"}]

2、编写角色controller层数据接口

controller层controller类写法

@RestController
@RequestMapping("/admin/system/sysRole")
public class SysRoleController {
    @Autowired
    private SysRoleService sysRoleService;


}

@RestController 注解用于支持ResultFul Api的开发

@RequestMapping 注解用于标识请求的映射地址

1、编写查询所有角色接口和删除指定角色接口

@RestController
@RequestMapping("/admin/system/sysRole")
public class SysRoleController {
    @Autowired
    private SysRoleService sysRoleService;

    /**
     * 查询所有角色
     * */
    @GetMapping("findAll")
    public List<SysRole> findAllRole(){
        List<SysRole> list = sysRoleService.list(null);
        return list;
    }

    /**
     * 删除角色接口
     * */
    @DeleteMapping("remove/{id}")
    public boolean removeRole(@PathVariable("id") Long id){
        boolean isSuccess = sysRoleService.removeById(id);
        return isSuccess;
    }
}

2、测试controler层角色模块api接口

可以采取下列两种方式中的任意一种

  • 接口测试客户端(自测使用)工具:postman、apifox、idea中也有
  • 整合swagger接口文档(给前端输出的接口文档)

1、swagger2整合

教程中是用了swagger2的增强型文档,knife4j它的文档页面更加美观。

<dependency>
  <groupId>com.github.xiaoymin</groupId>
  <artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>

因为在父工程已经进行版本管理,所以不用写版本号了。

在service-util模块中引入knife4j的坐标,并且在模块中创建包cn.chenmanman.system.config。

在包内创建knife4j的配置类,代码如下:

package cn.chenmanman.system.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.ArrayList;

/**
* swagger2接口文档生成工具,整合配置
* */
@Configuration
    @EnableSwagger2WebMvc
    public class Knife4jConfig {

        @Bean
        public Docket adminApiConfig(){
            ArrayList<Parameter> pars = new ArrayList<>();
            ParameterBuilder tokenPar = new ParameterBuilder();
            tokenPar.name("token")
                .description("用户token")
                .defaultValue("")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false)
                .build();
            pars.add(tokenPar.build());

            Docket adminApi = new Docket(DocumentationType.SWAGGER_2)
                .groupName("adminApi")
                .apiInfo(adminApiInfo())
                .select()
                //只显示admin路径下的页面
                .apis(RequestHandlerSelectors.basePackage("cn.chenmanman"))
                .paths(PathSelectors.regex("/admin/.*"))
                .build()
                .globalOperationParameters(pars);
            return adminApi;
        }


        private ApiInfo adminApiInfo(){

            return new ApiInfoBuilder()
                .title("后台管理系统-API文档")
                .description("本文档描述了后台管理系统微服务接口定义")
                .version("1.0")
                .contact(new Contact("陈慢慢", "https://user.qzone.qq.com/1738352551/infocenter", "1738352551@qq.com"))
                .build();
        }

    }

2、统一响应结果

统一响应结果,这一般和前端人员共同协定结果格式,好处就是规范的数据格式能让前端人员对数据的操作更友好。

一般的格式

{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "id": 2,
      "roleName": "系统管理员"
    }
  ]
}

在common-util模块中创建包cn.chenmanman.common.result

并在包下创建一个类,名为Result

package cn.chenmanman.common.result;

import lombok.Data;

/**
 * 全局统一返回结果类
 *
 */
@Data
public class Result<T> {

    //返回码
    private Integer code;

    //返回消息
    private String message;

    //返回数据
    private T data;

    public Result(){}

    // 返回数据
    protected static <T> Result<T> build(T data) {
        Result<T> result = new Result<T>();
        if (data != null)
            result.setData(data);
        return result;
    }

    public static <T> Result<T> build(T body, Integer code, String message) {
        Result<T> result = build(body);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }

    public static<T> Result<T> ok(){
        return Result.ok(null);
    }

    /**
     * 操作成功
     * @param data  baseCategory1List
     * @param <T>
     * @return
     */
    public static<T> Result<T> ok(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.SUCCESS);
    }

    public static<T> Result<T> fail(){
        return Result.fail(null);
    }

    /**
     * 操作失败
     * @param data
     * @param <T>
     * @return
     */
    public static<T> Result<T> fail(T data){
        Result<T> result = build(data);
        return build(data, ResultCodeEnum.FAIL);
    }

    public Result<T> message(String msg){
        this.setMessage(msg);
        return this;
    }

    public Result<T> code(Integer code){
        this.setCode(code);
        return this;
    }
}

还有枚举类

package cn.chenmanman.common.result;

import lombok.Getter;

/**
 * 统一返回结果状态信息类
 *
 */
@Getter
public enum ResultCodeEnum {

    SUCCESS(200,"成功"),
    FAIL(201, "失败"),
    SERVICE_ERROR(2012, "服务异常"),
    DATA_ERROR(204, "数据异常"),
    ILLEGAL_REQUEST(205, "非法请求"),
    REPEAT_SUBMIT(206, "重复提交"),
    ARGUMENT_VALID_ERROR(210, "参数校验异常"),

    LOGIN_AUTH(208, "未登陆"),
    PERMISSION(209, "没有权限"),
    ACCOUNT_ERROR(214, "账号不正确"),
    PASSWORD_ERROR(215, "密码不正确"),
    LOGIN_MOBLE_ERROR( 216, "账号不正确"),
    ACCOUNT_STOP( 217, "账号已停用"),
    NODE_ERROR( 218, "该节点下有子节点,不可以删除")
    ;

    private Integer code;

    private String message;

    private ResultCodeEnum(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
}

3、修改controller层接口方法

package cn.chenmanman.system.controller;

import cn.chenmanman.common.result.Result;
import cn.chenmanman.model.system.SysRole;
import cn.chenmanman.system.service.SysRoleService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;


@Api(tags = "角色管理")
@RestController
@RequestMapping("/admin/system/sysRole")
public class SysRoleController {
    @Autowired
    private SysRoleService sysRoleService;

    /**
     * 查询所有角色
     * */
    @ApiOperation(value = "获取全部角色列表")
    @GetMapping("findAll")
    public Result findAllRole(){
        List<SysRole> list = sysRoleService.list(null);
        return Result.ok(list);
    }


    /**
     * 删除角色接口
     * */
    @ApiOperation(value = "删除指定角色")
    @DeleteMapping("remove/{id}")
    public Result removeRole(@PathVariable("id") Long id){
        boolean isSuccess = sysRoleService.removeById(id);
        if (!isSuccess){
            return Result.fail();
        }
        return Result.ok();
    }
}

4、使用文档测试接口

文档地址:

http://localhost:8080/doc.html

3、配置MybatisPlus分页插件

在service-util模块中创建MybatisPlus的配置类

package cn.chenmanman.system.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("cn.chenmanman.system.mapper")
public class MybatisPlusConfig {

    // 添加分页的拦截器
    @Bean
    public MybatisPlusInterceptor addPaginationInnerInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //向Mybatis过滤器链中添加分页拦截器
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

4、编写分页查询接口

package cn.chenmanman.system.controller;

import cn.chenmanman.common.result.Result;
import cn.chenmanman.model.system.SysRole;
import cn.chenmanman.model.vo.SysRoleQueryVo;
import cn.chenmanman.system.service.SysRoleService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;


@Api(tags = "角色管理")
@RestController
@RequestMapping("/admin/system/sysRole")
public class SysRoleController {
    @Autowired
    private SysRoleService sysRoleService;

    /**
     * 查询所有角色
     * */
    @ApiOperation(value = "获取全部角色列表")
    @GetMapping("findAll")
    public Result findAllRole(){
        List<SysRole> list = sysRoleService.list(null);
        return Result.ok(list);
    }


    /**
     * 删除角色接口
     * */
    @ApiOperation(value = "删除指定角色")
    @DeleteMapping("remove/{id}")
    public Result removeRole(@PathVariable("id") Long id){
        boolean isSuccess = sysRoleService.removeById(id);
        if (!isSuccess){
            return Result.fail();
        }
        return Result.ok();
    }

    @ApiOperation(value="条件分页查询")
    @GetMapping("{page}/{limit}")
    public Result selectPage(@PathVariable("page") Long page,
                             @PathVariable("limit") Long limit,
                             SysRoleQueryVo sysRoleQueryVo){
        Page<SysRole> pageParam = new Page<>(page, limit);
        IPage<SysRole> roleModel = sysRoleService.selectPage(pageParam, sysRoleQueryVo);
        return Result.ok(roleModel);
    }
}
package cn.chenmanman.system.service;

import cn.chenmanman.model.system.SysRole;
import cn.chenmanman.model.vo.SysRoleQueryVo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;

public interface SysRoleService extends IService<SysRole> {
    IPage<SysRole> selectPage(Page<SysRole> pageParam, SysRoleQueryVo sysRoleQueryVo);
}
package cn.chenmanman.system.service.impl;

import cn.chenmanman.model.system.SysRole;
import cn.chenmanman.model.vo.SysRoleQueryVo;
import cn.chenmanman.system.mapper.SysRoleMapper;
import cn.chenmanman.system.service.SysRoleService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;


@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
    @Override
    public IPage<SysRole> selectPage(Page<SysRole> rolePage, SysRoleQueryVo sysRoleQueryVo) {
        return baseMapper.selectPage(rolePage, sysRoleQueryVo);
    }
}
package cn.chenmanman.system.mapper;

import cn.chenmanman.model.system.SysRole;
import cn.chenmanman.model.vo.SysRoleQueryVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface SysRoleMapper extends BaseMapper<SysRole> {
    IPage<SysRole> selectPage(Page<SysRole> page, @Param("vo") SysRoleQueryVo sysRoleQueryVo);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="cn.chenmanman.system.mapper.SysRoleMapper">
  <resultMap id="RoleMap" type="cn.chenmanman.model.system.SysRole" autoMapping="true">

  </resultMap>

  <sql id="baseRoleSelectSql">
    select
    id, role_name, role_code, description, create_time, update_time, is_deleted
    from sys_role
  </sql>

  <select id="selectPage" resultMap="RoleMap">
    <include refid="baseRoleSelectSql"/>
    <where>
      <if test="vo.roleName!=null and vo.roleName !=''">
        and role_name like concat('%', #{vo.roleName} ,'%')
      </if>
      and is_deleted = 0
    </where>
    order by id desc
  </select>
</mapper>

下面进行接口的测试

5、编写添加、修改、批量删除、获取指定角色接口

package cn.chenmanman.system.controller;

import cn.chenmanman.common.result.Result;
import cn.chenmanman.model.system.SysRole;
import cn.chenmanman.model.vo.SysRoleQueryVo;
import cn.chenmanman.system.service.SysRoleService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;


@Api(tags = "角色管理")
    @RestController
    @RequestMapping("/admin/system/sysRole")
    public class SysRoleController {
        @Autowired
        private SysRoleService sysRoleService;

        /**
* 查询所有角色
* */
        @ApiOperation(value = "获取全部角色列表")
        @GetMapping("findAll")
        public Result findAllRole(){
            List<SysRole> list = sysRoleService.list(null);
            return Result.ok(list);
        }


        /**
* 删除角色接口
* */
        @ApiOperation(value = "删除指定角色")
        @DeleteMapping("remove/{id}")
        public Result removeRole(@PathVariable("id") Long id){
            boolean isSuccess = sysRoleService.removeById(id);
            if (!isSuccess){
                return Result.fail();
            }
            return Result.ok();
        }

        @ApiOperation(value="条件分页查询")
        @GetMapping("{page}/{limit}")
        public Result selectPage(@PathVariable("page") Long page,
                                 @PathVariable("limit") Long limit,
                                 SysRoleQueryVo sysRoleQueryVo){
            Page<SysRole> pageParam = new Page<>(page, limit);
            IPage<SysRole> roleModel = sysRoleService.selectPage(pageParam, sysRoleQueryVo);
            return Result.ok(roleModel);
        }

        @ApiOperation(value = "添加新角色")
        @PostMapping
        public Result saveRole(@RequestBody SysRole sysRole){
            return sysRoleService.save(sysRole) ? Result.ok() : Result.fail();
        }

        @ApiOperation(value = "获取指定角色")
        @GetMapping("{id}")
        public Result findById(@PathVariable("id") Long id) {
            return Result.ok(sysRoleService.getById(id));
        }

        @ApiOperation(value="更新角色")
        @PostMapping("update")
        public Result updateRole(@RequestBody SysRole sysRole){
            boolean b = sysRoleService.updateById(sysRole);
            return b ? Result.ok():Result.fail();
        }

        @ApiOperation( value = "批量删除角色" )
        @DeleteMapping("deleteBatch")
        public Result deleteBatch(@RequestBody List<Long> ids){
            boolean b = sysRoleService.removeByIds(ids);
            return b?Result.ok():Result.fail();
        }
    }

6、编写全局异常处理器

全局异常处理器可以帮助我们拦截到接口中发生的异常,并作处理。

异常处理器分为

  • 全局异常处理器
  • 特定异常处理器
  • 自定义异常处理器

代码如下:

@RestControllerAdvice 是@ControllerAdvice注解和@ResponseBody注解的组合,支持我们的restful风格接口。

package cn.chenmanman.system.exception;

import cn.chenmanman.common.result.Result;
import cn.chenmanman.system.exception.extend.BizException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GloableExceptionHandler {

    /**
     * 全局异常处理
     * */
    @ExceptionHandler(Exception.class)
    public Result error(Exception ex){
        return Result.fail().message("系统错误!");
    }

    @ExceptionHandler(BizException.class)
    public Result error1(BizException bizException){
        return Result.fail().message(bizException.getMsg()).code(bizException.getCode());
    }
}

假如在这里即将抛出一个异常,这会被我的异常处理器捕获并直接响应给前端。