今日话题
基于 Spring Boot 实现接口分页和接口返回格式~
作者:云层上的光
时间:2024年7月11日 15时13分14秒
主线任务
分页代码和接口返回参数依旧在 demo-todo-list 中实现~
一、实现分页
1、改造 controller 中 UserController 类文件,用于接收前端传参
代码如下:
package com.chuxin.demotodolist.controller;
import com.chuxin.demotodolist.entity.User;
import com.chuxin.demotodolist.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 查看
@GetMapping("/getList")
public List<User> getList(@RequestParam int page, @RequestParam int pageSize) {
return userService.getList(page, pageSize);
}
}
2、改造 service 软件包下的 UserService 接口文件
代码如下:
package com.chuxin.demotodolist.service;
import com.chuxin.demotodolist.entity.User;
import java.util.List;
public interface UserService {
// 查看
List<User> getList(int page, int pageSize);
}
3、改造 service/impl 软件包下的 UserServiceImpl 类文件
代码如下:
package com.chuxin.demotodolist.service.impl;
import com.chuxin.demotodolist.entity.User;
import com.chuxin.demotodolist.mapper.UserMapper;
import com.chuxin.demotodolist.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
// 查看
@Override
public List<User> getList(int page, int pageSize) {
return userMapper.getList(page, pageSize);
}
}
4、改造 mapper 软件包中的 UserMapper 接口文件
代码如下:
package com.chuxin.demotodolist.mapper;
import com.chuxin.demotodolist.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface UserMapper {
// 查
@Select("select * from sys_user limit #{page},#{pageSize}")
List<User> getList(int page , int pageSize);
}
5、重新项目
6、浏览器访问:http://localhost:8080/user/getList?page=1&pageSize=2
7、查询的是数据库中 第2条 和 第3条
8、为了方便测试分页,此时我重复调用了多次 新增接口
9、数据库新增到18条数据了
10、再次改造 service/impl 软件包下的 UserServiceImpl 类文件
数据库 limit 和 js 中的 slice 用法一样:
- 默认传入 page = 1 和 pageSize = 10 时,应该查询 0到10 的数据
- page=2 时应该是从第11条数据开始查询
11、浏览器访问:http://localhost:8080/user/getList?page=1&pageSize=10
12、再次访问:http://localhost:8080/user/getList?page=2&pageSize=10
二、实现接口返回
1、新建 common 软件包
2、common 软件包中新建 result 软件包
3、common/result 软件包下新建 Result 类文件
4、改造 Result 类文件
代码如下:
package com.chuxin.demotodolist.common.result;
import lombok.Data;
@Data
public class Result<T> {
// 定义要返回的格式
private int code;
private T data;
private String msg;
// 定义成功方法的无参构造方法
public static <T> Result<T> success() {
return success(null);
}
// 定义成功方法的有参构造方法 这里的data 就是有参构造
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(0);
result.setMsg("操作成功");
result.setData(data);
return result;
}
}
5、再次改造 service/impl 软件包下的 UserServiceImpl 类文件
代码如下:
package com.chuxin.demotodolist.service.impl;
import com.chuxin.demotodolist.common.result.Result;
import com.chuxin.demotodolist.entity.User;
import com.chuxin.demotodolist.mapper.UserMapper;
import com.chuxin.demotodolist.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
// 查看
@Override
public Result<List<User>> getList(int page, int pageSize) {
page = (page - 1) * pageSize;
// 接收从数据库查询出来的数组
List<User> list = userMapper.getList(page, pageSize);
// 调用 Result.success 进行包装返回
return Result.success(list);
}
}
6、改造 service 软件包下的 UserService 接口文件
代码如下:
package com.chuxin.demotodolist.service;
import com.chuxin.demotodolist.common.result.Result;
import com.chuxin.demotodolist.entity.User;
import java.util.List;
public interface UserService {
// 查看
Result<List<User>> getList(int page, int pageSize);
}
7、改造 controller 中 UserController 类文件,修改新的返回格式
代码如下:
package com.chuxin.demotodolist.controller;
import com.chuxin.demotodolist.common.result.Result;
import com.chuxin.demotodolist.entity.User;
import com.chuxin.demotodolist.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 查看
@GetMapping("/getList")
public Result<List<User>> getList(@RequestParam int page, @RequestParam int pageSize) {
return userService.getList(page, pageSize);
}
}
8、此时,service/impl 软件包下的 UserServiceImpl 类文件 中 getList 就不报错了
9、重启项目
10、浏览器访问:http://localhost:8080/user/getList?page=1&pageSize=5
支线任务
一、分页查询
1、page - 1 的操作可以放到 mapper 里面么?会报错么?
2、注释 service 中 page - 1 相关逻辑
2、改造 mapper 软件包中的 UserMapper 接口文件
3、重启项目
4、结果发现,项目直接启动失败,报错了
5、回退代码
二、Result 类详解
1、Result 中出现了很多次 T ,慢慢开始接触 Java 的泛型了
2、在前端的 typescript 中有相同用法,泛型主要代表暂时不确定的类型可以先用一个类型描述占位,等真实使用时会传递类型进来,这个时候再用这个类型进行校验:
代码如下:
// 定义一个函数
function add<T>(data: T) {
console.log(data)
}
// 用户数据
const user = {
id: 1,
name: "chuxin",
password: "123456"
}
// 定义一个接口,用来演示泛型
interface IUser {
id: number,
name: string,
password: string
}
// 最终使用
console.log(add<IUser>(user))
3、尝试修改 user 中的 id 为 字符串类型,看 泛型 会报错么?
4、如果是这样的话,去掉 console.log(add(user)) 中的 IUser 那么泛型应该就和 any 效果一致
5、所以在 Java 中此处的含义显而易见
6、为什么 Result 可以直接 使用 而不需要 new 呢?
7、public static Result success() { 这里两个 T 分别代表什么意思呢?
8、setCode 和 setMsg 等方法都是拿来的?
java不像前端是直接对变量赋值,它们使用方法进行赋值,比如前端定义了一个变量 var b = 1;
那么我们通常是 b = 2 但是java的话 就会要求我们实现 getB 和 setB 然后用他们来操作 b
9、为什么定义两个 success 呢?
首先这个和业务调用时 可能有部分业务是成功的 但是data 是 null 所以给两个方法
10、用前端来理解的话就是,函数重载(这里不讨论泛型)
函数重载 主要还是用来解决 传参的描述 这样的话支持多种
代码如下:
// 定义一个 getInfo 函数,使用函数重载来支持不同的参数类型
// 重载签名:返回一个具有 name 和 age 属性的对象
function getInfo(name: string, age: number): { name: string, age: number };
// 重载签名:返回一个包含 name 的对象
function getInfo(name: string): { name: string };
// 实现函数,根据传入参数的不同进行处理
function getInfo(name: string, age?: number) {
if (age !== undefined) {
return { name, age }; // 如果提供了 age 参数,则返回包含 name 和 age 的对象
} else {
return { name }; // 如果只提供了 name 参数,则返回只包含 name 的对象
}
}
// 使用示例
const personInfo1 = getInfo('Alice', 30);
console.log(personInfo1); // 输出 { name: 'Alice', age: 30 }
const personInfo2 = getInfo('Bob');
console.log(personInfo2); // 输出 { name: 'Bob' }
对上面函数解释一下:
- 函数重载声明:
- 我们在函数 getInfo 的定义之前,提供了两个重载签名:
- function getInfo(name: string, age: number): { name: string, age: number };
- function getInfo(name: string): { name: string };
- 第一个重载签名指定了当同时传入 name 和 age 参数时,返回一个对象,该对象具有 name 和 age 属性。
- 第二个重载签名指定了当只传入 name 参数时,返回一个对象,该对象只具有 name 属性。
- 我们在函数 getInfo 的定义之前,提供了两个重载签名:
- 函数实现:
- 函数实现部分 function getInfo(name: string, age?: number),通过检查 age 参数是否定义来决定返回的对象类型。
- 如果 age 参数被提供,则返回包含 name 和 age 的对象。
- 如果 age 参数未提供,则返回只包含 name 的对象。
- 函数实现部分 function getInfo(name: string, age?: number),通过检查 age 参数是否定义来决定返回的对象类型。
- 使用示例:
- 我们展示了两种调用方式:
- getInfo(‘Alice’, 30),这里传入了 name 和 age 参数,所以 TypeScript 会调用第一个重载,返回一个对象 { name: ‘Alice’, age: 30 }。
- getInfo(‘Bob’),这里只传入了 name 参数,所以 TypeScript 会调用第二个重载,返回一个对象 { name: ‘Bob’ }。
- 我们展示了两种调用方式:
好处:
- 类型安全和可读性:通过函数重载,我们可以在类型系统内部处理不同的参数组合,使得代码更加类型安全和可读性更强。
- 简化调用:使用者可以根据需要选择传入的参数类型,而无需在调用时手动判断参数类型或者返回值类型。
- 清晰的接口:通过重载声明,我们明确了函数的不同用法,使得函数接口更加清晰和易于理解。
函数重载的优势在于可以通过类型系统提供更好的支持,使得函数在不同的调用场景下能够提供合适的响应。
代码仓库
spring-boot-demo/demo-todo-list at master · chuxin-cs/spring-boot-demo