文章目录

  • 技术栈
  • 编辑器
  • 数据库
  • 切换数据库
  • 创建数据表
  • 初始化数据
  • 后端代码
  • 实现UserEntity代码
  • 实现UserMapper代码
  • 创建userMapper.xml文件
  • 实现UserVo代码
  • 实现UserService代码
  • 实现UserLoginDto代码
  • 实现UserController代码
  • 解决跨域的问题
  • 前端代码
  • 实现portConfig.ts代码
  • 修改api.ts文件
  • 启动项目
  • 解决ant design pro登录成功无法跳转的问题
  • 分析问题
  • 解决问题
  • 修改前端代码
  • 修改后端代码
  • 最终效果


技术栈

实现前后单登录的接口,使用到的技术栈如下:

  • 前端
  1. ant desigin pro
  2. react
  3. typescript(ts)
  4. es
  • 后端
  1. spring boot
  2. mysql
  3. jdk1.8

编辑器

  • 前端
  • web storm
  • 后端
  • idea

数据库

切换数据库

mysql> use superjson;
Database changed

创建数据表

mysql> create table core_user(
    -> id int(11) PRIMARY key not null auto_increment comment '自增主键',
    -> username varchar(50) not null comment '用户名',
    -> password VARCHAR(50) not null comment '密码',
    -> avatar   VARCHAR(512) NOT NULL comment '头像',
    -> nick_name VARCHAR(255) comment '昵称'
    -> )  ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.04 sec)

初始化数据

在初始化admin数据时,没有将密码加密,因为只是使用ant design pro模拟登录,没有做这么复杂。

在实际工作中,我们应该以密文的形式存储密码。

mysql> INSERT INTO core_user ( username, PASSWORD, avatar, nick_name )VALUES(
    -> 'admin',
    -> 'ant.design',
    -> 'https://himg.bdimg.com/sys/portraitn/item/public.1.8a548439.18Y_0tyMCA-PRvCGNzwL6w',
    -> '念兮为美'
    -> );
Query OK, 1 row affected (0.01 sec)

后端代码

实现UserEntity代码

从数据库中查询出的用户【user】被装载到实体类【userEntity】中

package com.superjson.superjsonmanager.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author 念兮为美
 * @datetime 2022/8/8 15:21
 * @desc 从数据库中查询出的用户【user】被装载到实体类【userEntity】中
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserEntity {
  private Long id;
  private String password;
  private String username;
  private String nickName;
  private String avatar;
}

实现UserMapper代码

package com.superjson.superjsonmanager.mapper;

import com.superjson.superjsonmanager.entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @author 念兮为美
 * @datetime 2022/8/8 15:20
 * @desc user映射器
 */
@Mapper
public interface UserMapper {

  /**
   * 使用账户名和密码查询用户
   *
   * @author 念兮为美
   * @datetime 2022/8/8:15:41
   * @param username 账户名
   * @param password 密码
   */
  UserEntity getByUsernameAndPassword(@PathVariable String username, @PathVariable String password);
}

创建userMapper.xml文件

<?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.superjson.superjsonmanager.mapper.UserMapper">

    <select id="getByUsernameAndPassword" resultType="com.superjson.superjsonmanager.entity.UserEntity">
        select id,username,password,nick_name as nickName,avatar from core_user where username =#{username} and password = #{password} limit 1
    </select>
</mapper>

实现UserVo代码

userEntity的数据映射到userVo对象中

package com.superjson.superjsonmanager.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author 念兮为美
 * @datetime 2022/8/8 16:31
 * @desc userEntity的数据映射到userVo对象中
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserVo {

  private String name;
  private String currentAuthority;
  private String status;
  private String type;
  private String avatar;
}

实现UserService代码

package com.superjson.superjsonmanager.service;

import com.alibaba.fastjson.JSONObject;
import com.superjson.superjsonmanager.entity.UserEntity;
import com.superjson.superjsonmanager.mapper.UserMapper;
import com.superjson.superjsonmanager.vo.UserVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author 念兮为美
 * @datetime 2022/8/8 15:47
 * @desc 用户服务类
 */
@Service
public class UserService {

  @Resource private UserMapper userMapper;

  /**
   * @author 念兮为美
   * @datetime 2022/8/8:16:35
   * @param username 账户名
   * @param password 密码
   * @desc 使用账户名和密码查询用户
   */
  public JSONObject getByUsernameAndPassword(String username, String password, String type) {
    UserEntity userEntity = userMapper.getByUsernameAndPassword(username, password);

    UserVo userVo = new UserVo();
    userVo.setAvatar(userEntity.getAvatar());
    userVo.setName(userEntity.getNickName());
    userVo.setCurrentAuthority("admin");
    userVo.setType(type);
    userVo.setStatus("ok");

    return (JSONObject) JSONObject.toJSON(userVo);
  }
}

