角色管理模块
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());
}
}
假如在这里即将抛出一个异常,这会被我的异常处理器捕获并直接响应给前端。