0


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

中配置的代码如下:

packagecom.ums.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.cors.CorsConfiguration;importorg.springframework.web.cors.UrlBasedCorsConfigurationSource;importorg.springframework.web.filter.CorsFilter;@ConfigurationpublicclassMyCorsConfig{@BeanpublicCorsFiltercorsFilter(){CorsConfiguration configuration =newCorsConfiguration();// 允许什么网址来异步访问
        configuration.addAllowedOrigin("http://localhost:8888");// 获取cookie
        configuration.setAllowCredentials(true);// 允许什么方法? POST、GET,此处为* 意味全部允许
        configuration.addAllowedMethod("*");// 允许所有的请求头
        configuration.addAllowedHeader("*");// 设置资源过滤器,过滤什么资源UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource =newUrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**",configuration);returnnewCorsFilter(urlBasedCorsConfigurationSource);}}
MyRedisConfig

中用于配置的代码如下:

packagecom.ums.config;importcom.fasterxml.jackson.annotation.JsonAutoDetect;importcom.fasterxml.jackson.annotation.JsonInclude;importcom.fasterxml.jackson.annotation.JsonTypeInfo;importcom.fasterxml.jackson.annotation.PropertyAccessor;importcom.fasterxml.jackson.databind.DeserializationFeature;importcom.fasterxml.jackson.databind.MapperFeature;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.SerializationFeature;importcom.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.redis.connection.RedisConnectionFactory;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;importorg.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;importorg.springframework.data.redis.serializer.StringRedisSerializer;importjavax.annotation.Resource;importjava.text.SimpleDateFormat;importjava.util.TimeZone;@ConfigurationpublicclassMyRedisConfig{@ResourceprivateRedisConnectionFactory factory;@BeanpublicRedisTemplateredisTemplate(){RedisTemplate<String,Object> redisTemplate =newRedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);// 设置键值序列化
        redisTemplate.setKeySerializer(newStringRedisSerializer());Jackson2JsonRedisSerializer serializer =newJackson2JsonRedisSerializer<Object>(Object.class);
        redisTemplate.setValueSerializer(serializer);// 序列化,死代码ObjectMapper om =newObjectMapper();
        om.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
        om.setDateFormat(newSimpleDateFormat("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")publicResult<Map<String,Object>>login(@RequestBodyUser user){// 因为 user传过来为json字符串,所以用@RequestBody 进行实体转换// 业务代码在userService里完成Map<String,Object> data = userService.login(user);if(data !=null){returnResult.success(data,"登录成功");}returnResult.fail(2002,"用户名或密码错误");}

如下图所示

userService.login()

方法会爆红,因为该方法没有被定义或实现,此时鼠标点击并按

Alt+Enter

在这里插入图片描述

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

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

此时,接口上方有个提示

1 related problem

,鼠标左击,会跳转至接口的实现代码处

UserServiceImpl

在这里插入图片描述

在这里插入图片描述

在整个类的定义之处,同样

Alt + Enter

,选择第一个,弹出的对话框再选第一个,会生成代码
在这里插入图片描述
在这里插入图片描述

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

在该函数中写上下述代码

@OverridepublicMap<String,Object>login(User user){// 查询数据库LambdaQueryWrapper<User> wrapper =newLambdaQueryWrapper<>();
    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();// 存入redis
        loginUser.setPassword(null);// 设置密码为空,密码没必要放入
        redisTemplate.opsForValue().set(key, loginUser,30,TimeUnit.MINUTES);// timeout为登录时间// 返回数据Map<String,Object> data =newHashMap<>();
        data.put("token",key);return data;}// 结果不为空,生成token,前后端分离,前端无法使用session,可以使用token// 并将用户信息存入redisreturnnull;}

返回

UserController

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

按照上述方法如法炮制

UserController

中写获取

token

的代码和

logout

代码
在这里插入图片描述

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

代码如下

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

接着就是

Alt + Enter

修复bug

UserServiceImpl

中先定义一个

redisTemplate

在这里插入图片描述

然后在

UserServiceImpl

中写上下述代码

@OverridepublicMap<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 =newHashMap<>();
        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;}returnnull;}@Overridepublicvoidlogout(String token){
    redisTemplate.delete(token);// 从redis中删除token}

注意红圈中的代码,是联表查询,这是自定义的

SQL

查询,接下来定义它
在这里插入图片描述

找到

UserMapper

然后写上代码:

publicList<String>getRoleNameByUserId(Integer userId);

在这里插入图片描述

然后去

resources\mapper\sys\UserMapper.xml

中写SQL语句
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.ums.sys.mapper.UserMapper"><selectid="getRoleNameByUserId"parameterType="Integer"resultType="String">
        SELECT
               b.role_name
        FROM
             x_user_role a,x_role b
        WHERE
            a.role_id=b.role_id
          AND
            a.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中的代码packagecom.ums.sys.controller;importcom.ums.common.vo.Result;importcom.ums.sys.entity.User;importcom.ums.sys.service.IUserService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;importorg.springframework.stereotype.Controller;importjava.util.List;importjava.util.Map;/** * <p> * 前端控制器 * </p> * * @author anthony * @since 2023-06-16 */@RestController@RequestMapping("/user")// @CrossOrigin //处理跨域,因为前端和后端的IP一致但端口不一致,所以浏览器认为跨域,不给访问,可用Ngx来解决publicclassUserController{@AutowiredprivateIUserService userService;@GetMapping("/all")publicResult<List<User>>getAllUser(){List<User> list = userService.list();returnResult.success(list,"查询成功");}@PostMapping("/login")publicResult<Map<String,Object>>login(@RequestBodyUser user){// 因为 user传过来为json字符串,所以用@RequestBody 进行实体转换// 业务代码在userService里完成Map<String,Object> data = userService.login(user);if(data !=null){returnResult.success(data,"登录成功");}returnResult.fail(2002,"用户名或密码错误");}@GetMapping("/info")publicResult<Map<String,Object>>getUserInfo(@RequestParam("token")String token){// @RequestParam("token") 是从url中获取值// 根据token获取用户信息,信息存进了redis中Map<String,Object> data = userService.getUserInfo(token);if(data !=null){returnResult.success(data);}returnResult.fail(2003,"登录信息无效,请重新登录");}@PostMapping("/logout")publicResult<?>logout(@RequestHeader("X-Token")String token){ userService.logout(token);returnResult.success();}}
  2. mapper\UserMapper中的代码packagecom.ums.sys.mapper;importcom.ums.sys.entity.User;importcom.baomidou.mybatisplus.core.mapper.BaseMapper;importjava.util.List;/** * <p> * Mapper 接口 * </p> * * @author chenhao * @since 2023-06-16 */publicinterfaceUserMapperextendsBaseMapper<User>{publicList<String>getRoleNameByUserId(Integer userId);}
  3. service\IUserService接口中的代码packagecom.ums.sys.service;importcom.ums.sys.entity.User;importcom.baomidou.mybatisplus.extension.service.IService;importjava.util.Map;/** * <p> * 服务类 * </p> * * @author chenhao * @since 2023-06-16 */publicinterfaceIUserServiceextendsIService<User>{// Map<String, Object> login(User user);Map<String,Object>getUserInfo(String token);voidlogout(String token);Map<String,Object>login(User user);}
  4. service\impl\UserServiceImpl中的代码packagecom.ums.sys.service.impl;importcom.alibaba.fastjson2.JSON;importcom.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;importcom.ums.sys.entity.User;importcom.ums.sys.mapper.UserMapper;importcom.ums.sys.service.IUserService;importcom.baomidou.mybatisplus.extension.service.impl.ServiceImpl;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.stereotype.Service;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importjava.util.UUID;importjava.util.concurrent.TimeUnit;/** * <p> * 服务实现类 * </p> * * @author chenhao * @since 2023-06-16 */@ServicepublicclassUserServiceImplextendsServiceImpl<UserMapper,User>implementsIUserService{@AutowiredprivateRedisTemplate redisTemplate;@OverridepublicMap<String,Object>login(User user){// 查询数据库LambdaQueryWrapper<User> wrapper =newLambdaQueryWrapper<>(); 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();// 存入redis loginUser.setPassword(null);// 设置密码为空,密码没必要放入 redisTemplate.opsForValue().set(key, loginUser,30,TimeUnit.MINUTES);// timeout为登录时间// 返回数据Map<String,Object> data =newHashMap<>(); data.put("token",key);return data;}// 结果不为空,生成token,前后端分离,前端无法使用session,可以使用token// 并将用户信息存入redisreturnnull;}@OverridepublicMap<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 =newHashMap<>(); 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;}returnnull;}@Overridepublicvoidlogout(String token){ redisTemplate.delete(token);// 从redis中删除token}}

本文转载自: https://blog.csdn.net/qq_56039091/article/details/131329535
版权归原作者 Anthony_CH 所有, 如有侵权,请联系我们删除。

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

还没有评论