【总】前端 Swagger url 自动转 JavaScript方法(避免重复工作...)

news2024/11/15 13:51:31

前言

随着项目增多,且多数为项目定制化接口。避免前端重复封装,从 Swagger 入手,将 url 自动转 js 方法直接用。特别节约时间和资源~

Swagger 简介

Swagger 一款 RESTFUL 接口的、基于 YAML、JSON 语言的文档在线自动生成、代码自动生成的工具。

主要工具:

  • Swagger 编辑器 :基于浏览器的编辑器,可以在其中编写 OpenAPI 规范,并实时预览 API 文档。

  • Swagger UI :将 OpenAPI 规范呈现为交互式 API 文档,并可以在浏览器中尝试 API 调用。

  • Swagger Codegen :根据 OpenAPI 规范,生成服务器存根和客户端代码库。

实现

目录结构

.
├─ js
|   ├─MySwagger.js         # 主文件,1.url转js接口;2.接口查询界面解析接口;
|   └─ swagger             
|       ├─ axios.js	    # axios 对象及 包装后的 get,post,put,delete 等方法
|       └─ utils.js     # 工具文件,导入 axios.js,设置外部传入的 axios,url 解析为js方法名,定义 promise 等
└─ components
 	└─MySwaggerApi.vue # 组件,转换后的文件查看

主文件说明

MySwagger.js 中有两类方法

  • initSwaggerApi :用于生成 Js 接口;
  • initSwaggerDoc :用于界面显示接口信息;

文件 swagger/axios.js 和 swagger/utils.js 将在最后贴出

import Utils from "./swagger/utils"
import axios from "axios"

// 请求法类型
const REQUEST_METHODS = [ 'get', 'post', 'put', 'delete', 'patch'];


export default class MySwagger {
    /**
     * 初始化 Swagger Javascript Api 接口
     * @param {Object} axios,axios对象,注意已带 token
     * @param {Object} cfg,swagger 相关信息 {ignorePaths, jsonUrl, ignorePaths}
     * @param {Function} callback 回调函数
     * @returns 
     */
    static initSwaggerApi(myaxios, cfg, callback) {
        // swagger/axios.js 文件中的方法,设置外部传入的 axios 对象
        Utils.setHttp(myaxios);
        // 解析 swagger json 对象
        axios.get(cfg.jsonUrl).then(res => {
            // paths 列表
            const paths = res.data.paths;

            for(const path in paths) {
                const methods = paths[path];

                for(const method in methods) {
                    if(!REQUEST_METHODS.includes(method)) {
                        continue;
                    }
                    // swagger/axios.js 文件中的方法,url 转换为 js 方法名
                    const apiMethodName = Utils.restUrlToMethodName(method, path, cfg.ignorePaths);

                    // 注意是 this,直接放在 类上,为静态方法。api 方法对象集合
                    this[apiMethodName] = function(odt, odt2, odt3) {
                        // swagger/axios.js 文件中的方法,定义 promise
                        return Utils.definePromise(path, method, odt, odt2, odt3)
                    };
                }
            }
            callback(true)
            console.log('Swagger API 自动转js方法成功!');
        }).catch(err => {
            callback(false)
            console.error('Swagger API 自动转js方法失败', err);
        })
    }
    
