来来来, SAP BTP下使用CAP来生成PostgreSQL应用(一): Node.js篇

news2024/11/24 16:10:28

前言

SAP云应用程序编程模型(CAP)是一个语言、库和工具框架,用于构建企业级服务和应用程序。它引导开发人员沿着一条经过验证的最佳实践的“黄金之路”前进,并为反复出现的任务提供大量开箱即用的解决方案。

我们这就来看看SAP BTP的CAP到底提供了哪些便利。也以PostgreSQL作为数据库的后端为例 ,看看如何简单的应用CAP相关技术和技术栈。CAP不仅可以快速生成云上的应用,也可以生成本地可以运行的应用。

CAP框架的特点是混合了经过验证并被广泛采用的开源和SAP技术,如下图所示。

图片

image-20240310084908551

在开源技术基础上,CAP主要添加了:

  • Core Data Services (CDS):我们用于领域模型和服务定义的通用建模语言。

  • Service SDKs and runtimes :主为要node.js和Java.  提供实现和使用服务的库,以及自动服务众多请求的通用的程序实现。

基于CDS的运行架构图如下所示:

图片

image-20240310085301264

整个CAP里头,支持Node.js和Java两种技术栈。我们本篇就先简要介绍一下Node.js下的使用。友情提示:Node.js在SAP BTP云平台下的生态当中,占据着十分重要的地位。基本上除了Java以外,使用Node.js是最多的,其次还有GO相关技术栈。

环境搭建

安装Node.js:

从https://nodejs.org/en 下载最新的LTS长期稳定版,如:https://nodejs.org/dist/v20.11.1/node-v20.11.1-x64.msi

安装CAP的cds-sdk

npm add -g @sap/cds-dk
cds #> run the installed CLI

安装GIT

步骤: 略
git version

安装sqlite

只在WINDOWS平台上安装。 从:https://sqlite.org/download.html 下载即可。
从Precompiled Binaries for Windows 那一部分找。
下载完,将sqlite-tools-win-x64-3450100.zip解压,里边的sqlite3.exe就是要用到的sqlite3应用程序。

将sqlite3.exe添加到%PATH%环境变量里头。验证:

E:\work\3rdparty\postgres\postgres>sqlite3
SQLite version 3.45.1 2024-01-30 16:01:20 (UTF-16 console I/O)
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>

sqlite3是cds环境默认的数据库后端。主要用于开发测试使用。

安装mvn, java JDK (略)

这一部分是为Java技术栈提供的。只用Node.js时,可以不用装

安装MS vscode

直接从https://code.visualstudio.com/ 下载安装即可。

推荐安装以下扩展插件:

  • SAP CDS Language Support

  • ESLint

  • REST Client

  • SQLite Viewer

  • Rainbow CSV

安装配备PostgreSQL数据库

这个我们有足够的理由略。公众号以及官方文档里有大量的介绍。本文假定你已经提前准备好了PostgreSQL的运行环境。

实例

下面, 我们就来一个简单的示例来介绍一下使用CAP/cds来进行相关开发,最终能访问到PostgreSQL数据库。

1、初始化工程

cds init bookshop

E:\work\3rdparty\postgres\cap\bookshop>tree .
卷 Work 的文件夹 PATH 列表
卷序列号为 000000D0 3938:438F
E:\WORK\3RDPARTY\POSTGRES\CAP\BOOKSHOP
├─.vscode
├─app
├─db
└─srv

它会自动在下边生成app、db、srv三个子目录。我们可以用code bookshop直接打开这个工程。看到上边完整的目录结构。

package.json则定义了Node.js的运行包的依赖及启动定义。

2、定义一些schema

文件db/schema.cds, 内容如下:

using { Currency, managed, sap } from '@sap/cds/common';
namespace sap.capire.bookshop; 

entity Books : managed { 
  key ID : Integer;
  title  : localized String(111);
  descr  : localized String(1111);
  author : Association to Authors;
  genre  : Association to Genres;
  stock  : Integer;
  price  : Decimal(9,2);
  currency : Currency;
}

entity Authors : managed { 
  key ID : Integer;
  name   : String(111);
  books  : Association to many Books on books.author = $self;
}

