SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接

系列文章:
SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计
SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接
SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接
SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现
SpringBoot + Vue前后端分离项目实战 || 五:用户管理功能后续

文章目录

    • 前后端对接
      • 前端接口修改对接后端
      • 后端总体配置
      • 后端编写登录登出业务代码
    • 测试
    • 后端所有代码

前后端对接

前端接口修改对接后端

src\api\user.js中修改请求地址,与后端保持一致
在这里插入图片描述

记录下前端的src\utils\request.js中的X-Token字段
在这里插入图片描述

改变开发环境中的请求地址,更改为后端地址http://localhost:9999
在这里插入图片描述

将前端的模拟数据服务注释关闭
在这里插入图片描述

后端总体配置

后端新建一个config包,包中新建两个类
在这里插入图片描述

  • MyCorsConfig用于配置异步访问,对接前端的访问链接"http://localhost:8888",此配置可用Nginx代替
  • MyRedisConfig用于配置Redis序列化服务

MyCorsConfig中配置的代码如下:

package com.ums.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;@Configuration
public class MyCorsConfig {@Beanpublic CorsFilter corsFilter() {CorsConfiguration configuration = new CorsConfiguration();// 允许什么网址来异步访问configuration.addAllowedOrigin("http://localhost:8888");// 获取cookieconfiguration.setAllowCredentials(true);// 允许什么方法? POST、GET,此处为* 意味全部允许configuration.addAllowedMethod("*");// 允许所有的请求头configuration.addAllowedHeader("*");// 设置资源过滤器,过滤什么资源UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();urlBasedCorsConfigurationSource.registerCorsConfiguration("/**",configuration);return new CorsFilter(urlBasedCorsConfigurationSource);}
}

MyRedisConfig中用于配置的代码如下:

package com.ums.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.TimeZone;@Configuration
public class MyRedisConfig {@Resourceprivate RedisConnectionFactory factory;@Beanpublic RedisTemplate redisTemplate(){RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(factory);// 设置键值序列化redisTemplate.setKeySerializer(new StringRedisSerializer());Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);redisTemplate.setValueSerializer(serializer);// 序列化,死代码ObjectMapper om = new ObjectMapper();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));om.setTimeZone(TimeZone.getDefault());om.configure(MapperFeature.USE_ANNOTATIONS, false);om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);om.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);om.setSerializationInclusion(JsonInclude.Include.NON_NULL);serializer.setObjectMapper(om);return redisTemplate;}
}

后端编写登录登出业务代码

前端VUE项目的登录接口请求方法为POST,之前介绍过
在这里插入图片描述

UserController中新增代码,用于登录控制
在这里插入图片描述

@PostMapping("/login")
public Result<Map<String,Object>> login(@RequestBody User user){// 因为 user传过来为json字符串,所以用@RequestBody 进行实体转换// 业务代码在userService里完成Map<String,Object> data = userService.login(user);if(data != null){return Result.success(data,"登录成功");}return Result.fail(2002,"用户名或密码错误");
}

如下图所示userService.login()方法会爆红,因为该方法没有被定义或实现,此时鼠标点击并按Alt+Enter
在这里插入图片描述

选择第一项:
在这里插入图片描述

IDEA会自动生成接口代码
在这里插入图片描述

此时,接口上方有个提示1 related problem,鼠标左击,会跳转至接口的实现代码处UserServiceImpl
在这里插入图片描述

在这里插入图片描述

在整个类的定义之处,同样Alt + Enter,选择第一个,弹出的对话框再选第一个,会生成代码
在这里插入图片描述
在这里插入图片描述

生成的代码
在这里插入图片描述

在该函数中写上下述代码

@Override
public Map<String, Object> login(User user) {// 查询数据库LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getUsername, user.getUsername());wrapper.eq(User::getPassword, user.getPassword());User loginUser = this.baseMapper.selectOne(wrapper);// 结果不为空,生成token,将用户信息存入redisif (loginUser != null) {// 用UUID,终极方案是jwtString key = "user:" + UUID.randomUUID();// 存入redisloginUser.setPassword(null);    // 设置密码为空,密码没必要放入redisTemplate.opsForValue().set(key, loginUser,30, TimeUnit.MINUTES);   // timeout为登录时间// 返回数据Map<String, Object> data = new HashMap<>();data.put("token",key);return data;}// 结果不为空,生成token,前后端分离,前端无法使用session,可以使用token// 并将用户信息存入redisreturn null;
}

返回UserController,此时代码正常
在这里插入图片描述

按照上述方法如法炮制
UserController中写获取token的代码和logout代码
在这里插入图片描述

其中,这两个接口均未实现
在这里插入图片描述

代码如下

@GetMapping("/info")
public Result<Map<String,Object>> getUserInfo(@RequestParam("token") String token){// @RequestParam("token") 是从url中获取值// 根据token获取用户信息,信息存进了redis中Map<String,Object> data = userService.getUserInfo(token);if(data != null){return Result.success(data);}return Result.fail(2003,"登录信息无效,请重新登录");
}@PostMapping("/logout")
public Result<?> logout(@RequestHeader("X-Token") String token){userService.logout(token);return Result.success();

接着就是Alt + Enter修复bug

UserServiceImpl中先定义一个redisTemplate
在这里插入图片描述

然后在UserServiceImpl中写上下述代码

@Override
public Map<String, Object> getUserInfo(String token) {// 之前已将对象进行序列化处理存入redis,现在从redis中取出需要反序列化处理Object obj = redisTemplate.opsForValue().get(token);    // 此对象是map类型,稍后需要序列化为Json字符串if (obj!= null) {User loginUser = JSON.parseObject(JSON.toJSONString(obj), User.class);Map<String,Object> data = new HashMap<>();data.put("name",loginUser.getUsername());data.put("avatar",loginUser.getAvatar());// 先在xml里写SQL语句id=getRoleNameByUserId,然后去UserMapper里实现接口List<String> roleList = this.baseMapper.getRoleNameByUserId(loginUser.getId());data.put("roles",roleList);return data;}return null;
}@Override
public void logout(String token) {redisTemplate.delete(token);    // 从redis中删除token
}

注意红圈中的代码,是联表查询,这是自定义的SQL查询,接下来定义它
在这里插入图片描述

找到UserMapper然后写上代码:

public List<String> getRoleNameByUserId(Integer userId);

在这里插入图片描述

然后去resources\mapper\sys\UserMapper.xml中写SQL语句
在这里插入图片描述

<?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.ums.sys.mapper.UserMapper"><select id="getRoleNameByUserId" parameterType="Integer" resultType="String">SELECTb.role_nameFROMx_user_role a,x_role bWHEREa.role_id=b.role_idANDa.user_id = #{userId}</select>
</mapper>

测试

由于配置了redis,所以在启动SpringBoot之前先启动Redis

先找到redis的安装目录
在这里插入图片描述

打开cmd定位到该目录
运行命令redis-server.exe redis.windows.conf,回车,出现下述界面,然后此窗口最小化,千万别关闭
在这里插入图片描述

接着启动SprinfBoot后端
在这里插入图片描述

然后启动Vue前端
在这里插入图片描述

点击登录后,可以看到http://localhost:9999/user/login接口地址的变化
在这里插入图片描述

后端生成的token也注册在redis
在这里插入图片描述
在这里插入图片描述

点击退出登录,redis中的token也被注销了
在这里插入图片描述
在这里插入图片描述

后端所有代码

防止笔记失误,附上所有代码

  1. UserController中的代码
    package com.ums.sys.controller;import com.ums.common.vo.Result;
    import com.ums.sys.entity.User;
    import com.ums.sys.service.IUserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.stereotype.Controller;import java.util.List;
    import java.util.Map;/*** <p>*  前端控制器* </p>** @author anthony* @since 2023-06-16*/
    @RestController
    @RequestMapping("/user")
    // @CrossOrigin  //处理跨域,因为前端和后端的IP一致但端口不一致,所以浏览器认为跨域,不给访问,可用Ngx来解决
    public class UserController {@Autowiredprivate IUserService userService;@GetMapping("/all")public Result<List<User>> getAllUser() {List<User> list = userService.list();return Result.success(list,"查询成功");}@PostMapping("/login")public Result<Map<String,Object>> login(@RequestBody User user){// 因为 user传过来为json字符串,所以用@RequestBody 进行实体转换// 业务代码在userService里完成Map<String,Object> data = userService.login(user);if(data != null){return Result.success(data,"登录成功");}return Result.fail(2002,"用户名或密码错误");}@GetMapping("/info")public Result<Map<String,Object>> getUserInfo(@RequestParam("token") String token){// @RequestParam("token") 是从url中获取值// 根据token获取用户信息,信息存进了redis中Map<String,Object> data = userService.getUserInfo(token);if(data != null){return Result.success(data);}return Result.fail(2003,"登录信息无效,请重新登录");}@PostMapping("/logout")public Result<?> logout(@RequestHeader("X-Token") String token){userService.logout(token);return Result.success();}
    }
  2. mapper\UserMapper中的代码
    package com.ums.sys.mapper;import com.ums.sys.entity.User;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;import java.util.List;/*** <p>*  Mapper 接口* </p>** @author chenhao* @since 2023-06-16*/
    public interface UserMapper extends BaseMapper<User> {public List<String> getRoleNameByUserId(Integer userId);
    }
    
  3. service\IUserService接口中的代码
    package com.ums.sys.service;import com.ums.sys.entity.User;
    import com.baomidou.mybatisplus.extension.service.IService;import java.util.Map;/*** <p>*  服务类* </p>** @author chenhao* @since 2023-06-16*/
    public interface IUserService extends IService<User> {// Map<String, Object> login(User user);Map<String, Object> getUserInfo(String token);void logout(String token);Map<String, Object> login(User user);
    }
    
  4. service\impl\UserServiceImpl中的代码
    package com.ums.sys.service.impl;import com.alibaba.fastjson2.JSON;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.ums.sys.entity.User;
    import com.ums.sys.mapper.UserMapper;
    import com.ums.sys.service.IUserService;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Service;import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.UUID;
    import java.util.concurrent.TimeUnit;/*** <p>*  服务实现类* </p>** @author chenhao* @since 2023-06-16*/
    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic Map<String, Object> login(User user) {// 查询数据库LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getUsername, user.getUsername());wrapper.eq(User::getPassword, user.getPassword());User loginUser = this.baseMapper.selectOne(wrapper);// 结果不为空,生成token,将用户信息存入redisif (loginUser != null) {// 用UUID,终极方案是jwtString key = "user:" + UUID.randomUUID();// 存入redisloginUser.setPassword(null);    // 设置密码为空,密码没必要放入redisTemplate.opsForValue().set(key, loginUser,30, TimeUnit.MINUTES);   // timeout为登录时间// 返回数据Map<String, Object> data = new HashMap<>();data.put("token",key);return data;}// 结果不为空,生成token,前后端分离,前端无法使用session,可以使用token// 并将用户信息存入redisreturn null;}@Overridepublic Map<String, Object> getUserInfo(String token) {// 之前已将对象进行序列化处理存入redis,现在从redis中取出需要反序列化处理Object obj = redisTemplate.opsForValue().get(token);    // 此对象是map类型,稍后需要序列化为Json字符串if (obj!= null) {User loginUser = JSON.parseObject(JSON.toJSONString(obj), User.class);Map<String,Object> data = new HashMap<>();data.put("name",loginUser.getUsername());data.put("avatar",loginUser.getAvatar());// 先在xml里写SQL语句id=getRoleNameByUserId,然后去UserMapper里实现接口List<String> roleList = this.baseMapper.getRoleNameByUserId(loginUser.getId());data.put("roles",roleList);return data;}return null;}@Overridepublic void logout(String token) {redisTemplate.delete(token);    // 从redis中删除token}}
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/230417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【老牌期刊】IF:12,持续飙升,同领域期刊中的“佼佼者“,国人友好!

01 期刊概况 ARTIFICIAL INTELLIGENCE REVIEW ​ 【出版社】Springer 【ISSN】0269-2821 【EISSN】1573-7462 【检索情况】SCI&EI&Scopus在检 【WOS收录年份】1988年 【出刊频率】双月刊&#xff0c;最新一期December 2023 【期刊官网】 https://link.springe…

【Linux】进程周边005之环境变量

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.环境变量是什么&#xff1…

太阳能电池效能IV测试PV检测太阳光模拟器

目录 概述 一、系统组成 产品特点&#xff1a; 技术参数 数字源表 本系统支持Keithley24xx系列源表 标准太阳能电池 低阻测试夹具 自动化测试软件 概述 太阳能光伏器件的所有性能表征手段中&#xff0c;IV特性测试无疑是最直观、最有效、最被广泛应用的一种…

【OS】操作系统总复习笔记

操作系统总复习 文章目录 操作系统总复习一、考试题型1. 论述分析题2. 计算题3. 应用题 二、操作系统引论&#xff08;第1章&#xff09;2.1 操作系统的发展过程2.2 操作系统定义2.3 操作系统的基本特性2.3.1 并发2.3.2 共享2.3.3 虚拟2.3.4 异步 2.4 OS的功能2.5 OS结构2.5 习…

Android studio 按键控制虚拟LED

一、activity_main.xml代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.a…

《Linux C编程实战》笔记:进程操作之创建进程

进程是一个动态的实体&#xff0c;是程序的一次执行过程。进程是操作系统资源分配的基本单位。 以下是一些概念&#xff0c;我就直接抄书了 进程是操作系统的知识&#xff0c;简单理解的话&#xff0c;你写的代码运行起来算一个进程&#xff1f; 创建进程 每个进程由进程ID号…

GPT-4.5!!!

GPT-4 还没用明白&#xff0c;GPT-4.5 就要发布了。 最近&#xff0c;OpenAI 泄露了 GPT-4.5 的发布页面&#xff0c;除了进一步增强复杂推理和跨模态理解&#xff0c;GPT-4.5 增加了一个更加强大的功能——3D。 3D 功能的进一步支持&#xff0c;也就意味着多模态最后一块版图…

关于前端学习的思考-浮动元素嵌套块级元素12.18

1、块级元素嵌套浮动元素 先摆图片&#xff0c;当橘色的盒子高度减少的时候&#xff0c;NK AD TB PK NN并不会减少。如何解决呢&#xff1f; 加一个overflow&#xff1a;clip或者hidden 2、浮动元素嵌套块级元素 加一个overflow&#xff1a;clip或者hidden 综上所述&#xff0…

giee 添加公匙 流程记录

一、安装 百度网盘CSDN4文件夹下&#xff0c;或者官网下载&#xff1a;https://git-scm.com/downloads 二、生成密钥 1.右击打开git bash 2.$ ssh-keygen -t rsa -C “个人邮箱地址”&#xff0c;按3个回车&#xff0c;密码为空。 3.在C:\Users{windows用户名}.ssh目录下得到…

[Ray Tracing in One Weekend] 笔记

前言 本文参照自raytracing in one weekend教程&#xff0c;地址为&#xff1a;https://raytracing.github.io/books/RayTracingInOneWeekend.html 什么是光线追踪&#xff1f; 光线追踪模拟现实中的成像原理&#xff0c;通过模拟一条条直线在场景内反射折射&#xff0c;最终…

算法——分治

思想&#xff1a;分而治之&#xff0c;将大问题转化为若干个相同或相似的子问题。快排的题目常见的方法是利用三指针法将数组分三块搭配随机选择基准元素的思想 颜色分类&#xff08;分治_快排&#xff09; 颜色分类 题目解析 原地对它们进行排序&#xff0c;使得相同颜色的元…

Oracle-应用会话集中在RAC集群一个节点问题

问题&#xff1a; 用户一套Oracle19c RAC集群&#xff0c;出现一个奇怪的现象&#xff0c;通过SCAN IP访问的连接会话都集中在节点一实例&#xff0c;而且用户并没有做任何的节点服务访问去控制会话的连接节点&#xff0c;比如常见的通过集群的高可用服务去控制应用访问连接集中…

Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)

目录 一、前言 二、基于注解配置Bean 1.基本介绍 : 2.应用实例 : 3.注意事项 : 三、手动实现Spring 注解配置机制 1.需求 : 2.思路 : 3.实现 : 3.1 自定义注解类 3.2 自定义配置类 3.3 自定义容器类 3.4 在测试类中进行测试 四、自动装配 0.总述 : 1.AutoWired自动装…

LeetCode力扣每日一题(Java):69、x 的平方根

一、题目 二、解题思路 1、 我的思路 我的思路是直接循环暴力破解&#xff0c;定义计数器i&#xff0c;从1开始递增&#xff0c;直到i*i大于或等于x 于是有了如下代码 int i 1;while(true){if(i*i<x){i;}else if(i*ix){return i;}else{return i-1;}} 但提交之后超出了…

亚马逊、target、eBay、沃尔玛等平台采退、下卡,技术技巧大揭秘

今天想和大家分享一些关于做测评、采退和撸卡项目时所需的防关联和防封号环境的底层技术原理。这些内容相对比较复杂&#xff0c;相信很少有人能够完全掌握&#xff0c;因为涉及到一些比较高级的IT技术原理。 如果正在考虑开始做采退或者撸卡项目&#xff0c;或者已经在进行相…

libxls - 编译

文章目录 libxls - 编译概述笔记静态库工程测试控制台exe工程测试备注备注END libxls - 编译 概述 想处理.xls格式的excel文件. 查了一下libxls库可以干这个事. 库地址 https://github.com/libxls/libxls.git 但是这个库的makefile写的有问题, 在mingw和WSL下都编译不了. 好在…

高德地图绘制区域的地理围栏

官网示例 https://lbs.amap.com/demo/javascript-api-v2/example/overlayers/polygon-draw/ <!doctype html> <html> <head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta …

黑马点评06分布式锁 2Redisson

实战篇-17.分布式锁-Redisson功能介绍_哔哩哔哩_bilibili 1.还存在的问题 直接实现很麻烦&#xff0c;借鉴已有的框架。 2.Redisson用法 3.Redisson可重入原理 在获取锁的时候&#xff0c;看看申请的线程和拿锁的线程是否一致&#xff0c;然后计算该线程获取锁的次数。一个方法…

爬虫chrome浏览器抓包说明

chrome浏览器抓包说明 目标&#xff1a;掌握chrome在爬虫中的使用 1. 新建隐身窗口&#xff08;无痕窗口&#xff09; 作用&#xff1a;在打开无痕窗口的时候&#xff0c;第一次请求某个网站是没有携带cookie的&#xff0c;和代码请求一个网站一样&#xff0c;这样就能够尽可…

堆与二叉树(上)

本篇主要讲的是一些概念&#xff0c;推论和堆的实现&#xff08;核心在堆的实现这一块&#xff09; 涉及到的一些结论&#xff0c;证明放到最后&#xff0c;可以选择跳过&#xff0c;知识点过多&#xff0c;当复习一用差不多&#xff0c;如果是刚学这一块的&#xff0c;建议打…