前后端分离: vue3+SpringBoot+ElementPlus+Axios+MyBatisPuls
前后端分离: vue3+SpringBoot
- 项目介绍
- 搭建Vue前端工程
- axios请求响应拦截
- 跨域
- 搭建后端
- @TableId,@TableName
- 分页显示
- 配置Druid数据源
- 带条件的分页查询
- 后端校验
- lambda表达式说明
项目介绍
🌟项目页面
🌟技术栈:
1.前端技术栈: Vue3+Axios+ElementPlus
2.后端技术栈: SpringBoot+MyBatisPlus
3.数据库: MySQL
4.项目依赖管理: Maven
5.分页: MyBatisPlus的分页插件
6.切换数据源DruidDataSource
7.在LambdaQueryWrapper 引出知识点 lambda方法引用的 类名::实例方法
8.前端使用了axios关于request和respones的拦截器, 并且解决了跨域问题
gitee网址: https://gitee.com/zhao-zhiwei521/vue-springboot
搭建Vue前端工程
一,SSM整合-前后端分离(项目环境搭建)
二,SSM项目-前后端分离(搭建Vue前端工程)
vue create springboot_vue
axios请求响应拦截
//重要提示: 如果在启动前端项目时, 提示找不到axios, 把光标放在 import axios from "axios"的'axios', 会有一个修复提示, 导入axios, 导入即可正常使用. import axios from 'axios' const axios_ = axios.create({ timeout: 5000 }) //添加请求拦截器 axios_.interceptors.request.use(config => { //在请求之前请求头转为json数据 config.headers['Content-Type'] = 'application/json;charset=utf-8' return config }, error => { return Promise.reject(error) }) //添加响应拦截器 axios_.interceptors.response.use(response => { console.log('response======>', JSON.stringify(response)) let res = response.data; //如果返回的是文件 if (response.config.responseType === 'blob') { return res; } //如果是string类型, 就转为json if (typeof res === 'string') { res = res ? JSON.parse(res) : res; } return res; }, error => { return Promise.reject(error); }) export default axios_
跨域
module.exports = { devServer: { port: 10000, // 前端开发服务器运行端口(通过 http://localhost:10000 访问) proxy: { // 代理配置(用于解决开发环境跨域问题) '/api': { // 拦截所有以 /api 开头的请求 target: 'http://localhost:9090/', // 后端服务地址(对应您的 Spring Boot 应用) changeOrigin: true, // 修改请求头中的 Origin 为目标地址(模拟同源请求) pathRewrite: { '^/api': '' // 路径重写:移除请求路径中的 /api 前缀 } } } } }
搭建后端
SSM整合-前后端分离(实现增删改查)
@TableId,@TableName
//如果SysUser实体类名和数据库表名一致,或者经过驼峰换转后一致, 则不需要加@TableName注解 @Data //@TableName("sys_user") public class SysUser { //这里我们使用@TableId, 表主键标识 //当我们在private Integer id上标识了@TableId, 说明id对应的就是表的id字段, 而且是主键 @TableId(value = "id", type = IdType.AUTO) private Integer id; }
分页显示
思路:
1.后台使用mybatis-plus分页插件
2.前端使用vue分页组件
实现
1.src/main/java/com/zzw/springboot/config/MybatisPlusConfig.java
@Configuration public class MybatisPlusConfig { /** * 1.注入MybatisPlusInterceptor 对象/bean * 2.在MybatisPlusInterceptor bean 加入分页插件 PaginationInnerInterceptor */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); //这里的分页要指定数据库的类型,因为不同的数据库,分页的sql语句不一样 mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return mybatisPlusInterceptor; } }
2.SysUserController 分页查询
//前后端分离, 前端发出请求, 后端返回json数据 @Slf4j @RestController @RequestMapping("/sysUser") public class SysUserController { @Autowired private SysUserService sysUserService; /** * * @param pageNum 显示第几页, 默认为 1 * @param pageSize 每页有多少条 默认为10 * @return */ @GetMapping("listByPage") public Result listByPage(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum, @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) { //1.在javaweb中, 分页查询已经学过 Page page = sysUserService.page(new Page(pageNum, pageSize)); //2.返回数据, 查询分页查询的数据结构 return Result.success(page); } }
3.vue分页组件
配置Druid数据源
参考整合Druid到SpringBoot
带条件的分页查询
@GetMapping("listByCondition") public Result listByCondition(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, SysUser sysUser) { //1.先床啊进QueryWrapper, 可以将我们的检索条件封装进QueryWrapper QueryWrapper wrapper = new QueryWrapper(); // 根据用户名模糊查询 if (StringUtils.hasText(sysUser.getUsername()) ) { wrapper.like("username", sysUser.getUsername()); } Page page = sysUserService.page(new Page(pageNum, pageSize), wrapper); return Result.success(page); }
后端校验
/** * 验证表单 */ private Map validateForm(Errors errors) { Map errorMap = new HashMap(); List fieldErrors = errors.getFieldErrors(); for (FieldError fieldError : fieldErrors) { errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()); } return errorMap; } } @PostMapping("/save") public Result save(@RequestBody @Validated SysUser sysUser, Errors errors) { Map map = validateForm(errors); if (!map.isEmpty()) { return Result.error(map, "数据校验失败"); } boolean save = sysUserService.save(sysUser); if (save) { return Result.success("添加成功"); } return Result.error("添加失败"); }
lambda表达式说明
https://baijiahao.baidu.com/s?id=1652786021461159890&wfr=spider&for=pc
https://blog.csdn.net/hjl21/article/details/102702934
解读
//编写方法,使用lambdaQueryWrapper封装查询条件, 完成检索 @GetMapping("listByCondition2") public Result listByCondition2(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, SysUser sysUser) { //说明: 关于lambda表达式, 我们这里使用的是 类名::实例方法 //是lambda方法引用中不太好理解的 //解读 //1. SysUser::getUsername 通过lambda表达式 引用实例方法 getUsername //2. 这里就是把 SysUser::getUsername 赋给 SFunction 函数式接口 //3. 查看 SFunction 源代码 /** * @FunctionalInterface * public interface SFunction extends Function, Serializable { * } * 父接口 *@FunctionalInterface * public interface Function { * R apply(T t);//抽象方法, 表示根据类型T的参数, 获取类型R的结果 * * //这里有默认实现方法 * } */ //4.传入 SysUser::getUsername 后, 就相当于实现了 SFunction 的apply方法 //5.底层会根据 传入的 SysUser:getUsername 去得到该方法的对应的属性映射的表的字段, 更加灵活 // // //创建lambdaQueryWrapper, 封装查询条件 LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(); //判断 if (StringUtils.hasText(sysUser.getUsername())) { //lambdaQueryWrapper.like(SysUser::getUsername, sysUser.getUsername()); //换一个写法, 依然正确 SFunction sf = SysUser::getUsername;; lambdaQueryWrapper.like(sf, sysUser.getUsername()); } Page page = sysUserService.page(new Page(pageNum, pageSize), lambdaQueryWrapper); log.info("page={}", page); return Result.success(page); }
模拟实现src/main/java/com/zzw/springboot/lambda/Test.java
public class Test { public static void main(String[] args) { //传统的方法来实现ZzwFuntcion接口, 使用匿名内部类, 得到一个实现接口的对象 /** * class Test$1 implements ZzwFunction { * public Object apply (Aclass aclass) { * return "Aclass"; * } * } * Test$1 test$1 = new Test$1(); * test$1.apply(new Aclass()); */ //ZzwFunction zf = new ZzwFunction() { // @Override // public String apply(AClass aClass) { // return "AClass"; // } //}; //Object result = zf.apply(new AClass()); //System.out.println("result=" + result); ZzwFunction zf2 = AClass::getBrand; Object result2 = zf2.apply(new AClass()); System.out.println("result2=" + result2); //zf2.say(); } } //定义一个函数式接口: 有且只有一个抽象方法的接口 //可以使用@FunctionalInterface 来标识一个函数式接口 //ZzwFunction是一个函数式接口(这个是一个自定义泛型接口) @FunctionalInterface interface ZzwFunction { R apply(T t);//抽象方法: 表示根据类型T的参数, 获取类型R的结果 //函数式接口, 依然可以有多个默认是先方法 default public void say() { System.out.println("hello"); } } class AClass {//Bean private String name = "lambda AClass"; private String brand = "奔驰品牌"; public String getName() { return name; } public String getBrand() { return brand; } }