    /**
     * 初始化 Swagger Javascript Api 文档信息
     * @param {Object}   cfg swagger 相关信息 {jsonUrl, ignorePaths}
     * @param {Function} callback 成功回调 (data) 信息
     * @param {Function} errorback 失败回调 (e) 错误信息
     * @returns 
     */
    static initSwaggerDoc(cfg, callback, errorback) {
        let objs = {}
        // 解析 swagger json 对象
        axios.get(cfg.jsonUrl).then(res => {
            const data = res.data;
            // 判断 swagger 版本
            const version = (data.swagger || data.openapi).split('.')[0];
            // paths 列表
            const paths = data.paths;
			// swagger v2
            if(version==='2') { 
                for(const path in paths) {
                    const methods = paths[path];

                    for(const method in methods) {
                        // get/post 对象下
                        if(!REQUEST_METHODS.includes(method)) {
                            continue;
                        }
                        // swagger/axios.js 文件中的方法,url 转换为 js 方法名
                        const apiMethodName = Utils.restUrlToMethodName(method, path, cfg.ignorePaths);
                        const params = methods[method];
                        
                        const tag = params.tags[0];
                        if(!objs[tag]) {
                            objs[tag] = {
                                tag,
                                description: tag,
                                paths: []
                            }
                        }
                        objs[tag].paths.push({
                            path,
                            apiMethodName,
                            method,
                            summary: params.summary,// 接口描述
                            parameters: params.parameters,// 请求参数
                            version
                        })    
                    }
                }
            }
            else {// swagger v3,配置管理
                // 先解析 tag
                data.tags.forEach(t => {
                    objs[t.name] = {
                        tag: t.name,
                        description: `${t.name} ${t.description}`,
                        paths: []
                    }
                });
                // console.log('objs: ', objs);
                for(const path in paths) {
                    const methods = paths[path];

                    for(const method in methods) {
                        // get/post 对象下
                        if(!REQUEST_METHODS.includes(method)) {
                            continue;
                        }
                        // swagger/axios.js 文件中的方法,url 转换为 js 方法名
                        const apiMethodName = Utils.restUrlToMethodName(method, path, cfg.ignorePaths);
                        const params = methods[method];
                        
                        const tag = params.tags[0];
                        // console.log('objs[tag]', objs[tag], tag);
                        
                        // 要判断,有的 tags 与 path 不一致
                        objs[tag]?.paths.push({
                            path,
                            apiMethodName,
                            method,
                            summary: params.summary,// 接口描述
                            parameters: params.parameters,// 请求参数
                            version
                        })                
                    }
                }
            }
            callback(objs)
        }).catch(e => {
            errorback(e)
        })
    }    
}

功能使用

Swagger 解析配置

const SWAGGER_CFG = {
    // 过滤不必要的路径
    ignorePaths: ['v1/', 'myweb/'],
    // swagger json 文件
    jsonUrl: 'http://127.0.0.1:8000/swagger/v1/swagger.json',
    // swagger 接口文件地址
    docUrl: 'http://127.0.0.1:8000/swagger/index.html'
}
生成 Js 接口
  • 代码第 13 - 20 行,创建 axios 对象,外部传入更灵活,可设置 token 等信息;
  • 代码第 13 - 20 行,初始化 js 接口到 MySwagger 类上;
<template>
    <div>
        <h1>swagger测试</h1>
    </div>
</template>

<script>
import axios from 'axios'
import MySwagger from '../js/index'
export default {
    mounted() {
        // 外部传入更灵活,可设置 token 等信息
        const myAxios = axios.create({
            // 基地址
            baseURL: `${window.location.protocol}//${IP}:${PORT}/`,
            // 请求头带 token
            headers:{ 
                'Authorization': '111ssss22s2s2s2s2s2s22s22' 
            }
        })

        // 初始化 js 接口到 MySwagger 类上
        MySwagger 对象上.initSwaggerApi(myAxios, SWAGGER_CFG, (data) => {
            console.log(`初始化成功:${data}`);
        }, (err) => {
            console.log(`初始化失败:${err}`);
       })

       window.MySwagger = MySwagger;
    }
}
</script>

为方便查看 MySwagger 挂在 window。但不推荐…控制台输出可看到接口都挂到类上

在这里插入图片描述

接口界面
  • 封装成组件 Vue <MySwaggerApi>
  • 代码第 4 行,可打开原始 Swagger 接口地址;
  • 代码第 78 - 98 行,可复制接口;
  • 代码第 104 - 111 行,调接口 MySwagger.initSwaggerDoc 获取列表;
