一、角色管理
1.1、测试 controller 层
在service-system
下面创建包:com.gansu.system.controller
,并创建类 SysRoleController
① 查询接口
package com.gansu.system.controller;
import com.gansu.model.system.SysRole;
import com.gansu.system.service.SysRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin/system/sysrole")
public class SysRoleController {
@Autowired
private SysRoleService sysRoleService;
@GetMapping("findAll") //localhost:8800/admin/system/sysrole/findAll
public List<SysRole> findAll(){
//调用service
List<SysRole> list = sysRoleService.list();
return list;
}
}
测试:http://localhost:8800/admin/system/sysrole/findAll
② 逻辑删除接口
//2.逻辑删除接口
@DeleteMapping("remove/{id}")
public boolean remove(@PathVariable Long id){
boolean isRemove = sysRoleService.removeById(id);
return isRemove;
}
测试:http://localhost:8800/admin/system/sysrole/remove/1
问题:
分析:浏览器目前只支持
get
提交,其它的暂且不支持,所以得采用第三方测试接口。
idea中也可以测试,这个我前面总结中还没提到过:
1.2、整合 Swagger2
1.2.1、Swagger 介绍
前后端分离开发模式中,api文档是最好的沟通方式。
- Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。
- 1、
及时性
(接口变更后,能够及时准确地通知相关前后端开发人员)- 2、
规范性
(并且保证接口的规范性,如接口的地址,请求方式,参数及响应格式和错误信息)- 3、
一致性
(接口信息一致,不会出现因开发人员拿到的文档版本不一致,而出现分歧)- 4、
可测性
(直接在接口文档上进行测试,以方便理解业务)
1.2.2、集成 knife4j
knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。
knife4j属于service模块公共资源,因此我们集成到service-uitl模块
1.2.2.1 添加依赖
操作模块:service-uitl
① 引入依赖
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
说明:
gansu-auth-parent
已加入版本管理
1.2.2.2 添加 knife4j 配置类
操作模块:service-uitl
创建包:com.gansu.system.config
创建类 :Knife4jConfig
并导入如下配置:
package com.gansu.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;
import java.util.List;
/**
* knife4j配置信息
*/
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfig {
@Bean
public Docket adminApiConfig(){
List<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());
//添加head参数end
Docket adminApi = new Docket(DocumentationType.SWAGGER_2)
.groupName("adminApi")
.apiInfo(adminApiInfo())
.select()
//只显示admin路径下的页面
.apis(RequestHandlerSelectors.basePackage("com.gansu"))
.paths(PathSelectors.regex("/admin/.*"))
.build()
.globalOperationParameters(pars);
return adminApi;
}
private ApiInfo adminApiInfo(){
return new ApiInfoBuilder()
.title("后台管理系统-API文档")
.description("本文档描述了后台管理系统微服务接口定义")
.version("1.0")
.contact(new Contact("gansu", "http://gansu.com", "gansu@qq.com"))
.build();
}
}
1.2.2.3 Controller 层添加注解
package com.gansu.system.controller;
import com.gansu.model.system.SysRole;
import com.gansu.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;
//2.逻辑删除接口
@ApiOperation(value = "逻辑删除")
@DeleteMapping("remove/{id}")
public boolean remove(@PathVariable Long id){
boolean isRemove = sysRoleService.removeById(id);
return isRemove;
}
//1.查询所有记录
@ApiOperation(value = "获取全部角色列表")
@GetMapping("findAll") //localhost:8800/admin/system/sysrole/findAll
public List<SysRole> findAll(){
//调用service
List<SysRole> list = sysRoleService.list();
return list;
}
}
1.2.2.4、测试
http://localhost:8800/doc.html
1.3、定义统一返回结果对象
- 项目中我们会将响应封装成json返回,一般我们会将所有接口的数据格式统一, 使前端(iOS Android, Web)对数据的操作更一致、轻松。
- 一般情况下,统一返回数据格式没有固定的格式,只要能描述清楚返回的数据状态以及要返回的具体数据就可以。但是一般会包含状态码、返回消息、数据这几部分内容
例如,我们的系统要求返回的基本数据格式如下:
列表:
{
"code": 200,
"message": "成功",
"data": [
{
"id": 2,
"roleName": "系统管理员"
}
],
"ok": true
}
分页:
{
"code": 200,
"message": "成功",
"data": {
"records": [
{
"id": 2,
"roleName": "系统管理员"
},
{
"id": 3,
"name": "普通管理员"
}
],
"total": 10,
"size": 3,
"current": 1,
"orders": [],
"hitCount": false,
"searchCount": true,
"pages": 2
},
"ok": true
}
没有返回数据:
{
"code": 200,
"message": "成功",
"data": null,
"ok": true
}
失败:
{
"code": 201,
"message": "失败",
"data": null,
"ok": false
}
1.3.1、定义统一返回结果对象
操作模块:
common-util
后续其他模块也会用到,故抽取到
common-util
模块
在模块 common-util
下面创建包 com.gansu.common.result
再分别创建工具类 ResultCodeEnum
与Result
并分导入下面代码:
ResultCodeEnum
统一返回结果状态信息类
下面的状态后续都会用到,所以直接引入了
package com.gansu.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;
}
}
Result
package com.gansu.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;
}
}
1.3.2、改造 controller 方法
可以手动引入 工具类common-util
包
遇到如下问题:idea右边maven模块是灰色的
解决:三、idea识别不出来项目中某些Maven模块,显示模块为“灰色”
package com.gansu.system.controller;
import com.gansu.common.result.Result;
import com.gansu.model.system.SysRole;
import com.gansu.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;
//2.逻辑删除接口
@ApiOperation(value = "逻辑删除")
@DeleteMapping("remove/{id}")
public Result remove(@PathVariable Long id){
boolean isRemove = sysRoleService.removeById(id);
if (isRemove) {
return Result.ok();
} else {
return Result.fail();
}
}
//1.查询所有记录
@ApiOperation(value = "获取全部角色列表")
@GetMapping("findAll") //localhost:8800/admin/system/sysrole/findAll
public Result<List<SysRole>> findAll(){
//调用service
List<SysRole> roleList = sysRoleService.list();
return Result.ok(roleList);
}
}
再次启动主启动类测试:
删除测试:
1.4、分页查询
1.4.1、配置分页插件
操作模块:
service-uitl
,service
公共资源
条件分页查询步骤:
- 第一步 配置分页插件,通过配置类实现
- 第二步 创建controller方法,:,创建service方法,创建mapper方法
- 第三步 创建mapper的xml配置文件,编写sql语句实现
说明:我们将
@MapperScan("com.gansu.system.mapper")
提取到该配置类上面,统一管理,启动类就不需要了。
官网复制分页配置类:
package com.gansu.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("com.gansu.system.mapper")
public class MybatisPlusConfig {
/**
* 添加分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 如果配置多个插件, 切记分页最后添加
// 如果有多数据源可以不配具体类型, 否则都建议配上具体的 DbType
return interceptor;
}
}
1.4.2、分页 controller
//3.条件分页查询 pageNum 当前页 limit 每页显示的条数 SysRoleQueryVo 封装条件的
@ApiOperation(value = "条件分页查询")
@GetMapping("{pageNum}/{limit}")
public Result findSysRoleByLimitPage(
@ApiParam(name = "pageNum", value = "当前页码", required = true)
@PathVariable Long pageNum,
@ApiParam(name = "limit", value = "每页记录数", required = true)
@PathVariable Long limit,
@ApiParam(name = "roleQueryVo", value = "查询对象", required = true)
SysRoleQueryVo roleQueryVo){
Page<SysRole> pageParam = new Page<>(pageNum,limit);
IPage<SysRole> pageModel = sysRoleService.selectByPageSysRole(pageParam,roleQueryVo);
return Result.ok(pageModel);
}
1.4.3、service
/*条件分页查询*/
IPage<SysRole> selectByPageSysRole(Page<SysRole> pageParam, SysRoleQueryVo roleQueryVo);
@Override /*条件分页查询*/
public IPage<SysRole> selectByPageSysRole(Page<SysRole> pageParam, SysRoleQueryVo roleQueryVo) {
IPage<SysRole> selectByPageSysRole = baseMapper.selectByPageSysRole(pageParam,roleQueryVo);
return selectByPageSysRole;
}
1.4.4、mapper
/*条件分页查询*/
IPage<SysRole> selectByPageSysRole(Page<SysRole> pageParam, @Param("vo") SysRoleQueryVo roleQueryVo);
1.4.5、xml
在
resources
目录下创建mapper/SysRoleMapper.xml
文件
- 说明:分页我们统一定义到
xml
文件中,更方便直观
<?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="com.gansu.system.mapper.SysRoleMapper">
<sql id="columns">
role_name,role_code,description,create_time,update_time,is_deleted
</sql>
<resultMap id="sysRoleMap" type="com.gansu.model.system.SysRole" autoMapping="true">
</resultMap>
<select id="selectByPageSysRole" resultMap="sysRoleMap">
SELECT <include refid="columns"></include> FROM sys_role
<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>
启动主程序进行测试:
1.5、其他 controller 方法
1.5.1 添加角色接口
//4.添加角色的接口
@ApiOperation(value = "添加角色")
@PostMapping("addSysRole")
// @RequestBody 不能使用get提交方式 传递json格式数据,把json格式数据封装到对象里面{...}
public Result addSysRole(@RequestBody SysRole sysRole){
boolean isSuccess = sysRoleService.save(sysRole);
if (isSuccess){
return Result.ok(sysRole);
}else {
return Result.fail(sysRole);
}
}
1.5.2 根据id查询,修改,批量删除角色接口
//7.批量删除
@ApiOperation(value = "批量删除")
@DeleteMapping("batchDeleteById")
public Result batchDeleteById(@RequestBody List<Long> ids){
sysRoleService.removeByIds(ids);
return Result.ok();
}
//6.根据id修改
@ApiOperation(value = "根据id修改")
@PutMapping("updateById")
public Result updateById(SysRole sysRole){
boolean isSuccess = sysRoleService.updateById(sysRole);
if (isSuccess){
return Result.ok(sysRole);
}else {
return Result.fail(sysRole);
}
}
//5.根据id查询
@ApiOperation(value = "根据id查询")
@GetMapping("findSysRoleById/{id}")
public Result findSysRoleById(@PathVariable long id){
sysRoleService.getById(id);
return Result.ok();
}
修改接口测试:
修改前:
修改后:
批量删除前后:
1.6、统一异常处理
1.6.1、制造异常
除以0
我们想让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要统一异常处理。
① 制造异常
1.6.2、全局异常处理
操作模块:service-util
② 全局异常处理:
package com.gansu.system.exception;
import com.gansu.common.result.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e){
e.printStackTrace();
return Result.fail().message("执行了全局异常");
}
}
测试:
1.6.3、特定异常处理
③ 特定异常处理:
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public Result error(ArithmeticException e){
System.out.println("特定异常执行了。。。。。。。。。");
e.printStackTrace();
return Result.fail().message("执行了特定异常");
}
启动主程序进行测试:
1.6.4、自定义异常类
① 创建类 GansuException
package com.gansu.system.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GansuException extends RuntimeException {
private Integer code; //异常状态码
private String msg; //抛出异常的信息
}
② 添加自定义异常类,异常处理方法
@ExceptionHandler(GansuException.class)
@ResponseBody
public Result error(GansuException e){
System.out.println("自定义异常执行了。。。。。。。。。");
e.printStackTrace();
return Result.fail().message(e.getMsg()).code(e.getCode());
}
③ 修改 controller,业务中需要位置抛出
//1.查询所有记录
@ApiOperation(value = "获取全部角色列表")
@GetMapping("findAll") //localhost:8800/admin/system/sysrole/findAll
public Result<List<SysRole>> findAll(){
try {
int i = 9/0;
}catch (Exception e){
e.printStackTrace();
throw new GansuException(200001,"执行了自定义异常");
}
//调用service
List<SysRole> roleList = sysRoleService.list();
return Result.ok(roleList);
}
④ 启动主启动类进行测试