/** Hierarchically organized Code List for Genres */
entity Genres : sap.common.CodeList { 
  key ID   : Integer;
  parent   : Association to Genres;
  children : Composition of many Genres on children.parent = $self;
}

这时,我们如果运行cds watch, 可以看到,它把上边定义的schema, 部署到sqlite的内存模式的数据库里头去了。这是默认行为。

E:\work\3rdparty\postgres\cap\bookshop>cds watch

cds serve all --with-mocks --in-memory?
live reload enabled for browsers

        ___________________________

[cds] - loaded model from 2 file(s):

  db\schema.cds
  C:\Users\Think\AppData\Roaming\npm\node_modules\@sap\cds-dk\node_modules\@sap\cds\common.cds

[cds] - connect using bindings from: { registry: '~/.cds-services.json' }
[cds] - connect to db > sqlite { database: ':memory:' }
/> successfully deployed to in-memory database.


[cds] - server listening on { url: 'http://localhost:4004' }
[cds] - launched at 2024/3/10 17:58:59, version: 7.7.0, in: 6.550s
[cds] - [ terminate with ^C ]


    No service definitions found in loaded models.
    Waiting for some to arrive...

而当你打开浏览器访问:http://localhost:4004 它也能为你打开一个初具雏形的页面。我们需要在后边进行适当补充。

同时,可以使用如下命令,将schema定义转化成json, yml, sql等多种形式:

cds db/schema.cds -2 json
cds db/schema.cds -2 yml
cds db/schema.cds -2 sql

--看看它转化成的SQL语句的样子:(节选)
CREATE TABLE sap_capire_bookshop_Books (
  createdAt TIMESTAMP_TEXT,
  createdBy NVARCHAR(255),
  modifiedAt TIMESTAMP_TEXT,
  modifiedBy NVARCHAR(255),
  ID INTEGER NOT NULL,
  title NVARCHAR(111),
  descr NVARCHAR(1111),
  author_ID INTEGER,
  genre_ID INTEGER,
  stock INTEGER,
  price DECIMAL(9, 2),
  currency_code NVARCHAR(3),
  PRIMARY KEY(ID)
);

CREATE TABLE sap_capire_bookshop_Authors (
  createdAt TIMESTAMP_TEXT,
  createdBy NVARCHAR(255),
  modifiedAt TIMESTAMP_TEXT,
  modifiedBy NVARCHAR(255),
  ID INTEGER NOT NULL,
  name NVARCHAR(111),
  PRIMARY KEY(ID)
);

CREATE TABLE sap_capire_bookshop_Genres (
  name NVARCHAR(255),
  descr NVARCHAR(1000),
  ID INTEGER NOT NULL,
  parent_ID INTEGER,
  PRIMARY KEY(ID)
);

CREATE TABLE sap_common_Currencies (
  name NVARCHAR(255),
  descr NVARCHAR(1000),
  code NVARCHAR(3) NOT NULL,
  symbol NVARCHAR(5),
  minorUnit SMALLINT,
  PRIMARY KEY(code)
);
.......

这里考虑到PostgreSQL中表名或其它对象名的63个字符长度的限制,我们还真不能把包名得太长,一不小心就会超长了。

3、定义相关服务(service)

定义完schema之后,我们就可以定义一下服务(service)了。

文件 svc/admin-service.cds

using { sap.capire.bookshop as my } from '../db/schema';
service AdminService @(requires:'authenticated-user') { 
  entity Books as projection on my.Books;
  entity Authors as projection on my.Authors;
}

文件 srv/cat-service.cds
using { sap.capire.bookshop as my } from '../db/schema';
service CatalogService @(path:'/browse') { 

  @readonly entity Books as select from my.Books {*,
    author.name as author
  } excluding { createdBy, modifiedBy };

  @requires: 'authenticated-user'
  action submitOrder (book: Books:ID, quantity: Integer);
}

这里解释一下这两个service的逻辑:

admin-service: 它需要进行user的认证,认证通过以后,就可以基于Books和Authors两个schema描述的entity进行正常的访问了。

cat-service: 它直接可以进行浏览数据 ,能以只读方式访问Books, 顺带访问Author(根据作者名字). 但是会排除createdBy, modifiedBy两个字段。同时,如果提供了用户认证,则可以按照Book的ID和数量来提交订单(action:submitOrder)。

