C#结合JavaScript实现多文件上传
目录
需求
引入
关键代码
操作界面
JavaScript包程序
服务端 ashx 程序
服务端上传后处理程序
小结
需求
在许多应用场景里,多文件上传是一项比较实用的功能。实际应用中,多文件上传可以考虑如下需求:
1、对上传文件的类型、大小有一个基本的控制。
2、上传文件时有一个进度显示,包括当前文件和整体进度。
3、上传后,在服务端后续事件进行一些处理。
引入
首先请在WEB应用程序根目录下创建COMMON目录,并引入 JavaScript 程序包,该程序包已经打包,下载地址为:https://download.csdn.net/download/michaelline/88615565。
下载成功后解压到COMMON目录即可,请引入如下图中的 JS 文件:

另外,我们还需要在 app_data目录下创建 ajaxUploadFiles 子目录,以备上传创建文件使用。
关键代码
操作界面
界面上放置标准的 input file 控件,并将其服务器化,即 runat="server"。点击选择文件,选中所有目标文件后,自动实现文件上传功能。
示例界面如下:
示例UI代码如下:
<input class="file" type="file" id="ajaxMfile" runat="server" onbeginupload="ajax_uploadFiles_beginUpload" onprogressupload="ajax_uploadFiles_progressUpload" onendupload="ajax_uploadFiles_endUpload" multiple="multiple" allowtype="pptx|docx|mp3|txt|std" allowsize="500m|100m" fileindex="0" name="fileupload"serverbuttonid="ajaxEndBtn" serverfilelistid="ajaxReturnFileName"progresspanelid="ajaxMfileProgressPanel"onchange="ajax_uploadFiles(this);return false" /><asp:TextBox runat="server" Width="100%" ID="ajaxReturnFileName" style="display:none" ></asp:TextBox><br /><asp:button ID="ajaxEndBtn" text="后台处理" runat="server" style="display:none" onclick="ajaxEndBtn_Click" /><br /><br /><table style="display:none; color:White" id="ajaxMfileProgressPanel"><tr><td >当前文件:</td><td style="position:relative; padding:0px"><asp:Label Font-Size="9pt" style="z-index:1;position:absolute;left:0px;top:-9px;" Width="300px" runat="server" ID="ajax_uploadFiles_curfilename"/></td></tr><tr><td style="position:relative; padding:0px;width:120px">当前文件进度<asp:Label style="z-index:1;position:absolute;left:85px;top:-9px;" runat="server" Font-Size="9pt" ID="ajax_uploadFiles_upprogress"></asp:Label></td><td style="position:relative; padding:10px"><img id="ajax_uploadFiles_curprogress" style="z-index:1;position:absolute;left:0px;top:4px;width:0px;height:12px" alt="" src="/common/Jquery/images/win7progress.jpg" /><div id="ajax_uploadFiles_curbg" style="z-index:0;position:absolute;left:0px;top:4px;width:300px;height:12px;background-color:Gray"></div></td></tr><tr><td style="position:relative; padding:0px">上传总量进度<asp:Label style="z-index:1;position:absolute;left:85px;top:-9px;" runat="server" Font-Size="9pt" ID="ajax_uploadFiles_cprogress"></asp:Label></td><td style="position:relative; padding:10px"><img id="ajax_uploadFiles_totalprogress" style="z-index:1;position:absolute;left:0px;top:4px;width:0px;height:12px" alt="" src="/common/Jquery/images/win7progress2.jpg" /><div id="ajax_uploadFiles_totalbg" style="z-index:0; position:absolute;left:0px;top:4px;width:300px;height:12px;background-color:Gray"></div></td></tr></table><table style="color:White; width:100%"><tr><td style="position:relative"><asp:Label runat="server" Font-Size="11pt" ID="ajax_uploadFiles_serverProcessTip"></asp:Label></td></tr></table>
input file 控件的一些设置如下:
(1)onbeginupload="ajax_uploadFiles_beginUpload" js方法,开始上传前事件,默认值
(2)onprogressupload="ajax_uploadFiles_progressUpload" js方法,上传中事件,默认值
(3)onendupload="ajax_uploadFiles_endUpload" js方法,选择完文件上传事件,默认值
(4)multiple="multiple" 控件属性,允许多文件选中上传
(5)allowtype="pptx|docx|mp3|txt|std" 自定义属性,允许上传的文件类型,以 | 分隔
(6)allowsize="500m|100m" 自定义属性,允许上传的文件最大尺寸,可以以 | 分隔,并一一对应,如果不对应,则根据 allowtype 的设置从左至右进行匹配
如举例中的设置则表示为,pptx 允许最大 500M , docx 最大 100M,后面未设置则均为100M
(7) serverbuttonid="ajaxEndBtn" 自定义属性,执行的服务器按钮ID,默认值
(8)serverfilelistid="ajaxReturnFileName" 自定义属性,服务器端返回的文件ID列表,默认值
(9)οnchange="ajax_uploadFiles(this);return false" 自定义属性,js方法,选择文件后自动执行上传功能,默认值
根据示例代码的设置,以上部分除了 allowtype和 allowsize 均可以不用改变设置。
上传中的效果如下图:

