伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 02

伙伴匹配系统(移动端 H5 网站(APP 风格)基于Spring Boot 后端 + Vue3 - 02

项目地址:

@[toc]


后端整合 Swagger + Knife4j 接口文档

什么是接口文档,写接口信息的文档。

每个接口的信息包括:

  • 请求参数
  • 响应参数:
    • 错误码
  • 接口地址
  • 接口名称
  • 请求类型
  • 请求格式
  • 备注

谁用接口文档?

答:一般是后端或者负责人来提供,后端和前端都要使用

为什么需要接口文档?

  • 有一个书面内容(背书或者归档),便于大家参考和查阅,便于沉淀和维护,拒绝口口相传。
  • 接口文档便于前端和后端开发对接,前后端联调的介质,后端 => 接口文档 <= 前端。
  • 好的接口文档支持在线调试,在线测试,可以作为工具提高我们的开发测试效率。

怎么做接口文档?

  • 手写:比如腾讯文档、Markdown笔记
  • 自动化接口文档生成:自动根据项目代码生成完整的文档或在线调试的网页。Swagger、Postman(侧重接口管理)(国外);apifox、apipost、eolink(国产)

使用 Swagger

  1. 引l入依赖(Swagger或Knife4j:doc.xiaominfo.com/knife4j/doc...)
  2. 自定义Swagger配置类
  3. 定义需要生成接口文档的代码位置(Controller)
  4. 千万注意:线上环境不要把接口暴露出去!!!可以通过在SwaggerConfig配置文件开头加上@Profile({"dev","test"})限定配置仅在部分环境开启
  5. 启动即可
  6. 可以通过在controller方法上添加[@Api、@ApilmplicitParam(name]VApi、@ApilmplicitParam(name)="name",value="姓名",required=true)[@ApiOperation(value]/ApiOperation(value)="向客人问好")等注解来自定义生成的接口描述信息

使用 swagger 日志

swagger 官网地址:swagger.io/

导入相关的依赖

xml 复制代码
        <!-- swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>3.0.0</version>
        </dependency>

在配置文件config目录下,添加swagger 的配置文件 SwaggerConfig.java

java 复制代码
package com.yupi.yupao.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

/**
 * 自定义 Swagger 接口文档的配置
 *
 * @author <a href="https://github.com/rainbowsea">Raibnowsea</a>
 */
@Configuration
//@EnableSwagger2WebMvc
@EnableSwagger2
@Profile({"dev", "test"})  // 表示该项目在什么样的开发环境下,对外开发接口文档
public class SwaggerConfig {

    @Bean(value = "defaultApi2")  //
    public Docket defaultApi2() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // 这里一定要标注你控制器的位置
                .apis(RequestHandlerSelectors.basePackage("com.rainbowsea.yupao.controller"))
                .paths(PathSelectors.any())
                .build();
    }


    /**
     * api 信息
     *
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("鱼皮用户中心")
                .description("鱼皮用户中心接口文档")
                .termsOfServiceUrl("https://github.com/rainbowsea")
                .contact(new Contact("yupi", "https://github.com/rainbowsea", "xxx@qq.com"))
                .version("1.0")
                .build();
    }
}
java 复制代码
apis(RequestHandler)

如果 Spring Boot Verision >= 2.6 ,需要添加如下配置

yaml 复制代码
spring:
  mvc:
  	pathmatch:
      matching-strategy: ANT_PATH_MATCHER

访问路径:你的项目名映射路径+/doc.html ;比如: localhost:8080/api/doc.html

网页内容抓取-存量用户信息导入及同步

看上了网页信息,怎么抓到的

  1. 分析原网站是怎么获取这些数据的?哪个接口? F12,刷新------>触发请求

  2. 用程序去调用接口

  3. 处理(清洗)一下数据,之后就可以写到数据库里。

流程:

  1. 从 Excel 中导入全量用户数据,判重
  2. 抓取写了自我介绍的同学信息,提取出用户昵称,用户唯一 id,自我介绍信息。
  3. 从自我介绍中提取信息,

Easy Excel 读取 Excel 当中的信息

Easy Excel 官网地址:alibaba-easyexcel.github.io/index.html

Easy Excel 官方文档:easyexcel.opensource.alibaba.com/docs/curren...

两种读 Excel 的方式:

  1. 确定表头:建立对象;和表头形成映射
  2. 不确定表头:每一行数据映射为 Map<String.Object>

两种读取模式:

  1. 监听器:先创建监听器,再读取文件时绑定监听器。单独抽离处理逻辑,代码清晰易于维护;一条一条处理,适用于数据量大的场景。
  2. 同步读:无需创建监听器,一次性获取完整数据。方便简单,但是数据量大时会有等待时常,也可能内存溢出。

导入 Easy Excel 依赖

xml 复制代码
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.1.1</version>
</dependency>

这里我们创建一个:最简单的读的对象。用于存放我们读取到的 Excel 信息将其映射为一个对象。

  1. 确定表头:建立对象;和表头形成映射
  2. 不确定表头:每一行数据映射为 Map<String.Object>
java 复制代码
package com.rainbowsea.yupao.one;


import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

@Data
public class DemoExcelData {

    //@ExcelProperty(index = 1) 可以用列表匹配

    /**
     * id 
     * 强制读取第几个,这里不建议用 index 和 name 同时使用,
     * 要么一个对象只用 index ,要么一个对象只用 name 去匹配
     */
    @ExcelProperty("成员编号")
    private String planeCode;

    /**
     * 用户昵称
     */
    @ExcelProperty("成员昵称")
    private String username;

}

