0基礎學習Mybatis系列數據庫操作框架——Mysql的Geometry數據處理之WKB方案

大綱

  • 序列化
  • 反序列化
  • 完整TypeHandler
  • SQL XML
    • 完整XML
  • Mapper
  • 測試代碼
  • 代碼

在《0基礎學習Mybatis系列數據庫操作框架——Mysql的Geometry數據處理之WKT方案》中,我們介紹WTK方案的優點,也感受到它的繁瑣和缺陷。比如:

  • 需要借助ST_GeomFromText和ST_AsText,讓SQL語句顯得復雜。
select id, ST_AsText(geometry) AS geometry, update_time, create_time from geometry_data
  • 沒有一種GeomFromText方案可以覆蓋所有的Geometry結構,使得類似的SQL要寫多份。
insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, ST_GeomFromText(#{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKTHandler}), now(), now())insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, ST_GeomCollFromText(#{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKTHandler}), now(), now())
  • 沒有針對LinearRing(一種特殊的LineString)的處理方法。

而本文介紹的WKB方法,則可以解決上述問題。
WKB全程Well-Known Binary,它是一種二進制存儲幾何信息的方法。
在《0基礎學習Mybatis系列數據庫操作框架——Mysql的Geometry數據處理之WKT方案》中介紹的WKT方法,可以用字符串形式表達幾何信息,如POINT (1 -1)。
WKB則表達為

0101000000000000000000F03F000000000000F0BF

這段二進制的拆解如下

ComponentSizeValue
Byte order1 byte01
WKB type4 bytes01000000
X coordinate8 bytes000000000000F03F
Y coordinate8 bytes000000000000F0BF

byte order可以是0或者1,它表示是大頂堆(0)還是小頂堆(1)存儲。
WKB type表示幾何類型。值的對應關系如下:

  • 1 Point
  • 2 LineString
  • 3 Polygon
  • 4 MultiPoint
  • 5 MultiLineString
  • 6 MultiPolygon
  • 7 GeometryCollection

剩下的是坐標信息。

雖然這個結構已經很基礎,但是**Mysql的Geometry結構并不是WKB。準確的說,WKB只是Mysql的Geometry結構中的一部分。**它們的差異是,Mysql的Geometry結構是在WKB之前加了4個字節,用于存儲SRID。
在這里插入圖片描述
還有一點需要注意的是,Mysql存儲Geometry數據使用的是小頂堆。所以WKB的Byte order字段值一定是1。
有了這些知識,我們就可以定義WKB類型的TypeHandler了。

序列化

這段代碼先從org.locationtech.jts.geom.Geometry中獲取SRID碼;然后以小頂堆模式,使用WKBWriter將幾何信息保存為WKB的二進制碼。然后申請比WKB大4個字節的空間,分別填入SRID和WKB。這樣整個內存結構就匹配Mysql內部的Geometry內存結構了。

    private byte[] serializeGeometry(Geometry geometry) {int srid = geometry.getSRID();byte[] bytes = new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN).write(geometry);return ByteBuffer.allocate(bytes.length + 4).order(ByteOrder.LITTLE_ENDIAN).putInt(srid).put(bytes).array();}

反序列化

這段代碼會將Mysql內部的Geometry內存結構讀出來,轉換成小頂堆模式。然后獲取SRID,并以此創建GeometryFactory。剩下的內容就是WKB的內存了,最后使用WKBReader將這段內存轉換成org.locationtech.jts.geom.Geometry。

    private static Geometry deserializeGeometry(byte[] bytes) throws ParseException {if (bytes == null) {return null;}ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);int srid = buffer.getInt();byte[] geometryBytes = new byte[buffer.remaining()];buffer.get(geometryBytes);GeometryFactory geometryFactory = GEOMETRY_FACTORIES.computeIfAbsent(srid, i -> new GeometryFactory(PRECISION_MODEL, i));WKBReader reader = new WKBReader(geometryFactory);return reader.read(geometryBytes);}

完整TypeHandler

