理想论坛记录

1 #nullable enable 2 using System; 3 using System.Collections.Generic; 4 using System.Threading.Tasks; 5 using System.Linq; 6 using cn.edu.yangtzeu.mqtt; 7 using System.Text.Json; 8 9 namespace NetProxy 10 { 11 internal static class Program 12 { 13 private static void Main(string[] args) 14 { 15 try 16 { 17 var configJson =JsonDocument.Parse(System.IO.File.ReadAllText("config.json")); 18 19 Dictionary<string, ProxyConfig>? configs = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, ProxyConfig>>(configJson.RootElement.GetProperty("sipProxy")); 20 if (configs == null) 21 { 22 throw new Exception("configs is null"); 23 } 24 25 var tasks = configs.SelectMany(c => ProxyFromConfig(c.Key, c.Value)); 26 Task.WhenAll(tasks).Wait(); 27 } 28 catch (Exception ex) 29 { 30 Console.WriteLine($"An error occurred : {ex}"); 31 } 32 } 33 34 private static IEnumerable<Task> ProxyFromConfig(string proxyName, ProxyConfig proxyConfig) 35 { 36 var forwardPort = proxyConfig.forwardPort; 37 var localPort = proxyConfig.localPort; 38 var forwardIp = proxyConfig.forwardIp; 39 var localIp = proxyConfig.localIp; 40 var protocol = proxyConfig.protocol; 41 try 42 { 43 if (forwardIp == null) 44 { 45 throw new Exception("forwardIp is null"); 46 } 47 if (!forwardPort.HasValue) 48 { 49 throw new Exception("forwardPort is null"); 50 } 51 if (!localPort.HasValue) 52 { 53 throw new Exception("localPort is null"); 54 } 55 if (protocol != "udp" && protocol != "tcp" && protocol != "any") 56 { 57 throw new Exception($"protocol is not supported {protocol}"); 58 } 59 } 60 catch (Exception ex) 61 { 62 Console.WriteLine($"Failed to start {proxyName} : {ex.Message}"); 63 throw; 64 } 65 66 bool protocolHandled = false; 67 if (protocol == "udp" || protocol == "any") 68 { 69 protocolHandled = true; 70 Task task; 71 try 72 { 73 var proxy = new UdpProxy(); 74 task = proxy.Start(forwardIp, forwardPort.Value, localPort.Value, localIp); 75 } 76 catch (Exception ex) 77 { 78 Console.WriteLine($"Failed to start {proxyName} : {ex.Message}"); 79 throw; 80 } 81 82 yield return task; 83 } 84 85 if (protocol == "tcp" || protocol == "any") 86 { 87 protocolHandled = true; 88 Task task; 89 try 90 { 91 var proxy = new TcpProxy(); 92 93 task = proxy.Start(forwardIp, forwardPort.Value, localPort.Value, localIp); 94 } 95 catch (Exception ex) 96 { 97 Console.WriteLine($"Failed to start {proxyName} : {ex.Message}"); 98 throw; 99 } 100 101 yield return task; 102 } 103 104 if (!protocolHandled) 105 { 106 throw new InvalidOperationException($"protocol not supported {protocol}"); 107 } 108 } 109 } 110 111 public class ProxyConfig 112 { 113 public string? protocol { get; set; } 114 public ushort? localPort { get; set; } 115 public string? localIp { get; set; } 116 public string? forwardIp { get; set; } 117 public ushort? forwardPort { get; set; } 118 } 119 120 internal interface IProxy 121 { 122 Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp = null); 123 } 124 }

1 { 2 "sipProxy": { 3 "http": { 4 "localPort": 2023, 5 "protocol": "tcp", 6 "forwardIp": "10.203.1.237", 7 "forwardPort": 2002 8 } 9 }, 10 "localWebApi": "http://127.0.0.1:2016/api/readerholding", 11 "isCustomized": true 12 }

1 #nullable enable 2 using System; 3 using System.Buffers; 4 using System.Collections.Concurrent; 5 using System.Collections.Generic; 6 using System.IO; 7 using System.Linq; 8 using System.Net; 9 using System.Net.Http; 10 using System.Net.Mail; 11 using System.Net.Sockets; 12 using System.Text; 13 using System.Threading; 14 using System.Threading.Tasks; 15 16 using cn.edu.yangtzeu.mqtt; 17 18 namespace NetProxy 19 { 20 internal class TcpProxy : IProxy 21 { 22 //lagerror 23 BdMqtt bdMqtt = new BdMqtt(); 24 //处理MQTT消息 25 public void handleMqtt(string msg) 26 { 27 Console.WriteLine("delegate:" + msg); 28 MqttMsg mqttMsg = new MqttMsg(); 29 mqttMsg.Source = "sip2"; 30 mqttMsg.Code = 0; 31 mqttMsg.Msg = msg; 32 //修改后通过WEBAPI上传,减少连接数和流量 33 //把MSG传给webapi,借书和还书 34 bdMqtt.UploadAsync(mqttMsg); 35 } 36 /// <summary> 37 /// Milliseconds 38 /// </summary> 39 public int ConnectionTimeout { get; set; } = (4 * 60 * 1000); 40 41 public async Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp) 42 { 43 var connections = new ConcurrentBag<TcpConnection>(); 44 45 IPAddress localIpAddress = string.IsNullOrEmpty(localIp) ? IPAddress.IPv6Any : IPAddress.Parse(localIp); 46 var localServer = new TcpListener(new IPEndPoint(localIpAddress, localPort)); 47 localServer.Server.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); 48 localServer.Start(); 49 50 Console.WriteLine($"TCP proxy started [{localIpAddress}]:{localPort} -> [{remoteServerHostNameOrAddress}]:{remoteServerPort}"); 51 52 //开一个线程,10秒一次,清除超时的连接,默认值4分钟 53 var _ = Task.Run(async () => 54 { 55 while (true) 56 { 57 58 await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false); 59 60 var tempConnections = new List<TcpConnection>(connections.Count); 61 while (connections.TryTake(out var connection)) 62 { 63 tempConnections.Add(connection); 64 } 65 66 foreach (var tcpConnection in tempConnections) 67 { 68 if (tcpConnection.LastActivity + ConnectionTimeout < Environment.TickCount64) 69 { 70 tcpConnection.Stop(); 71 } 72 else 73 { 74 connections.Add(tcpConnection); 75 } 76 } 77 } 78 }); 79 80 while (true) 81 { 82 try 83 { 84 var ips = await Dns.GetHostAddressesAsync(remoteServerHostNameOrAddress).ConfigureAwait(false); 85 86 var tcpConnection = await TcpConnection.AcceptTcpClientAsync(localServer, 87 new IPEndPoint(ips[0], remoteServerPort)) 88 .ConfigureAwait(false); 89 //代理处理关联 90 tcpConnection.mqttPush = handleMqtt; 91 tcpConnection.Run(); 92 connections.Add(tcpConnection); 93 } 94 catch (Exception ex) 95 { 96 Console.ForegroundColor = ConsoleColor.Red; 97 Console.WriteLine(ex); 98 Console.ResetColor(); 99 } 100 } 101 } 102 103 } 104 105 internal class TcpConnection 106 { 107 private readonly TcpClient _localServerConnection; 108 private readonly EndPoint? _sourceEndpoint; 109 private readonly IPEndPoint _remoteEndpoint; 110 private readonly TcpClient _forwardClient; 111 private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); 112 private readonly EndPoint? _serverLocalEndpoint; 113 private EndPoint? _forwardLocalEndpoint; 114 private long _totalBytesForwarded; 115 private long _totalBytesResponded; 116 public long LastActivity { get; private set; } = Environment.TickCount64; 117 //自定义 118 //public BdMqtt bdMqtt = new BdMqtt(); 119 public delegate void sipCallback(string msg); 120 public sipCallback? mqttPush; 121 122 public static async Task<TcpConnection> AcceptTcpClientAsync(TcpListener tcpListener, IPEndPoint remoteEndpoint) 123 { 124 var localServerConnection = await tcpListener.AcceptTcpClientAsync().ConfigureAwait(false); 125 localServerConnection.NoDelay = true; 126 return new TcpConnection(localServerConnection, remoteEndpoint); 127 } 128 129 private TcpConnection(TcpClient localServerConnection, IPEndPoint remoteEndpoint) 130 { 131 _localServerConnection = localServerConnection; 132 _remoteEndpoint = remoteEndpoint; 133 134 _forwardClient = new TcpClient {NoDelay = true}; 135 136 _sourceEndpoint = _localServerConnection.Client.RemoteEndPoint; 137 _serverLocalEndpoint = _localServerConnection.Client.LocalEndPoint; 138 } 139 140 public void Run() 141 { 142 RunInternal(_cancellationTokenSource.Token); 143 } 144 145 public void Stop() 146 { 147 try 148 { 149 _cancellationTokenSource.Cancel(); 150 } 151 catch (Exception ex) 152 { 153 Console.WriteLine($"An exception occurred while closing TcpConnection : {ex}"); 154 } 155 } 156 157 private void RunInternal(CancellationToken cancellationToken) 158 { 159 Task.Run(async () => 160 { 161 try 162 { 163 using (_localServerConnection) 164 using (_forwardClient) 165 { 166 await _forwardClient.ConnectAsync(_remoteEndpoint.Address, _remoteEndpoint.Port, cancellationToken).ConfigureAwait(false); 167 _forwardLocalEndpoint = _forwardClient.Client.LocalEndPoint; 168 169 Console.WriteLine($"Established TCP {_sourceEndpoint} => {_serverLocalEndpoint} => {_forwardLocalEndpoint} => {_remoteEndpoint}"); 170 171 using (var serverStream = _forwardClient.GetStream()) 172 using (var clientStream = _localServerConnection.GetStream()) 173 //task取消时候关闭流 174 using (cancellationToken.Register(() => 175 { 176 serverStream.Close(); 177 clientStream.Close(); 178 }, true)) 179 //等待数据传输完毕 180 { 181 await Task.WhenAny( 182 CopyToAsync(clientStream, serverStream, 81920, Direction.Forward, cancellationToken), 183 CopyToAsync(serverStream, clientStream, 81920, Direction.Responding, cancellationToken) 184 ).ConfigureAwait(false); 185 } 186 } 187 } 188 catch (Exception ex) 189 { 190 Console.WriteLine($"An exception occurred during TCP stream : {ex}"); 191 } 192 finally 193 { 194 Console.WriteLine($"Closed TCP {_sourceEndpoint} => {_serverLocalEndpoint} => {_forwardLocalEndpoint} => {_remoteEndpoint}. {_totalBytesForwarded} bytes forwarded, {_totalBytesResponded} bytes responded."); 195 } 196 }); 197 } 198 199 private async Task CopyToAsync(Stream source, Stream destination, int bufferSize = 81920, Direction direction = Direction.Unknown, CancellationToken cancellationToken = default) 200 { 201 byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize); 202 203 try 204 { 205 while (true) 206 { 207 int bytesRead = await source.ReadAsync(new Memory<byte>(buffer), cancellationToken).ConfigureAwait(false); 208 if (bytesRead == 0) break; 209 LastActivity = Environment.TickCount64; 210 await destination.WriteAsync(new ReadOnlyMemory<byte>(buffer, 0, bytesRead), cancellationToken).ConfigureAwait(false); 211 //自定义 212 /*1.线程内发送 2.代理发送 213 Console.WriteLine(direction.ToString() + "|" + Encoding.UTF8.GetString(buffer.Skip(0).Take(bytesRead).ToArray())); 214 MqttMsg mqttMsg = new MqttMsg(); 215 mqttMsg.Source = "sip2"; 216 mqttMsg.Code = 0; 217 mqttMsg.MsgId = Guid.NewGuid().ToString("N"); 218 mqttMsg.Msg = "数据正常";*/ 219 Console.WriteLine(direction.ToString() + "|" + Encoding.UTF8.GetString(buffer.Skip(0).Take(bytesRead).ToArray())); 220 string temp = Encoding.UTF8.GetString(buffer.Skip(0).Take(bytesRead).ToArray()); 221 //string temp1 = Encoding.UTF8.GetString(new byte[bytesRead](buffer, 0, bytesRead)); 222 if (temp.Substring(0, 2) == "12" || temp.Substring(0, 2) == "10") 223 { 224 //bdMqtt.publish(mqttMsg, "$iot/JournalBrowse/user/cxstar"); 225 mqttPush(temp); 226 } 227 228 229 //计算转发字节数 230 switch (direction) 231 { 232 case Direction.Forward: 233 Interlocked.Add(ref _totalBytesForwarded, bytesRead); 234 break; 235 case Direction.Responding: 236 Interlocked.Add(ref _totalBytesResponded, bytesRead); 237 break; 238 } 239 } 240 } 241 finally 242 { 243 ArrayPool<byte>.Shared.Return(buffer); 244 } 245 } 246 } 247 248 internal enum Direction 249 { 250 Unknown = 0, 251 Forward, 252 Responding, 253 } 254 }