读取方式一:监听器:先创建监听器,再读取文件时绑定监听器。单独抽离处理逻辑,代码清晰易于维护;一条一条处理,适用于数据量大的场景。

java 复制代码
package com.rainbowsea.yupao.one;


import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import lombok.extern.slf4j.Slf4j;

/**
 * Excel 读取监听
 *
 */
@Slf4j
public class TableListener implements ReadListener<DemoExcelData> {

    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(DemoExcelData data, AnalysisContext context) {
        System.out.println(data);
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        System.out.println("已解析完成");
    }
}
java 复制代码
package com.rainbowsea.yupao.one;


import com.alibaba.excel.EasyExcel;

import java.util.List;

/**
 * 导入 Excel
 *
 */
public class ImportExcel {

    /**
     * 读取数据
     */
    public static void main(String[] args) {
        // todo 记得改为自己的测试文件
        String fileName = "E:\\Java\\project\\鱼皮星球项目\\伙伴匹配系统\\yupao\\yupao-backend\\src\\main\\resources\\testExcel.xlsx";
        readByListener(fileName);
    }

    /**
     * 监听器读取
     * @param fileName
     */
    public static void readByListener(String fileName) {
        EasyExcel.read(fileName, DemoExcelData.class, new TableListener()).sheet().doRead();
    }


}

读取方式二:同步读:无需创建监听器,一次性获取完整数据。方便简单,但是数据量大时会有等待时常,也可能内存溢出。

java 复制代码
package com.rainbowsea.yupao.one;


import com.alibaba.excel.EasyExcel;

import java.util.List;

/**
 * 导入 Excel
 *
 */
public class ImportExcel {

    /**
     * 读取数据
     */
    public static void main(String[] args) {
        // todo 记得改为自己的测试文件
        String fileName = "E:\\Java\\project\\鱼皮星球项目\\伙伴匹配系统\\yupao\\yupao-backend\\src\\main\\resources\\testExcel.xlsx";
        
        synchronousRead(fileName);
    }



    /**
     * 同步读
     *
     * @param fileName
     */
    public static void synchronousRead(String fileName) {
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish
        List<DemoExcelData> totalDataList =
                EasyExcel.read(fileName).head(DemoExcelData.class).sheet().doReadSync();
        for (DemoExcelData xingQiuTableUserInfo : totalDataList) {
            System.out.println(xingQiuTableUserInfo);
        }
    }

  


}

**技巧:**读取 Excel 当前的数据,进行一个过滤,提交操作

java 复制代码
package com.yupi.yupao.once.importuser;

import com.alibaba.excel.EasyExcel;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 导入星球用户到数据库
 *
 * @author <a href="https://github.com/liyupi">程序员鱼皮</a>
 * @from <a href="https://yupi.icu">编程导航知识星球</a>
 */
public class ImportXingQiuUser {

    public static void main(String[] args) {
        // todo 记得改为自己的测试文件
        String fileName = "E:\\星球项目\\yupao-backend\\src\\main\\resources\\prodExcel.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 同步读取会自动finish
        List<XingQiuTableUserInfo> userInfoList =
                EasyExcel.read(fileName).head(XingQiuTableUserInfo.class).sheet().doReadSync();
        System.out.println("总数 = " + userInfoList.size());
        Map<String, List<XingQiuTableUserInfo>> listMap =
                userInfoList.stream()
                        .filter(userInfo -> StringUtils.isNotEmpty(userInfo.getUsername()))
                        .collect(Collectors.groupingBy(XingQiuTableUserInfo::getUsername));
        for (Map.Entry<String, List<XingQiuTableUserInfo>> stringListEntry : listMap.entrySet()) {
            if (stringListEntry.getValue().size() > 1) {
                System.out.println("username = " + stringListEntry.getKey());
                System.out.println("1");
            }
        }
        System.out.println("不重复昵称数 = " + listMap.keySet().size());
    }
}

关于 Easy Excel 的写入到 Excel 的操作,大家可以参考官方文档: easyexcel.opensource.alibaba.com/docs/curren...

前端页面跳转传值

  1. query => url serachParams ,url 后附加参数,传递的值长度有限。
  2. vuex(全局状态管理),eg:搜索页将关键词塞到状态中,搜索结果页从状态取值。

banner.txt 广告位

只需要在 resource根目录下创建一个: banner.txt 文件即可

文件当中输入/填写你所想要让你的项目启动的时候的一些提示信息即可。

这样其他人沿用了你的项目,启动该项目的时候,则会看到你的这个广告信息。

latex 复制代码
用户中心------> RainbowSea CSDN 博客地址: rainbowsea.blog.csdn.net

