Spring Boot与MyBatis结合 实现对mock平台改造

news2024/12/24 9:11:11

上一章: 

测开工具:spring boot 实现mock平台_springboot搭建mock_做测试的喵酱的博客-CSDN博客

代码地址:

GitHub - 18713341733/mock: Spring Boot与MyBatis结合 实现对mock平台改造

一、背景 

读取数据改为从mysql数据库中读取。

Spring Boot 版本为2.4.4 

mysql版本为8.0

二、设计

我们以前是直接读取的txt文件,现在该了直接从mysql读取。

本期改造没有使用任何设计模式,直接水流线实现 了我们的功能。

数据库数据:

 根据用户请求的uri,作为条件,去表里查询数据。当同一个uri下,有多条数据时,就要去对比请求参数的命中的权重,取一个权重最大的返回数据。

举例:

在数据中,有两条uri为/baidu/search 的数据。

uriresponse_contentparams
/baidu/search{"type":"类型一","key11":"${random:id:6}","key2":"${random:str:10}","count":3,"person":[{"id":${hook:id}},"name":"张三"},{"id":2,"name":"李四"}],"object":{"id":1,"msg":"对象里的对象"}}{"name=book":1,"classification=Language":5}
/baidu/search{"type":"类型二","key11":"${random:id:6}","key2":"${random:str:10}","count":3,"person":[{"id":${hook:id}},"name":"张三"},{"id":2,"name":"李四"}],"object":{"id":1,"msg":"对象里的对象"}}{"name=book":1,"classification=Math":4}

数据1的params 为:{"name=book":1,"classification=Language":5}

数据2的params 为:{"name=book":1,"classification=Math":4}


用户的请求为:

http://127.0.0.1:8081/baidu/search?name=book&classification=Math

数据1,命中"name=book",权重为1

数据2,命中"name=book",权重为1,命中"classification=Math",权重为4,数据2的总权重为1+4=5

5>1,所以我们取数据2的返回值进行返回。

对数据2的返回数据,再次进行加工,比如替换随机字符串等等。

三、数据初始化

1、创建为名mockserver的库

2、创建表response

3、插入几条用于演示的数据