package org.example.typehandlers;import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.io.ByteOrderValues;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKBWriter;import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class GeometryTypeWKBHandler extends BaseTypeHandler<Geometry>  {private static final PrecisionModel PRECISION_MODEL = new PrecisionModel(PrecisionModel.FIXED);private static final Map<Integer, GeometryFactory> GEOMETRY_FACTORIES = new ConcurrentHashMap<>();@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Geometry parameter, JdbcType jdbcType) throws SQLException {byte[] bytes = serializeGeometry(parameter);ps.setBytes(i, bytes);}@Overridepublic Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException {byte[] bytes = rs.getBytes(columnName);try {return deserializeGeometry(bytes);} catch (ParseException e) {throw new SQLException(e);}}@Overridepublic Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException {byte[] bytes = rs.getBytes(columnIndex);try {return deserializeGeometry(bytes);} catch (ParseException e) {throw new SQLException(e);}}@Overridepublic Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {byte[] bytes = cs.getBytes(columnIndex);try {return deserializeGeometry(bytes);} catch (ParseException e) {throw new SQLException(e);}}private static Geometry deserializeGeometry(byte[] bytes) throws ParseException {if (bytes == null) {return null;}ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);int srid = buffer.getInt();byte[] geometryBytes = new byte[buffer.remaining()];buffer.get(geometryBytes);GeometryFactory geometryFactory = GEOMETRY_FACTORIES.computeIfAbsent(srid, i -> new GeometryFactory(PRECISION_MODEL, i));WKBReader reader = new WKBReader(geometryFactory);return reader.read(geometryBytes);}private byte[] serializeGeometry(Geometry geometry) {int srid = geometry.getSRID();byte[] bytes = new WKBWriter(2, ByteOrderValues.LITTLE_ENDIAN).write(geometry);return ByteBuffer.allocate(bytes.length + 4).order(ByteOrder.LITTLE_ENDIAN).putInt(srid).put(bytes).array();}
}

SQL XML

使用了WKB模式,SQL就會寫的很簡潔,而不需要用ST_GeomFromText和ST_AsText轉來轉去。比如之前因為要用ST_AsText處理返回值,導致需要寫明每個返回的字段。而使用WKB后,可以寫成

    <resultMap id="GeometryDataResultMap" type="org.example.model.GeometryData"><result property="id" column="id"/><result property="geometry" column="geometry" typeHandler="org.example.typehandlers.GeometryTypeWKBHandler" jdbcType="BLOB"/><result property="updateTime" column="update_time"/><result property="createTime" column="create_time"/></resultMap><select id="findAll" resultMap="GeometryDataResultMap">select * from geometry_data</select>

作為對比可以看下WKT的模式,如下。

    <resultMap id="GeometryDataResultMap" type="org.example.model.GeometryData"><result property="id" column="id"/><result property="geometry" column="geometry" typeHandler="org.example.typehandlers.GeometryTypeWKTHandler" jdbcType="BLOB"/><result property="updateTime" column="update_time"/><result property="createTime" column="create_time"/></resultMap><select id="findAll" resultMap="GeometryDataResultMap">select id, ST_AsText(geometry) AS geometry, update_time, create_time from geometry_data</select>

插入操作也會變得簡單,下面是WKB模式

    <insert id="insertOne" parameterType="org.example.model.GeometryData"  useGeneratedKeys="true" keyProperty="id">insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, #{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, now(), now())</insert>

