Combate real del proyecto de separación de front-end y back-end de SpringBoot + Vue || Tres: conexión de back-end de Spring Boot y front-end de Vue

Serie de artículos:
Práctica del proyecto de separación de front-end y back-end de SpringBoot + Vue || Uno: diseño de front-end de Vue
Práctica del proyecto de separación de front-end de SpringBoot + Vue || Dos: backend de Spring Boot y conexión de base de datos
SpringBoot + Vue front-end práctica del proyecto de separación final || Tres: conexión Spring Boot back-end y Vue front-end
Práctica del proyecto de separación SpringBoot + Vue front-end y back-end || Cuatro: implementación de la función de gestión de usuarios Práctica del proyecto de separación SpringBoot + Vue front-end || Tres: implementación de la función de gestión de usuarios
SpringBoot + Vue práctica del proyecto de separación front-end || Tres: conexión de back-end de Spring Boot y Vue front-end | | Cinco: Seguimiento de la función de gestión de usuarios

Acoplamiento frontal y posterior

Modifique la interfaz del front-end para conectarse al back-end

src\api\user.jsModifique la dirección de solicitud para mantenerla coherente con el backend
Insertar descripción de la imagen aquí

Registre los campos src\utils\request.jsen la parte frontal.X-Token
Insertar descripción de la imagen aquí

Cambie la dirección de solicitud en el entorno de desarrollo a la dirección de backendhttp://localhost:9999
Insertar descripción de la imagen aquí

Desactivar la anotación del servicio de datos simulados de front-end
Insertar descripción de la imagen aquí

Configuración general del backend

Cree un nuevo configpaquete en el backend y cree dos nuevas clases en el paquete
Insertar descripción de la imagen aquí

  • MyCorsConfigSe utiliza para configurar el acceso asincrónico y conectarse al enlace de acceso front-end "http://localhost:8888". Esta configuración se puede Nginxutilizar en su lugar.
  • MyRedisConfigSe utiliza para configurar el servicio de serialización de Redis.

MyCorsConfigEl código configurado en es el siguiente:

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 {
    
    

    @Bean
    public CorsFilter corsFilter() {
    
    
        CorsConfiguration configuration = new CorsConfiguration();

        // 允许什么网址来异步访问
        configuration.addAllowedOrigin("http://localhost:8888");

        // 获取cookie
        configuration.setAllowCredentials(true);

        // 允许什么方法? POST、GET,此处为* 意味全部允许
        configuration.addAllowedMethod("*");

        // 允许所有的请求头
        configuration.addAllowedHeader("*");

        // 设置资源过滤器,过滤什么资源
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**",configuration);

        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

MyRedisConfigEl código utilizado para la configuración es el siguiente:

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 {
    
    

    @Resource
    private RedisConnectionFactory factory;

    @Bean
    public 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;
    }
}

Escriba el código comercial de inicio y cierre de sesión en el backend

El método de solicitud de la interfaz de inicio de sesión del proyecto VUE front-end es el POSTpresentado anteriormente
Insertar descripción de la imagen aquí

UserControllerAgregue código para el control de inicio de sesión
Insertar descripción de la imagen aquí

@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,"用户名或密码错误");
}

Como se muestra en la figura siguiente userService.login(), el método se volverá popular porque el método no se ha definido ni implementado. En este momento, haga clic con el mouse y presioneAlt+Enter
Insertar descripción de la imagen aquí

Seleccione el primer elemento:
Insertar descripción de la imagen aquí

IDEA generará automáticamente el código de interfaz
Insertar descripción de la imagen aquí

En este momento, hay un mensaje encima de la interfaz 1 related problem. Al hacer clic con el botón izquierdo del mouse, se saltará al código de implementación de la interfaz.UserServiceImpl
Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

De manera similar, en la definición de toda la clase Alt + Enter, seleccione la primera, luego seleccione la primera en el cuadro de diálogo emergente y se generará el código.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

código generado
Insertar descripción de la imagen aquí

Escribe el siguiente código en esta función.

@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,将用户信息存入redis
    if (loginUser != null) {
    
    
        // 用UUID,终极方案是jwt
        String key = "user:" + UUID.randomUUID();

        // 存入redis
        loginUser.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
    // 并将用户信息存入redis
    return null;
}

Regresar UserController, el código es normal en este momento.
Insertar descripción de la imagen aquí

Siga el método anterior y escriba el código obtenido y el código
enUserControllertokenlogout
Insertar descripción de la imagen aquí

Entre ellos, estas dos interfaces no están implementadas.
Insertar descripción de la imagen aquí

El código se muestra a continuación.

@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();

Entonces es hora Alt + Enterde corregir el error.

Primero UserServiceImpldefine unredisTemplate
Insertar descripción de la imagen aquí

Luego UserServiceImplescribe el siguiente código en

@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
}

Tenga en cuenta que el código en el círculo rojo es una consulta de tabla conjunta. Esta es una SQLconsulta personalizada. A continuación, defínala
Insertar descripción de la imagen aquí

Encuentra UserMappery escribe el código:

public List<String> getRoleNameByUserId(Integer userId);

Insertar descripción de la imagen aquí

Luego vaya resources\mapper\sys\UserMapper.xmly escriba la declaración SQL en
Insertar descripción de la imagen aquí

<?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">
        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>

prueba

Una vez configurado redis, Redis se inicia antes de iniciar SpringBoot.

Primero busque el directorio de instalación de redis.
Insertar descripción de la imagen aquí

Abra cmdel directorio y
ejecute el comando redis-server.exe redis.windows.conf, presione Enter, aparecerá la siguiente interfaz, luego minimice esta ventana, no la cierre
Insertar descripción de la imagen aquí

Luego inicia SprinfBootel backend
Insertar descripción de la imagen aquí

Luego comienza Vuela parte delantera.
Insertar descripción de la imagen aquí

Después de hacer clic para iniciar sesión, podrá ver http://localhost:9999/user/loginel cambio de la dirección de la interfaz.
Insertar descripción de la imagen aquí

Los generados por el backend tokentambién se registran redisen
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Haga clic en 退出登录, el token en redis también se cancela
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Todo el código en el backend

Evite errores al tomar notas y adjunte todos los códigos

  1. UserControllercódigo en
    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 {
          
          
        @Autowired
        private 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\UserMappercódigo en
    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\IUserServicecódigo en la interfaz
    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\UserServiceImplcódigo en
    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 {
          
          
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        @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,将用户信息存入redis
            if (loginUser != null) {
          
          
                // 用UUID,终极方案是jwt
                String key = "user:" + UUID.randomUUID();
    
                // 存入redis
                loginUser.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
            // 并将用户信息存入redis
            return null;
        }
    
        @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
        }
    
    }
    

Supongo que te gusta

Origin blog.csdn.net/qq_56039091/article/details/131329535
Recomendado
Clasificación