实现UserLoginDto代码

用户登录请求参数

package com.superjson.superjsonmanager.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author 念兮为美
 * @datetime 2022/8/5 21:34
 * @desc 用户登录请求参数
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserLoginDto {
    private String password;
    private String type;
    private String username;
}

实现UserController代码

package com.superjson.superjsonmanager.controller;

import com.alibaba.fastjson.JSONObject;
import com.superjson.superjsonmanager.dto.UserLoginDto;
import com.superjson.superjsonmanager.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @author 念兮为美
 * @datetime 2022/8/5 21:30
 * @desc 用户登录控制器
 */
@RestController
@RequestMapping("/user")
public class UserController {

  @Autowired private UserService userService;

  @PostMapping("/login")
  public JSONObject login(@RequestBody UserLoginDto userLogin) {
    return userService.getByUsernameAndPassword(
        userLogin.getUsername(), userLogin.getPassword(), userLogin.getType());
  }
}

解决跨域的问题

这是解决跨域的问题,如下图所示:

typescript 后端接口返回二进制流文件下载_ant desigin pro

package com.superjson.superjsonmanager.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author 念兮为美
 * @datetime 2022/8/5 22:32
 * @desc 解决跨域的过滤器
 */
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //添加映射路径
        registry.addMapping("/**")
                //是否发送Cookie
                .allowCredentials(true)
                //设置放行哪些原始域   SpringBoot2.4.4下低版本使用.allowedOrigins("*")
                .allowedOriginPatterns("*")
                //放行哪些请求方式
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
                //.allowedMethods("*") //或者放行全部
                //放行哪些原始请求头部信息
                .allowedHeaders("*")
                //暴露哪些原始请求头部信息
                .exposedHeaders("*");
    }
}

前端代码

实现portConfig.ts代码

/**
 * 这是api端口号的配置
 */
const portConfigs = {
  dev: {
    baseUrl: 'http://127.0.0.1:8088',
  },
  test: {},
  prd: {
    baseUrl: 'http://https://www.superjson.com/api',
  },
};

export const portConfig: { baseUrl: string } = portConfigs['dev']

修改api.ts文件

  • 打开 src -> services -> ant-design-pro ->目录下的 api.ts文件。
  • 找到login方法
  • 将login方法中的/api/login/account修改为`${portConfig.baseUrl}/user/login`
  • 如下代码所示:
/** 登录接口 POST /api/login/account */
export async function login(body: API.LoginParams, options?: { [key: string]: any }) {
  return request<API.LoginResult>(`${portConfig.baseUrl}/user/login`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    data: body,
    ...(options || {}),
  });
}

启动项目

  1. 启动spring boot项目,如下图所示:

typescript 后端接口返回二进制流文件下载_mybatis_02

  1. 使用 npm run start 启动 ant design pro项目
  2. 输入用户名、密码,点击登录,如下图所示:

typescript 后端接口返回二进制流文件下载_mybatis_03

满心欢喜地点击登录,也出现了登录成功的弹出框,但页面就是没有跳转过去,为什么会出现这种情况呢?

解决ant design pro登录成功无法跳转的问题

分析问题

明明是登录成功了,为什么没有跳转呢?

于是,使用F12打开调试面板,发现/api/currentUser接口报错了,错误信息是没有授权,如下图所示:

typescript 后端接口返回二进制流文件下载_ant desigin pro_04

而且,请求地址是http://127.0.0.1:8001/,并非我定义的后端地址http://127.0.0.1:8088

解决问题

修改前端代码

因而,在ant design pro 项目中搜索接口/api/currentUser,定位到src -> services -> ant-design-pro ->目录下的 api.ts文件的currentUser方法。

于是,将currentUser中的/api/currentUser修改为`${portConfig.baseUrl}/user/currentUser` ,如下所示:

/** 获取当前的用户 GET /api/currentUser */
export async function currentUser(options?: { [key: string]: any }) {
  return request<{
    data: API.CurrentUser;
  }>(`${portConfig.baseUrl}/user/currentUser`, {
    method: 'GET',
    ...(options || {}),
  });
}

修改后端代码

UserController中增加currentUser方法,将数据库的数据直接返回,没有使用userServiceuserMapper调用的方式,读者可以自行实现这部分代码。

currentUser方法如下代码:

@GetMapping("/currentUser")
  public JSONObject currentUser() {
    JSONObject data = new JSONObject();
    data.put("name", "念兮为美");
    data.put("access", "admin");
    data.put("avatar", "https://himg.bdimg.com/sys/portraitn/item/public.1.8a548439.18Y_0tyMCA-PRvCGNzwL6w");

    JSONObject body = new JSONObject();
    body.put("data", data);
    body.put("success", true);
    return body;
  }

最终效果

typescript 后端接口返回二进制流文件下载_前端_05