而WKT模式,因為不能使用ST_GeomFromText處理GeometryCollection,導致只能拆成兩條SQL。如下

    <insert id="insertOne" parameterType="org.example.model.GeometryData"  useGeneratedKeys="true" keyProperty="id">insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, ST_GeomFromText(#{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKTHandler}), now(), now())</insert><insert id="insertGeometryCollection" parameterType="org.example.model.GeometryData"  useGeneratedKeys="true" keyProperty="id">insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, ST_GeomCollFromText(#{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKTHandler}), now(), now())</insert>

可以見得WKB模式讓SQL XML變得簡單。

完整XML

<?xml version="1.0" encoding="UTF-8"?>
<!-- AllTypeMapper-1.xml -->
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.example.mapper.GeometryDataWKBMapper"><resultMap id="GeometryDataResultMap" type="org.example.model.GeometryData"><result property="id" column="id"/><result property="geometry" column="geometry" typeHandler="org.example.typehandlers.GeometryTypeWKBHandler" jdbcType="BLOB"/><result property="updateTime" column="update_time"/><result property="createTime" column="create_time"/></resultMap><select id="findAll" resultMap="GeometryDataResultMap">select * from geometry_data</select><select id="find" resultMap="GeometryDataResultMap">select * from geometry_data where id = #{id}</select><insert id="insertOne" parameterType="org.example.model.GeometryData"  useGeneratedKeys="true" keyProperty="id">insert into geometry_data(id, geometry, update_time, create_time) values(#{id}, #{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, now(), now())</insert><insert id="insertList" parameterType="list">insert into geometry_data(id, geometry, update_time, create_time) values<foreach item="item" collection="list" separator=",">(#{item.id}, #{item.geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, now(), now())</foreach></insert><update id="updateOne" parameterType="org.example.model.GeometryData">update geometry_data set geometry = #{geometry, jdbcType=BLOB, typeHandler=org.example.typehandlers.GeometryTypeWKBHandler}, update_time = now() where id = #{id} </update>
</mapper>

Mapper

package org.example.mapper;import java.util.List;import org.example.model.GeometryData;public interface GeometryDataWKBMapper {public List<GeometryData> findAll();public GeometryData find(Long id);public Long insertOne(GeometryData geometryData);public Long insertList(List<GeometryData> geometryDataList);public Long updateOne(GeometryData geometryData);
} 

測試代碼

相較于WKT模式,我們給WKB模式的測試用例增加了LinearRing類型。這是WKT模式所不支持的。

package org.example;import static org.junit.jupiter.api.Assertions.fail;import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.example.mapper.GeometryDataWKBMapper;
import org.example.model.GeometryData;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryCollection;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.MultiLineString;
import org.locationtech.jts.geom.MultiPoint;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Polygon;public class GeometryDataWKBTest {private static SqlSessionFactory sqlSF;@BeforeAllstatic void CreateSessionFactory() throws IOException {InputStream in = Resources.getResourceAsStream("mybatis/config/mybatis-config-geometry-wkb.xml");sqlSF = new SqlSessionFactoryBuilder().build(in);}@Testpublic void testFindAll() {List<GeometryData> all = null;try (SqlSession session = sqlSF.openSession()) {all = session.getMapper(GeometryDataWKBMapper.class).findAll();} catch (Exception e) {System.out.println(e.getMessage());}for (GeometryData a : Objects.requireNonNull(all)) {System.out.println(a.getGeometry());}}@Testpublic void testFind() {try (SqlSession session = sqlSF.openSession()) {GeometryDataWKBMapper GeometryDataWKBMapper = session.getMapper(GeometryDataWKBMapper.class);GeometryData one = GeometryDataWKBMapper.find(1L);System.out.println(one.getGeometry());} catch (Exception e) {System.out.println(e.getMessage());}}@Testpublic void testInsert() {try (SqlSession session = sqlSF.openSession()) {GeometryDataWKBMapper GeometryDataWKBMapper = session.getMapper(GeometryDataWKBMapper.class);GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();Coordinate coordinate = new Coordinate(1, 1);Geometry geometry = geometryFactory.createPoint(coordinate);geometryData.setGeometry(geometry);long count = GeometryDataWKBMapper.insertOne(geometryData);System.out.println(count);session.commit();} catch (Exception e) {System.out.println(e.getMessage());fail();}}@Testpublic void testUpdate() {try (SqlSession session = sqlSF.openSession()) {GeometryDataWKBMapper GeometryDataWKBMapper = session.getMapper(GeometryDataWKBMapper.class);GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();Coordinate coordinate = new Coordinate(2, 2);Geometry geometry = geometryFactory.createPoint(coordinate);geometryData.setId(1L);geometryData.setGeometry(geometry);long count = GeometryDataWKBMapper.updateOne(geometryData);System.out.println(count);session.commit();} catch (Exception e) {System.out.println(e.getMessage());fail();}}@Testpublic void testInsertList() {try (SqlSession session = sqlSF.openSession()) {GeometryDataWKBMapper GeometryDataWKBMapper = session.getMapper(GeometryDataWKBMapper.class);List<GeometryData> geometryDataList = new ArrayList<>();{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();Coordinate coordinate = new Coordinate(3, 3);Geometry geometry = geometryFactory.createPoint(coordinate);geometryData.setGeometry(geometry);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();LineString lineString = geometryFactory.createLineString(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2) });geometryData.setGeometry(lineString);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();MultiLineString multiLineString = geometryFactory.createMultiLineString(new LineString[] {geometryFactory.createLineString(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2) }),geometryFactory.createLineString(new Coordinate[] { new Coordinate(3, 3), new Coordinate(4, 4) })});geometryData.setGeometry(multiLineString);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();MultiPolygon multiPolygon = geometryFactory.createMultiPolygon(new Polygon[] {geometryFactory.createPolygon(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2),new Coordinate(3, 3), new Coordinate(1, 1) }),geometryFactory.createPolygon(new Coordinate[] { new Coordinate(4, 4), new Coordinate(5, 5),new Coordinate(6, 6), new Coordinate(4, 4) })});geometryData.setGeometry(multiPolygon);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();LinearRing linearRing = geometryFactory.createLinearRing(new Coordinate[] { new Coordinate(1, 1),new Coordinate(2, 2), new Coordinate(3, 3), new Coordinate(1, 1) });geometryData.setGeometry(linearRing);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();MultiPoint multiPoint = geometryFactory.createMultiPointFromCoords(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2), new Coordinate(3, 3) });geometryData.setGeometry(multiPoint);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();Polygon polygon = geometryFactory.createPolygon(new Coordinate[] { new Coordinate(1, 1),new Coordinate(2, 2), new Coordinate(3, 3), new Coordinate(1, 1) });geometryData.setGeometry(polygon);geometryDataList.add(geometryData);}{GeometryData geometryData = new GeometryData();GeometryFactory geometryFactory = new GeometryFactory();GeometryCollection geometryCollection = geometryFactory.createGeometryCollection(new Geometry[] {geometryFactory.createPoint(new Coordinate(1, 1)),geometryFactory.createLineString(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2) }),geometryFactory.createPolygon(new Coordinate[] { new Coordinate(1, 1), new Coordinate(2, 2),new Coordinate(3, 3), new Coordinate(1, 1) })});geometryData.setGeometry(geometryCollection);geometryDataList.add(geometryData);}long count = GeometryDataWKBMapper.insertList(geometryDataList);System.out.println(count);session.commit();} catch (Exception e) {System.out.println(e.getMessage());fail();}}
}