<template>
    <div class="my-swagger-api__main">
        <div class="header">
            <el-link icon="el-icon-view" @click="openLink">Swagger 接口地址</el-link>
            <el-input v-model="searchKey" placeholder="路径搜索" @input="searchPath">
                <el-button icon="el-icon-search" ></el-button>
            </el-input>
        </div>
        <div class="main">
            <div class="row" v-for="item of tableData" :key="item.tag">
                <div class="first-title">{{item.description}}</div>
                <el-table class="api-list-table" :data="item.paths" border style="width: 100%" :row-class-name="tableRowClassName" @cell-click="onCopyText" >
                    <el-table-column type="expand" @click="copyHandle( 'icon-' + item.font_class)">
                        <template #default="props">
                            <el-form label-position="left" inline class="demo-table-expand">
                                <el-form-item label="请求方法:">
                                    <el-tag size="medium" :type="tagTypes[props.row.method]">
                                        {{ props.row.method }}
                                    </el-tag>
                                </el-form-item>
                                <el-form-item label="JS方法名:" >
                                    <el-tag size="mini" type="info">{{ props.row.apiMethodName }}</el-tag>
                                    <span></span>
                                </el-form-item>
                                <el-form-item label="描述:">
                                    <span>{{ props.row.summary }}</span>
                                </el-form-item>
                            </el-form>
                        </template>
                    </el-table-column>

                    <el-table-column prop="path" label="路径"> </el-table-column>
                    <el-table-column prop="apiMethodName" label="JS方法名" class-name="api-method-name-cell"> </el-table-column>
                    <el-table-column prop="summary" label="描述"> </el-table-column>
                </el-table>
            </div>
        </div>
    </div>
</template>

<script>
import MySwagger from '../js/MySwagger'
export default {
    props: {
        config: {
            type: Object,
            default() {
                return {
                    // ignorePaths: ['v1/'],
                    // jsonUrl: 'http://127.0.0.1:7008/swagger/v1/swagger.json',// 解析的 json 路径
                    // docUrl: 'http://127.0.0.1:7008/swagger/index.html' // 官方接口列表
                }
            }
        }
    },
    data() {
        return {
            tableData: {},//API_LIST,
            tagTypes: {
                post: 'success',
                get: '',
                put:'info',
                delete: 'danger',
                patch: 'warning'
            },
            searchKey: '',
        }
    },
    methods: {
        tableRowClassName({ row, rowIndex }) {
            // return `${row.method}-row`;
        },
        // 打开
        openLink() {
            window.open(this.config.docUrl, '_blank')
        },
        // 拷贝
        onCopyText(row, column, cell, event) {
            console.log(row, column, cell, event);
            if(column.property!=='apiMethodName') {
                return
            }
            // 获取输入框的内容
            const copyText = row.apiMethodName; 
            
            let copy = (e) => {
                e.preventDefault()
                e.clipboardData.setData('text/plain', copyText)
                // 提示用户复制成功
                this.$message({
                    type: 'success',
                    message: `${column.label} 复制成功`
                })
                document.removeEventListener('copy', copy)
            }
            document.addEventListener('copy', copy)
            document.execCommand('copy')
        },
        // 查询
        searchPath(val) {
            console.log(this.searchKey, val);
        }
    },
    mounted() {
        // 初始化
        MySwagger.initSwaggerDoc(this.config, (data=>{
            this.tableData = data;
            console.log('this.tableData',this.tableData);
        }),(e)=>{
            console.error('获取错误',e);
        });
    },
};
</script>