这里感觉整个过程,基本上没怎么写代码,全部给你生成了相应的逻辑。

这次我们再看看效果:

cds watch
......
[cds] - serving AdminService { path: '/odata/v4/admin' }
[cds] - serving CatalogService { path: '/browse' }

[cds] - server listening on { url: 'http://localhost:4004' }
[cds] - launched at 2024/3/10 20:03:40, version: 7.7.0, in: 991.416ms
[cds] - [ terminate with ^C ]

这里我们看到了/odata/v4/admin的rest路径了。使用浏览器访问,看到如下效果:

图片

image-20240310200645298

访问:http://localhost:4004/odata/v4/admin/$metadata 时,可以使用alice这个缺省用户,不用输入密码即可得到admin权限。

4、配置访问使用数据库

默认方式使用的就是sqlite内存方式启动的数据库。我们一步步演化推进:

添加如下两个csv格式的数据文件:

db/data/sap.capire.bookshop-Books.csv
ID,title,author_ID,stock
201,Wuthering Heights,101,12
207,Jane Eyre,107,11
251,The Raven,150,333
252,Eleonora,150,555
271,Catweazle,170,22

db/data/sap.capire.bookshop-Authors.csv
ID,name
101,Emily Brontë
107,Charlotte Brontë
150,Edgar Allen Poe
170,Richard Carpenter

我们修改一下package.json, 指定一下数据库,添加内容如下:

"cds": { "requires": {
   "db": {
      "kind": "sqlite",
      "credentials": { "url": "db.sqlite" } 
   }
}}

这个时候,我们只要运行cds deploy就可以将数据deploy到sqlite数据库当中。文件名为db.sqlite.

E:\work\3rdparty\postgres\cap\bookshop>cds deploy
  > init from db\data\sap.capire.bookshop-Books.csv
  > init from db\data\sap.capire.bookshop-Authors.csv
/> successfully deployed to db.sqlite

E:\work\3rdparty\postgres\cap\bookshop>sqlite3 db.sqlite
SQLite version 3.45.1 2024-01-30 16:01:20 (UTF-16 console I/O)
Enter ".help" for usage hints.
sqlite> .tables
AdminService_Authors
AdminService_Books
AdminService_Books_texts
AdminService_Currencies
AdminService_Currencies_texts
AdminService_Genres
AdminService_Genres_texts
CatalogService_Books
CatalogService_Books_texts
CatalogService_Currencies
CatalogService_Currencies_texts
CatalogService_Genres
............
sap_capire_bookshop_Authors
sap_capire_bookshop_Books
sap_capire_bookshop_Books_texts
sap_capire_bookshop_Genres
sap_capire_bookshop_Genres_texts
sap_common_Currencies
sap_common_Currencies_texts

sqlite> select * from sap_capire_bookshop_Books;
2024-03-10T13:37:12.624Z|anonymous|2024-03-10T13:37:12.624Z|anonymous|201|Wuthering Heights||101||12||
2024-03-10T13:37:12.624Z|anonymous|2024-03-10T13:37:12.624Z|anonymous|207|Jane Eyre||107||11||
2024-03-10T13:37:12.624Z|anonymous|2024-03-10T13:37:12.624Z|anonymous|251|The Raven||150||333||
2024-03-10T13:37:12.624Z|anonymous|2024-03-10T13:37:12.624Z|anonymous|252|Eleonora||150||555||
2024-03-10T13:37:12.624Z|anonymous|2024-03-10T13:37:12.624Z|anonymous|271|Catweazle||170||22||

你会发现它建了很多表。上边两个数据文件的数据也都添加进去了。

如果我们访问:http://localhost:4004/odata/v4/admin/Books 都能看到对应的数据了。