在這里插入圖片描述

代碼

https://github.com/f304646673/mybatis_demo

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/18225.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/18225.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/18225.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

element+ 引入圖標報錯 Failed to resolve import “@element-plus/icons-vue“ from “

element 引入圖標報錯 Internal server error: Failed to resolve import “element-plus/icons-vue” from “src\components\TimeLine.vue”. Does the file exist? 原因&#xff1a;element-plus需要單獨引入 icons 文檔 pnpm install element-plus/icons-vue之后就可以…

350種類型、10W+量級的API,企業應該怎么管?

忽如一夜春風來&#xff0c;萬物皆可API。 在互聯網時代&#xff0c;API無處不在&#xff1a;企業對外開放的數據、服務和業務能力&#xff0c;以API的形式提供給合作方&#xff1b;企業內部應用與應用、App與App之間的通信&#xff0c;通過API進行&#xff1b;甚至應用內部的…

php 連接sqlserver步驟

1.首先要確定使用的是sqlserver的哪個版本&#xff0c;比如sqlserver2012 2.確定服務器是64位還是32位的 3.確認一下使用php的哪個版本&#xff0c;比如php7.1 SQL Server 的 Microsoft PHP 驅動程序 Microsoft Drivers for PHP 支持矩陣 - PHP drivers for SQL Server | Mi…

Flutter 中的 CupertinoTabView 小部件:全面指南

Flutter 中的 CupertinoTabView 小部件&#xff1a;全面指南 在 Flutter 中&#xff0c;CupertinoTabView 是 Cupertino 組件庫中的一個 widget&#xff0c;它用于創建 iOS 風格的標簽頁視圖。這個 widget 通常與 CupertinoTabScaffold 結合使用&#xff0c;提供了一個底部帶有…

怎么做好客戶信息管理?

根據Forrester的調查表示&#xff0c;客戶滿意度的影響可能會使某些行業的收入每年增加高達 10 億美元。而提升客戶滿意度的關鍵環節便是做好客戶信息管理。但企業在進行客戶信息管理中往往會遇到以下問題&#xff1a; 客戶信息亂&#xff1a;客戶信息存在各個 Excel表格、個人…

PMP報考條件怎么查詢?如何判定自己是否符合條件?

PMP報考條件在PMI官網上就可以查詢&#xff0c;PMP報考條件只需要符合項目管理培訓經歷和項目管理經驗兩個方面的要求即可&#xff0c;大家可以對照下方的規定判斷自己是否符合PMP報名條件 PMP報考條件 以下是PMI&#xff08;中國&#xff09;官網對于PMP報名條件的規定&…

優秀的數據分析師需要具備哪些?

在數據驅動的時代&#xff0c;數據分析師的角色越來越被重視。本文將探討優秀數據分析師必備的三大核心能力&#xff0c;并通過實際案例說明如何將這些能力轉化為業務價值&#xff0c;幫助你在職業道路上更進一步。 在數字化迅速發展的今天&#xff0c;數據分析師扮演著極其重要…

ubuntu strace命令

strace 是 Linux 系統中的一個調試工具&#xff0c;用于跟蹤并記錄系統調用&#xff08;system calls&#xff09;和信號&#xff08;signals&#xff09;。在 Ubuntu 中&#xff0c;strace 命令可以幫助開發者和系統管理員了解一個程序在運行時如何與操作系統內核進行交互&…

TypeScript常見面試題第八節