<style lang="scss" scoped>
.my-swagger-api__main {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow: hidden;
    .header {
        padding: 50px 50px 20px 50px;
        display: flex;
        justify-content: space-between;
        width: 100%;
        .el-input {
            width: 350px;    
        }    
    }
}
.main {
    position: absolute;
    top: 100px;
    left: 50px;
    right: 50px;
    bottom: 50px;
    overflow: auto;
    .row {
        margin-bottom: 20px;
    }
}
.first-title {
    font-size: 17px;
    font-weight: 600;
    height: 45px;
    line-height: 45px;
    padding-left: 5px;
    border-left: 4px solid #0d64d4;
    color: #333;
    background:#f0f8ff;
}
.demo-table-expand {
    margin-left: 50px;
    background:#fafdff;

    :deep(.el-form-item) {
        display: block;
        .el-form-item__label {
            width: 90px;
        }
    }
}
.api-list-table {
    :deep(.api-method-name-cell) {
        cursor: pointer;
    }
}

</style>
<style lang="scss">

.get-row {
    background: rgba(97, 175, 254, .5) !important;
}
.post-row {
    background: rgba(73, 204, 144, .5) !important;
}
</style>

界面组件的使用

<template>
    <my-swagger-api :config="config"/>
</template>

<script>
import MySwaggerApi from '../components/MySwaggerApi.vue';
export default {
    components: {
        MySwaggerApi
    },
    data() {
        return {
            config: SWAGGER_CFG
        }
    }
}
</script>

效果

在这里插入图片描述

使用

此处只列出特殊的。

Post

{urlParams}
  • Post 方式,同时存在 Parameters 和 RequestBody
  • 第一个参数:对象类型,RequestBody。如果没参数,就传 null;
  • 第二个参数,对象类型,Parameters。注意 key 与下图一致;
// 第一个参数 RequestBody
const requestBody = { 
    ip: '127.0.0.1',
    port: '6163'
};

// 第二个参数 Parameters
const parameters = {
    dataSourceName: 'pg123'
};
MySwagger.postConfSpatDatasourceEdit(requestBody, parameters);

在这里插入图片描述

url + Params
/v1/gms/conf/set-default-slice-cache-db
  • Post 方式,同时存在 Parameters 和 RequestBody
  • 第一个参数:对象类型,RequestBody。如果没参数,就传 null;
  • 第二个参数,对象类型,Parameters。注意 key 与下图一致;
// 第二个参数 Parameters
const parameters = {
    id: 'pg123'
};
MySwagger.postConfSetDefaultSliceCacheDb(null, parameters).then(res=>{
   console.log(res);             
}).catch(err => {
	console.log(err);
})

在这里插入图片描述

Get

{urlParams}
  • Get 方式,在 URL 上赋值参数
  • 第一个参数,对象类型,Parameters。注意 key 与下图一致;
// 第一个参数是对象类型,且 key 与下图一致
const parameters = {
    dataSourceName: 'pg123'
}

// 请求
MySwagger.getConfSpatDatasourceInfo(parameters).then(res=>{
    console.log(res);
}).catch(err => {
    console.error(err);
})

在这里插入图片描述

url + Params
/v1/gms/conf/spat/gdb-list
  • Get 方式,在 URL 上赋值参数
  • 第一个参数,对象类型,Parameters。注意 key 与下图一致;
// 第一个参数是对象类型,且 key 与下图一致
const parameters = {
    gdbp: 'pg123'
}

MySwagger.getConfSpatGdbList(parameters).then(res=>{
    console.log(res);
}).catch(err => {
    console.log(err);
})

在这里插入图片描述

最后

swagger/axios.js

// 导入封装好的axios实例
let service;

