前后端分离: vue3+SpringBoot+ElementPlus+Axios+MyBatisPuls

前后端分离: vue3+SpringBoot

项目介绍

🌟项目页面


🌟技术栈:

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请求响应拦截

js 复制代码
//重要提示: 如果在启动前端项目时, 提示找不到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_

跨域

java 复制代码
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

java 复制代码
//如果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

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 分页查询

java 复制代码
//前后端分离, 前端发出请求, 后端返回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<SysUser> page = sysUserService.page(new Page<>(pageNum, pageSize));
        //2.返回数据, 查询分页查询的数据结构
        return Result.success(page);
    }
}

3.vue分页组件

html 复制代码
<el-pagination
    v-model:current-page="searchForm.currentPage"
    v-model:page-size="searchForm.pageSize"
    :total="total"
    :page-sizes="[10, 20, 50, 100]"
    layout="total, sizes, prev, pager, next, jumper"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
/>

配置Druid数据源

参考整合Druid到SpringBoot

带条件的分页查询

java 复制代码
@GetMapping("listByCondition")
public Result listByCondition(@RequestParam(defaultValue = "1") Integer pageNum,
                              @RequestParam(defaultValue = "10") Integer pageSize,
                              SysUser sysUser) {

    //1.先床啊进QueryWrapper, 可以将我们的检索条件封装进QueryWrapper
    QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
    // 根据用户名模糊查询
    if (StringUtils.hasText(sysUser.getUsername()) ) {
        wrapper.like("username", sysUser.getUsername());
    }

    Page<SysUser> page = sysUserService.page(new Page<>(pageNum, pageSize), wrapper);
    return Result.success(page);
}

后端校验

java 复制代码
/**
 * 验证表单
 */
private Map<String, Object> validateForm(Errors errors) {
    Map<String, Object> errorMap = new HashMap<>();
    List<FieldError> 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<String, Object> 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

解读

java 复制代码
//编写方法,使用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<T,R> 函数式接口
    //3. 查看 SFunction<T,R> 源代码
    /**
     * @FunctionalInterface
     * public interface SFunction<T, R> extends Function<T, R>, Serializable {
     * }
     * 父接口
     *@FunctionalInterface
     * public interface Function<T, R> {
     *      R apply(T t);//抽象方法, 表示根据类型T的参数, 获取类型R的结果
     *
     *      //这里有默认实现方法
     * }
     */
    //4.传入 SysUser::getUsername 后, 就相当于实现了 SFunction<T,R> 的apply方法
    //5.底层会根据 传入的 SysUser:getUsername 去得到该方法的对应的属性映射的表的字段, 更加灵活
    //<resultMap id="BaseResultMap" type="com.zzw.springboot.bean.SysMenu">
    //        <id column="id" jdbcType="INTEGER" property="id"/>

    //创建lambdaQueryWrapper, 封装查询条件
    LambdaQueryWrapper<SysUser> lambdaQueryWrapper = Wrappers.<SysUser>lambdaQuery();

    //判断
    if (StringUtils.hasText(sysUser.getUsername())) {
        //lambdaQueryWrapper.like(SysUser::getUsername, sysUser.getUsername());
        //换一个写法, 依然正确
        SFunction<SysUser, Object> sf = SysUser::getUsername;;
        lambdaQueryWrapper.like(sf, sysUser.getUsername());
    }

    Page<SysUser> page = sysUserService.page(new Page<SysUser>(pageNum, pageSize), lambdaQueryWrapper);
    log.info("page={}", page);
    return Result.success(page);
}

模拟实现src/main/java/com/zzw/springboot/lambda/Test.java

java 复制代码
public class Test {
    public static void main(String[] args) {
        //传统的方法来实现ZzwFuntcion接口, 使用匿名内部类, 得到一个实现接口的对象
        /**
         * class Test$1 implements ZzwFunction<AClass, Object> {
         *     public Object apply (Aclass aclass) {
         *          return "Aclass";
         *     }
         * }
         * Test$1 test$1 = new Test$1();
         * test$1.apply(new Aclass());
         */
        //ZzwFunction<AClass, String> zf = new ZzwFunction<AClass, String>() {
        //    @Override
        //    public String apply(AClass aClass) {
        //        return "AClass";
        //    }
        //};
        //Object result = zf.apply(new AClass());
        //System.out.println("result=" + result);
        ZzwFunction<AClass, String> zf2 = AClass::getBrand;
        Object result2 = zf2.apply(new AClass());
        System.out.println("result2=" + result2);
        //zf2.say();
    }
}

//定义一个函数式接口: 有且只有一个抽象方法的接口
//可以使用@FunctionalInterface 来标识一个函数式接口
//ZzwFunction是一个函数式接口(这个是一个自定义泛型接口)
@FunctionalInterface
interface ZzwFunction<T,R> {
    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;
    }
}
相关推荐
0x7CF3 小时前
SetThrowSegvLongjmpSEHFilter错误和myFuncInitialize 崩溃
java·linux·算法
diving deep7 小时前
springboot集成日志配置文件
java·spring boot·后端·logback
蟹至之8 小时前
【Java】异常的初步认识
java·开发语言·类和对象·异常
广西千灵通网络科技有限公司8 小时前
基于Java的话剧购票小程序【附源码】
java·小程序·apache
苏小瀚8 小时前
[Java] idea的调试介绍
java·intellij-idea
源码云商8 小时前
基于 SpringBoot + Vue 的海滨体育馆管理系统设计与实现
vue.js·spring boot·后端
JWenzz18 小时前
Redis删除策略
java·数据库·redis·缓存
幻听嵩的留香8 小时前
javaEE课程项目-壁纸管理系统
java·java-ee
liubo666_8 小时前
SpringMVC(结合源码浅析工作流程)
java·spring·springmvc
speop9 小时前
TASK05【Datawhale 组队学习】系统评估与优化
android·java·学习