JavaScript包程序
本包程序实现了前面设置的界面元素方法、事件、属性的实现及对文件上传的客户端控制,示例代码如下:
//批量上传文件的内置默认辅助方法,表示每上传一个文件之前发生的事件,//事件的fileObj参数代表 file对象(上传控件),由主方法自动传入,开发者可以重新指定自定义方法function ajax_uploadFiles_beginUpload(fileObj) {var fIndex = parseInt(fileObj.getAttribute("fileindex"), 10);if (fIndex == 0) {document.getElementById('ajax_uploadFiles_serverProcessTip').innerHTML = '';document.getElementById("ajax_uploadFiles_upprogress").innerHTML = "";document.getElementById("ajax_uploadFiles_cprogress").innerHTML = "";document.getElementById("ajax_uploadFiles_totalprogress").style.width = "0px";document.getElementById(fileObj.getAttribute("serverfilelistid")).value = "";}document.getElementById("ajax_uploadFiles_curfilename").innerHTML = fileObj.files[fIndex].name;}//批量上传文件的内置默认辅助方法,表示当前正在上传文件时发生的事件(主要用于显示上传进度),//事件的fileObj参数代表 file对象(上传控件), loaded:已经上传的文件总字节, total:正在上传的文件总字数,// percent:不超过100的整数,表示为百分比。这些参数由主方法自动传入,开发者可以重新指定自定义方法function ajax_uploadFiles_progressUpload(fileObj, loaded, total, percent) {document.getElementById("ajax_uploadFiles_upprogress").innerHTML = ("" + percent + "%");var curb = parseInt(document.getElementById("ajax_uploadFiles_curbg").style.width, 10);document.getElementById("ajax_uploadFiles_curprogress").style.width = Math.floor(curb * loaded / total) + "px";}//批量上传文件的内置默认辅助方法,表示当前文件上传完成时发生的事件(主要用于处理文件上传后的跟踪处理,并且返回服务器上保存的文件列到一个文本框中,以|分隔),//事件的fileObj参数代表 file对象(上传控件), type:上传状态返回,包括success成功,error失败, //data:文件的数据,暂时未使用, desfile:要保存在服务器上的文件名// 这些参数由主方法自动传入,开发者可以重新指定自定义方法function ajax_uploadFiles_endUpload(fileObj, type, data, desfile) {var fIndex = parseInt(fileObj.getAttribute("fileindex"), 10);var filecount = fileObj.files.length;document.getElementById(fileObj.getAttribute("serverfilelistid")).value += desfile + "|";var totalb = parseInt(document.getElementById("ajax_uploadFiles_totalbg").style.width, 10);document.getElementById("ajax_uploadFiles_totalprogress").style.width = Math.floor(totalb * (fIndex + 1) / filecount) + "px";document.getElementById("ajax_uploadFiles_cprogress").innerHTML = ("" + Math.floor(100 * (fIndex + 1) / filecount) + "%");if (fIndex < filecount - 1) {fIndex++;fileObj.setAttribute("fileindex", fIndex);ajax_uploadFiles(fileObj);return;}fileObj.setAttribute("fileindex", 0);if (type == "success") {document.getElementById('ajaxMfile').style.display='none';document.getElementById('ajax_uploadFiles_serverProcessTip').innerHTML = '上传完成!正在进行后台处理...';document.getElementById(fileObj.getAttribute("serverbuttonid")).click();} else if (type == "error") {alert("error");}}//生成一个guidfunction newguid() {function S4() {return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);}return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());}//批量上传文件的主方法,fileObj参数代表 file对象(上传控件)function ajax_uploadFiles(fileObj) {var formData = new FormData();var fIndex = parseInt(fileObj.getAttribute("fileindex"), 10);var filecount = fileObj.files.length;if (filecount == 0) {alert('请先浏览选择文件...');return;}var uploadSessionId = newguid();var upfile = fileObj.files[fIndex].name;var dotpos = upfile.lastIndexOf('.');var desfile = "";var exname = "";if (dotpos > 0) {exname = upfile.substring(dotpos + 1, upfile.length);desfile = uploadSessionId + upfile.substring(0, dotpos) + '.' + exname;} else {desfile = uploadSessionId + upfile;}// alert(Math.round(upsize / 1024));if (fIndex == 0) {var allowtype = fileObj.getAttribute("allowtype");var allowsize = fileObj.getAttribute("allowsize");var at = allowtype.split('|');var as = allowsize.split('|');for (var j = 0; j < filecount; j++) {var validfile = fileObj.files[j].name;var upsize = fileObj.files[j].size;var validdotpos = validfile.lastIndexOf('.');var validexname = "";if (validdotpos > 0) {validexname = validfile.substring(validdotpos + 1, validfile.length);}var i = 0;if (allowtype != "") {var find = false;for (i = 0; i < at.length; i++) {if (at[i].toLowerCase() == validexname.toLowerCase()) {find = true;break;}}if (find == false) {alert("文件" + validfile + "上传的类型不符合要求!仅允许上传扩展名为:" + allowtype.split("|").join("、") + "的文件。");fileObj.style.display = '';document.getElementById(fileObj.getAttribute("progresspanelid")).style.display = 'none';var t = fileObj;t.outerHTML = t.outerHTML;return;}}if (allowsize != "") {if (at.length <= as.length) {} else {i = 0;}as[i] = as[i].toLowerCase();var csize = parseInt(as[i]);var tsize = upsize;if (as[i].lastIndexOf('k') != -1) {csize = csize * 1024;tsize = Math.round(upsize / 1024) + "KB";} else if (as[i].lastIndexOf('m') != -1) {csize = csize * 1024 * 1024;tsize = Math.round(upsize / 1024 / 1024) + "MB";} else if (as[i].lastIndexOf('g') != -1) {csize = csize * 1024 * 1024 * 1024;tsize = Math.round(upsize / 1024 / 1024 / 1024) + "GB";} else if (as[i].lastIndexOf('t') != -1) {csize = csize * 1024 * 1024 * 1024 * 1024;tsize = Math.round(upsize / 1024 / 1024 / 1024 / 1024) + "TB";}if (upsize > csize) {alert("上传文件" + validfile + "的大小近" + tsize + ",系统规定大小不能超过" + as[i].toUpperCase() + ",请重新选择。");fileObj.style.display = '';document.getElementById(fileObj.getAttribute("progresspanelid")).style.display = 'none';var t = fileObj;t.outerHTML = t.outerHTML;return;}}} //j} // findex// document.getElementById(callObjId).disabled = 'disabled';// if (beginFuncName != null) {// beginFuncName(fIndex, filecount,upfile);// }fileObj.style.display = 'none';document.getElementById(fileObj.getAttribute("progresspanelid")).style.display = '';var findfunc = fileObj.getAttribute("onbeginupload");if (eval(findfunc)) {var execfunc = eval(findfunc);// alert(findfunc);execfunc(fileObj);}formData.append("file", fileObj.files[fIndex]); //append()里面的第一个参数file对应permission/upload里面的参数filevar processUploadUrl = window.location.protocol + "//" + window.location.host + "//common//uploadfile.ashx?guid=" + uploadSessionId;$.ajax({type: "post",async: true, //这里要设置异步上传,才能成功调用myXhr.upload.addEventListener('progress',function(e){}),progress的回掉函数Accept: 'text/html;charset=UTF-8',data: formData,contentType: "multipart/form-data",url: processUploadUrl,processData: false, // 告诉jQuery不要去处理发送的数据contentType: false, // 告诉jQuery不要去设置Content-Type请求头xhr: function () {myXhr = $.ajaxSettings.xhr();if (myXhr.upload) { // check if upload property existsmyXhr.upload.addEventListener('progress', function (e) {var loaded = e.loaded; //已经上传大小情况 var total = e.total; //附件总大小 var percent = Math.floor(100 * loaded / total); //已经上传的百分比 // if (progressFuncName != null) {// progressFuncName(loaded, total, percent);// }var findfunc = fileObj.getAttribute("onprogressupload");if (eval(findfunc)) {var execfunc = eval(findfunc);// alert(findfunc);execfunc(fileObj, loaded, total, percent);}// $("#processBar").css("width", percent);}, false); // for handling the progress of the upload}return myXhr;},success: function (data) {if (fIndex == fileObj.files.length - 1) {fileObj.style.display = '';document.getElementById(fileObj.getAttribute("progresspanelid")).style.display = 'none';var t = fileObj;t.outerHTML = t.outerHTML;}// if (endFuncName != null) {// endFuncName("success", data, desfile, fIndex,filecount);// }var findfunc = fileObj.getAttribute("onendupload");if (eval(findfunc)) {var execfunc = eval(findfunc);// alert(findfunc);execfunc(fileObj, "success", data, desfile);}},error: function (XMLHttpRequest, textStatus, errorThrown) {alert(errorThrown);if (endFuncName != null) {endFuncName(fileObj, "error", null, '');}}});}
服务端 ashx 程序
ashx,一般处理程序(HttpHandler)是·NET众多web组件的一种。一个 httpHandler 接受并处理一个http请求,类似 Java 中的 servlet 。
本程序实现服务器端上传文件的接收和另存操作,在这里我们存为uploadfile.ashx,代码如下:
<%@ WebHandler Language="C#" Class="Handler" %>using System;
using System.Web;
using System.IO;public class Handler : IHttpHandler {public void ProcessRequest (HttpContext context) {if (context.Request.Files.Count > 0){//HttpContext.Current.Request.FilePath;string strPath = System.Web.HttpContext.Current.Server.MapPath("~/app_data/ajaxUploadFiles/");string strName = context.Request.Files[0].FileName;string ext=Path.GetExtension(strName);string filename =HttpContext.Current.Request.QueryString["guid"].ToString()+Path.GetFileNameWithoutExtension(strName);if(ext!=""){filename = filename + ext;}context.Request.Files[0].SaveAs(System.IO.Path.Combine(strPath, filename));}}public bool IsReusable {get {return false;}}}
服务端上传后处理程序
在多个文件上传到服务器后,我们需要对文件进行后期处理,在前端我们设置了ID为 “ajaxEndBtn”的服务器按钮,进行模拟调用其 click 事件。
服务器端按钮处理事件示例代码如下:
void ajaxEndBtn_Click(object sender, EventArgs e){//得到保存后的文件名列表string[] upfiles = ajaxReturnFileName.Text.Split('|');//给予用户基本的提示ajax_uploadFiles_serverProcessTip.Text = "本次上传分析:共计上传" + (upfiles.Length - 1).ToString() + "个文件。";//遍历上传文件列表,进行后期处理foreach (string filename in upfiles){if (filename.Trim() == "") continue;string upfilename = Request.PhysicalApplicationPath + "app_data\\ajaxUploadFiles\\" + filename;string exname = System.IO.Path.GetExtension(upfilename);//执行业务处理程序}
小结
以上提供的代码仅供参考,默认的设置仅可能提供最基础的实现,比如 ashx 程序还需要进行安全控制;进度图片和UI可以重新设计;实际的业务可以根据需求对控件的属性、事件进行重写。
以上就是自己的一些分享,时间仓促,不妥之处还请大家批评指正!
相关文章:
C#结合JavaScript实现多文件上传
目录 需求 引入 关键代码 操作界面 JavaScript包程序 服务端 ashx 程序 服务端上传后处理程序 小结 需求 在许多应用场景里,多文件上传是一项比较实用的功能。实际应用中,多文件上传可以考虑如下需求: 1、对上传文件的类型、大小…...
STM32——继电器
继电器工作原理 单片机供电 VCC GND 接单片机, VCC 需要接 3.3V , 5V 不行! 最大负载电路交流 250V/10A ,直流 30V/10A 引脚 IN 接收到 低电平 时,开关闭合。...
性能监控体系:InfluxDB Grafana Prometheus
InfluxDB 简介 什么是 InfluxDB ? InfluxDB 是一个由 InfluxData 开发的,开源的时序型数据库。它由 Go 语言写成,着力于高性能地查询与存储时序型数据。 InfluxDB 被广泛应用于存储系统的监控数据、IoT 行业的实时数据等场景。 可配合 Te…...
CS106L2023 and CS106B 环境配置(详细教程)
1.问题: (1)CS106L 运行./setup.sh 脚本时出错 (windows 请下载git,在git bash 打开运行) (2)CS106B,QT构建 构建错误:一般构建错误,例如 Erro…...
Docker-多容器应用
一、概述 到目前为止,你一直在使用单个容器应用。但是,现在您将 MySQL 添加到 应用程序堆栈。经常会出现以下问题 - “MySQL将在哪里运行?将其安装在同一个 容器还是单独运行?一般来说,每个容器都应该做一件事&#x…...
Golang导入导出Excel表格
最近项目开发中有涉及到Excel的导入与导出功能,特别是导出表格时需要特定的格式(单元格合并等),废话不多说,直接上代码了。 首先用到一个第三方库,实测还是很强大很好用的,就是这个https://git…...
基于Maven的Spring Boot应用版本号获取解析
引言 在Spring Boot应用的开发和部署中,了解应用的版本号对于管理和监控应用至关重要。本文将深入解析一种基于Maven打包的Spring Boot应用中,根据不同的运行环境获取应用版本号的解决方案。在开始介绍代码之前,我们先来了解一下可能的文件目…...
LLM微调(二)| 微调LLAMA-2和其他开源LLM的两种简单方法
本文将介绍两种开源工具来微调LLAMA-2。 一、使用autotrain-advanced微调LLAMA-2 AutoTrain是一种无代码工具,用于为自然语言处理(NLP)任务、计算机视觉(CV)任务、语音任务甚至表格任务训练最先进的模型。 1…...
AVP对纵向控制ESP(Ibooster)的需求规范
目录 1. 版本记录... 3 2. 文档范围和控制... 4 2.1 目的/范围... 4 2.2 文档冲突... 4 2.3 文档授权... 4 2.4 文档更改控制... 4 3. 功能概述... 5 4. 系统架构... 6 5. 主要安全目标... 7 5.1 …...
小模型学习(1)-人脸识别
【写作背景】因为最近一直在研究大模型,在与客户进行交流时,如果要将大模型的变革性能力讲清楚,就一定要能将AI小模型的一些原理和效果讲清楚,进而形成对比。当然这不是一件简单的事情,一方面大模型分析问题的的本质原…...
sublime Text使用
1、增加install 命令面板 工具(tool)->控制面板(command palette) -> 输入install ->安装第一个install package controller,以下安装过了,所以没展示 2、安装json格式化工具 点击install package,等几秒会进入控制面板࿰…...
基于深度学习的yolov7植物病虫害识别及防治系统
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介简介YOLOv7 系统特性工作流程 二、功能三、系统四. 总结 一项目简介 # YOLOv7植物病虫害识别及防治系统介绍 简介 该系统基于深度学习技术,采…...
Leetcode 2963. Count the Number of Good Partitions
Leetcode 2963. Count the Number of Good Partitions 1. 解题思路2. 代码实现 题目链接:2963. Count the Number of Good Partitions 1. 解题思路 这一题根据题意,显然我们可以将其先分为 n n n个原子partition,确保任意两个partition之间…...
C语言动态内存经典笔试题分析
C语言动态内存经典笔试题分析 文章目录 C语言动态内存经典笔试题分析1. 题目一2. 题目二3. 题目三4. 题目四 1. 题目一 void GetMemory(char *p){p (char *)malloc(100);} void Test(void){char *str NULL;GetMemory(str);strcpy(str, "hello world");printf(str)…...
截断正态分布stats.truncnorm()X.rvs(10000)
就是在均值和方差之外,再指定正态分布随机数群的上下限,如 [ μ − 3 σ , μ 3 σ ] [\mu-3\sigma,\mu3\sigma] [μ−3σ,μ3σ] stats.truncnorm()参数 X stats.truncnorm(-2, 2, locmu, scalesigma) -2 2是截断的正态分布…...
第59天:django学习(八)
事务 事务是MySQL数据库中得一个重要概念,事务的目的:为了保证多个SQL语句执行成功,执行失败,前后保持一致,保证数据安全。 开启事务的三个关键字 start transaction commit rollback 开启事务 from django.db import transaction…...
举例说明自然语言处理(NLP)技术。
本文章由AI生成! 以下是自然语言处理(NLP)技术的一些例子: 机器翻译:将一种语言翻译成另一种语言的自动化过程。常见的机器翻译系统包括谷歌翻译,百度翻译等。 语音识别:将口头语言转换成文本…...
echarts地图marker自定义图标并添加点击事件
symbol如果引用https图片链接会报403,直接引用本地 series: [{type: scatter, // 使用散点图系列 coordinateSystem: geo, // 设置坐标系为地理坐标系 zlevel: 100,data: [{name: 上海,value: [121.48, 31.22], // 上海的经纬度坐标 symbol: image:// require(/…...
C盘瘦身,C盘清理
以下只是我的C盘清理经验~ 一.【用软件简单清理C盘】 使用一些垃圾清理软件,简单的初步把C盘先清理一遍。(这种软件太多我就不推荐了……) 二.【WPS清理大师】 因为我电脑装了WPS,发现右键单击C盘有个选项【释放C盘空间】…...
STM32F103
提示:来源正点原子,参考STM32F103 战舰开发指南V1.3PDF资料 文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: 开发环境硬件普中科技,接…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...
【无标题】湖北理元理律师事务所:债务优化中的生活保障与法律平衡之道
文/法律实务观察组 在债务重组领域,专业机构的核心价值不仅在于减轻债务数字,更在于帮助债务人在履行义务的同时维持基本生活尊严。湖北理元理律师事务所的服务实践表明,合法债务优化需同步实现三重平衡: 法律刚性(债…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
HTTPS证书一年多少钱?
HTTPS证书作为保障网站数据传输安全的重要工具,成为众多网站运营者的必备选择。然而,面对市场上种类繁多的HTTPS证书,其一年费用究竟是多少,又受哪些因素影响呢? 首先,HTTPS证书通常在PinTrust这样的专业平…...