export default {
    
    // axios实例,外部传入,用于外部设置 token
    setHttp(axios) {
        service = axios;
    },

    /**
     * get 请求
     * @param {String} url     必填,请求地址 
     * @param {Object} params  选填,与请求一起发送的 url 参数
     * @param {Object} options 选填,其它配置参数
     */
    get(url, params, options = {}) {
        // 是否解析带参数的url
        url = parseParamsUrl(url, params);
        // 参数
        const config = {
            method: 'get',
            url: encodeURI(url)
        }
        // 是否有 params
        if (params) config.params = params
        // 其它参数
        for (let key in options) {
            config[key] = options[key]
        }
        // console.log('get',config);
        return service(config)
    },
    /**
     * post 请求
     * @param {String} url     必填,请求地址 
     * @param {Object} data    选填,请求主体数据
     * @param {Object} params  选填,与请求一起发送的 url 参数
     * @param {Object} options 选填,其它配置参数
     */
    post(url, data, params, options = {}) {
        // 是否解析带参数的url
        url = parseParamsUrl(url, params);
        // 参数
        const config = {
            method: 'post',
            url: encodeURI(url)
        }
        // 是否有 params
        if (params) config.params = params
        // 是否有 data
        if (data) config.data = data
        // 其它参数
        for (let key in options) {
            config[key] = options[key]
        }

        // console.log('post',config);
        return service(config)
    },
    put(url, params) {
        const config = {
            method: 'put',
            url: encodeURI(url)
        }
        if (params) config.params = params
        return service(config)
    },
    delete(url, params) {
        const config = {
            method: 'delete',
            url: encodeURI(url)
        }
        if (params) config.params = params
        return service(config)
    }
}


/**
 * 解析 url 带参数
 * @param {String} url     必填,请求地址 
 * @param {Object} params  选填,与请求一起发送的 url 参数
 */
function parseParamsUrl(url, params) {
    if(params && Object.keys(params) && Object.keys(params).length > 0) {
        Object.keys(params).forEach(key => {
            // 对应的参数
            const reg = `{${key}}`;
            if(url.indexOf(reg) > -1) {
                url = url.replace(reg, params[key])
                
            }
        })
    }
    // console.log('url2', url);
    return url;
}

swagger/utils.js

import http from "./axios.js"

export default {
    
    // axios实例,外部传入,用于外部设置 token
    setHttp(axios) {
        http.setHttp(axios)
    },

    /**
     * url 转方法名
     * @param {*} method:get, post, put, delete, patch
     * @param {*} url
     * @returns 
     */
    restUrlToMethodName(method, url, ignorePaths) { 
        // 把 -或者 . 也换成 /
        url = url.replace(/-|\./g, '/');
        // 去除不要的
        ignorePaths.forEach(p=>{
            url = url.replace(p, '');
        })
        // 移除路径中的斜杠和参数占位符  
        const paths = url.split('/');
        const methodName = paths.reduce((x,y)=>{
            // 去掉 {},首字符大写
            const part = y.replace(/\{.*?\}/g, '');
            // 首字符大写
            const part2 = part.charAt(0).toUpperCase() + part.slice(1);
            return x + part2;
        }, '') 
        
        return method + methodName;  
    },
    /**
     * 定义 promise
     * @param {String} url
     * @param {String} method:get, post, put, delete, patch
     * @param {Object} odt,如果方法是 get,此参数为 params。如果是 post,为 RequestBody
     * @param {Object} odt2,如果方法是 get,此参数为 options。如果是 post,为 params
     * @param {Object} odt3,如果方法是 post,为 params
     * @returns 
     */
    definePromise(url, method, odt, odt2, odt3) {
        let promise;
        switch(method) {
            case 'get': {
                promise = new Promise(function(resolve, reject) {
                    http.get(url, odt, odt2).then(function(resp) {
                        const d = resp.data;
                        (d && d.succ) ? resolve(d.obj||d): reject(d);
                    }).catch(e=>{
                        reject(e)
                    })
                })
                break;
            }
            case 'post': {
                promise = new Promise(function(resolve, reject) {
                    http.post(url, odt, odt2, odt3).then(function(resp) {
                        const d = resp.data;
                        (d && d.succ) ? resolve(d): reject(d);
                    })
                })
                break;
            }
        }
        return promise;
    },



}

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

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

相关文章

Metasploit——强大的渗透测试框架

