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.hqwc.cn/news/283929.html

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

相关文章

力扣200. 岛屿数量(java DFS解法)

Problem: 200. 岛屿数量 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 该问题可以归纳为一类遍历二维矩阵的题目&#xff0c;此类中的一部分题目可以利用DFS来解决&#xff0c;具体到本题目&#xff1a; 1.我们首先要针对于二维数组上的每一个点&#xff0c;尝试展…

搜维尔科技:让鳄鱼在银幕上唱跳,奇幻电影《鳄鱼莱莱》幕后揭秘

把《鳄鱼莱莱》从儿童读物改编成真人电影&#xff0c;这绝非易事。首先需要塑造一条长一米八的鳄鱼&#xff0c;然后还能栩栩如生地唱歌跳舞&#xff0c;并与奥斯卡获奖演员哈维尔巴登&#xff08;Javier Bardem&#xff09;一起表演&#xff0c;向观众展现原作中吸引人的神奇之…

B01、JVM与Java体系结构-01

字节码与多语言混合编程 字节码概述&#xff1a; 我们平时说的java字节码&#xff0c;指的是用java语言编译成的字节码。准确的说任何能在jvm平台上执行的字节码格式都是一样的。所以应该统称为&#xff1a;jvm字节码。不同的编译器&#xff0c;可以编译出相同的字节码文件&…

Docker实战案例研究:深入行业应用与最佳实践

Docker作为一种轻量级、可移植、可扩展的容器化技术&#xff0c;在各行各业都得到了广泛应用。本文将通过深入实际案例&#xff0c;介绍Docker在不同行业的应用以及相应的最佳实践&#xff0c;提供更加丰富的示例代码&#xff0c;以帮助大家更全面地理解和运用Docker的强大功能…

法大大邀业内大咖剖析汽车名企数智化实战路径

法大大发布中国首部《汽车行业合同数智化白皮书》&#xff0c;聚焦趋势&#xff0c;解读行业数字化转型攻坚战的破局之道&#xff1b;深入内部&#xff0c;剖析名企数字化的探索实践。 长安汽车、蔚来汽车、上汽大通、 东风汽车集团、奥托立夫、长城滨银汽金… 一众名企高层…

sqlserver dba日常操作

查询慢sql的方法 1.whoisactive 安装方法 http://whoisactive.com/downloads/下载地址 将下载好的zip包放到sqlserver服务器中 文件-打开-文件-下载好的zip包-在查询窗口点击执行 新建一个查询窗口&#xff0c;输入sp_whoisactive&#xff0c;获取当前运行的所有sql语句 使用…

宝塔部署flask项目

宝塔(bt.cn)部署flask项目&#xff0c;发现问题还挺多。不过终于是搞定了。 先可以用pycharm建一个空的flask项目&#xff0c;这样好发现问题。 到网站栏目点击python项目&#xff0c;新建一个python项目。 要选择flask框架&#xff0c;uwsgi运行方式。 端口如果选择80端口&a…

执行计划EXPLAIN详解

什么是EXPLAIN&#xff1f; EXPLAIN是MySQL提供的一条语句&#xff0c;用于详细展示MySQL如何执行一条SELECT语句。通过使用EXPLAIN&#xff0c;开发者可以看到MySQL如何处理查询及连接表&#xff0c;帮助我们诊断性能问题。 使用方法非常直接&#xff0c;只需在SELECT查询前…

儿童玩具行业分析:发展态势良好,市场空间不断拓展

玩具是有利于促进幼儿体、德、智、美的全面发展;符合儿童年龄特征&#xff0c;能满足其好奇心、好动和探索活动的愿望;造型优美&#xff0c;反映事物的典型特征;活动多变&#xff0c;有助于鼓励学习。中国玩具产品包括毛绒玩具、塑胶玩具、纸质玩具、电子玩具、木制玩具、金属玩…

虚拟机无法进入系统问题

概述 客户在华为云平台上创建了两台虚拟机并部署aarch64 V10 OS&#xff0c;2021-10-28其中一台虚拟机业务出现异常&#xff0c;运维重启虚拟机后系统进不去&#xff0c;左上角光标闪烁&#xff0c;接着重启另一台虚拟机同样起不来&#xff0c;现象一致。 分析 通过分析现场…

嵌入式Linux学习(3)——中断(Interrupt)子系统概念

目录 一. 中断概念与分类 1.1 中断分类 1.2 中断事件的处理流程 1.3 中断号(IRQ number) 1.4 中断源(Interrupt Source) 1.5 中断触发方式 二. 中断子系统架构 2.1 GIC 2.2 中断子系统架构 2.3 GIC与IP 2.3.1 典型GIC IP PLC390 GIC 400 GIC 500 REF 一. 中断概念与…

如何基于企业需求,又便宜又快地定制开发一套CRM客户管理系统?

如何基于企业需求&#xff0c;又便宜又快地定制开发一套CRM客户管理系统&#xff1f; 定制开发CRM客户管理系统是为了满足企业个性化需求而进行的&#xff0c;它可以帮助企业提高客户关系管理效率&#xff0c;提供更好的客户服务和实现精细化运营。本文将为大家介绍CRM定制开发…