{
    "@odata.context": "$metadata#Books",
    "value": [{
        "createdAt": "2024-03-10T13:44:54.391Z",
        "createdBy": "anonymous",
        "modifiedAt": "2024-03-10T13:44:54.391Z",
        "modifiedBy": "anonymous",
        "ID": 201,
        "title": "Wuthering Heights",
        "descr": null,
        "author_ID": 101,
        "genre_ID": null,
        "stock": 12,
        "price": null,
        "currency_code": null
    },
    ...
}

截至目前为止,我们看到的还是连接到sqlite数据库。大多数功能都是直接提供给你的。

我们看看,切换到PostgreSQL数据库是啥样的?该如何做?

对于Node.js而言,有如下依赖关系:

DatabasePackageRemarks
SAP HANA Cloud@sap/cds-hanarecommended for production
SQLite@cap-js/sqliterecommended for development
PostgreSQL@cap-js/postgresmaintained by community + CAP team

可以使用 npm add @cap-js/postgres 来添加对PostgreSQL的依赖。

我这里是提前准备好的一个VM上的PostgreSQL环境,CentOS7.9,  PG14.x,  用户名mydb, 密码test123,它的数据库名也为mydb。提前准备好。

E:\work\3rdparty\postgres\postgres>psql -h 192.168.0.20 -U mydb -p 5555
用户 mydb 的口令:
psql (14.4, 服务器 14.11)
输入 "help" 来获取帮助信息.

mydb=> \d
没有找到任何关系.
mydb=>

如果要设成PostgreSQL的数据库连接环境,在工程根目录下边建一个文件.env。内容如下:

cds.requires.db.[pg].kind = postgres
cds.requires.db.[pg].credentials.host = 192.168.0.20
cds.requires.db.[pg].credentials.port = 5555
cds.requires.db.[pg].credentials.user = mydb
cds.requires.db.[pg].credentials.password = test123
cds.requires.db.[pg].credentials.database = mydb

这是一种配置方式,另一种方式是使用直接在package.json中修改添加相关的数据库类型及连接信息:

  "cds": {
    "requires": {
      "db": {
        "[sqlite]": { "kind": "sqlite", "impl": "@cap-js/sqlite", "credentials": { "url": "db.sqlite" } },
        "[pg]": {"kind": "postgres", "impl": "@cap-js/postgres", 
          "credentials": {
             "host": "192.168.0.20", 
             "port": 5555,
             "user": "mydb",
             "password": "test123",
             "database": "mydb"
          }
        }
      }
    }
  },

上边[pg]部分定义的就是与PostgreSQL相关的内容。

我们可以使用下边的命令诊断一下:(注 --profile 用于指定是哪种profile)

E:\work\3rdparty\postgres\cap\bookshop>cds env requires.db --profile pg
{
  impl: '@cap-js/postgres',
  dialect: 'postgres',
  vcap: { label: 'postgresql-db' },
  schema_evolution: 'auto',
  kind: 'postgres',
  credentials: {
    host: '192.168.0.20',
    port: 5555,
    user: 'mydb',
    password: 'test123',
    database: 'mydb'
  }
}

5、验证访问PostgreSQL

我们再次启动这个应用:

cds watch --profile pg
.......
[cds] - connect using bindings from: { registry: '~/.cds-services.json' }
[cds] - connect to db > postgres {
  host: '192.168.0.200',
  port: 5555,
  user: 'mydb',
  password: '...',
  database: 'mydb'
}
[cds] - using auth strategy {
  kind: 'mocked',
  impl: 'node_modules\\@sap\\cds\\lib\\auth\\basic-auth'
}

[cds] - serving AdminService { path: '/odata/v4/admin' }
[cds] - serving CatalogService { path: '/browse' }

[cds] - server listening on { url: 'http://localhost:4004' }
[cds] - launched at 2024/3/13 05:07:19, version: 7.7.1, in: 16.285s
[cds] - [ terminate with ^C ]

同时,数据库部分,需要对SCHEMA以及数据表中的数据进行初始化:

E:\work\3rdparty\postgres\cap\bookshop>cds deploy --profile pg
  > init from db\data\sap.capire.bookshop-Books.csv
  > init from db\data\sap.capire.bookshop-Authors.csv
/> successfully deployed to 192.168.0.20:5555

我们再次访问PG里头的数据库:mydb:

mydb=# \d
                       List of relations
 Schema |                 Name                  | Type  | Owner
--------+---------------------------------------+-------+-------
 public | adminservice_authors                  | view  | mydb
 public | adminservice_books                    | view  | mydb
 public | adminservice_books_texts              | view  | mydb
 public | adminservice_currencies               | view  | mydb
 public | adminservice_currencies_texts         | view  | mydb
 public | adminservice_genres                   | view  | mydb
 public | adminservice_genres_texts             | view  | mydb
 public | catalogservice_books                  | view  | mydb
 public | catalogservice_books_texts            | view  | mydb
 public | catalogservice_currencies             | view  | mydb
 public | catalogservice_currencies_texts       | view  | mydb
 public | catalogservice_genres                 | view  | mydb
 public | catalogservice_genres_texts           | view  | mydb
 public | cds_model                             | table | mydb
 public | localized_adminservice_authors        | view  | mydb
 public | localized_adminservice_books          | view  | mydb
 public | localized_adminservice_currencies     | view  | mydb
 public | localized_adminservice_genres         | view  | mydb
 public | localized_catalogservice_books        | view  | mydb
 public | localized_catalogservice_currencies   | view  | mydb
 public | localized_catalogservice_genres       | view  | mydb
 public | localized_sap_capire_bookshop_authors | view  | mydb
 public | localized_sap_capire_bookshop_books   | view  | mydb
 public | localized_sap_capire_bookshop_genres  | view  | mydb
 public | localized_sap_common_currencies       | view  | mydb
 public | sap_capire_bookshop_authors           | table | mydb
 public | sap_capire_bookshop_books             | table | mydb
 public | sap_capire_bookshop_books_texts       | table | mydb
 public | sap_capire_bookshop_genres            | table | mydb
 public | sap_capire_bookshop_genres_texts      | table | mydb
 public | sap_common_currencies                 | table | mydb
 public | sap_common_currencies_texts           | table | mydb

我们会发现创建了8张表以及近24个视图。自动创建的东西看来不少。

如果我们去访问网页:http://localhost:4004/browse/Books

确实能得到标准的OData数据(json格式输出):

{"@odata.context":"$metadata#Books","value":[{"ID":201,"descr":null,"price":null,"stock":12,"title":"Wuthering Heights","author":"Emily Brontë","genre_ID":null,"createdAt":"2024-03-12T21:10:32.074Z","modifiedAt":"2024-03-12T21:10:32.074Z","currency_code":null},{"ID":207,"descr":null,"price":null,"stock":11,"title":"Jane Eyre","author":"Charlotte Brontë","genre_ID":null,"createdAt":"2024-03-12T21:10:32.074Z","modifiedAt":"2024-03-12T21:10:32.074Z","currency_code":null},{"ID":251,"descr":null,"price":null,"stock":333,"title":"The Raven","author":"Edgar Allen Poe","genre_ID":null,"createdAt":"2024-03-12T21:10:32.074Z","modifiedAt":"2024-03-12T21:10:32.074Z","currency_code":null},{"ID":252,"descr":null,"price":null,"stock":555,"title":"Eleonora","author":"Edgar Allen Poe","genre_ID":null,"createdAt":"2024-03-12T21:10:32.074Z","modifiedAt":"2024-03-12T21:10:32.074Z","currency_code":null},{"ID":271,"descr":null,"price":null,"stock":22,"title":"Catweazle","author":"Richard Carpenter","genre_ID":null,"createdAt":"2024-03-12T21:10:32.074Z","modifiedAt":"2024-03-12T21:10:32.074Z","currency_code":null}]}

而这也是SAP产品规范中很重要的一环。它的大部分产品的输出结果就是按照OData规范,输出成Json格式的。

至此,这个简单的实验结束 。

总结 :

本文只是简要的介绍了一下CAP框架下,使用cds (core data service)生成框架,快速搭建一个Node.js应用,访问和管理存储到PostgreSQL中的企业数据。CAP在Node.js技术栈下,目前支持三种数据库(sqlite, PostgreSQL, HANA),目前,不支持SAP Sybase ASE。

只要环境搭建好,使用访问还是非常方便的。而且整个应用会全部使用Node.js。因为本文侧重于访问数据库这一块。如果你要想全面了解CAP开发框架,那么,关于安全、UI、云平台部署等方面,也需要进行相关的了解,可以仔细阅读参考部分的网址。里边各节都有相关介绍。

参考

https://cap.cloud.sap/docs/:  SAP (The Cloud Application Programming Model) 

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

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

相关文章

蓝桥杯--日期统计

目录 一、题目 二、解决代码 三、代码分析 ​四、另一种思路 五、关于set文章推荐 一、题目 二、解决代码 #include <bits/stdc.h> using namespace std; int main() {int arr[100] { 5,6,8,6,9,1,6,1,2,4,9,1,9,8,2,3,6,4,7,7,5,9,5,0,3,8,7,5,8,1,5,8,6,1,8,3,0,…

【DDR】DDR4学习记录

这里以美光DDR4芯片 MT40A512M16HA-075E datasheet 为例&#xff0c;说明DDR4存储器的原理及仿真。   根据开发板手册ug1302&#xff0c;在vcu128&#xff08;xcvu37p&#xff09;开发板上&#xff0c;共具有5块DDR4芯片&#xff0c;在数据信号上4块DDR4具有16位数据线&#…

模拟电子技术实验(二)

单选题 1. 本实验的实验目的中&#xff0c;输出电阻测量是第几个目的&#xff1f; A. 1个。 B. 2个。 C. 3个。 D. 4个。 答案&#xff1a;C 评语&#xff1a;10分 单选题 2.本实验电路有一个元件参数有问题&#xff0c;需要修改&#xff1f; A. …

漏洞发现-漏扫项目篇NucleiYakitGobyAfrogXrayAwvs联动中转被动

知识点 1、综合类-Burp&Xray&Awvs&Goby 2、特征类-Afrog&Yakit&Nuclei 3、联动类-主动扫描&被动扫描&中转扫描 章节点&#xff1a; 漏洞发现-Web&框架组件&中间件&APP&小程序&系统 扫描项目-综合漏扫&特征漏扫&被动…

ThreadLocal 快速入门

ThreadLocal 快速入门 ThreadLocal 是 Java 中的一个类&#xff0c;用于创建线程局部变量。线程局部变量是一种特殊的变量&#xff0c;每个线程都有自己的副本&#xff0c;互相之间不会相互影响。这在多线程环境中非常有用&#xff0c;可以避免线程间共享变量导致的并发问题。…

产品之美6|用户根据习惯选择双列或单列布局

某红书的首页排版:双列排版 另一个社交app首页排版:单列排版 现在某社交app,用户根据自己浏览习惯&#xff0c;可选择双列 选择单列 启发:不同的用户有不同的浏览习惯&#xff0c;选择权交给用户。

Tableau 新建工作薄

1. 进入“Tableau编辑” tab 2. 找到一个已存在的工作薄(最好功能类似)&#xff0c;点击“编辑工作薄”Tab 3. 点击“发布为”tab&#xff0c;会生成一个新的工作薄 随便起一个名字&#xff0c;选定项目文件夹&#xff0c;发布即可。 4. 修改数据表 &#xff08;1&#xff09;…

合金采样电阻有什么作用?

采样电阻又叫电流检测电阻、取样电阻是指电流采样和电压采样而电流采样串联电阻值小的电阻其作用在于电路中能够精准的采集电流&#xff0c;电压采样并联电阻值大的电阻。此类电阻&#xff0c;是按照产品使用以及功能作用来命名也因此工程师称采样电阻。 采样电阻作用 采样电阻…

微信小程序开发系列(二十九)·界面交互API·loading 提示框、showModal模态对话框、showToast消息提示框

目录 1. loading 提示框 1. 1 wx.showLoading()显示loading提示框 1.2 wx.hideLoading()关闭 loading 提示框 2. showModal 模态对话框 3. showToast 消息提示框 小程序提供了一些用于界面交互的 API&#xff0c;例如&#xff1a;loading 提示框、消息提示框、模态对…

【嵌入式——QT】标准对话框

【嵌入式——QT】标准对话框 文件对话框颜色对话框字体对话框输入对话框消息框代码示例 文件对话框 QFileDialog 常用静态函数 getOpenFileName&#xff1a;选择打开一个文件&#xff1b;getOpenFileNames&#xff1a;选择打开多个文件&#xff1b;getSaveFileName&#xff1…

36+程序员3站考研:国家线轻松拿捏

基本情况是&#xff1a;年龄较大&#xff0c;比36还大&#xff0c;本科是自考&#xff0c;十几年来一直从事编程相关工作。 第一年考数学太慌了&#xff0c;选择题全蒙的&#xff0c;结果填空题一道没算对&#xff0c;大题全不会&#xff0c;所以尽管总分280多但是数学没过国家…

制造行业大数据应用:四大领域驱动产业升级与智慧发展

一、大数据应用&#xff1a;制造行业的智慧引擎 随着大数据技术的不断突破与普及&#xff0c;制造行业正迎来一场前所未有的变革。大数据应用&#xff0c;如同智慧引擎一般&#xff0c;为制造行业注入了新的活力&#xff0c;推动了产业升级与创新发展。 二、大数据应用在制造行…

测试用例的设计(2)

目录 1.前言 2.正交排列(正交表) 2.1什么是正交表 2.2正交表的例子 2.3正交表的两个重要性质 3.如何构造一个正交表 3.1下载工具 3.1构造前提 4.场景设计法 5.错误猜测法 1.前言 我们在前面的文章里讲了测试用例的几种设计方法,分别是等价类发,把测试例子划分成不同的类…

Druid连接池经常性断链问题

前段时间有应用使用Druid连接池经常的提示断链报错&#xff0c;整个问题排查分析过程很有意思。这里将Druid连接池、数据库层以及负载均衡层的配置分析下&#xff0c;记录整个问题的分析过程&#xff0c;同时梳理下Druid连接池的配置和连接保活及回收机制。 1、问题背景 应用…

【图文详解】Maven Helper插件解决Maven冲突

文章目录 插件问题解决过程 在面试中解决问题的能力和思路是考察的重点&#xff0c;面试官问会问我们有没有解决过maven冲突。以下造了一个maven冲突&#xff0c;手把手教学如何解决Maven冲突。 插件 插件在idea插件中搜索Maven Helper 问题 解决过程 根据上面日志知道是log…

基于SWOT的智能手机企业财务战略研究1.62

摘 要 近些年&#xff0c;网络技术日新月异&#xff0c;智能手机深受消费者喜爱&#xff0c;人们通过网络&#xff0c;手机应用&#xff0c;可以极大地方便人们学习&#xff0c;工作等等。由于国家对电信行业的大力支持&#xff0c;中国消费者群体逐步成为最具潜力的手机购买者…

【Emgu CV教程】9.3、形态学常用操作之开运算

文章目录 一、相关概念1.什么叫开运算3.开运算的函数 二、演示1.原始素材2.代码3.运行结果 一、相关概念 1.什么叫开运算 腐蚀、膨胀已经讲完&#xff0c;这两个是最基础的形态学操作。这次讲的是开运算&#xff0c;它是一个先腐蚀、后膨胀的过程。原始图像先被腐蚀&#xff…

对GIS与游戏引擎(UE4 或 U3D)结合的看法

GIS与游戏引擎结合&#xff0c;这在6年前就已经很多公司在进行探索了&#xff0c;经过这几年的发展&#xff0c;结合当前的政策&#xff0c;从以下几方面说一下我的看法&#xff1a; 1.GIS客户都是特殊单位及领域。2018年后&#xff0c;国内已经对国产化有明确要求了&#xff0…

Spring中使用自带@Autowired注解实现策略模式

场景 SpringBoot中策略模式工厂模式业务实例(接口传参-枚举类查询策略映射关系-执行不同策略)规避大量if-else&#xff1a; SpringBoot中策略模式工厂模式业务实例(接口传参-枚举类查询策略映射关系-执行不同策略)规避大量if-else_springboot编写策略工厂-CSDN博客 设计模式…

BUUCTF-----[SWPU2019]Web1

打开页面&#xff0c;原本以为是二次注入,结果不是&#xff0c;先注册一个账户 在申请发布广告中&#xff0c;发现反射性xss(然而没有什么用) 在广告申请名字中发现注入点 开始注入 通过一系列的测试&#xff0c;发现系统过滤了#&#xff0c;or&#xff0c;空格 orde…