一、引言 在网络安全领域&#xff0c;渗透测试是评估系统安全性的重要手段。而 Metasploit 作为一款知名的渗透测试框架&#xff0c;为安全研究人员和测试人员提供了强大的工具和资源。本文将详细介绍 Metasploit 的特点、功能、使用方法以及在实际场景中的应用。 二、Metasp…

cad文字转arcgis注记

cad中文字转为arcgis注记&#xff0c;步骤如下&#xff1a; 1、将dwg文件下annotation文件加到图层中 2、文件点击右键&#xff0c;转换地理数据库注记 3、 导入默认地理数据库中&#xff0c;或自己新建地理数据库&#xff0c;起个文件名、点确定&#xff08;注意&#xff1a…

Codeforces Round 916 (Div. 3) D 题 Three Activities

题目描述 Winter holidays are coming up. They are going to last for nn days. During the holidays, Monocarp wants to try all of these activities exactly once with his friends: go skiing;watch a movie in a cinema;play board games. Monocarp knows that, on …

Mysql主从脚本

注意&#xff1a;先执行从服务器的脚本&#xff0c;再执行主服务器脚本 执行脚本时&#xff0c;务必使用source 脚本名称执行脚本 两个脚本都运行完之后 主服务器配置 从服务器配置

Machine-Learning 机器学习

目录 基本概念与分类 工作原理 应用领域 发展趋势 机器学习中的深度学习是如何工作的&#xff0c;以及它如何影响其他机器学习算法&#xff1f; 在机器学习中&#xff0c;哪些特定的数据预处理技术最有效&#xff0c;特别是在处理大规模数据集时&#xff1f; 强化学习在…

DatenLord前沿技术分享 No.40

达坦科技始终致力于打造高性能 Al Cloud 基础设施平台&#xff0c;积极推动AI应用的落地。达坦科技通过软硬件深度融合的方式&#xff0c;提供高性能存储和高性能网络。为 AI 应用提供弹性、便利、经济的基础设施服务&#xff0c;以此满足不同行业客户对 AICloud 的需求。 在本…

AI全息手术:未来医疗的奇迹,你准备好了吗?

想象一下&#xff0c;未来的手术室中&#xff0c;医生们不再依赖二维的X光片或CT扫描&#xff0c;而是通过空中悬浮的三维全息影像&#xff0c;直观地观察和操作人体内部结构。这并非科幻电影中的场景&#xff0c;而是正在成为现实的AI全息影像手术技术。 手术室中的三维魔法 传…

SOEM 源码解析 ecx_eeprom_waitnotbusyAP

