数据返回
一般项目中为了便于交互,都会将相应结果封装为json字符串进行返回,同时还需要统一返回数据格式,一般都有以下几种基础的数据返回场景
列表:
{
"success": true,
"code": 20000,
"message": "成功",
"data": {
"items": [
{
"id": "1",
"name": "刘德华",
"intro": "毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余"
}
]
}
}
分页
{
"success": true,
"code": 20000,
"message": "成功",
"data": {
"total": 17,
"rows": [
{
"id": "1",
"name": "刘德华",
"intro": "毕业于师范大学数学系,热爱教育事业,执教数学思维6年有余"
}
]
}
}
没有数据返回时也需要有响应体:
{
"success": true,
"code": 20000,
"message": "成功",
"data": {}
}
失败:
{
"success": false,
"code": 20001,
"message": "失败",
"data": {}
}
因此,我们定义统一结果
{
"success": 布尔, //响应是否成功
"code": 数字, //响应码
"message": 字符串, //返回消息
"data": HashMap //返回数据,放在键值对中
}
统一结果返回实现
一般统一结果返回都会在项目中创建一个公共模块来进行实现,然后其他模块使用的时候直接引入公共模块依赖即可.
首先在公共模块创建一个基础接口,用于声明响应状态码:
public interface ResultCode {
Integer SUCCESS = 20000; //成功
Integer ERROR = 20001; //失败
}
然后创建一个工具类
@Data
@Accessors(chain = true) //链式编程注解
public class Result {
@ApiModelProperty(value = "是否成功") //swagger注解
private Boolean success;
@ApiModelProperty(value = "返回状态码")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回数据")
private Map<String,Object> data = new HashMap<String,Object>();
//构造方法私有化,使其他类不能new 只能使用类中固定的方法
private Result(){}
//成功静态方法
@NotNull
public static Result succeed(){
Result resultReturn = new Result();
resultReturn
.setSuccess(true)
.setCode(ResultCode.SUCCESS) //直接引用状态码接口
.setMessage("执行成功");
return resultReturn;
}
//失败静态方法
@NotNull
public static Result error(){
Result resultReturn = new Result();
resultReturn.setSuccess(false);
resultReturn.setCode(ResultCode.ERROR); //直接引用状态码接口
resultReturn.setMessage("执行失败");
return resultReturn;
}
public Result success(Boolean success){
this.setSuccess(success);
return this;
}
public Result message(String message){
this.setMessage(message);
return this;
}
public Result code(Integer code){
this.setCode(code);
return this;
}
public Result Data(String key, Object value){
this.data.put(key,value);
return this;
}
public Result Data(Map<String,Object> map){
this.setData(map);
return this;
}
}
在这个工具类中已经定义好了几个相应的基础数据类型,这个时候可以直接将控制层的返回类型全部定义为Result,方便进行统一的管理和其他附加操作:
//查询所有教师
@ApiOperation("查询所有讲师")
@GetMapping("findAll")
private Result findAll(){
List<EduTeacher> list = eduTeacherService.list(null);
return Result.succeed().Data("items",list).setCode(2001) ;
}
//实现教师的逻辑删除 id通过路径来进行传递,并且通过@PathVariable 来直接获取路径中传递过来的值
@ApiOperation("逻辑删除讲师")
@DeleteMapping("{id}")
private Result delete(
@ApiParam(name = "id",value = "讲师id",required = true)
@PathVariable String id){
if (eduTeacherService.getById(id) == null) {
return Result.error().setMessage("ID不存在,请重新确认");
}else {
Boolean b = eduTeacherService.removeById(id);
return b? Result.succeed():Result.error();
}
}
分页查询
springboot整合3.5.1版本mybatisPlus需要用最新的分页拦截器插件:
// 最新mybatisplus分页需要实现分页拦截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
分页查询使用到了Page类,控制层具体的实现方法如下:
//分页查询讲师方法
@ApiOperation("讲师分页")
@GetMapping("pageTeacher/{current}/{limit}")
public Result pageListTeacher(@PathVariable long current,
@PathVariable long limit){
//创建page对象 1代表当前页,3代表页面记录数量 通过路径来传递值
Page<EduTeacher> page = new Page<>(current, limit);
//调用方法,把所有数据封装到pageTeacher中
eduTeacherService.page(page,null);
long total = page.getTotal();//获取总记录数
List<EduTeacher> records = page.getRecords();//获取分页后的list集合
long pages = page.getPages(); //总页数
long current1 = page.getCurrent(); //当前是第几个分页
long size = page.getSize(); //分页中最大行数
boolean hasNext = page.hasNext(); //是否有下一页
boolean hasPrevious = page.hasPrevious(); //是否还有上一页
//HashMap<String, Object> map = new HashMap<>();
//map.put("total", total);
//map.put("rows", records);
return Result
.succeed()
.data("当前分页数据集合",records)
.data("总记录数",total)
.data("总页数",pages)
.data("当前页码",current1)
.data("分页最大行数",size)
.setMessage("分页查询成功");
}
TMD卡了我一晚上,焯! 我想到了版本的问题,但是我就是不想降低版本迁就,我就是想用这个高版本来实现功能
条件分页查询
多了一个wrapper条件构造器,在正常情况下为了方便与前端交互,会专门在实体包中在创建一个vo实体类:
@Data
public class TeacherQuery {
//串行版本UID 不知道是什么玩意 老师用了,我注释掉后也能用
//private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "教师名称,模糊查询")
private String name;
@ApiModelProperty(value = "头衔 1代表高级讲师 2代表首席讲师")
private Integer level;
//这里swagger的example(示例),代表如果没有特别输入,就按照这个来当做默认值
@ApiModelProperty(value = "查询开始时间", example = "2019-01-01 10:10:10")
private String begin;//注意,这里使用的是String类型,前端传过来的数据无需进行类型转换
@ApiModelProperty(value = "查询结束时间", example = "2019-12-01 10:10:10")
private String end;
}
这个vo实体类是专门接收用来条件查询的关键字段的,比如这里可以通过使用姓名和头衔之类来进行查询,没有标明的关键字段,比如讲师的介绍之类的,就无法通过这个查询.
然后就直接在控制层来写方法:
//条件查询带分页的方法
@GetMapping("pageTeacherCondition/{current}/{limit}")
public Result pageTeacherCondition(
@PathVariable long current,
@PathVariable long limit,
TeacherQuery teacherQuery){
//创建page对象
Page<EduTeacher> page = new Page<>(current, limit);
//再新建一个条件构造器
QueryWrapper<EduTeacher> wrapper = new QueryWrapper<>();
String name = teacherQuery.getName();
Integer level = teacherQuery.getLevel();
String begin = teacherQuery.getBegin();
String end = teacherQuery.getEnd();
//非空判断.注意是springframework的依赖,同名的太多了
if (!StringUtils.isEmpty(name)){
wrapper.like("name",name);
}
if (!StringUtils.isEmpty(level)){
wrapper.eq("level",level); //eq代表等于
}
if (!StringUtils.isEmpty(begin)){ //wrapper构造器中ge代表大于等于
wrapper.ge("gmt_create",begin);
}
if (!StringUtils.isEmpty(end)){ //gt代表小于等于
wrapper.gt("gmt_modified",end);
}
//将写好的wrapper构造器注入进去
eduTeacherService.page(page,wrapper);
long total = page.getTotal();//获取总记录数
List<EduTeacher> records = page.getRecords();//获取分页后的list集合
long pages = page.getPages(); //总页数
long current1 = page.getCurrent(); //当前是第几个分页
long size = page.getSize(); //分页中最大行数
boolean hasNext = page.hasNext(); //是否有下一页
boolean hasPrevious = page.hasPrevious(); //是否还有上一页
Map<String, Object> map = new HashMap<>();
map.put("总记录数", total);
map.put("当前分页数据集合",records);
map.put("总页数",pages);
map.put("当前页码",current1);
map.put("分页最大行数",size);
map.put("是否含有上一页",hasPrevious);
map.put("是否含有下一页",hasNext);
return Result
.succeed()
.data(map)
.setMessage("分页查询成功");
}
swagger页面是这样的:
控制层的请求头还可以改成:
@PostMapping("pageTeacherCondition/{current}/{limit}")
public Result pageTeacherCondition(
@PathVariable long current,
@PathVariable long limit,
@RequestBody(required = false) TeacherQuery teacherQuery){
这样在swagger页面中需要进入整体的编辑栏进行编辑wrapper条件,不能像最上面一样直接在分好的编辑栏中编辑