后端接受前端值时出现的问题:

问题:我们需要将前端的传值的格式修改一下,修改为一个可以被后端识别为一个字符串的值。

**这里使用 ****axios-js****的一个前端库,进行解决 **

axios-js 官网地址:www.axios-http.cn/docs/intro

bash 复制代码
yarn add axios

@CrossOrigin 后端跨域,允许任何请求都同意

一般都是后端处理跨域问题的,更加灵活。后端统一防守。只能防前端,不能防止后端

java 复制代码
@CrossOrigin(origins="localhost:8080")

改造用户中心,把单机登录改为分布式 Session 登录

还有一种方式就是:使用 Tociket 。但是 Tociket 过期时间不是那么容易简单控制的(需要额外配置,但是更加灵活)

Session 共享

种 Session 的时候注意范围:cookie.domain

比如两个域名:

如果要共享 cookie,可以种一个更高层的公共域名,比如:yupi.com

为什么服务器 A 登录后,请求发送到服务器 B,不认识该用户?

**思考:**为什么服务器 A 登录后,请求发到服务器 B,不认识该用户?

原因如下:

  1. 用户在 A 登录,所以 Session(用户登录信息)存在了 A 上
  2. 结果请求 B 时,B 没有用户信息,所以不认识

如图:

解决方案:共享存储,而不是把数据放到单台服务器的内存中。

Redis 基于内存的 K/V 数据库 ,此处选择 Redis,因为用户信息读取?(是否登录的判断极其频繁),Redis 基于内存,读写性能很高,简单的数据单机 qps 5w-10w

通过将打包的项目,使用java -jar .\yupao-backend-0.0.1-SNAPSHOT.jar --server.port=8081定义 8081 作为该项目的新的端口,从而启动一个新的项目上的作为一个新的服务器启动一个项目------》到达分布式服务器的一种方式。

bash 复制代码
E:\Java\project\鱼皮星球项目\伙伴匹配系统\yupao\yupao-backend\target>java -jar .\yupao-backend-0.0.1-SNAPSHOT.jar --server.port=8081

Redis Windows 安装

  1. 安装 Windows 版本的 Redis

在 application.yaml 文件配置 Redis 的相关配置:

yaml 复制代码
spring:
  # Redis 配置
  redis:
    port: 6379
    host: localhost
    database: 0
  1. 引入 redis. 能够操作 redis:尽量和你的 Spring Boot 的版本一一对应上。
xml 复制代码
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.6.4</version>
</dependency>
  1. 引入 spring-session 和 Redis 的整合,使得自动将 session 存储到 Redis 当中。同样:尽量和你的 Spring Boot 的版本一一对应上。
xml 复制代码
<!-- https://mvnrepository.com/artifact/org.springframework.session/spring-session-data-redis -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    <version>2.6.4</version>
</dependency>
  1. 修改 spring-session 存储配置,默认是在 spring.session.store-type默认是 none ,表示存储在单台服务器。
  • store-type:redis 表示从 redis 读写两个都从 Redis 来 session 。
yaml 复制代码
spring:
  session:
    timeout: 86400
    store-type: redis
yaml 复制代码
server:
  port: 8080
  servlet:
    context-path: /api
spring:
  profiles:
    active: dev
  application:
    name: yupao-backend
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  # DataSource Config
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/usercenter
    username: root
    password: MySQL123
    # session 失效时间
  session:
    timeout: 86400
    store-type: redis
  # Redis 配置
  redis:
    port: 6379
    host: localhost
    database: 0
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: isDelete # 全局逻辑删除字段名,所以项目表当中所有逻辑删除,都用这个字段名,保证全局性
      logic-delete-value: 1 # 逻辑已删除值(默认值为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认值为 0)
  configuration:
    # 取消数据库驼峰映射
    map-underscore-to-camel-case: false
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新启动两个项目,模拟分布式,测试

最后:

"在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。"

相关推荐
fouryears_234171 小时前
适配器模式——以springboot为例
java·spring boot·适配器模式
汽车功能安全啊2 小时前
利用对称算法及非对称算法实现安全启动
java·开发语言·安全
paopaokaka_luck3 小时前
基于Spring Boot+Vue的吉他社团系统设计和实现(协同过滤算法)
java·vue.js·spring boot·后端·spring
摸鱼仙人~4 小时前
Spring Boot中的this::语法糖详解
windows·spring boot·python
Warren984 小时前
Java Stream流的使用
java·开发语言·windows·spring boot·后端·python·硬件工程
架构师沉默5 小时前
Java优雅使用Spring Boot+MQTT推送与订阅
java·开发语言·spring boot
tuokuac5 小时前
MyBatis 与 Spring Boot版本匹配问题
java·spring boot·mybatis
zhysunny6 小时前
05.原型模式:从影分身术到细胞分裂的编程艺术
java·原型模式
90后的晨仔7 小时前
条件渲染:从传统原生到 Vue 的进化之路
前端·vue.js
草履虫建模7 小时前
RuoYi-Vue 项目 Docker 容器化部署 + DockerHub 上传全流程
java·前端·javascript·vue.js·spring boot·docker·dockerhub