/* 在超时时间内、设置EEprom 状态机忙位busy→idle、APRD方法* param[in] context context struct* 上下文结构体* param[in] aiadr auto increment address of slave* 从站自增地址* param[in] timeout …

Java数据结构 | 树的常见习题一(考研题、面试题)

树的常见练习题一 1、一棵非空的二叉树的先序遍历序列与后序遍历序列正好相反&#xff0c;则该二叉树一定满足&#xff08; &#xff09;2、在一颗度为3的树中&#xff0c;度为3的结点有2个&#xff0c;度为2的结点有1个&#xff0c;度为1的结点有2个&#xff0c;则叶子结点有&…

全志平台串口编号更改记录 A133 T527 T133 A523 A527串口编号更改

总纲 android13 rom 开发总纲说明 目录 1.前言 2.问题分析 3. 情况讨论 4.代码修改 5.彩蛋 1.前言 在嵌入式开发中,更改串口编号是一种常见的操作,以满足特定的硬件配置或调试需求。根据我们之前的文章 android13 串口编号修改 串口名修改-CSDN博客 在全志平台下面使…

如何成为具有竞争力的智能电表厂家

要成为具有竞争力的智能电表厂家&#xff0c;需要在多个方面进行深入布局和持续优化。以下是从市场定位、技术创新、产品质量、销售策略、客户服务以及合作伙伴关系等六个方面进行的详细分析&#xff1a; 一、明确市场定位与目标 市场细分&#xff1a;智能电表厂家需要明确自己…

未发先火,Smartbi AIChat频频“出圈”

近日&#xff0c;思迈特正式官宣&#xff0c;将于8月8日线上新品发布会上推出自研的全新AI应用——Smartbi AIChat&#xff0c;这款应用在还未正式推向市场前&#xff0c;已获得媒体、分析机构等多方关注&#xff0c;热度飙升&#xff0c;思迈特软件及其新品再一次成为业界内外…

RabbitMq如何确保消息不丢失

问题&#xff1a;在生产环境中由于一些不明原因&#xff0c;导致 rabbitmq 重启&#xff0c;在 RabbitMQ 重启期间生产者消息投递失败&#xff0c;导致消息丢失&#xff0c;需要手动处理和恢复。于是&#xff0c;我们开始思考&#xff0c;如何才能进行 RabbitMQ 的消息可靠投递…

RLVF:避免过度泛化地从口头反馈中学习

人工智能咨询培训老师叶梓 转载标明出处 大模型在不同行业和个人中的广泛应用要求模型能够根据具体的用户反馈进行调整或定制&#xff0c;以满足细微的要求和偏好。虽然通过高层次的口头反馈来指定模型调整非常方便&#xff0c;例如“在给老板起草电子邮件时不要使用表情符号”…

Ubuntu 20.04 几种微信安装错误汇总,最后成功

1. wine 安装 参考 Ubuntu 20.04.2 LTS安装 最新版 微信&#xff08;wine&#xff09; 1.1 连网下载文件 在终端执行 winetricks riched20下载不了 W2KSP4_EN.EXE 和 InstMsiW.exe 两个文件 可以网页端下载&#xff0c;或者 wget https://web.archive.org/web/2000/https:…

MySQL——数据库的设计、事务、视图

文章目录 数据库的设计1.多表之间的关系2.实现关系3.数据库设计的范式 事务1.事务的基本介绍2.事务的四大特征ACID3.事务的隔离级别&#xff08;了解即可&#xff09; 视图1.什么是视图&#xff1f;2.视图创建及使用方法3.注意事项4.为什么使用视图 数据库的设计 1.多表之间的…

GIS,矢量瓦片加载速度优化

文章目录 一、前言二、矢量瓦片的基础知识三、矢量切片加载速度优化3.1 地图缩编3.2 矢量瓦片中的图层根据显示层级定制3.3 矢量瓦片中的图层字段要按需定制3.4 多个图层合并为矢量切片图层组发布 四、总结 一、前言 单个矢量瓦片的大小并没有固定的上限&#xff0c;这意味着在…

一款功能强大且完全免费的在线AI抠图工具,还可以制作证件照

适用于人像、宠物、汽车等物品的智能抠图。它利用先进的算法和发丝级AI技术&#xff0c;能够快速精准地完成图片背景移除&#xff0c;并提供透明背景、场景切换和证件照制作等多种增值服务。此外&#xff0c;还支持批量处理和多种图片格式&#xff0c;适合不同用户的需求。无论…

【xilinx】如何从 Vivado GUI 启用/禁用 IP Core container

问题描述 如何从 Vivado GUI 启用/禁用 IP 核容器&#xff1f; 解决方案 要通过 GUI 启用/禁用 2023.1 之前的 Vivado 版本中的 IP 核容器&#xff0c;请按照以下步骤操作&#xff1a; 选择设置 -> IP -> 使用核心容器 在 Vivado 2023.1 及更高版本中&#xff0c;请按照…

中国自动驾驶出租车冲击网约车市场

近年来&#xff0c;中国的自动驾驶技术迅速发展&#xff0c;对传统网约车市场构成了越来越大的冲击。随着科技巨头百度旗下的萝卜快跑等公司加速推广无人驾驶出租车&#xff0c;这一趋势引发了广泛的讨论和担忧。 自动驾驶技术的迅猛发展 中国自动驾驶行业正处于快速发展阶段&…