題目三十六:什么是參數解構? 一、講解視頻 TS面試題三十六:什么是參數解構? 二、題目解析 本題目考察 ts 中的解構,解構是一種特殊語法,可以將對象解構到一個或多個局部變量中,可展開操作符相反,展開是允許將一個數組展開為另一個數組,或將一個對象展開為另一個對象,…

vue+antd實踐:在輸入框光標處插入內容

今天來看一個很簡單的需求。 需求描述&#xff1a;在輸入框光標處&#xff0c;插入指定的內容。 效果如下&#xff1a; 實現思路&#xff1a;剛開始還在想怎么獲取光標的位置&#xff0c;但是發現所做的項目是基于vue3antd組件&#xff0c;那么不簡單了嘛&#xff0c;只要調…

JAVA自制小游戲之推箱子

給家里孩子實現益智游戲開發,教會他怎么使用編程。以下是一個簡單的推箱子游戲的Java實現,包含兩個關卡: 這個程序包含兩個關卡,每個關卡都是一個字符串表示的地圖。游戲會提示玩家輸入移動方向(WASD),然后根據輸入的方向移動玩家。如果玩家成功將所有的箱子推到目標位…

配置物聯網平臺 保姆級教程

一、云平臺配置&#xff08;我們這里使用阿里云&#xff09; 1、注冊和登錄 &#xff08;1&#xff09;找到云平臺官網&#xff0c;點擊右上角的注冊登錄&#xff0c;完成之后&#xff0c;進行實名認證&#xff0c;任選一種認證方式。 ??????? 2、實例的開通和創建 …

Scala環境的搭建

要搭建Scala&#xff0c;我們必須先下載java&#xff0c;由于我的電腦已經搭建好了環境&#xff0c;因此我這里用截圖來教大家搭建環境。 可以從網上搜索安裝包對其進行安裝 IntelliJ IDEA – 領先的 Java 和 Kotlin IDE 不建議下載最新版的&#xff0c;大家下載的版本可以下…

本殺小程序開發實戰手冊:從構思到上線

一、引言 隨著移動互聯網的快速發展&#xff0c;劇本殺作為一種新興的娛樂方式&#xff0c;受到了越來越多年輕人的喜愛。為了滿足市場需求&#xff0c;開發一款劇本殺小程序成為了許多創業者和開發者的選擇。本文將從構思、設計、開發到上線等方面&#xff0c;為您詳細解析劇…

第52期|GPTSecurity周報

GPTSecurity是一個涵蓋了前沿學術研究和實踐經驗分享的社區&#xff0c;集成了生成預訓練Transformer&#xff08;GPT&#xff09;、人工智能生成內容&#xff08;AIGC&#xff09;以及大語言模型&#xff08;LLM&#xff09;等安全領域應用的知識。在這里&#xff0c;您可以找…

萬界星空科技定制化MES系統幫助實現數字化生產

由于不同企業的生產流程、需求和目標各異&#xff0c;MES管理系統的個性化和定制化需求也不同。有些企業需要將MES管理系統與ERP等其他管理系統進行集成&#xff0c;以實現全面的信息共享和協同工作。有些企業需要將MES管理系統與SCADA等控制系統進行集成&#xff0c;以實現實時…

windows ollama 指定模型下載路徑

為Ollama指定模型的下載路徑 在Windows系統中&#xff0c;如果想為Ollama指定模型的下載路徑&#xff0c;可以通過設置環境變量來實現。以下是詳細的步驟&#xff1a; 確定默認下載路徑&#xff1a; 默認情況下&#xff0c;Ollama的模型可能會下載到C:\Users\<用戶名>…

qt 讀取圖片,相機 編譯目錄 實戰

目錄 查看相機個數 QPixmap讀取圖片失敗,用opencv代替: QPixmap讀取圖片失敗,用QFile代替:相對目錄OK,程序所在目錄

企業內網終端監控管理軟件有哪些?推薦4款企業終端監控管理軟件

企業內網終端監控管理軟件是一種專為企業內部網絡設計的安全與管理工具&#xff0c;旨在幫助企業管理、監控和保護其內部網絡中的各種終端設備&#xff0c;如個人電腦、筆記本、移動設備等。 這類軟件的主要功能包括但不限于以下幾個方面&#xff1a; 1&#xff0c;實時監控&a…

快消終端門店真實性新玩法:全流程校驗+多元認證多重保障

在某飲品企業會議室&#xff0c;氣氛凝重。城市經理一臉嚴肅地掃視著團隊成員&#xff0c;小李、小張和小陳等人在這銳利的目光下顯得有些局促不安。 城市經理沉聲開口&#xff1a;小李上報的“幸福超市”’新店在XX大街上并不存在。這是怎么回事&#xff1f; 小李支吾著回答…