#nullable enable using System; using System.Collections.Concurrent; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace NetProxy { internal class UdpProxy : IProxy { /// <summary> /// Milliseconds /// </summary> public int ConnectionTimeout { get; set; } = (4 * 60 * 1000); public async Task Start(string remoteServerHostNameOrAddress, ushort remoteServerPort, ushort localPort, string? localIp = null) { var connections = new ConcurrentDictionary<IPEndPoint, UdpConnection>(); // TCP will lookup every time while this is only once. var ips = await Dns.GetHostAddressesAsync(remoteServerHostNameOrAddress).ConfigureAwait(false); var remoteServerEndPoint = new IPEndPoint(ips[0], remoteServerPort); var localServer = new UdpClient(AddressFamily.InterNetworkV6); localServer.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); IPAddress localIpAddress = string.IsNullOrEmpty(localIp) ? IPAddress.IPv6Any : IPAddress.Parse(localIp); localServer.Client.Bind(new IPEndPoint(localIpAddress, localPort)); Console.WriteLine($"UDP proxy started [{localIpAddress}]:{localPort} -> [{remoteServerHostNameOrAddress}]:{remoteServerPort}"); var _ = Task.Run(async () => { while (true) { await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false); foreach (var connection in connections.ToArray()) { if (connection.Value.LastActivity + ConnectionTimeout < Environment.TickCount64) { connections.TryRemove(connection.Key, out UdpConnection? c); connection.Value.Stop(); } } } }); while (true) { try { var message = await localServer.ReceiveAsync().ConfigureAwait(false); var sourceEndPoint = message.RemoteEndPoint; var client = connections.GetOrAdd(sourceEndPoint, ep => { var udpConnection = new UdpConnection(localServer, sourceEndPoint, remoteServerEndPoint); udpConnection.Run(); return udpConnection; }); await client.SendToServerAsync(message.Buffer).ConfigureAwait(false); } catch (Exception ex) { Console.WriteLine($"an exception occurred on receiving a client datagram: {ex}"); } } } } internal class UdpConnection { private readonly UdpClient _localServer; private readonly UdpClient _forwardClient; public long LastActivity { get; private set; } = Environment.TickCount64; private readonly IPEndPoint _sourceEndpoint; private readonly IPEndPoint _remoteEndpoint; private readonly EndPoint? _serverLocalEndpoint; private EndPoint? _forwardLocalEndpoint; private bool _isRunning; private long _totalBytesForwarded; private long _totalBytesResponded; private readonly TaskCompletionSource<bool> _forwardConnectionBindCompleted = new TaskCompletionSource<bool>(); public UdpConnection(UdpClient localServer, IPEndPoint sourceEndpoint, IPEndPoint remoteEndpoint) { _localServer = localServer; _serverLocalEndpoint = _localServer.Client.LocalEndPoint; _isRunning = true; _remoteEndpoint = remoteEndpoint; _sourceEndpoint = sourceEndpoint; _forwardClient = new UdpClient(AddressFamily.InterNetworkV6); _forwardClient.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); } public async Task SendToServerAsync(byte[] message) { LastActivity = Environment.TickCount64; await _forwardConnectionBindCompleted.Task.ConfigureAwait(false); var sent = await _forwardClient.SendAsync(message, message.Length, _remoteEndpoint).ConfigureAwait(false); Interlocked.Add(ref _totalBytesForwarded, sent); } public void Run() { Task.Run(async () => { using (_forwardClient) { _forwardClient.Client.Bind(new IPEndPoint(IPAddress.Any, 0)); _forwardLocalEndpoint = _forwardClient.Client.LocalEndPoint; _forwardConnectionBindCompleted.SetResult(true); Console.WriteLine($"Established UDP {_sourceEndpoint} => {_serverLocalEndpoint} => {_forwardLocalEndpoint} => {_remoteEndpoint}"); while (_isRunning) { try { var result = await _forwardClient.ReceiveAsync().ConfigureAwait(false); LastActivity = Environment.TickCount64; var sent = await _localServer.SendAsync(result.Buffer, result.Buffer.Length, _sourceEndpoint).ConfigureAwait(false); Interlocked.Add(ref _totalBytesResponded, sent); } catch (Exception ex) { if (_isRunning) { Console.WriteLine($"An exception occurred while receiving a server datagram : {ex}"); } } } } }); } public void Stop() { try { Console.WriteLine($"Closed UDP {_sourceEndpoint} => {_serverLocalEndpoint} => {_forwardLocalEndpoint} => {_remoteEndpoint}. {_totalBytesForwarded} bytes forwarded, {_totalBytesResponded} bytes responded."); _isRunning = false; _forwardClient.Close(); } catch (Exception ex) { Console.WriteLine($"An exception occurred while closing UdpConnection : {ex}"); } } } }

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 using System.Threading.Tasks; 7 using Newtonsoft.Json; 8 9 using MQTTnet; 10 using MQTTnet.Client; 11 using System.Net.Http; 12 using System.Text.Json; 13 using System.Net; 14 15 namespace cn.edu.yangtzeu.mqtt 16 { 17 public class BdMqtt 18 { 19 public string? urlStr; 20 public bool isCustomized; 21 22 public BdMqtt() 23 { 24 var configJson = JsonDocument.Parse(System.IO.File.ReadAllText("config.json")); 25 urlStr= configJson.RootElement.GetProperty("localWebApi").GetString(); 26 isCustomized = configJson.RootElement.GetProperty("isCustomized").GetBoolean(); 27 if (isCustomized == false) 28 { 29 urlStr = urlStr + "?isCustomized=false"; 30 } 31 else 32 { 33 urlStr = urlStr + "?isCustomized=true"; 34 } 35 } 36 37 public async void UploadAsync(MqttMsg msg) 38 { 39 try 40 { 41 //Console.WriteLine("接收到要POST到readerandholding接口的数据:{0},url:{1}",msg.Msg,urlStr); 42 string result = string.Empty; 43 using (HttpContent httpContent = new StringContent(System.Text.Json.JsonSerializer.Serialize(msg), System.Text.Encoding.UTF8, "application/json")) 44 { 45 using (HttpClient httpClient = new HttpClient()) 46 { 47 try 48 { 49 using (HttpResponseMessage httpRes = await httpClient.PostAsync(urlStr, httpContent)) 50 { 51 //if (httpRes.IsSuccessStatusCode) 52 //{ 53 result = httpRes.Content.ReadAsStringAsync().Result; 54 Console.WriteLine("UPLOAD SIP2消息到readerandholding接口的返回值:{0},statusCode:{1}",result,httpRes.StatusCode.ToString()); 55 //} 56 httpRes.Dispose(); 57 } 58 59 } 60 catch (Exception ex) 61 { 62 Console.WriteLine("bdmqtt:" + ex.Message); 63 } 64 finally 65 { 66 httpClient.Dispose(); 67 httpContent.Dispose(); 68 } 69 } 70 } 71 return ; 72 } 73 catch (Exception ex) 74 { 75 Console.WriteLine("bdmqtt:"+ex.Message); 76 } 77 } 78 } 79 80 public class MqttMsg 81 { 82 public string? Source { set; get; } 83 public string? MsgId { set; get; } 84 public int? Code { set; get; } 85 public string? Msg { set; get; } 86 public dynamic? Data { set; get; } 87 } 88 public class RetMsg 89 { 90 public int? ReturnCode { set; get; } 91 public string? ReturnMsg { set; get; } 92 public dynamic? data { set; get; } 93 } 94 95 }
//运行截图
1.2 接收SIP2的借还数据后取得读者证号获取读者信息和图书条码号获取图书信息,其中读者数据来源于网信中心,图书数据来源于INERLIB的biblios和holding表
//读者和馆藏获取

using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; using Oracle.ManagedDataAccess.Client; using readerAndholding.Model; using readerAndholding.Mqtt; using System.Collections; using System.Data; using System.Text; namespace readerAndholding.Controllers { [Route("api/[controller]")] [ApiController] public class ReaderHoldingController : ControllerBase { IConfiguration? _configuration; IHttpClientFactory _httpClientFactory; MqttHttp _mqttHttp; string Save; string University; public ReaderHoldingController(IConfiguration configuration, IHttpClientFactory httpClientFactory,MqttHttp mqttHttp) { _configuration = configuration; University = _configuration["MqttOption:UniversityName"].ToString(); Save= _configuration["MqttOption:Save"].ToString(); _httpClientFactory = httpClientFactory; _mqttHttp = mqttHttp; } /// <summary> /// 用来回溯借阅记录 /// </summary> /// <param name="readerNo">读者证号</param> /// <param name="barcode">条码号</param> /// <param name="timestamp">借阅时间戳</param> /// <returns></returns> [HttpGet] public async Task<ActionResult> Get(string readerNo, string barcode,Int64 timestamp) { Msg msg = new Msg(); //将教师信息屏蔽 if (readerNo.Length < 7) { msg.code = 1; msg.message = "屏蔽教职工数据"; msg.reflection = "ReaderHoldingController.get"; Logger.Warn(msg.ToString()); return Ok(msg); } string retLocal = "{'msg':'发送错误'}"; Hashtable ht = new Hashtable(); try { //获取读者信息 Reader reader = new Reader().getReader(readerNo); //获取书目信息 Holding holding = new Holding().GetHolding(barcode); //如果没有查到读者或者书目,直接返回 if(reader.ReaderNo== null || holding.RecordNo==null) { msg.code = 2; msg.message = "读者或书目记录为空"; msg.reflection = "ReaderHoldingController.get"; Logger.Warn(msg.ToString()); return Ok(msg); } ht.Add("reader", reader); ht.Add("holding", holding); //先推送到本地 retLocal = Newtonsoft.Json.JsonConvert.SerializeObject(ht); await MqttPublish.MqttPulishAsync(retLocal, "local/readerAndholding/" +University); //再推送到云端 Tsdb tsdb=new Tsdb(); tsdb.datapoints = new List<DatapointsItem>(); DatapointsItem datapointsItem = new DatapointsItem(); Tags tags= new Tags(); tags.CalisId = holding.CalisId; tags.ISBN = holding.ISBN; tags.Title = holding.Title; tags.PublishDate = holding.PublishDate; tags.Publisher = holding.Publisher; tags.Price = holding.Price; tags.ClassNo = holding.ClassNo; tags.Author = holding.Author; tags.RecordNo = holding.RecordNo; //引用第三方,从MARC中获取CALISID号,但多数没有同步 tags.CalisId = holding.CalisId; tags.Save =Save; tags.University = University; tags.Academy = reader.Academy; tags.Major = reader.Major; tags.Subject = reader.Subject; tags.Grade = reader.Grade; tags.Degree = reader.Degree; tags.Sex = reader.Sex; datapointsItem.field = "ReaderNo"; datapointsItem.metric = "circulationT"; datapointsItem.type = "String"; datapointsItem.value = reader.ReaderNo; if(timestamp>1000) { datapointsItem.timestamp = timestamp; } datapointsItem.tags= tags; tsdb.datapoints.Add(datapointsItem); string retCloud = Newtonsoft.Json.JsonConvert.SerializeObject(tsdb); await _mqttHttp.HttpPublish(retCloud); } catch (Exception ex) { msg.code = 3; msg.message = ex.Message; msg.data = ex.StackTrace; msg.reflection = "ReaderHoldingController.get"; Logger.Error(msg.ToString(), ex); return Ok(msg); } Logger.Info(msg.ToString()); return Ok(retLocal); } /// <summary> /// 接收SIP2代理传过来的原始数,查询读者和书目信息,并入库和推送 /// </summary> /// <param name="mqttMsg">SIP2消息</param> /// <param name="isCustomized">是否实现了书目和读者的信息接口</param> /// <returns></returns> [HttpPost] public async Task<ActionResult> Post([FromBody] MqttMsg mqttMsg,bool isCustomized) { Msg msg= new Msg(); //如果获取读者和书目信息没有本地定制,则直接发送SIP2中的10,12消息头到本地 if (!isCustomized) { try { //推送到本地 await MqttPublish.MqttPulishAsync(Newtonsoft.Json.JsonConvert.SerializeObject(mqttMsg), "local/readerAndholding/" + _configuration["MqttOption:UniversityName"].ToString()); } catch (Exception ex) { msg.code = 4; msg.message = ex.Message; msg.source = "发送MQTTMsg到本地错误"; msg.data = ex.StackTrace; msg.reflection = "ReaderHoldingController.post"; Logger.Error(msg.ToString(), ex); return Ok(msg); } return Ok(true); } //获取读者和书目信息没有本地定制,推送到本地和云端 else { try { var temp = mqttMsg.Msg.Split("|"); string readerNo = ""; string name; string barcode = ""; string title; string remark; for (int i = 0; i < temp.Length; i++) { if (temp[i].Substring(0, 2) == "AA") { readerNo = temp[i].Substring(2, temp[i].Length - 2); } else if (temp[i].Substring(0, 2) == "AB") { barcode = temp[i].Substring(2, temp[i].Length - 2); } else if (temp[i].Substring(0, 2) == "AE") { name = temp[i].Substring(2, temp[i].Length - 2); } else if (temp[i].Substring(0, 2) == "AF") { remark = temp[i].Substring(2, temp[i].Length - 2); } else if (temp[i].Substring(0, 2) == "AJ") { title = temp[i].Substring(2, temp[i].Length - 2); } } //将教师信息屏蔽 if (readerNo.Length < 7) { msg.code = 1; msg.message = "屏蔽教职工数据"; msg.reflection = "ReaderHoldingController.get"; Logger.Warn(msg.ToString()); return Ok(msg); } string retLocal = "{'msg':'发送错误'}"; Hashtable ht = new Hashtable(); try { //获取读者信息 Reader reader = new Reader().getReader(readerNo); //获取书目信息 Holding holding = new Holding().GetHolding(barcode); ht.Add("reader", reader); ht.Add("holding", holding); //如果没有查到读者或者书目,直接返回 if (reader.ReaderNo == null || holding.RecordNo == null) { msg.code = 2; msg.message = "读者或书目记录为空"; msg.reflection = "ReaderHoldingController.get"; Logger.Warn(msg.ToString()); return Ok(msg); } mqttMsg.Data = ht; //先推送到本地 retLocal = Newtonsoft.Json.JsonConvert.SerializeObject(mqttMsg); await MqttPublish.MqttPulishAsync(retLocal, "local/readerAndholding/" + University); //再推送到云端 Tsdb tsdb = new Tsdb(); tsdb.datapoints = new List<DatapointsItem>(); DatapointsItem datapointsItem = new DatapointsItem(); Tags tags = new Tags(); tags.CalisId = holding.CalisId; tags.ISBN = holding.ISBN; tags.Title = holding.Title; tags.PublishDate = holding.PublishDate; tags.Publisher = holding.Publisher; tags.Price = holding.Price; tags.ClassNo = holding.ClassNo; tags.Author = holding.Author; tags.RecordNo = holding.RecordNo; //引用第三方,从MARC中获取CALISID号,但多数没有同步 tags.CalisId = holding.CalisId; tags.Save = Save; tags.University = University; tags.Academy = reader.Academy; tags.Major = reader.Major; tags.Subject = reader.Subject; tags.Grade = reader.Grade; tags.Degree = reader.Degree; tags.Sex = reader.Sex; datapointsItem.field = "ReaderNo"; datapointsItem.metric = "circulationT"; datapointsItem.type = "String"; datapointsItem.value = reader.ReaderNo; datapointsItem.tags = tags; TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); datapointsItem.timestamp = Convert.ToInt64(ts.TotalMilliseconds); tsdb.datapoints.Add(datapointsItem); retLocal = Newtonsoft.Json.JsonConvert.SerializeObject(tsdb); await _mqttHttp.HttpPublish(retLocal); } catch (Exception ex) { Logger.Error(msg.ToString(),ex); return NoContent(); } } catch (Exception ex) { msg.code = 3; msg.message = ex.Message; msg.data = ex.StackTrace; msg.reflection = "ReaderHoldingController.post"; Logger.Error(msg.ToString(), ex); return Ok(msg); } Logger.Info(msg.ToString()); return Ok(msg); } } /// <summary> /// 按年度回溯借阅日志(只适合INTERLIB) /// </summary> /// <param name="year">年</param> /// <returns></returns> [HttpGet] [Route("updateYear")] public async Task<ActionResult> updateYear(string year) { Msg msg= new Msg(); int i = 0; int j = 0; using (OracleConnection conn = new OracleConnection()) { string oracleConnstr = "Data Source = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 10.203.1.237)(PORT = 1521)))(CONNECT_DATA = (SERVICE_NAME = interlib))); User Id = inter; Password = win ; "; conn.ConnectionString = oracleConnstr; conn.Open(); OracleCommand comm = new OracleCommand(); comm.Connection = conn; string commstr ; commstr = "select data2,data3,to_char(regtime,'yyyy-mm-dd hh24:mi:ss') from log_cir where to_char(regtime, 'yyyy') = :year and logtype = '30001'"; comm.CommandText = commstr; //取出long类型中的字符串 comm.Parameters.Clear(); comm.Parameters.Add("@year", year); OracleDataReader dataReader= comm.ExecuteReader(); HttpClient hc= new HttpClient(); string readerNo=""; string barcode=""; Int64 timestamp = 0; while(dataReader.Read()) { try { i++; readerNo = dataReader.GetString(0); Console.WriteLine(i.ToString()+":"+readerNo); barcode = dataReader.GetString(1); timestamp = (Convert.ToDateTime(dataReader.GetString(2)).ToUniversalTime().Ticks - 621355968000000000) / 10000; string url = string.Format("http://127.0.0.1:2016/api/readerholding?readerNo={0}&barcode={1}×tamp={2}", readerNo, barcode, timestamp); var httpResponseMessage = await hc.GetAsync(url); if (httpResponseMessage.IsSuccessStatusCode) { var tempStr = await httpResponseMessage.Content.ReadAsStringAsync(); j++; } } catch(Exception ex) { msg.message = ex.StackTrace; msg.source = "在循环处理年度日志中发生错误"; msg.reflection = "ReaderHoldingController:updateyear"; msg.code = 1; Logger.Error(msg.ToString(), ex); } } } msg.message = string.Format("i:{0};j:{1}",i,j); Logger.Info(msg.ToString()); return Ok(msg); } } }
//主程序,实现的MQTT协议和WEBSOCKER的数据转发,可以提供WEB端的大屏幕实时数据展示,其中推送到BAIDU IOT 平台采用了HTTP的方式,为了节约MQTT的连接数

1 using MQTTnet.AspNetCore; 2 using MQTTnet.Server; 3 using readerAndholding.Mqtt; 4 5 var builder = WebApplication.CreateBuilder(args); 6 7 var host = Host.CreateDefaultBuilder(Array.Empty<string>()) 8 .ConfigureWebHostDefaults( 9 webBuilder => 10 { 11 webBuilder.UseKestrel( 12 o => 13 { 14 // This will allow MQTT connections based on TCP port 1883. 15 o.ListenAnyIP(2012, v => v.UseMqtt()); 16 17 // This will allow MQTT connections based on HTTP WebSockets with URI "localhost:5000/mqtt" 18 // See code below for URI configuration. 19 o.ListenAnyIP(2014); // Default HTTP pipeline 20 21 }); 22 23 webBuilder.UseStartup<Startup>(); 24 }); 25 host.RunConsoleAsync(); 26 27 // Add services to the container. 28 29 builder.Services.AddControllers(); 30 builder.Services.AddHttpClient(); 31 builder.Services.AddSingleton<MqttHttp>(); 32 33 var app = builder.Build(); 34 35 // Configure the HTTP request pipeline. 36 app.UseRouting(); 37 38 app.UseAuthorization(); 39 40 app.UseStaticFiles(); 41 42 app.MapControllers(); 43 44 app.Run("http://*:2016");
//运行截图
1.3 订阅百度IOT数据,通过Z3950协议查询ISBN,记录下CALISID,将书目和读者数据入库并提供MQTT和websocket数据推送
//主程序

using Microsoft.EntityFrameworkCore; using Mqtt.Models.Z39; using MQTTnet.AspNetCore; using z39web.Models.DB; using z39web.Models.Mqtt; using z39web.Models.Z39; var builder = WebApplication.CreateBuilder(args); //添加MQTT服务 var host = Host.CreateDefaultBuilder(Array.Empty<string>()) .ConfigureWebHostDefaults( webBuilder => { webBuilder.UseKestrel( o => { o.ListenAnyIP(2020, v => v.UseMqtt()); o.ListenAnyIP(2022); }); webBuilder.UseStartup<Startup>(); }); host.RunConsoleAsync(); // Add services to the container. /*MYSQL,直接用原始SQL语句插入JSON var connStr =builder.Configuration["ConnectionStrings:MysqlConnection"]; builder.Services.AddDbContext<MyDBContext>(options => options.UseMySQL(connStr) ); */ //isbn,calisId查询 builder.Services.AddSingleton<IZ39,Z39>(); builder.Services.AddSingleton<IMqttReceive,MqttReceive>(); builder.Services.AddControllers(); builder.Services.AddHttpClient(); var app = builder.Build(); // Configure the HTTP request pipeline. app.UseRouting(); app.UseAuthorization(); app.UseStaticFiles(); app.MapControllers(); app.Run("http://*:2018");
//CALIS查询比对和入库,用到的是群友dp2的开源代码,其中封装好的z39的检索和解析库

1 using System.Text; 2 using System.Reflection.Metadata; 3 using System; 4 5 using MySql.Data; 6 using MySql.EntityFrameworkCore; 7 using MySql; 8 9 using DigitalPlatform.Z3950; 10 using static DigitalPlatform.Z3950.ZClient; 11 using DigitalPlatform.Text; 12 using DigitalPlatform.Net; 13 using System.Web; 14 using DigitalPlatform.Marc; 15 using System.Xml; 16 using z39web.Models.DB; 17 using Microsoft.EntityFrameworkCore; 18 using MySql.Data.MySqlClient; 19 using ConfigurationManager = Microsoft.Extensions.Configuration.ConfigurationManager; 20 21 namespace z39web.Models.Z39 22 { 23 public class Z39 : IZ39 24 { 25 public ZClient _zclient; 26 public TargetInfo _targetInfo; 27 28 public Z39() 29 { 30 //初始化变量 31 ConfigurationManager configurationManager = new ConfigurationManager(); 32 configurationManager.AddJsonFile("appsettings.json", true, reloadOnChange: false); 33 string MysqlConnection = configurationManager["ConnectionStrings:MysqlConnection"].ToString(); 34 35 _targetInfo = new TargetInfo(); 36 _targetInfo.HostName = configurationManager["Calis:Host"].ToString(); 37 _targetInfo.Password = configurationManager["Calis:Password"].ToString(); 38 _targetInfo.UserName = configurationManager["Calis:UserName"].ToString(); 39 _targetInfo.Port = Convert.ToInt32(configurationManager["Calis:Port"]); 40 _targetInfo.DbNames = new string[] { configurationManager["Calis:DbNames"].ToString() }; 41 _targetInfo.AuthenticationMethod = Convert.ToInt32(configurationManager["Calis:AuthenticationMethod"]); 42 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); 43 _targetInfo.DefaultQueryTermEncoding = Encoding.GetEncoding(936); 44 _targetInfo.DefaultRecordsEncoding = Encoding.GetEncoding(936); 45 _targetInfo.PresentPerBatchCount = 1; 46 47 //全局连接 48 _zclient = new ZClient(); 49 50 InitialResult result = _zclient.TryInitialize(_targetInfo).GetAwaiter().GetResult(); 51 Console.WriteLine("calis z39初始化结果:"+result.ToString()); 52 if (result.Value == -1) 53 { 54 Console.WriteLine("全局联机错误:{0}", result.ErrorInfo); 55 } 56 } 57 58 //接口实现,指定查询类型isbn和calisId,isbn不加-,calisId不加CAL_ 59 public Msg Search(string typ, string str) 60 { 61 Msg msg = new Msg(); 62 63 msg = LocalSearch(typ, str); 64 if (msg.Code == 0) 65 { 66 return msg; 67 } 68 else 69 { 70 msg = CalisSearch(typ, str); 71 msg.Source = "calis"; 72 } 73 return msg; 74 } 75 76 //本地检索,若没有对应的calisId, 77 private Msg LocalSearch(string typ, string str) 78 { 79 Msg msg = new Msg(); 80 string commstr = ""; 81 Biblios biblios = new Biblios(); 82 if (string.IsNullOrWhiteSpace(typ) && string.IsNullOrWhiteSpace(str)) 83 { 84 msg.Code = 1; 85 msg.Message = "查询类型和变量不符合要求"; 86 return msg; 87 } 88 if (typ == "calisId") 89 { 90 commstr = "select * from biblios where calisId=@calisId"; 91 } 92 else if (typ == "isbn") 93 { 94 commstr = "select * from biblios where isbn=@isbn"; 95 } 96 else 97 { 98 msg.Code = 1; 99 msg.Message = "查询类型和变量不符合要求"; 100 return msg; 101 } 102 //从本地数据库中查找MARC记录 103 try 104 { 105 using (MySqlConnection conn = new MySqlConnection()) 106 { 107 string connstr = "server=10.40.6.13;user id=root;Password=this;sslmode=None;database=calisbiblios"; 108 conn.ConnectionString = connstr; 109 conn.Open(); 110 MySqlCommand comm = new MySqlCommand(); 111 comm.Connection = conn; 112 comm.CommandText = commstr; 113 comm.Parameters.Clear(); 114 if (typ == "calisId") 115 { 116 comm.Parameters.Add("@calisId", MySqlDbType.VarString).Value = str; 117 } 118 else 119 { 120 comm.Parameters.Add("@isbn", MySqlDbType.VarString).Value = str.Replace("-", ""); 121 } 122 MySqlDataReader dr = comm.ExecuteReader(); 123 if (dr.Read()) 124 { 125 biblios.CalisId = dr["calisId"].ToString(); 126 biblios.Isbn = dr["isbn"].ToString(); 127 biblios.Title = dr["title"].ToString(); 128 biblios.Author = dr["author"].ToString(); 129 biblios.Publisher = dr["publisher"].ToString(); 130 biblios.PublishDate = dr["publishDate"].ToString(); 131 biblios.ClassNo = dr["classNo"].ToString(); 132 biblios.Price = dr["price"].ToString(); 133 biblios.Marc = Convert.ToBase64String(Encoding.UTF8.GetBytes(dr["marc"].ToString())); 134 msg.Data = biblios; 135 } 136 else 137 { 138 msg.Code = 2; 139 msg.Message = "本地没有找到记录"; 140 } 141 dr.Close(); 142 conn.Close(); 143 } 144 } 145 catch (Exception ex) 146 { 147 msg.Code = 3; 148 msg.Message = ex.Message; 149 } 150 return msg; 151 } 152 153 //calis检索,则查询CALIS并插入本地库 154 private Msg CalisSearch(string typ, string str) 155 { 156 Msg msg = new Msg(); 157 /* 158 //初始化连接 159 InitialResult result = _zclient.TryInitialize(_targetInfo).GetAwaiter().GetResult(); 160 //连接错误返回 161 if (result.Value == -1) 162 { 163 Console.WriteLine("初始化连接发送错误:{0}", result.ErrorInfo); 164 msg.Code = 1; 165 msg.Message = result.ErrorInfo; 166 return msg; 167 }*/ 168 //参数检查 169 string strQueryString = ""; 170 if (typ == "isbn") 171 { 172 strQueryString = "\"" + str + "\"/1=7"; 173 } 174 else if (typ == "calisId") 175 { 176 strQueryString = "\"" + str + "\"/1=12"; 177 } 178 else 179 { 180 msg.Code = 1; 181 msg.Message = "参数不合要求"; 182 return msg; 183 } 184 //查询 185 SearchResult search_result = _zclient.Search( 186 strQueryString, 187 _targetInfo.DefaultQueryTermEncoding, 188 _targetInfo.DbNames, 189 _targetInfo.PreferredRecordSyntax, 190 "default").Result; 191 Console.WriteLine("calis z39查询结果:"+search_result.ToString()); 192 if (search_result.ResultCount < 1) 193 { 194 msg.Message = "没有检索到数据"; 195 return msg; 196 } 197 //检索错误,返回 198 if (search_result.Value == -1 || search_result.Value == 0) 199 { 200 Console.WriteLine("检索发送错误:{0}", search_result.ErrorInfo); 201 msg.Code = 2; 202 msg.Message = search_result.ErrorInfo; 203 return msg; 204 } 205 else 206 { 207 Console.WriteLine("检索共命中记录:{0} ", search_result.ResultCount); 208 } 209 //取回数据 210 long _resultCount = search_result.ResultCount; 211 int _fetched = 0; 212 PresentResult present_result = _zclient.Present( 213 "default", 214 _fetched, 215 Math.Min((int)_resultCount - _fetched, 1), 216 1, 217 "F", 218 _targetInfo.PreferredRecordSyntax).Result; 219 220 //取回数据错误,返回 221 if (present_result.Value == -1) 222 { 223 Console.WriteLine("present result:{0}", present_result.ToString()); 224 msg.Code = 3; 225 msg.Message = present_result.ErrorInfo; 226 return msg; 227 } 228 else 229 { 230 //如果查到MARC数据,并且在本地数据库中没有,则插入到本地 231 if (present_result.Records.Count == 1) 232 { 233 Biblios biblios = new Biblios(); 234 string? calisIdValue = ""; 235 string? isbnValue = ""; 236 string? priceValue = ""; 237 string? titleValue = ""; 238 string? authorValue = ""; 239 string? publisherValue = ""; 240 string? publishDateValue = ""; 241 string? classNoValue = ""; 242 string strMarc="", strXml, strError; 243 try 244 { 245 XmlDocument xmlDocument; 246 MarcLoader.ConvertIso2709ToMarcString(present_result.Records[0].m_baRecord, Encoding.GetEncoding(936), false, out strMarc, out strError); 247 MarcUtil.Marc2Xml(strMarc, "unimarc", out xmlDocument, out strError); 248 var nsmgr = new XmlNamespaceManager(xmlDocument.NameTable); 249 nsmgr.AddNamespace("unimarc", "http://dp2003.com/UNIMARC"); 250 var json = Newtonsoft.Json.JsonConvert.SerializeXmlNode(xmlDocument); 251 //取出索引字段 252 var calisIdxml = xmlDocument.SelectSingleNode("//unimarc:controlfield[@tag='001']", nsmgr); 253 calisIdValue=calisIdxml==null?"":calisIdxml.InnerText; 254 var isbnxml = xmlDocument.SelectSingleNode("//unimarc:datafield[@tag='010']/unimarc:subfield[@code='a']", nsmgr); 255 isbnValue=isbnxml==null?"":isbnxml.InnerText; 256 var pricexml = xmlDocument.SelectSingleNode("//unimarc:datafield[@tag='010']/unimarc:subfield[@code='d']", nsmgr); 257 priceValue= pricexml == null ? "" : pricexml.InnerText; 258 var titlexml = xmlDocument.SelectSingleNode("//unimarc:datafield[@tag='200']/unimarc:subfield[@code='a']", nsmgr); 259 titleValue = titlexml == null ? "" : titlexml.InnerText; 260 var authorxml = xmlDocument.SelectSingleNode("//unimarc:datafield[@tag='200']/unimarc:subfield[@code='f']", nsmgr); 261 authorValue = authorxml == null ? "" : authorxml.InnerText; 262 var publisherxml = xmlDocument.SelectSingleNode("//unimarc:datafield[@tag='210']/unimarc:subfield[@code='c']", nsmgr); 263 publisherValue = publisherxml == null ? "" : publisherxml.InnerText; 264 var publishDatexml = xmlDocument.SelectSingleNode("//unimarc:datafield[@tag='210']/unimarc:subfield[@code='d']", nsmgr); 265 publishDateValue = publishDatexml == null ? "" : publishDatexml.InnerText; 266 //因为下载限制,使用采用简编数据填充并标识 267 var classNoxml = xmlDocument.SelectSingleNode("//unimarc:datafield[@tag='690']/unimarc:subfield[@code='a']", nsmgr); 268 classNoValue = classNoxml == null ? "simple" : classNoxml.InnerText; 269 //返回biblios 270 biblios.Author = authorValue; 271 biblios.Publisher = publisherValue; 272 biblios.PublishDate = publishDateValue; 273 biblios.Price = priceValue; 274 biblios.CalisId = calisIdValue.Substring(4); 275 biblios.Title = titleValue; 276 biblios.Isbn = isbnValue; 277 biblios.Marc = Convert.ToBase64String(Encoding.UTF8.GetBytes(strMarc)); 278 msg.Data = biblios; 279 //简编没有分类号 280 biblios.ClassNo = classNoValue; 281 } 282 catch (Exception ex) 283 { 284 msg.Code = 100; 285 msg.Message = ex.Message; 286 msg.Source = "解析MARC数据错误"; 287 msg.ToString(); 288 } 289 //数据插入 290 using (MySqlConnection conn = new MySqlConnection()) 291 { 292 string connstr = "server=10.40.6.13;user id=root;Password=this;sslmode=None;database=calisbiblios"; 293 conn.ConnectionString = connstr; 294 conn.Open(); 295 MySqlCommand comm = new MySqlCommand(); 296 comm.Connection = conn; 297 string commstr = "insert into biblios (calisId,isbn,title,author,publisher,publishDate,price,classNo,marc) values (@calisId,@isbn,@title,@author,@publisher,@publishDate,@price,@classNo,@marc)"; 298 comm.CommandText = commstr; 299 comm.Parameters.Clear(); 300 comm.Parameters.Add("@calisId", MySqlDbType.VarString).Value = calisIdValue.Substring(4); 301 comm.Parameters.Add("@isbn", MySqlDbType.VarString).Value = isbnValue.Replace("-", ""); 302 comm.Parameters.Add("@title", MySqlDbType.VarString).Value = titleValue; 303 comm.Parameters.Add("@author", MySqlDbType.VarString).Value = authorValue; 304 comm.Parameters.Add("@publisher", MySqlDbType.VarString).Value = publisherValue; 305 comm.Parameters.Add("@publishDate", MySqlDbType.VarString).Value = publishDateValue; 306 comm.Parameters.Add("@price", MySqlDbType.VarString).Value = priceValue; 307 comm.Parameters.Add("@classNo", MySqlDbType.VarString).Value = classNoValue; 308 comm.Parameters.Add("@marc", MySqlDbType.VarString).Value = strMarc; 309 try 310 { 311 int i = comm.ExecuteNonQuery(); 312 } 313 catch (Exception ex) 314 { 315 Console.WriteLine(ex.Message); 316 msg.Code = 4; 317 msg.Message = ex.Message; 318 } 319 finally 320 { 321 conn.Close(); 322 } 323 } 324 } 325 else 326 { 327 msg.Code = 5; 328 msg.Message = "calis书目数据中未能查到记录"; 329 } 330 } 331 return msg; 332 } 333 } 334 }
//运行截图

目的
为了进一步加强数据库的安全性 ,建议需要开启数据库的归档模式。
这样做的好处有:
1.数据库文件出现因为磁盘坏块出现坏块,能快速应用归档日志进行恢复。
2.数据库服务器掉电产生数据库文献错误需要进行介质恢复的之后,可以直接应用归档恢复。
3.归档日志开启建议有条件的所有用户开启,oracle默认没有开启。
注意事项:
1.Imp批导入大量数据,大数据量批操作的时候建议关闭归档模式
2.建议磁盘空间够用的情况下,将归档日志目录设置到最大值。比如磁盘剩余200G那么归档日志存放目录大小就设置为200G
**(重要说明:开启归档日志是需要图书馆技术人员有维护能力,因为归档日志如果没有做好任务计划导致满了,那么数据库将自动宕机。
以下命令涉及数据库的重启,所以如果需要操作建议在非业务时间做好数据库全备份的前提下进行)**
开启方式:
步骤一: 闭馆后在数据库服务器上备份数据库,并把数据库备份文件拷贝到其他机器保存。
步骤二:进入命令窗口 输入sqlplus “/as sysdba” 进入超级用户sql环境
步骤三:运行 archive log list 命令得出下列界面,如果是 非存档模式就需要做调整
步骤四:shutdown immediate 关闭数据库,然后 startup mount 打开数据库到加载模式
步骤五:alter database archivelog;改变归档模式为开启归档
步骤六:使用alter system set db_recovery_file_dest_size=200G scope=both;
更改归档目录大小;
alter database open;启动打开数据库
步骤七:设置自动任务计划每天任务计划删除7天前的过久的归档日志,释放磁盘空间。
脚本文件内容如下,附件中也附带脚本:
delete_arch.sh 文件内容:
#!bin/sh
source /home/oracle/.bash_profile
rman target / cmdfile=/opt/app/oracle/scrip_delete_arch/del_arch.sh
del_arch.sh 文件内容:
delete archivelog all completed before 'sysdate-7';
windows环境下对于的脚本:
在根盘符创建一个delete_arch的目录,比如D盘。
Delete_arch目录里面包含两个文件:
第一个文件:delte_arch.bat文件,文件内容是:
rman target / cmdfile=D:\ delete_arch\del_arch.sql
第二个文件:del_arch.sql
文件内容是:
delete archivelog all completed before 'sysdate-7';
将delte_arch.bat加入任务计划,每天晚上执行。

1 package com.example.sendmessage; 2 3 import com.alibaba.fastjson.JSON; 4 import com.alibaba.fastjson.JSONArray; 5 import com.alibaba.fastjson.JSONObject; 6 import com.alibaba.fastjson.parser.Feature; 7 import com.alibaba.fastjson.parser.ParserConfig; 8 import com.alibaba.fastjson.serializer.SerializerFeature; 9 import com.google.gson.Gson; 10 import com.ververica.cdc.connectors.oracle.OracleSource; 11 import com.ververica.cdc.connectors.shaded.org.apache.kafka.connect.source.SourceRecord; 12 import com.ververica.cdc.debezium.JsonDebeziumDeserializationSchema; 13 14 import org.apache.flink.streaming.api.datastream.DataStream; 15 import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; 16 import org.apache.flink.streaming.api.functions.sink.SinkFunction; 17 import org.apache.flink.streaming.api.functions.source.SourceFunction; 18 import org.apache.flink.api.common.functions.MapFunction; 19 import org.apache.http.HttpEntity; 20 import org.apache.http.client.methods.CloseableHttpResponse; 21 import org.apache.http.client.methods.HttpPost; 22 import org.apache.http.entity.ContentType; 23 import org.apache.http.entity.StringEntity; 24 import org.apache.http.impl.client.CloseableHttpClient; 25 import org.apache.http.impl.client.HttpClients; 26 import org.apache.http.util.EntityUtils; 27 28 import java.io.InputStream; 29 import java.util.Properties; 30 import java.util.Scanner; 31 32 public class TEST { 33 public static void main(String[] args) throws Exception { 34 Properties pro=new Properties(); 35 pro.put("database.pdb.name","inte"); 36 pro.put("log.mining.strategy","online_catalog"); 37 //pro.put("log.mining.continuous.mine","true"); 38 SourceFunction<String> sourceFunction = OracleSource.<String>builder() 39 .hostname("10.40.6.131") 40 .url("jdbc:oracle:thin:@10.40.6.13:1521/inter") 41 .port(1521) 42 .database("inter") // monitor XE database 43 .schemaList("inter") // monitor inventory schema 44 //.startupOptions(StartupOptions.latest()) 45 .tableList("inter.loan_work") // monitor products table 46 .debeziumProperties(pro) 47 .username("c##dbzuser") 48 .password("this") 49 .deserializer(new JsonDebeziumDeserializationSchema()) // converts SourceRecord to JSON String 50 .build(); 51 // Configuration configuration=new Configuration(); 52 //configuration.setString("execution.savepoint.path","file:///D:/checkoracle/cd720959c394888c1bc277e310b35b2d/chk-23"); 53 54 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); 55 56 //env.enableCheckpointing(30000); 57 //env.getCheckpointConfig().setCheckpointStorage("file:///d:/checkoracle"); 58 // 获取 CDC 数据流 59 String URL = "http://reader.yzu.edu.cn/syncdb/api/loan_work"; 60 // DataStream<String> cdcStream = env.addSource(sourceFunction); 61 DataStream<String> mappedStream = processCdcStream(env, sourceFunction); 62 63 mappedStream.addSink(new HttpSink(URL)); 64 // mappedStream.print(); 65 // mappedStream.print(); 66 67 68 69 env.execute(); 70 String str = System.console().readLine(); 71 } 72 //数据map 处理部分 73 public static DataStream<String> processCdcStream(StreamExecutionEnvironment env, SourceFunction<String> source) { 74 DataStream<String> cdcStream = env.addSource(source); 75 DataStream<String> mappedStream = cdcStream.map(new MapFunction<String, String>() { 76 @Override 77 public String map(String value) throws Exception { 78 // 在这里对输入数据进行处理 79 //JOSN数组 80 JSONArray jsonArray = new JSONArray(); 81 //全部的json数据 82 JSONObject jsonObject = JSON.parseObject(value); 83 JSONObject allJson = new JSONObject(); 84 allJson.put("id",2); 85 allJson.put("source",jsonObject.toString()); 86 allJson.put("university","Yangtze University"); 87 allJson.put("token","4-8-2021"); 88 jsonArray.add(allJson); 89 90 91 value=JSON.toJSONString(jsonArray); 92 // 返回处理后的输出数据 93 return value ; 94 } 95 }); 96 return mappedStream; 97 } 98 99 public static class HttpSink implements SinkFunction<String> { 100 private String URL; 101 102 public HttpSink(String URL) { 103 this.URL = URL; 104 } 105 106 @Override 107 public void invoke(String value, Context context) throws Exception { 108 CloseableHttpClient httpclient = HttpClients.createDefault(); 109 110 111 HttpPost httpPost = new HttpPost(URL); 112 113 httpPost.setHeader("Content-Type", "application/json"); 114 JSONArray jsonArray = JSONArray.parseArray(value); 115 String json = jsonArray.toString(); 116 HttpEntity requestEntity = new StringEntity(json, ContentType.APPLICATION_JSON); 117 String requestStr = EntityUtils.toString(requestEntity); 118 System.out.println(requestStr); 119 httpPost.setEntity(requestEntity); 120 121 // 122 123 CloseableHttpResponse response = httpclient.execute(httpPost); 124 try { 125 HttpEntity responseEntity = response.getEntity(); 126 if (responseEntity != null) { 127 System.out.println("Response body: " + EntityUtils.toString(responseEntity)); 128 } 129 } finally { 130 response.close(); 131 } 132 } 133 134 } 135 }

1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 <parent> 6 <groupId>org.springframework.boot</groupId> 7 <artifactId>spring-boot-starter-parent</artifactId> 8 <version>2.3.1.RELEASE</version> 9 <relativePath/> <!-- lookup parent from repository --> 10 </parent> 11 <groupId>com.example</groupId> 12 <artifactId>sendMessage</artifactId> 13 <version>0.0.1-SNAPSHOT</version> 14 <name>sendMessage</name> 15 <description>sendMessage</description> 16 <properties> 17 <java.version>8</java.version> 18 <flink-version>1.13.0</flink-version> 19 </properties> 20 <dependencies> 21 <dependency> 22 <groupId>org.springframework.boot</groupId> 23 <artifactId>spring-boot-starter-web</artifactId> 24 <version>3.0.4</version> 25 </dependency> 26 27 <dependency> 28 <groupId>org.springframework.boot</groupId> 29 <artifactId>spring-boot-devtools</artifactId> 30 <version>3.0.4</version> 31 <scope>runtime</scope> 32 <optional>true</optional> 33 </dependency> 34 <dependency> 35 <groupId>org.springframework.boot</groupId> 36 <artifactId>spring-boot-starter-test</artifactId> 37 <version>3.0.4</version> 38 <scope>test</scope> 39 </dependency> 40 <dependency> 41 <groupId>org.apache.flink</groupId> 42 <artifactId>flink-java</artifactId> 43 <version>${flink-version}</version> 44 </dependency> 45 <dependency> 46 <groupId>org.apache.flink</groupId> 47 <artifactId>flink-streaming-java_2.12</artifactId> 48 <version>${flink-version}</version> 49 </dependency> 50 <dependency> 51 <groupId>org.apache.flink</groupId> 52 <artifactId>flink-clients_2.12</artifactId> 53 <version>${flink-version}</version> 54 </dependency> 55 <dependency> 56 <groupId>mysql</groupId> 57 <artifactId>mysql-connector-java</artifactId> 58 <version>8.0.32</version> 59 </dependency> 60 <!-- https://mvnrepository.com/artifact/com.ververica/flink-sql-connector-oracle-cdc --> 61 <dependency> 62 <groupId>com.ververica</groupId> 63 <artifactId>flink-sql-connector-oracle-cdc</artifactId> 64 <version>2.3.0</version> 65 </dependency> 66 <dependency> 67 <groupId>org.apache.flink</groupId> 68 <artifactId>flink-table-planner-blink_2.12</artifactId> 69 <version>${flink-version}</version> 70 </dependency> 71 <dependency> 72 <groupId>com.ververica</groupId> 73 <artifactId>flink-connector-mysql-cdc</artifactId> 74 <version>2.2.1</version> 75 </dependency> 76 <!--老版本的用户打开这个注释,把上面2.0注释掉 77 <dependency> 78 <groupId>com.alibaba.ververica</groupId> 79 <artifactId>flink-connector-mysql-cdc</artifactId> 80 <version>1.4.0</version> 81 </dependency>--> 82 <dependency> 83 <groupId>org.projectlombok</groupId> 84 <artifactId>lombok</artifactId> 85 <version>1.18.20</version> 86 </dependency> 87 88 <dependency> 89 <groupId>com.alibaba</groupId> 90 <artifactId>fastjson</artifactId> 91 <version>1.2.75</version> 92 </dependency> 93 <dependency> 94 <groupId>com.google.code.gson</groupId> 95 <artifactId>gson</artifactId> 96 <version>2.8.6</version> 97 </dependency> 98 <dependency> 99 <groupId>com.ververica</groupId> 100 <artifactId>flink-connector-debezium</artifactId> 101 <version>2.3.0</version> 102 </dependency> 103 104 105 <dependency> 106 <groupId>org.apache.httpcomponents</groupId> 107 <artifactId>httpcore</artifactId> 108 <version>4.4.5</version> 109 </dependency> 110 <dependency> 111 <groupId>org.apache.httpcomponents</groupId> 112 <artifactId>httpclient</artifactId> 113 <version>4.5.6</version> 114 </dependency> 115 <dependency> 116 <groupId>org.apache.httpcomponents</groupId> 117 <artifactId>httpmime</artifactId> 118 <version>4.5.2</version> 119 </dependency> 120 <dependency> 121 <groupId>org.apache.flink</groupId> 122 <artifactId>flink-connector-http_2.12</artifactId> 123 <version>${flink-version}</version> 124 </dependency> 125 </dependencies> 126 127 <build> 128 <plugins> 129 <plugin> 130 <groupId>org.springframework.boot</groupId> 131 <artifactId>spring-boot-maven-plugin</artifactId> 132 <version>2.3.1.RELEASE</version> 133 </plugin> 134 </plugins> 135 </build> 136 137 </project>
四、云平台(模拟)
正在编写测试代码中,没有完成,推动相关各方部署(ZOOKEEPER,KAFKA,ORACLE 19C,MONGODB等及管理均用DOCKER部署,相关部署参考DOCKER IMAGE HUB)
1,接受各馆管理系统数据(以interlib和汇文为示例)
1.1 interlib 主要提交数据为BIBLIOS,HOLDING,READER,LOG_CIR,LOAN_WORK表

1 package org.example; 2 3 import com.alibaba.fastjson.JSON; 4 import com.alibaba.fastjson.JSONArray; 5 import com.alibaba.fastjson.JSONObject; 6 import com.ververica.cdc.connectors.base.options.StartupOptions; 7 import com.ververica.cdc.connectors.oracle.OracleSource; 8 import com.ververica.cdc.debezium.JsonDebeziumDeserializationSchema; 9 10 import org.apache.flink.streaming.api.datastream.DataStream; 11 import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; 12 import org.apache.flink.streaming.api.functions.sink.SinkFunction; 13 import org.apache.flink.streaming.api.functions.source.SourceFunction; 14 import org.apache.flink.api.common.functions.MapFunction; 15 16 import org.apache.http.HttpEntity; 17 import org.apache.http.HttpStatus; 18 import org.apache.http.client.methods.CloseableHttpResponse; 19 import org.apache.http.client.methods.HttpPost; 20 import org.apache.http.entity.ContentType; 21 import org.apache.http.entity.StringEntity; 22 import org.apache.http.impl.client.CloseableHttpClient; 23 import org.apache.http.impl.client.HttpClients; 24 import org.apache.http.util.EntityUtils; 25 26 import java.io.InputStream; 27 import java.util.Properties; 28 29 import org.apache.logging.log4j.LogManager; 30 import org.apache.logging.log4j.Logger; 31 32 33 public class postDB { 34 public static void main(String[] args) throws Exception { 35 //log4j2 36 Logger logger = LogManager.getLogger(postDB.class.getName()); 37 //读取配置文件 38 InputStream inputStream = ClassLoader.getSystemResourceAsStream("application.properties"); 39 Properties properties = new Properties(); 40 properties.load(inputStream); 41 System.out.println("====================读取配置文件=========================="); 42 String pdbname = properties.getProperty("pdbname"); 43 String hostname=properties.getProperty("hostname"); 44 String url=properties.getProperty("url"); 45 int port= Integer.parseInt(properties.getProperty("port")); 46 String database=properties.getProperty("database"); 47 String schemaList= properties.getProperty("schemaList"); 48 String tableList=properties.getProperty("tableList"); 49 String username=properties.getProperty("username"); 50 String password=properties.getProperty("password"); 51 int StartupOptionsLatest=Integer.parseInt(properties.getProperty("StartupOptionsLatest")); 52 53 String CheckpointStorage=properties.getProperty("CheckpointStorage"); 54 String postUrl=properties.getProperty("postUrl"); 55 56 String university=properties.getProperty("university"); 57 String token=properties.getProperty("token"); 58 59 //初始化设置 60 Properties pro=new Properties(); 61 //pro.put("database.pdb.name", pdbname); 62 pro.put("log.mining.strategy","online_catalog"); 63 pro.put("offset.flush.interval.ms", "60000"); 64 //pro.put("log.mining.continuous.mine","true"); 65 SourceFunction<String> sourceFunction = OracleSource.<String>builder() 66 .hostname(hostname) 67 .url(url) 68 .port(port) 69 .database(database) // monitor database 70 .schemaList(schemaList) // monitor schema 71 //.startupOptions(StartupOptions.latest()) //是否只监听最新数据 72 .tableList(tableList) // monitor table 73 .debeziumProperties(pro) 74 .username(username) 75 .password(password) 76 .deserializer(new JsonDebeziumDeserializationSchema()) // converts SourceRecord to JSON String 77 .build(); 78 //设置起始点 79 // Configuration configuration=new Configuration(); 80 //configuration.setString("execution.savepoint.path","file:///D:/checkoracle/cd720959c394888c1bc277e310b35b2d/chk-23"); 81 82 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); 83 //保存读取点 84 env.enableCheckpointing(30000); 85 env.getCheckpointConfig().setCheckpointStorage(CheckpointStorage); 86 // 获取 CDC 数据流 87 DataStream<String> mappedStream = processCdcStream(env, sourceFunction,university,token); 88 89 mappedStream.addSink(new HttpSink(postUrl)); 90 91 env.execute(); 92 String str = System.console().readLine(); 93 } 94 //数据map 处理部分 95 public static DataStream<String> processCdcStream(StreamExecutionEnvironment env, SourceFunction<String> source,String university,String token) { 96 DataStream<String> cdcStream = env.addSource(source); 97 DataStream<String> mappedStream = cdcStream.map(new MapFunction<String, String>() { 98 @Override 99 public String map(String value) throws Exception { 100 // 在这里对输入数据进行处理 101 //JSONArray jsonArray = new JSONArray(); 102 //全部的json数据 103 //JSONObject jsonObject = JSON.parseObject(value); 104 JSONObject allJson = new JSONObject(); 105 allJson.put("id",2); 106 //allJson.put("source",jsonObject.toString()); 107 allJson.put("source",value); 108 allJson.put("university",university); 109 allJson.put("token",token); 110 //jsonArray.add(allJson); 111 value=JSON.toJSONString(allJson); 112 // 返回处理后的输出数据 113 return value ; 114 } 115 }); 116 return mappedStream; 117 } 118 public static class HttpSink implements SinkFunction<String> { 119 private String URL; 120 121 public HttpSink(String URL) { 122 this.URL = URL; 123 } 124 125 @Override 126 public void invoke(String value, Context context) throws Exception { 127 CloseableHttpClient httpclient = HttpClients.createDefault(); 128 HttpPost httpPost = new HttpPost(URL); 129 httpPost.setHeader("Content-Type", "application/json"); 130 //JSONArray jsonArray = JSONArray.parseArray(value); 131 //String json = jsonArray.toString(); 132 133 StringEntity s = new StringEntity(value, "UTF-8"); 134 s.setContentType("application/json");//发送json数据需要设置contentType 135 httpPost.setEntity(s); 136 137 CloseableHttpResponse res = httpclient.execute(httpPost); 138 try 139 { 140 if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 141 String result = EntityUtils.toString(res.getEntity());// 返回json格式: 142 System.out.println(JSONObject.parseObject(result)); 143 } 144 }catch (Exception ex) 145 { 146 System.out.println(ex.toString()); 147 } 148 /* 149 HttpEntity requestEntity = new StringEntity(value, ContentType.APPLICATION_JSON); 150 String requestStr = EntityUtils.toString(requestEntity); 151 System.out.println(requestStr); 152 httpPost.setEntity(requestEntity); 153 154 CloseableHttpResponse response = httpclient.execute(httpPost); 155 try { 156 HttpEntity responseEntity = response.getEntity(); 157 if (responseEntity != null) { 158 System.out.println("Response body: " + EntityUtils.toString(responseEntity)); 159 } 160 161 } */ 162 finally { 163 res.close(); 164 } 165 } 166 167 } 168 169 170 }
1.2 汇文正在寻找合作伙伴,请有兴趣的联系
2、推送到KAFKA后提供给以下功能消费订阅
客户端通过FLINK CDC提交到模拟云平台,服务器端解析后直接推送到KAFKA;

1 using Confluent.Kafka; 2 using Microsoft.AspNetCore.Mvc; 3 using syncdb.Model; 4 using System.Diagnostics; 5 using System.Net; 6 using System.Text.Encodings.Web; 7 using System.Text.Json; 8 using System.Text.Unicode; 9 10 // For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 11 12 namespace syncdb.Controllers 13 { 14 [Route("api/[controller]")] 15 [ApiController] 16 public class InterlibController : ControllerBase 17 { 18 // GET: api/<Loan_WorkController> 19 [HttpGet] 20 public ActionResult<Interlib> Get() 21 { 22 Interlib value=new Interlib(); 23 value.Id= 1; 24 value.Source = "source中文"; 25 value.University = "yangtzeu"; 26 value.Token= "token"; 27 bool result= SendKafkaMsg("cn.hbdlib.yangtzeu.interlib", JsonSerializer.Serialize(value, new JsonSerializerOptions() 28 { 29 Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) 30 })).Result; 31 if (result) 32 { 33 return Ok(value); 34 } 35 else 36 { 37 return BadRequest(value); 38 } 39 } 40 41 // GET api/<Loan_WorkController>/5 42 [HttpGet("{id}")] 43 public Interlib Get(int id) 44 { 45 Interlib value = new Interlib(); 46 value.Id = 2; 47 value.Source = "source中文"; 48 value.University = "yangtzeu"; 49 value.Token = "token"; 50 return value; 51 } 52 53 // POST api/<Loan_WorkController> 54 [HttpPost] 55 public async Task<Msg> Post(Interlib value) 56 { 57 Msg msg=new Msg(); 58 try 59 { 60 Console.WriteLine("post:"+ value.Id+"|"+value.University); 61 string topic = "cn.hbdlib." + value.University+".interlib"; 62 var result=await SendKafkaMsg(topic, JsonSerializer.Serialize(value, new JsonSerializerOptions() 63 { 64 Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) 65 })); 66 if (!result) 67 { 68 msg.Code = 1; 69 msg.Message = "Interlib:Post:在发送到Kafka时没有成功"; 70 msg.Data = value; 71 } 72 } 73 catch(Exception ex) { 74 msg.Code = 2; 75 msg.Message = "Interlib:Post:在发送到Kafka时: "+ ex.Message; 76 msg.Data = value; 77 } 78 return(msg); 79 } 80 private async Task<bool> SendKafkaMsg(string topic, string message) 81 { 82 ProducerConfig config = new ProducerConfig 83 { 84 BootstrapServers = "10.40.6.139:9092", 85 ClientId = Dns.GetHostName() 86 }; 87 88 try 89 { 90 using (var producer = new ProducerBuilder<Null, string>(config).Build()) 91 { 92 var result = await producer.ProduceAsync(topic, 93 new Message<Null, string> 94 { 95 Value = message 96 } 97 ); 98 99 //Console.WriteLine($"SendKafkaMsg:{ topic}:{message}"); 100 return await Task.FromResult(true); 101 } 102 } 103 catch (Exception ex) 104 { 105 Console.WriteLine($"SendKafkaMsg:Error:{ex.Message}"); 106 } 107 108 return await Task.FromResult(false); 109 } 110 111 // PUT api/<Loan_WorkController>/5 112 [HttpPut("{id}")] 113 public void Put(int id, [FromBody] string value) 114 { 115 } 116 117 // DELETE api/<Loan_WorkController>/5 118 [HttpDelete("{id}")] 119 public void Delete(int id) 120 { 121 } 122 } 123 }
3、入库
3.1 mongodb,直接存放提交的JSON数据,不做修改,用于保存;

1 // See https://aka.ms/new-console-template for more information 2 using Confluent.Kafka; 3 using System.Text.Json.Nodes; 4 using System.Threading; 5 using syncdb.Model; 6 using System.Text.Json; 7 using System.Text.Encodings.Web; 8 using System.Text.Unicode; 9 10 var config = new ConsumerConfig 11 { 12 BootstrapServers = "10.40.6.139:9092", 13 GroupId = "test-group", 14 AutoOffsetReset = AutoOffsetReset.Earliest 15 }; 16 17 using (var consumer = new ConsumerBuilder<Ignore, string>(config).Build()) 18 { 19 string topics = "cn.hbdlib.yangtzeu.interlib"; 20 consumer.Subscribe(topics); 21 CancellationToken cancellationToken = new CancellationToken(); 22 while (true) 23 { 24 try 25 { 26 var consumeResult = consumer.Consume(cancellationToken); 27 Interlib newtonInterlib = Newtonsoft.Json.JsonConvert.DeserializeObject<Interlib>(consumeResult.Message.Value); 28 Console.WriteLine(newtonInterlib.Source.ToString()); 29 new mongo().insert(newtonInterlib); 30 } 31 catch (Exception ex) 32 { 33 Console.WriteLine(ex.Message); 34 } 35 } 36 37 consumer.Close(); 38 } 39 40 41 Console.WriteLine("Hello, World!");
//消费KAFKA并插入到数据库

1 using Microsoft.VisualBasic; 2 using MongoDB.Bson; 3 using MongoDB.Driver; 4 using Newtonsoft.Json.Linq; 5 using System.Text.Json.Nodes; 6 7 namespace syncdb.Model 8 { 9 public class Interlib 10 { 11 public int Id { get; set; } 12 public string? Source { set; get; } 13 public string? University { set; get; } 14 public string? Token { set; get; } 15 } 16 17 public interface interlib_mongodb 18 { 19 public bool insert(Interlib interlib); 20 } 21 public class mongo : interlib_mongodb 22 { 23 string connstr = "mongodb://root:th@10.40.6.139:27017"; 24 MongoClient client; 25 public mongo() { 26 client=new MongoClient(connstr); 27 } 28 public bool insert(Interlib interlib) 29 { 30 bool flag=false; 31 32 try 33 { 34 //取出学校名 35 IMongoDatabase db = client.GetDatabase(interlib.University); 36 //转换为bson文档 37 var document = BsonDocument.Parse(interlib.Source); 38 //取出数据库名和表名 39 string dbStr=document.GetValue("source").AsBsonDocument.GetValue("db").AsString; 40 string tableStr=document.GetValue("source").AsBsonDocument.GetValue("table").AsString; 41 //存放到不同的COLLECTION中 42 IMongoCollection<BsonDocument> collection = db.GetCollection< BsonDocument>(dbStr+"."+tableStr); 43 collection.InsertOne(document); 44 flag=true; 45 } 46 catch(Exception ex) 47 { 48 Console.WriteLine(ex.Message); 49 } 50 51 return flag; 52 } 53 } 54 55 public interface interlib_oracle 56 { 57 public bool update(JsonObject json); 58 public bool delete(JsonObject json); 59 public bool insert(JsonObject json); 60 61 } 62 63 }
//原始数据示例

{ "_id": "ObjectId('64589d0022308d4b25e8c8ba')", "before": null, "after": { "RDID": "300603", "BARCODE": "CD11115345", "RULESTATE": 1, "LOANCOUNT": 0, "LOANDATE": 1667407539000000, "RETURNDATE": 1675183539434000, "DUETIME": 1667407539000000, "ATTACHMENT": 0, "SENDFLAG": "0", "HASHVALUE": null }, "source": { "version": "1.6.4.Final", "connector": "oracle", "name": "oracle_logminer", "ts_ms": 1683528934877, "snapshot": "true", "db": "INTERLIB", "sequence": null, "schema": "INTERLIB", "table": "LOAN_WORK", "txId": null, "scn": "13206765", "commit_scn": null, "lcr_position": null }, "op": "r", "ts_ms": 1683528934877, "transaction": null }
MONGODB存放的数据
3.2 oracle 19c,解析JSON数据后,存放数据库和各管理系统的源数据库保持一致,为将来系统提供基础数据;
4、关联
4.1 和CCBD数据比对,记录下CCKBID和书目记录号;
4.2 记录下条码号,为将来馆藏统计提供基础数据
5、推送
5.1 通过MQTT和WEBSOCKET协议实时推送数据,用于大屏幕展示,如借还数据显示;(这个功能能吸引眼球)
5.2 和其它业务系统对接,微信公众号的消息模板,借还书的信息推送,纸质图书和数字图书的推荐,闸机刷卡签到(这个功能实用)
6、分析
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)