/*
 Navicat Premium Data Transfer

 Source Server         : 本地- mysql
 Source Server Type    : MySQL
 Source Server Version : 50710
 Source Host           : localhost:3306
 Source Schema         : mockserver

 Target Server Type    : MySQL
 Target Server Version : 50710
 File Encoding         : 65001

 Date: 25/07/2023 14:32:19
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for response
-- ----------------------------
DROP TABLE IF EXISTS `response`;
CREATE TABLE `response` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uri` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `response_content` text COLLATE utf8mb4_unicode_ci,
  `params` text COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ----------------------------
-- Records of response
-- ----------------------------
BEGIN;
INSERT INTO `response` (`id`, `uri`, `response_content`, `params`) VALUES (1, '/baidu/search', '{\"type\":\"类型一\",\"key11\":\"${random:id:6}\",\"key2\":\"${random:str:10}\",\"count\":3,\"person\":[{\"id\":${hook:id}},\"name\":\"张三\"},{\"id\":2,\"name\":\"李四\"}],\"object\":{\"id\":1,\"msg\":\"对象里的对象\"}}', '{\"name=book\":1,\"classification=Language\":5}');
INSERT INTO `response` (`id`, `uri`, `response_content`, `params`) VALUES (2, '/baidu/search', '{\"type\":\"类型二\",\"key11\":\"${random:id:6}\",\"key2\":\"${random:str:10}\",\"count\":3,\"person\":[{\"id\":${hook:id}},\"name\":\"张三\"},{\"id\":2,\"name\":\"李四\"}],\"object\":{\"id\":1,\"msg\":\"对象里的对象\"}}', '{\"name=book\":1,\"classification=Math\":4}');
INSERT INTO `response` (`id`, `uri`, `response_content`, `params`) VALUES (3, '/sougou/search', '{\"type\":\"sougou_3\",\"key11\":\"${random:id:6}\",\"key2\":\"${random:str:10}\",\"count\":3,\"person\":[{\"id\":${hook:id}},\"name\":\"张三\"},{\"id\":2,\"name\":\"李四\"}],\"object\":{\"id\":1,\"msg\":\"对象里的对象\"}}', '{\"name=sougou\":2,\"classification=Math\":4}');
INSERT INTO `response` (`id`, `uri`, `response_content`, `params`) VALUES (4, '/sougou/search', '{\"type\":\"sougou_4\",\"key11\":\"${random:id:6}\",\"key2\":\"${random:str:10}\",\"count\":3,\"person\":[{\"id\":${hook:id}},\"name\":\"张三\"},{\"id\":2,\"name\":\"李四\"}],\"object\":{\"id\":1,\"msg\":\"对象里的对象\"}}', '{\"name=sougou\":2,\"classification=Language\":5}');
COMMIT;


四、应用MyBatis

4.1 依赖

  1. 在Spring Boot项目中添加所需的依赖。在你的项目的pom.xml文件中,添加以下依赖关系:
<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
<dependency>

4.2  配置数据库连接

配置数据库连接。在application.propertiesapplication.yml文件中配置你的数据库连接信息,例如:

application.properties:

spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=dbuser
spring.datasource.password=dbpassword

application.yml:

server:
  port: 8081

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mockserver?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

创建MyBatis映射器接口和对应的SQL映射文件。在你的包结构中创建一个映射器接口,并为该接口定义需要执行的数据库操作。同时,在resources目录下创建与映射器接口相对应的XML文件,存放SQL语句和查询逻辑。

在Spring Boot主类中添加@MapperScan注解。在你的Spring Boot主类上添加@MapperScan注解,指定包路径以扫描MyBatis映射器接口。

4.3 实例层entity

存放的是我们需要的实例。

MockOnlyResponse  对应数据库中的response表中的数据 

我们还在这个类中,提供了读取数据的方法。

package com.example.mockserver.entity;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.HashMap;
import java.util.Map;


@Data
@NoArgsConstructor
public class MockOnlyResponse {
    private String response_content;
    private String params;

    public MockOnlyResponse(String response_content,String params) {
        this.response_content = response_content;
        this.params = params;
    }

    public Map<String, Integer> getMapParams() {
        // 将接口拿到的数据库中的请求体,设置为字典
        return getMap(this.params);

    }

    // 将字符串直接转成字典
    public Map<String, Integer> getMap(String jsonString) {
//        String jsonString = "{\"name=book\":1,\"classification=Language\":5}";

        try {
            ObjectMapper objectMapper = new ObjectMapper();
            Map<String, Integer> dictionary = objectMapper.readValue(jsonString, Map.class);

            return dictionary;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;

    }

}

4.4  mybatis的mapper层

接口:

OnlyResponseMapper

package com.example.mockserver.mapper;


import com.example.mockserver.entity.MockOnlyResponse;
import org.springframework.stereotype.Repository;
import java.util.List;

import org.apache.ibatis.annotations.Select;


@Repository
public interface OnlyResponseMapper {
    @Select("select r.response_content,r.params from response r where uri = #{uri}")
    List<MockOnlyResponse> findByUri(String uri);
}

执行sql,通过uri 查询数据

4.5  spring boot service 层

service接口,OnlyResponseService

package com.example.mockserver.service;

import com.example.mockserver.entity.MockOnlyResponse;



import java.util.List;

public interface OnlyResponseService {
    List<MockOnlyResponse> findByUri(String uri);
}

service实现类,ResponseServiceImpl

package com.example.mockserver.service.imp;
import com.example.mockserver.entity.MockOnlyResponse;
import com.example.mockserver.mapper.OnlyResponseMapper;
import com.example.mockserver.service.OnlyResponseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ResponseServiceImpl implements OnlyResponseService {

    @Autowired
    private OnlyResponseMapper onlyMapper;

    @Override
    public List<MockOnlyResponse> findByUri(String uri) {
        return onlyMapper.findByUri(uri);
    }

}

我们在spring boot service 实现类中,注入了mybatis 的 mapper接口。

4.6 controller层

ResponseController

package com.example.mockserver.controller;
import com.example.mockserver.entity.MockOnlyResponse;
import com.example.mockserver.service.OnlyResponseService;
import com.example.mockserver.util.ArrayUtil;
import com.example.mockserver.util.ReplaceRandomUtil;
import lombok.extern.slf4j.Slf4j;

import com.example.mockserver.model.MockContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@Slf4j
public class ResponseController {
    @Autowired
    private OnlyResponseService onlyResponseService;

    @Autowired
    private HttpServletRequest request;


    @RequestMapping("/**")
    public String doMock() throws IOException {

        log.info("请求的URI---------:"+request.getRequestURI());
        log.info("请求IP---------:"+request.getRemoteAddr());
        log.info("请求的参数---------:"+request.getParameterMap());


        // 将获取的用户数据 ip 参数 URI ,存储到 mockContext 这个类里
        MockContext mockContext = MockContext.builder()
                .requestIp(request.getRemoteAddr()) // 获取ip
                .requestParams(getParams(request.getParameterMap()))
                .requestURI(request.getRequestURI()) // 获取请求的URI
                .build();

        // [name=zhangsan, classification=Language]
        List<String> userParamStringList = mockContext.getParamStringList();
        Integer totalNum = 0;
        String response = "";
        System.out.println(userParamStringList);



        // 开始遍历
        List<MockOnlyResponse> mockOnlyResponseList = onlyResponseService.findByUri(mockContext.getRequestURI());
        System.out.println(mockOnlyResponseList);
        for (MockOnlyResponse mockOnlyResponse : mockOnlyResponseList) {
            Integer num = 0;
            for(String str:userParamStringList){
                // 字典
                Map<String, Integer> mapParams = mockOnlyResponse.getMapParams();
                if (mapParams.containsKey(str)) {
                    num += mapParams.get(str);
                }
            }
            if(num>totalNum){
                totalNum = num;
                response = mockOnlyResponse.getResponse_content();
            }
        }
        // 随机数字/字符串处理
        response = ReplaceRandomUtil.replaceRandomFields(response);
        return response;

    }

    // 获取用户的传参,value是一个数组。这里为了将来处理方便,我们将这数组转成一个字符串。
    // 我们默认,这个数据的长度是1,那我们只需要取出来数组的第一个值就可以了。
    public Map<String,String> getParams(Map<String,String[]> parameterMap){
        Map<String,String> params = parameterMap.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> ArrayUtil.getFirst(e.getValue())));
        return params;

    }
}

4.7  应用启动层MockServerApplication

package com.example.mockserver;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
@MapperScan(basePackages = "com.example.mockserver.mapper")
public class MockServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(MockServerApplication.class, args);
    }

}


我们需要在项目启动层,增加mapper的扫描。

相对于单纯的mybatis 使用,spring boot 应用mybatis 缺少了mybatis 的总配置文件。

这里填写包名。@MapperScan(basePackages = 

五、对数据处理

数据的处理逻辑,主要都在ResponseController 中,我们暂时没有把它封装出来。

逻辑:

1、获取用户的请求 uri 与请求体

2、将用户的请求体转换为Map

3、根据请求uri,去数据库捞取数据,返回值是一个List

4、对List遍历,取权重最大的返回值的数据

5、对得到的数据进行加工,处理随机字符串等等。

六、演示

七、相关文章

spring boot 应用mybatis_springboot mybatis debug_做测试的喵酱的博客-CSDN博客


                

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/788135.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RDIFramework.NET CS敏捷开发框架 V6.0发布(支持.NET6+、Framework双引擎,全网唯一)

全新RDIFramework.NET V6.0 CS敏捷开发框架发布&#xff0c;全网唯一支持.NET6&#xff0c;Framework双引擎&#xff0c;降低开发成本&#xff0c;提高产品质量&#xff0c;提升用户体验与开发团队稳定性&#xff0c;做软件就选RDIFramework.NET开发框架。 1、RDIFramework.NET…

主从复制高级进阶

从主库入手&#xff1a; 关闭 主&#xff1a;修改配置文件 /etc/my.cnf 查看日志 查看 从&#xff1a; 修改重启 重启后报错&#xff0c;可能是uuid相同&#xff0c;要修改 查看状态 都是yes 从 从库入手 修改配置文件重启 从3&#xff1a; 从2&#xff1a; 先停止slave …

redis中使用bloomfilter的白名单功能解决缓存预热问题

一 缓存预热 1.1 缓存预热 将需要的数据提前缓存到缓存redis中&#xff0c;可以在服务启动时候&#xff0c;或者在使用前一天完成数据的同步等操作。保证后续能够正常使用。 1.2 解决办法PostConstruct注解初始化

微服务框架入门

微服务 微服务是一种经过良好架构设计的分布式架构方案&#xff0c;微服务架构特征&#xff1a; 单一职责&#xff1a;微服务拆分粒度小&#xff0c;每一个服务都对应唯一的业务能力&#xff0c;做到单一职责&#xff0c;避免重复业务开发面向服务&#xff1a;微服务对外暴露…

闲置旧手机搭建服务器?在安卓手机上使用Termux搭建web服务「公网远程访问」

文章目录 概述1.搭建apache2.安装cpolar内网穿透3.公网访问配置4.固定公网地址5.添加站点 概述 Termux是一个Android终端仿真应用程序&#xff0c;用于在 Android 手机上搭建一个完整的Linux 环境&#xff0c;能够实现Linux下的许多基本操作&#xff0c;不需要root权限Termux就…

MobileViG实战:使用MobileViG实现图像分类任务(一)

文章目录 摘要安装包安装timm安装 grad-cam 数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集 摘要 论文翻译&#xff1a;https://blog.csdn.net/m0_47867638/article/details/131860981?spm1001.2014.3001.5502 官方源码&#xff1a;https://github.com/SLDGroup/M…

Qt Core学习日记——第四天QMetaEnum(下)

类定义&#xff1a; 成员变量就只有QMetaObject *mobj和uint handle&#xff0c;handle同样用于计算在qt_meta_stringdata_XTest的位置 成员函数&#xff1a; 接下以test类进行函数讲解 test.h #pragma once #include <qobject.h> #include <QFlags> class X…

源码跟踪,案例详解Spark的分区规则

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 目录 一、默认分区规则 1. 从集合中创建RDD - makeRDD   2. 读取外部存储系统创建RDD - textFile 二、指定分区规则 1. 从集合中创建RDD指定分区 - makeRDD   2. 读取外部存储系统创建RDD指定分…

基于Java+SpringBoot+vue前后端分离甘肃非物质文化网站设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

TCP/UDP的首部

TCP/UDP首部信息 TCP首部第一个4字节第二个4字节与第三个4字节第四个4字节第五个4字节选项最大报文段长度&#xff08;MSS&#xff09;选项窗口扩大选项时间戳选项 什么时候发送RST包UDP首部 TCP首部 TCP 首部长度为20字节&#xff0c;加上选项部分最大可达60字节。 第一个4…

移动端商品详情页设计

效果图 代码如下 页面设计 <div class"container"><!--商品详情 start--><van-image class"goods-item-image" :src"goods.goodsHeadImg"></van-image><div class"goods-price">&#xffe5;<span&…

MySQL函数讲解(谓词、CASE)

目录 MySQL常见函数 字符串函数 进行字符串操作的函数 算术函数 进行数值计算的函数 日期函数 进行日期操作的函数 转换函数 进行数据类型和值转换的函数 流程函数 进行条件删选 聚合函数 进行数据聚合的函数 谓词 一般用于条件判断 什么是函数 函数指一段可以直接被…

web前端tips:js继承——原型链继承

原型链继承 原型链继承是 JavaScript 中实现继承的一种方式&#xff0c;它通过使用原型来实现对象之间的继承关系。 在 JavaScript 中&#xff0c;每个对象都有一个原型&#xff08;prototype&#xff09;&#xff0c;它是一个指向另一个对象的引用。当我们访问一个对象的属性…

Quartz线程调度源码分析

Quartz作为任务调度的组件&#xff0c;其中涉及到多种线程&#xff0c;主要分为主线程、调度线程和工作线程。 主线程&#xff1a;创建Quartz的调度工厂(SchedulerFactory)、调度器(Scheduler)、触发器(Trigger)、任务&#xff08;Job&#xff09;并启动调度器的线程。这里的主…

Pytest结合数据驱动-yaml

Pytest 结合数据驱动 YAML 数据驱动 什么是数据驱动&#xff1f; 数据驱动就是数据的改变从而驱动自动化测试的执行&#xff0c;最终引起测试结果的改变。简单来说&#xff0c;就是参数化的应用。数据量小的测试用例可以使用代码的参数化来实现数据驱动&#xff0c;数据量大的…

Ceph社区上游正式合入openEuler原生支持,并通过CI持续验证

作为覆盖全场景应用、支持多样性算力的面向数字基础设施的开源操作系统&#xff0c;openEuler始终遵循“上游优先”的策略&#xff0c;帮助上游开源软件原生支持openEuler&#xff0c;让openEuler系操作系统的用户可以在开发、集成、使用这些开源软件或基于这些开源软件的产品和…

比较版本号(力扣)思维 JAVA

给你两个版本号 version1 和 version2 &#xff0c;请你比较它们。 版本号由一个或多个修订号组成&#xff0c;各修订号由一个 ‘.’ 连接。每个修订号由 多位数字 组成&#xff0c;可能包含 前导零。每个版本号至少包含一个字符。修订号从左到右编号&#xff0c;下标从 0 开始…

vue3+ts+elementui-plus二次封装树形表格

复制粘贴即可&#xff1a; 一、定义table组件 <template><div classmain><div><el-table ref"multipleTableRef" :height"height" :default-expand-all"isExpend" :data"treeTableData"style"width: 100%…

IL汇编字符串连接

在此实现了一个基本的IL汇编程序&#xff1b; 了解MSIL汇编和IL汇编评估堆栈_bcbobo21cn的博客-CSDN博客 它用了下面两句来在屏幕输出字符串&#xff0c; ldstr "I am from the IL Assembly Language..." call void [mscorlib]System.Console::WriteLine (string) …

Ros终端出现找不到bash: /home/***/devel/setup.bash: 没有那个文件或目录

现象&#xff1a;Ros终端出现找不到bash: /home/***/devel/setup.bash: 没有那个文件或目录 问题&#xff1a;配置时路径写错 解决方法&#xff1a;改正路径 1.打开文件 gedit ~/.bashrc2.修改正确路径