form表单上传数据的几种方式

form 的基本使用

1、什么是表单

表单在网页中主要负责数据采集功能。HTML中的标签,就是用于采集用户输入的信息,并通过标签的提交操作,把用户收集到的信息发送到 Web 服务器进行处理。

在这里插入图片描述

2、表单的组成部分
  1. 表单标签

就是我们常说的form表单,就是所谓的表单标签。

  1. 表单域

也就是表单标签之间的部分,这里面包含了文本框、密码框、隐藏域、多行文本框、复选框、单选框、下拉选择框、和文件上传框等.各种用于采集用户信息的标签。

这里面还可以包含一个特殊的部分,隐藏域:
隐藏域是用来收集或发送信息的不可见元素,对于网页的访问者来说,隐藏域是看不见的。当表单被提交时,隐藏域就会将信息用你设置时定义的名称和值发送到服务器上。
代码格式:<input type="hidden" name="..." value="...">

  1. 表单按钮

既然采集完用户对应输入的信息了,我还还需要将其提交到服务器,这时就需要借助提交按钮了。按钮的种类很多,如button、submit、reset,各自有各自的特点。

<!-- type=text  键值对,方式提交 -->
<!-- type=file  上传formData这种数据 -->
<form action="">
	<input type="text" name="username" />
	<input type="password" name="password">
	<input type="file" name="file" onchange="fileChange()" />
	<button type="submit">提交</button>
</form>
3、<form>标签的属性

<form>标签用来采集数据

<form>标签的属性则是用来规定如何把采集到的数据发送到服务器。

属性描述
acceptMIME_typeHTML5 不支持。规定服务器接收到的文件的类型。(文件是通过文件上传提交的)
accept-charsetcharacter_set规定服务器可处理的表单数据字符集。
actionURL规定当提交表单时向何处发送表单数据。
autocomplete(new)on
off
规定是否启用表单的自动完成功能。
enctypeapplication/x-www-form-urlencoded
multipart/form-data
text/plain
规定在向服务器发送表单数据之前如何对其进行编码。(适用于 method=“post” 的情况)
methodget
post
规定用于发送表单数据的 HTTP 方法。
nametext规定表单的名称。
novalidate(new)novalidate如果使用该属性,则提交表单时不进行验证。
target_blank
_self
_parent
_top
规定在何处打开 action URL。

form表单上传数据(POST)

注意:
1、文件类型(word、excel、image/png、mp4)等文件都需要使用 formData格式上传文件至服务器
2、其他的数据内容基本是那个都是按照对象的形式传递的

1、直接传递对应的参数

实例代码基于jquery实现

$(function() {
	$('button').on('click', function(e) {
	    e.preventDefault();
	    $.ajax({
	        url: 'xxx',
	        type: 'POST',
	        //键值对的方式:
	        data: {
	            username: $('[name="username"]').val(),
	            password: $('[name="password"]').val()
	        },
	        success: (res) => {
	            console.log(res);
	        }
	    })
	})
});
2、formData上传数据(文本、文件、视频、图片等)
fileChange(){
	//选中文件后,会触发input=file的change事件,即会进入此函数
	// 1.先创建formData数据格式 传递HTML对象(文件上传推荐)
	var formData = new FormData()[0]);
	// 2.把传递给服务器数据,追加到formData对象里面
	// 第一种写法:一个个append
	formData.append('username', $('[name="username"]').val())
	formData.append('password', $('[name="password"]').val());
	//添加选择的文件 key值为file
	formData.append('file',$('[name="file"]')[0].files[0]); 
	
	// 第二种写法:遍历写法
	let obj = {
		username: $('[name="username"]').val(),
		password: $('[name="password"]').val(),
		file: $('[name="file"]')[0].files[0]
	}
	$.each(obj,function(key,value) {
	  formData.append(key,value)
	})
	
	//删除数据
	//formData.delete('username');
	//发送请求
	$.ajax({
	    url: 'xxx',
	    type: 'POST',
	    data: formData,
	    //如果提交数据格式为formData类型 必须加下面两句,不添加就报错
	    processData: false, //不希望使用   application/x-www-form-urlencoded
	    contentType: false, //不采用默认的数据类型 
	    //数据格式是 application/x-www-form-urlencoded
	    success: (res) => {
	        console.log(res);
	    },
	    error: function(err) {
	        console.log(err);
	    }
	})
}
3、form表单数据序列化(serialize将传递表单中的数据序列化)
//serialize form表单里面具有name属性的标签进行序列化, 序列化字符串
console.log($('form').serialize());
//输出:
username=admin&password=123123

//serializeArray form表单里面具有name属性的标签进行序列化, 序列化数组套object
console.log($('form').serializeArray());
//输出:
[ 
  {name: 'username', value: 'admin'}, 
  {name: 'password', value: '123123'},
]

console.log(serializeObject($('form'));
//输出:
{username:"admin",password:"123123"}
// 将表单中用户输入的内容转换为对象类型
// 封装一个方法: serializeObject()  ——返回对象
function serializeObject(obj) {
	var params = obj.serializeArray();
	// 使用each方法对params进行操作
	var result = {};
	// 循环数组,将数组转为对象类型
	$.each(params, function(index, value) {
	    result[value.name] = value.value;
	})
	return result;
}

$.ajax({
    url: 'xxx',
    type: 'POST',
    data: JSON.stringify(serializeObject($('form')),
    success: (res) => {
        console.log(res);
    },
    error: function(err) {
        console.log(err);
    }
})
            
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
说在前头的 1. 闪烁吧!看看extjs那些美丽的例子。 1.1. 一切从extjs发布包开始 1.2. 看看ext-2.0.2的文档 1.3. 为什么有的例子必须放在服务器上才能看到效果? 1.4. 为什么自己按照例子写的代码,显示出来总找不到图片 1.5. 我们还需要什么? 1.6. 入门之前,都看helloworld。 1.6.1. 直接使用下载的发布包 1.6.2. 只把必要的东西放进项目中 2. 震撼吧!让你知道ext表格控件的厉害。 2.1. 功能丰富,无人能出其右 2.2. 让我们搞一个grid出来耍耍吧。 2.3. grid默认自带的功能 2.4. 按顺序,咱们先要把常见功能讲到 2.4.1. 自主决定每列的宽度 2.4.2. 让grid支持按列排序 2.4.3. 中文排序是个大问题 2.5. 让单元格里显示红色的字,图片,按钮,你还能想到什么? 2.6. 更进一步,自动行号和多选checkbox 2.6.1. 自动行号 2.6.2. 全选checkbox的时间了,请允许我让2.0先上场。 2.7. 分页了吗?分页了吗?如果还没分就看这里吧。 2.7.1. 表面工作,先把分页工具条弄出来。 2.7.2. 自定义分页工具条 2.7.3. 迫不得已,要加上后台脚本了。 2.7.4. 其实分页不一定要踩在脚下,也可以顶在头上。 2.7.5. 谣言说ext不支持前台排序 2.8. 爱生活,EditorGrid。 2.8.1. 旋动舞步,看我们怎么把这个EditorGrid炫出来。 2.8.2. 添加一行,再把它踢掉 2.8.3. 一切就绪,你可以按保存按钮了。 2.8.4. 天马行空,保证提交的数据绝对有效 2.8.5. 限制类型,让用户只能选择我们提供的数据 2.9. 连坐法,关于选择模型 2.10. 2.0有,1.x里没有的那些可怕的控件 2.10.1. 谓之曰PropertyGrid属性表格 2.10.1.1. 小插曲:只能看不能动的PropertyGrid。 2.10.1.2. 小舞曲:强制对name列排序 2.10.1.3. 小夜曲:根据name获得value 2.10.1.4. 奏鸣曲:自定义编辑器 2.10.2. 分组表格,嘻嘻,这是交叉报表吗? 2.11. 午夜怪谈,论可以改变大小,可以拖拽的表格 2.11.1. 先看看怎么拖拽改变表格的大小 2.11.2. 再看怎么在表格里拖动行 2.11.2.1. 无用功 之 同一个表格里拖拽 2.11.2.2. 无间道 之 从这个表格拖到另一个表格 2.11.2.3. 无疆界 之 从表格里拖到树上 2.12. 大步流星,后台排序 2.13. grid与右键菜单 3. 歌颂吧!只为了树也要学ext。 3.1. 真的,我是为了树,才开始学ext的。 3.2. 传统是先做出一棵树来。 3.3. 超越一个根 3.4. 对tree进行统一配置 3.5. 这种装配树节点的形式,真是让人头大。 3.5.1. TreeLoader外传 之 JsonPlugin 3.5.2. TreeLoader外传 之 读取本地json 3.6. jsp的例子是一定要有的 3.7. 让你知道树都可以做些什么 3.7.1. 检阅树形的事件 3.7.2. 右键菜单并非单纯的事件 3.7.3. 默认图标好单调,改一下撒 3.7.4. 偷偷告诉你咋从节点弹出对话框 3.7.5. 小小提示 3.7.6. 给树节点设置超链接 3.8. 灰壳显灵!让我直接修改树节点的名称吧! 3.9. 我拖,我拖,我拖拖拖。 3.9.1. 树形节点的拖拽有三种形式 3.9.2. 用事件控制拖拽 3.9.2.1. 叶子不能append 3.9.2.2. 把节点扔到哪里啦 3.9.2.3. 裟椤双树,常与无常 3.10. 树形过滤器TreeFilter 3.11. TreeSorter对树形排序 4. 祝福吧!把表单和输入控件都改成ext的样式。 4.1. 不用ext的form啊,不怕错过有趣的东西吗? 4.2. 慢慢来,先建一个form再说 4.3. 胡乱扫一下输入控件 4.4. 起点高撒,从comboBox往上蹦 4.4.1. 凭空变出个comboBox来。 4.4.2. 把select变成comboBox。 4.4.3. 破例研究下comboBox的内在本质哟 4.4.4. 嘿嘿~本地的做完了,试试远程滴。 4.4.5. 给咱们的comboBox安上零配件 4.4.6. 每次你选择什么,我都知道 4.4.7. 露一小手,组合上面所知,省市县三级级联。哈哈~ 4.4.7.1. 先做一个模拟的,所有数据都在本地 4.4.7.2. 再做一个有后台的,需要放在服务器上咯 4.5. 把form里的那些控件全部拿出来看看 4.6. form提交数据的三重门 4.6.1. ext中默认的提交形式 4.6.2. 使用html原始的提交形式 4.6.3. 单纯ajax 4.7. 验证苦旅 4.7.1. 不能为空 4.7.2. 最大长度,最小长度 4.7.3. 借助vtype 4.7.4. 自定义验证规则 4.7.5. 算不上校验的NumberField 4.7.6. 使用后台返回的校验信息 4.8. 关于表单内部控件的布局问题 4.8.1. 什么都不做,默认的平铺布局 4.8.2. 分裂,分列 4.8.3. fieldset是个神奇的东西 4.8.4. 当某一天,需要往form加个图片什么的,该咋办? 4.9. 还要做文件上传哟 4.10. 非想非想,单选框多选框 4.10.1. 多选呢checkbox 4.10.2. 单选呢radio 4.11. 自动把数据填充到form里 5. 雀跃吧!超脱了一切的弹出窗口。 5.1. 呵呵~跳出来和缩回去总给人惊艳的感觉。 5.2. 先看看最基本的三个例子 5.2.1. Ext.MessageBox.alert() 5.2.2. Ext.MessageBox.confirm() 5.2.3. Ext.MessageBox.prompt() 5.3. 如果你想的话,可以控制得更多 5.3.1. 可以输入多行的输入框 5.3.2. 再看一个例子呗 5.3.3. 下一个例子是进度条 5.3.4. 动画效果,跳出来,缩回去 5.4. 让弹出窗口,显示我们想要的东东,比如表格 5.4.1. 2.0的弹出表格哦 5.4.2. 向window里加表格 5.4.3. 把form放进对话框里 6. 奔腾吧!让不同的浏览器里显示一样的布局。 6.1. 有了它,我们就可以摆脱那些自称ui设计师的人了。 6.2. ViewPort对整个窗口布局 6.3. 脑袋上有几个标签的tabPanel 6.4. 让布局复杂一点儿 6.5. 向诸位介绍一下各具特色的布局 6.5.1. accordion就是QQ那样的伸缩菜单 6.5.2. CardLayout?其实就是Wizard啦。 6.5.3. 呼呼,TableLayout就是合并行,合并列 7. 低鸣吧!拖拽就像呼吸一样容易。 7.1. 如此拖拽,简直就像与生俱来的本能一样。 7.2. 第一!乱拖。 7.3. 第二!代理proxy和目标target 7.4. yui自远方来,不亦乐乎 7.4.1. Basic,基础 7.4.2. Handles,把手 7.4.3. On Top,总在上边 7.4.4. Proxy,代理 7.4.5. Groups,组 7.4.6. Grid,网格 7.4.7. Circle,圆形 7.4.8. Region,范围 8. 哭泣吧!现在才开始讲基础问题。 8.1. Ext.get 8.2. 要是我们想一下子获得一堆元素咋办? 8.3. DomHelper和Template动态生成html 8.3.1. DomHelper用来生成小片段 8.3.2. 批量生成还是需要Template模板 8.3.3. 醍醐灌顶,功能强劲的模板引擎XTemplate。 8.4. Ext.data命名空间 8.4.1. proxy系列 8.4.1.1. 人畜无害MemoryProxy 8.4.1.2. 常规武器HttpProxy 8.4.1.3. 洲际导弹ScriptTagProxy 8.4.2. reader系列 8.4.2.1. 简单易行ArrayReader 8.4.2.2. 灵活轻便JsonReader 8.4.2.3. 久负盛名XmlReader 8.4.3. 相信你知道怎么做加法 8.5. 跟我用json,每天五分钟 8.5.1. Hello 老爸。 8.5.2. 老妈等等,孩子先上场。 8.5.3. 老妈来了,老妈来啦。 8.5.4. Ext对json的支持力度 8.5.5. 反向操作,ext把json变成字符串 8.6. 小声说说scope 8.7. 菜单和工具条 8.7.1. 至简至廉的菜单 8.7.2. 丰富一点儿的多级菜单 8.7.3. 单选多选,菜单里搞这套 8.7.4. 小把戏,定制好的菜单 8.7.5. SplitButton让按钮和菜单结合 8.8. 蓝与灰,切换主题 8.9. 悬停提示 8.9.1. 起初,初始化 8.9.2. 诞生,注册提示 8.9.3. 分支,标签提示 8.9.4. 发展,全局配置 8.9.5. 进化,个体配置 8.10. 灵异事件,Ext.state 8.11. 所谓的事件 8.12. 回头谈一谈Ext里的ajax 9. 沉寂吧!我们要自己的控件。 9.1. 下拉树形选择框TreeField 9.2. 带全选的checkbox树形CheckBoxTree 9.3. 带全选的checkbox的grid 9.4. fisheye 9.5. 可以设置时间的日期控件 9.6. JsonView实现用户卡片拖拽与右键菜单 9.7. 下拉列表选择每页显示多少数据 10. 撕裂吧!邪魔外道与边缘学科。 10.1. dwr与ext整合 10.1.1. 无侵入式整合dwr和ext 10.1.2. DWRProxy 10.1.3. DWRTreeLoader 10.1.4. DWRProxy和ComboBox 10.2. localXHR让你在不用服务器就玩ajax 10.3. 在form中使用fckeditor 10.4. 健康快乐动起来,fx里的动画效果 10.5. 悄悄的更新网页内容 A. 常见问题乱弹 A.1. ext到底是收费还是免费 A.2. 怎么查看ext2里的api文档 A.3. 如何在页面中引用ext A.3.1. 顺便说说常见的Ext is not defined错误 A.4. 想把弹出对话框单独拿出来用的看这里 A.5. 想把日期选择框单独拿出来用的看这里 A.6. 听说有人现在还不会汉化ext A.7. 碰到使用ajax获得数据,或者提交数据出现乱码 A.8. TabPanel使用autoLoad加载的页面中的js脚本没有执行 A.9. 有关grid的一些小问题 A.9.1. 如何让grid总所有的列都支持排序 A.9.2. 修改一个grid的ColumnModel和Store A.9.3. 动态为ds添加参数baseParams A.10. 有关tree的一些小问题 A.10.1. 如何选中树中的某个节点 A.10.2. 刷新树的所有节点 A.10.3. 如果取得json中自定义的属性 A.11. 如何使用input type="image" A.12. Ext.Window中的closeAction A.13. 使用同步ajax B. 修改日志 C. 后记 C.1. 2007年12月5日,迷茫阶段 C.1.1. 仇恨 C.1.2. 反省 C.2. 关于ext与dwr整合部分的讨论 C.3. 怎么看文档附件里的范例 C.4. ext开发计划 D. 贡献者列表 D.1. 感谢[飘]的大力支持 D.2. 感谢[吧啦吧啦]的大力支持 D.3. 感谢[游戏人生]的大力支持 D.4. 感谢[綄帥]的大力支持 D.5. 感谢[葡萄]的大力支持 D.6. 感谢[天外小人]的大力支持 D.7. 感谢[我想我是海]的大力支持 D.8. 还要感谢:
Struts+Spring+Hibernate实现上传下载      本文将围绕SSH文件上传下载的主题,向您详细讲述如何开发基于SSH的Web程序。SSH各框架的均为当前最新版本:   •Struts 1.2   •Spring 1.2.5   •Hibernate 3.0   本文选用的数据库为Oracle 9i,当然你可以在不改动代码的情况下,通过配置文件的调整将其移植到任何具有Blob字段类型的数据库上,如MySQL,SQLServer等。   总体实现   上传文件保存到T_FILE表中,T_FILE表结构如下: 图 1 T_FILE表结构   其中:   •FILE_ID:文件ID,32个字符,用Hibernate的uuid.hex算法生成。   •FILE_NAME:文件名。   •FILE_CONTENT:文件内容,对应Oracle的Blob类型。   •REMARK:文件备注。   文件数据存储在Blob类型的FILE_CONTENT表字段上,在Spring中采用OracleLobHandler来处理Lob字段(包括Clob和Blob),由于在程序中不需要引用到oracle数据驱动程序的具体类且屏蔽了不同数据库处理Lob字段方法上的差别,从而撤除程序在多数据库移植上的樊篱。   1.首先数据表中的Blob字段在Java领域对象中声明为byte[]类型,而非java.sql.Blob类型。   2.数据表Blob字段在Hibernate持久化映射文件中的type为org.springframework.orm.hibernate3.support.BlobByteArrayType,即Spring所提供的用户自定义的类型,而非java.sql.Blob。 3在Spring中使用org.springframework.jdbc.support.lob.OracleLobHandler处理Oracle数据库的Blob类型字段。   通过这样的设置和配置,我们就可以象持久化表的一般字段类型一样处理Blob字段了。   以上是Spring+Hibernate将文件二进制数据持久化到数据库的解决方案,而Struts通过将表单中file类型的组件映射为ActionForm中类型为org.apache.struts.upload. FormFile的属性来获取表单提交的文件数据。   工程的类按SSH的层次结构划分为数据持久层、业务层和Web层;WEB-INF下的applicationContext.xml为Spring的配置文件,struts-config.xml为Struts的配置文件,file-upload.jsp为文件上传页面,file-list.jsp为文件列表页面。   本文后面的章节将从数据持久层->业务层->Web层的开发顺序,逐层讲解文件上传下载的开发过程。   数据持久层   1、领域对象及映射文件   您可以使用Hibernate Middlegen、HIbernate Tools、Hibernate Syhchronizer等工具或手工的方式,编写Hibernate的领域对象和映射文件。其中对应T_FILE表的领域对象Tfile.java为:   代码 1 领域对象Tfile 1. package sshfile.model; 2. public class Tfile 3.{ 4. private String fileId; 5. private String fileName; 6. private byte[] fileContent; 7. private String remark; 8. …//getter and setter 9. }   特别需要注意的是:数据库表为Blob类型的字段在Tfile中的fileContent类型为byte[]。Tfile的Hibernate映射文件Tfile.hbm.xml放在Tfile .java类文件的相同目录下:   代码 2 领域对象映射文件 1. <?xml version="1.0"?> 2. <!DOCTYPE hibernate-mapping PUBLIC 3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > 5. <hibernate-mapping> 6. <class name="sshfile.model.Tfile" table="T_FILE"> 7. <id name="fileId" type="java.lang.String" column="FILE_ID"> 8. <generator class="uuid.hex"/> 9. </id> 10. <property name="fileContent" 11. type="org.springframework.orm.hibernate3.support.BlobByteArrayType" 12. column="FILE_CONTENT" lazy="true"/> 13. …//其它一般字段的映射 14. </class> 15. </hibernate-mapping>   fileContent字段映射为Spring所提供的BlobByteArrayType类型,BlobByteArrayType是用户自定义的数据类型,它实现了Hibernate 的org.hibernate.usertype.UserType接口。BlobByteArrayType使用从sessionFactory获取的Lob操作句柄lobHandler将byte[]的数据保存到Blob数据库字段中。这样,我们就再没有必要通过硬编码的方式,先insert然后再update来完成Blob类型数据的持久化,这个原来难伺候的老爷终于被平民化了。关于lobHandler的配置请见本文后面的内容。   此外lazy="true"说明地返回整个Tfile对象时,并不返回fileContent这个字段的数据,只有在显式调用tfile.getFileContent()方法时才真正从数据库中获取fileContent的数据。这是Hibernate3引入的新特性,对于包含重量级大数据的表字段,这种抽取方式提高了对大字段操作的灵活性,否则加载Tfile对象的结果集时如果总是返回fileContent,这种批量的数据抽取将可以引起数据库的"洪泛效应"。   2、DAO编写和配置   Spring强调面向接口编程,所以我们将所有对Tfile的数据操作的方法定义在TfileDAO接口中,这些接口方法分别是:   •findByFildId(String fileId)   •save(Tfile tfile)   •List findAll()   TfileDAOHibernate提供了对TfileDAO接口基于Hibernate的实现,如代码 3所示:   代码 3 基于Hibernate 的fileDAO实现类 1. package sshfile.dao; 2. 3. import sshfile.model.*; 4. import org.springframework.orm.hibernate3.support.HibernateDaoSupport; 5. import java.util.List; 6. 7. public class TfileDAOHibernate 8. extends HibernateDaoSupport implements TfileDAO 9. { 10. public Tfile findByFildId(String fileId) 11. { 12. return (Tfile) getHibernateTemplate().get(Tfile.class, fileId); 13. } 14. public void save(Tfile tfile) 15. { 16. getHibernateTemplate().save(tfile); 17. getHibernateTemplate().flush(); 18. } 19. public List findAll() 20. { 21. return getHibernateTemplate().loadAll(Tfile.class); 22. } 23. }   TfileDAOHibernate通过扩展Spring提供的Hibernate支持类HibernateDaoSupport而建立,HibernateDaoSupport封装了HibernateTemplate,而HibernateTemplate封装了Hibernate所提供几乎所有的的数据操作方法,如execute(HibernateCallback action),load(Class entityClass, Serializable id),save(final Object entity)等等。   所以我们的DAO只需要简单地调用父类的HibernateTemplate就可以完成几乎所有的数据库操作了。   由于Spring通过代理Hibernate完成数据层的操作,所以原Hibernate的配置文件hibernate.cfg.xml的信息也转移到Spring的配置文件中:   代码 4 Spring中有关Hibernate的配置信息 1. <beans> 2. <!-- 数据源的配置 //--> 3. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 4. destroy-method="close"> 5. <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> 6. <property name="url" value="jdbc:oracle:thin:@localhost:1521:ora9i"/> 7. <property name="username" value="test"/> 8. <property name="password" value="test"/> 9. </bean> 10. <!-- Hibernate会话工厂配置 //--> 11. <bean id="sessionFactory" 12. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 13. <property name="dataSource" ref="dataSource"/> 14. <property name="mappingDirectoryLocations"> 15. <list> 16. <value>classpath:/sshfile/model</value> 17. </list> 18. </property> 19. <property name="hibernateProperties"> 20. <props> 21. <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop> 22. <prop key="hibernate.cglib.use_reflection_optimizer">true</prop> 23. </props> 24. </property> 25. </bean> 26. <!-- Hibernate 模板//--> 27. <bean id="hibernateTemplate" 28. class="org.springframework.orm.hibernate3.HibernateTemplate"> 29. <property name="sessionFactory" ref="sessionFactory"/> 30. </bean> 31. <!--DAO配置 //--> 32. <bean id="tfileDAO" class="sshfile.dao.TfileDAOHibernate"> 33. <property name="hibernateTemplate" ref="hibernateTemplate" /> 34. </bean> 35. … 36. </beans>   第3~9行定义了一个数据源,其实现类是apache的BasicDataSource,第11~25行定义了Hibernate的会话工厂,会话工厂类用Spring提供的LocalSessionFactoryBean维护,它注入了数据源和资源映射文件,此外还通过一些键值对设置了Hibernate所需的属性。   其中第16行通过类路径的映射方式,将sshfile.model类包目录下的所有领域对象的映射文件装载进来,在本文的例子里,它将装载进Tfile.hbm.xml映射文件。如果有多个映射文件需要声明,使用类路径映射方式显然比直接单独指定映射文件名的方式要简便。   第27~30行定义了Spring代理Hibernate数据操作的HibernateTemplate模板,而第32~34行将该模板注入到tfileDAO中。   需要指定的是Spring 1.2.5提供了两套Hibernate的支持包,其中Hibernate 2相关的封装类位于org.springframework.orm.hibernate2.*包中,而Hibernate 3.0的封装类位于org.springframework.orm.hibernate3.*包中,需要根据您所选用Hibernate版本进行正确选择。   3、Lob字段处理的配置   我们前面已经指出Oracle的Lob字段和一般类型的字段在操作上有一个明显的区别--那就是你必须首先通过Oracle的empty_blob()/empty_clob()初始化Lob字段,然后获取该字段的引用,通过这个引用更改其值。所以要完成对Lob字段的操作,Hibernate必须执行两步数据库访问操作,先Insert再Update。   使用BlobByteArrayType字段类型后,为什么我们就可以象一般的字段类型一样操作Blob字段呢?可以确定的一点是:BlobByteArrayType不可能逾越Blob天生的操作方式,原来是BlobByteArrayType数据类型本身具体数据访问的功能,它通过LobHandler将两次数据访问的动作隐藏起来,使Blob字段的操作在表现上和其他一般字段业类型无异,所以LobHandler即是那个"苦了我一个,幸福十亿人"的那位幕后英雄。   LobHandler必须注入到Hibernate会话工厂sessionFactory中,因为sessionFactory负责产生与数据库交互的Session。LobHandler的配置如代码 5所示:   代码 5 Lob字段的处理句柄配置 1. <beans> 2. … 3. <bean id="nativeJdbcExtractor" 4. class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor" 5. lazy-init="true"/> 6. <bean id="lobHandler" 7. class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true"> 8. <property name="nativeJdbcExtractor"> 9. <ref local="nativeJdbcExtractor"/> 10. </property> 11. </bean> 12. … 13. </beans>   首先,必须定义一个能够从连接池中抽取出本地数据库JDBC对象(如OracleConnection,OracleResultSet等)的抽取器:nativeJdbcExtractor,这样才可以执行一些特定数据库的操作。对于那些仅封装了Connection而未包括Statement的简单数据连接池,SimpleNativeJdbcExtractor是效率最高的抽取器实现类,但具体到apache的BasicDataSource连接池,它封装了所有JDBC的对象,这时就需要使用CommonsDbcpNativeJdbcExtractor了。Spring针对几个著名的Web服务器的数据源提供了相应的JDBC抽取器:   •WebLogic:WebLogicNativeJdbcExtractor   •WebSphere:WebSphereNativeJdbcExtractor   •JBoss:JBossNativeJdbcExtractor   在定义了JDBC抽取器后,再定义lobHandler。Spring 1.2.5提供了两个lobHandler:   •DefaultLobHandler:适用于大部分的数据库,如SqlServer,MySQL,对Oracle 10g也适用,但不适用于Oracle 9i(看来Oracle 9i确实是个怪胎,谁叫Oracle 公司自己都说Oracle 9i是一个过渡性的产品呢)。   •OracleLobHandler:适用于Oracle 9i和Oracle 10g。   由于我们的数据库是Oracle9i,所以使用OracleLobHandler。   在配置完LobHandler后, 还需要将其注入到sessionFactory的Bean中,下面是调用后的sessionFactory Bean的配置:   代码 6 将lobHandler注入到sessionFactory中的配置 1. <beans> 2. … 3. <bean id="sessionFactory" 4. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 5. <property name="dataSource" ref="dataSource"/> 6. <!-- 为处理Blob类型字段的句柄声明 //--> 7. <property name="lobHandler" ref="lobHandler"/> 8. … 9. </bean> 10. … 11. </beans>   如第7所示,通过sessionFactory的lobHandler属性进行注入。  业务层   1、业务层接口   "面向接口而非面向类编程"是Spring不遗余力所推荐的编程原则,这条原则也已经为大部开发者所接受;此外,JDK的动态代理只对接口有效,否则必须使用CGLIB生成目标类的子类。我们依从于Spring的倡导为业务类定义一个接口:   代码 7 业务层操作接口 1. public interface FileService 2. { 3. void save(FileActionForm fileForm);//将提交的上传文件保存到数据表中 4. List getAllFile();//得到T_FILE所示记录 5. void write(OutputStream os,String fileId);//将某个文件的文件数据写出到输出流中 6. String getFileName(String fileId);//获取文件名 7. }   其中save(FileActionForm fileForm)方法,将封装在fileForm中的上传文件保存到数据库中,这里我们使用FileActionForm作为方法入参,FileActionForm是Web层的表单数据对象,它封装了提交表单的数据。将FileActionForm直接作为业务层的接口入参,相当于将Web层传播到业务层中去,即将业务层绑定在特定的Web层实现技术中,按照分层模型学院派的观点,这是一种反模块化的设计,但在"一般"的业务系统并无需提供多种UI界面,系统Web层将来切换到另一种实现技术的可能性也微乎其微,所以笔者觉得没有必要为了这个业务层完全独立于调用层的过高目标而去搞一个额外的隔离层,浪费了原材料不说,还将系统搞得过于复杂,相比于其它原则,"简单"始终是最大的一条原则。   getAllFile()负责获取T_FILE表所有记录,以便在网页上显示出来。   而getFileName(String fileId)和write(OutputStream os,String fileId)则用于下载某个特定的文件。具体的调用是将Web层将response.getOutputStream()传给write(OutputStream os,String fileId)接口,业务层直接将文件数据输出到这个响应流中。具体实现请参见错误!未找到引用源。节下载文件部分。   2、业务层接口实现类   FileService的实现类为FileServiceImpl,其中save(FileActionForm fileForm)的实现如下所示:   代码 8 业务接口实现类之save() 1. … 2. public class FileServiceImpl 3. implements FileService 4. { 5. private TfileDAO tfileDAO; 6. public void save(FileActionForm fileForm) 7. { 8. Tfile tfile = new Tfile(); 9. try 10. { 11. tfile.setFileContent(fileForm.getFileContent().getFileData()); 12. } 13. catch (FileNotFoundException ex) 14. { 15. throw new RuntimeException(ex); 16. } 17. catch (IOException ex) 18. { 19. throw new RuntimeException(ex); 20. } 21. tfile.setFileName(fileForm.getFileContent().getFileName()); 22. tfile.setRemark(fileForm.getRemark()); 23. tfileDAO.save(tfile); 24. } 25. … 26. }   在save(FileActionForm fileForm)方法里,完成两个步骤:   其一,象在水桶间倒水一样,将FileActionForm对象中的数据倒入到Tfile对象中;   其二,调用TfileDAO保存数据。   需要特别注意的是代码的第11行,FileActionForm的fileContent属性为org.apache.struts.upload.FormFile类型,FormFile提供了一个方便的方法getFileData(),即可获取文件的二进制数据。通过解读FormFile接口实现类DiskFile的原码,我们可能知道FormFile本身并不缓存文件的数据,只有实际调用getFileData()时,才从磁盘文件输入流中获取数据。由于FormFile使用流读取方式获取数据,本身没有缓存文件的所有数据,所以对于上传超大体积的文件,也是没有问题的;但是,由于数据持久层的Tfile使用byte[]来缓存文件的数据,所以并不适合处理超大体积的文件(如100M),对于超大体积的文件,依然需要使用java.sql.Blob类型以常规流操作的方式来处理。   此外,通过FileForm的getFileName()方法就可以获得上传文件的文件名,如第21行代码所示。   write(OutputStream os,String fileId)方法的实现,如代码 9所示:   代码 9 业务接口实现类之write() 1. … 2. public class FileServiceImpl 3. implements FileService 4. { 5. 6. public void write(OutputStream os, String fileId) 7. { 8. Tfile tfile = tfileDAO.findByFildId(fileId); 9. try 10. { 11. os.write(tfile.getFileContent()); 12. os.flush(); 13. } 14. catch (IOException ex) 15. { 16. throw new RuntimeException(ex); 17. } 18. } 19. … 20. }   write(OutputStream os,String fileId)也简单地分为两个操作步骤,首先,根据fileId加载表记录,然后将fileContent写入到输出流中。   3、Spring事务配置   下面,我们来看如何在Spring配置文件中为FileService配置声明性的事务 1. <beans> 2. … 3. <bean id="transactionManager" 4. class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 5. <property name="sessionFactory" ref="sessionFactory"/> 6. </bean> 7. <!-- 事务处理的AOP配置 //--> 8. <bean id="txProxyTemplate" abstract="true" 9. class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 10. <property name="transactionManager" ref="transactionManager"/> 11. <property name="transactionAttributes"> 12. <props> 13. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> 14. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> 15. <prop key="save">PROPAGATION_REQUIRED</prop> 16. <prop key="write">PROPAGATION_REQUIRED,readOnly</prop> 17. </props> 18. </property> 19. </bean> 20. <bean id="fileService" parent="txProxyTemplate"> 21. <property name="target"> 22. <bean class="sshfile.service.FileServiceImpl"> 23. <property name="tfileDAO" ref="tfileDAO"/> 24. </bean> 25. </property> 26. </bean> 27. </beans>   Spring的事务配置包括两个部分:   其一,定义事务管理器transactionManager,使用HibernateTransactionManager实现事务管理;   其二,对各个业务接口进行定义,其实txProxyTemplate和fileService是父子节点的关系,本来可以将txProxyTemplate定义的内容合并到fileService中一起定义,由于我们的系统仅有一个业务接口需要定义,所以将其定义的一部分抽象到父节点txProxyTemplate中意义确实不大,但是对于真实的系统,往往拥有为数众多的业务接口需要定义,将这些业务接口定义内容的共同部分抽取到一个父节点中,然后在子节点中通过parent进行关联,就可以大大简化业务接口的配置了。   父节点txProxyTemplate注入了事务管理器,此外还定义了业务接口事务管理的方法(允许通过通配符的方式进行匹配声明,如前两个接口方法),有些接口方法仅对数据进行读操作,而另一些接口方法需要涉及到数据的更改。对于前者,可以通过readOnly标识出来,这样有利于操作性能的提高,需要注意的是由于父类节点定义的Bean仅是子节点配置信息的抽象,并不能具体实现化一个Bean对象,所以需要特别标注为abstract="true",如第8行所示。   fileService作为一个目标类被注入到事务代理器中,而fileService实现类所需要的tfileDAO实例,通过引用3.2节中定义的tfileDAO Bean注入。   Web层实现   1、Web层的构件和交互流程   Web层包括主要3个功能:   •上传文件。   •列出所有已经上传的文件列表,以供点击下载。   •下载文件。   Web层实现构件包括与2个JSP页面,1个ActionForm及一个Action:   •file-upload.jsp:上传文件的页面。   •file-list.jsp:已经上传文件的列表页面。   •FileActionForm:file-upload.jsp页面表单对应的ActionForm。   •FileAction:继承org.apache.struts.actions.DispatchAction的Action,这样这个Action就可以通过一个URL参数区分中响应不同的请求。   Web层的这些构件的交互流程如图 6所示: 图 6 Web层Struts流程图   其中,在执行文件上传的请求时,FileAction在执行文件上传后,forward到loadAllFile出口中,loadAllFile加载数据库中所有已经上传的记录,然后forward到名为fileListPage的出口中,调用file-list.jsp页面显示已经上传的记录。   2、FileAction功能   Struts 1.0的Action有一个弱项:一个Action只能处理一种请求,Struts 1.1中引入了一个DispatchAction,允许通过URL参数指定调用Action中的某个方法,如http://yourwebsite/fileAction.do?method=upload即调用FileAction中的upload方法。通过这种方式,我们就可以将一些相关的请求集中到一个Action当中编写,而没有必要为某个请求操作编写一个Action类。但是参数名是要在struts-config.xml中配置的: 1. <struts-config> 2. <form-beans> 3. <form-bean name="fileActionForm" type="sshfile.web.FileActionForm" /> 4. </form-beans> 5. <action-mappings> 6. <action name="fileActionForm" parameter="method" path="/fileAction" 7. type="sshfile.web.FileAction"> 8. <forward name="fileListPage" path="/file-list.jsp" /> 9. <forward name="loadAllFile" path="/fileAction.do?method=listAllFile" /> 10. </action> 11. </action-mappings> 12. </struts-config>   第6行的parameter="method"指定了承载方法名的参数,第9行中,我们还配置了一个调用FileAction不同方法的Action出口。   FileAction共有3个请求响应的方法,它们分别是:   •upload(…):处理上传文件的请求。   •listAllFile(…):处理加载数据库表中所有记录的请求。   •download(…):处理下载文件的请求。   下面我们分别对这3个请求处理方法进行讲解。   2.1 上传文件   上传文件的请求处理方法非常简单,简之言之,就是从Spring容器中获取业务层处理类FileService,调用其save(FileActionForm form)方法上传文件,如下所示: 1. public class FileAction 2. extends DispatchAction 3. { 4. //将上传文件保存到数据库中 5. public ActionForward upload(ActionMapping mapping, ActionForm form, 6. HttpServletRequest request, 7. HttpServletResponse response) 8. { 9. FileActionForm fileForm = (FileActionForm) form; 10. FileService fileService = getFileService(); 11. fileService.save(fileForm); 12. return mapping.findForward("loadAllFile"); 13. } 14. //从Spring容器中获取FileService对象 15. private FileService getFileService() 16. { 17. ApplicationContext appContext = WebApplicationContextUtils. 18. getWebApplicationContext(this.getServlet().getServletContext()); 19. return (FileService) appContext.getBean("fileService"); 20. } 21. … 22. }   由于FileAction其它两个请求处理方法也需要从Spring容器中获取FileService实例,所以我们特别提供了一个getFileService()方法(第15~21行)。重构的一条原则就是:"发现代码中有重复的表达式,将其提取为一个变量;发现类中有重复的代码段,将其提取为一个方法;发现不同类中有相同的方法,将其提取为一个类"。在真实的系统中,往往拥有多个Action和多个Service类,这时一个比较好的设置思路是,提供一个获取所有Service实现对象的工具类,这样就可以将Spring 的Service配置信息屏蔽在一个类中,否则Service的配置名字散落在程序各处,维护性是很差的。   2.2 列出所有已经上传的文件   listAllFile方法调用Servie层方法加载T_FILE表中所有记录,并将其保存在Request域中,然后forward到列表页面中: 1. public class FileAction 2. extends DispatchAction 3. { 4. … 5. public ActionForward listAllFile(ActionMapping mapping, ActionForm form, 6. HttpServletRequest request, 7. HttpServletResponse response) 8. throws ModuleException 9. { 10. FileService fileService = getFileService(); 11. List fileList = fileService.getAllFile(); 12. request.setAttribute("fileList",fileList); 13. return mapping.findForward("fileListPage"); 14. } 15. }   file-list.jsp页面使用Struts标签展示出保存在Request域中的记录: 1. <%@page contentType="text/html; charset=GBK"%> 2. <%@taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%> 3. <%@taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> 4. <html> 5. <head> 6. <title>file-download</title> 7. </head> 8. <body bgcolor="#ffffff"> 9. <ol> 10. <logic:iterate id="item" name="fileList" scope="request"> 11. <li> 12. <a href='fileAction.do?method=download&fileId= 13. <bean:write name="item"property="fileId"/>'> 14. <bean:write name="item" property="fileName"/> 15. </a> 16. </li> 17. </logic:iterate> 18. </ol> 19. </body> 20. </html>   展现页面的每条记录挂接着一个链接地址,形如:fileAction.do?method=download&fileId=xxx,method参数指定了这个请求由FileAction的download方法来响应,fileId指定了记录的主键。   由于在FileActionForm中,我们定义了fileId的属性,所以在download响应方法中,我们将可以从FileActionForm中取得fileId的值。这里涉及到一个处理多个请求Action所对应的ActionForm的设计问题,由于原来的Action只能对应一个请求,那么原来的ActionForm非常简单,它仅需要将这个请求的参数项作为其属性就可以了,但现在一个Action对应多个请求,每个请求所对应的参数项是不一样的,此时的ActionForm的属性就必须是多请求参数项的并集了。所以,除了文件上传请求所对应的fileContent和remark属性外还包括文件下载的fileId属性: 图 7 FileActionForm   当然这样会造成属性的冗余,比如在文件上传的请求中,只会用到fileContent和remark属性,而在文件下载的请求时,只会使用到fileId属性。但这种冗余是会带来好处的--它使得一个Action可以处理多个请求。   2.3 下载文件   在列表页面中点击一个文件下载,其请求由FileAction的download方法来响应,download方法调用业务层的FileService方法,获取文件数据并写出到response的响应流中。通过合理设置HTTP响应头参数,将响应流在客户端表现为一个下载文件对话框,其代码如下所示:   代码 10 业务接口实现类之download 1. public class FileAction 2. extends DispatchAction 3. { 4. … 5. public ActionForward download(ActionMapping mapping, ActionForm form, 6. HttpServletRequest request, 7. HttpServletResponse response) 8. throws ModuleException 9. { 10. FileActionForm fileForm = (FileActionForm) form; 11. FileService fileService = getFileService(); 12. String fileName = fileService.getFileName(fileForm.getFileId()); 13. try 14. { 15. response.setContentType("application/x-msdownload"); 16. response.setHeader("Content-Disposition", 17. "attachment;" + " filename="+ 18. new String(fileName.getBytes(), "ISO-8859-1")); 19. fileService.write(response.getOutputStream(), fileForm.getFileId()); 20. } 21. catch (Exception e) 22. { 23. throw new ModuleException(e.getMessage()); 24. } 25. return null; 26. } 27. }   第15~18行,设置HTTP响应头,将响应类型设置为application/x-msdownload MIME类型,则响应流在IE中将弹出一个文件下载的对话框,如图 4所示。IE所支持的MIME类型多达26种,您可以通过这个网址查看其他的MIME类型: http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp。   如果下载文件的文件名含有中文字符,如果不对其进行硬编码,如第18行所示,客户文件下载对话框中出现的文件名将会发生乱码。 第19行代码获得response的输出流,作为FileServie write(OutputStream os,String fileId)的入参,这样文件的内容将写到response的输出流中。   3、web.xml文件的配置 Spring容器在何时启动呢?我可以在Web容器初始化来执行启动Spring容器的操作,Spring提供了两种方式启动的方法:   •通过org.springframework.web.context .ContextLoaderListener容器监听器,在Web容器初始化时触发初始化Spring容器,在web.xml中通过<listener></listener>对其进行配置。   •通过Servlet org.springframework.web.context.ContextLoaderServlet,将其配置为自动启动的Servlet,在Web容器初始化时,通过这个Servlet启动Spring容器。   在初始化Spring容器之前,必须先初始化log4J的引擎,Spring也提供了容器监听器和自动启动Servlet两种方式对log4J引擎进行初始化:  •org.springframework.web.util .Log4jConfigListener  •org.springframework.web.util.Log4jConfigServlet   下面我们来说明如何配置web.xml启动Spring容器:   代码 11 web.xml中对应Spring的配置内容 1. <web-app> 2. <context-param> 3. <param-name>contextConfigLocation</param-name> 4. <param-value>/WEB-INF/applicationContext.xml</param-value> 5. </context-param> 6. <context-param> 7. <param-name>log4jConfigLocation</param-name> 8. <param-value>/WEB-INF/log4j.properties</param-value> 9. </context-param> 10. <servlet> 11. <servlet-name>log4jInitServlet</servlet-name> 12. <servlet-class>org.springframework.web.util.Log4jConfigServlet</servlet-class> 13. <load-on-startup>1</load-on-startup> 14. </servlet> 15. <servlet> 16. <servlet-name>springInitServlet</servlet-name> 17. <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class> 18. <load-on-startup>2</load-on-startup> 19. </servlet> 20. … 21. </web-app>   启动Spring容器时,需要得到两个信息:Spring配置文件的地址和Log4J属性文件,这两上信息分别通过contextConfigLocationWeb和log4jConfigLocation容器参数指定,如果有多个Spring配置文件,则用逗号隔开,如: /WEB-INF/applicationContext_1.xml, /WEB-INF/applicationContext_1.xm2   由于在启动ContextLoaderServlet之前,必须事先初始化Log4J的引擎,所以Log4jConfigServlet必须在ContextLoaderServlet之前启动,这通过<load-on-startup>来指定它们启动的先后顺序。   乱码是开发Web应用程序一个比较老套又常见问题,由于不同Web应用服务器的默认编码是不一样的,为了方便Web应用在不同的Web应用服务器上移植,最好的做法是Web程序自身来处理编码转换的工作。经典的作法是在web.xml中配置一个编码转换过滤器,Spring就提供了一个编码过滤器类CharacterEncodingFilter,下面,我们为应用配置上这个过滤器: 1. <web-app> 2. … 3. <filter> 4. <filter-name>encodingFilter</filter-name> 5. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 6. <init-param> 7. <param-name>encoding</param-name> 8. <param-value>GBK</param-value> 9. </init-param> 10. </filter> 11. <filter-mapping> 12. <filter-name>encodingFilter</filter-name> 13. <url-pattern>/*</url-pattern> 14. </filter-mapping> 15. … 16. </web-app>   Spring的过滤器类是org.springframework.web.filter.CharacterEncodingFilter,通过encoding参数指定编码转换类型为GBK,<filter-mapping>的配置使该过滤器截获所有的请示。   Struts的框架也需要在web.xml中配置,想必读者朋友对Struts的配置都很熟悉,故在此不再提及,请参见本文所提供的源码。   总结   本文通过一个文件上传下载的Web应用,讲解了如何构建基于SSH的Web应用,通过Struts和FormFile,Spring的LobHandler以及Spring为HibernateBlob处理所提供的用户类BlobByteArrayType ,实现上传和下载文件的功能仅需要廖廖数行的代码即告完成。读者只需对程序作稍许的调整,即可处理Clob字段:   •领域对象对应Clob字段的属性声明为String类型;   •映射文件对应Clob字段的属性声明为org.springframework.orm.hibernate3.support.ClobStringType类型。
form 表单的提交有以下几种方式: 1. GET 方法提交:当表单的 `method` 属性设置为 `GET` 时,表单数据会附加在 URL 的查询参数中,通过 GET 请求发送给服务器。这种方式适用于对数据安全性要求不高、数据量较小的情况,例如搜索表单。 2. POST 方法提交:当表单的 `method` 属性设置为 `POST` 时,表单数据会作为请求的内容体发送给服务器。这种方式适用于传输敏感数据或者数据量较大的情况,例如用户注册或登录表单。 3. AJAX 提交:使用 JavaScript 的 XMLHttpRequest 或 Fetch API,可以通过异步的方式将表单数据发送给服务器。这种方式可以在不刷新整个页面的情况下发送数据,并且可以处理服务器返回的结果,实现无刷新的交互效果。 4. File Upload 提交:当表单包含文件上传字段时,可以使用特殊的 enctype 属性(如 `enctype="multipart/form-data"`)以及相应的后端处理逻辑来实现文件的上传。这种方式适用于需要上传文件的场景,例如上传图片、视频等。 5. 使用 JavaScript 提交:通过 JavaScript 可以监听表单的提交事件,并自定义处理逻辑。可以使用 JavaScript 构建请求并将表单数据发送给服务器,例如使用 Fetch API 或其他 AJAX 库来完成提交操作。 需要注意的是,在表单提交时,通常会通过设置 `action` 属性指定处理表单数据的后端地址。同时,表单字段需要通过 `name` 属性来标识,以便后端能够正确解析和处理数据。 根据具体的需求和场景,可以选择适合的提交方式来实现表单数据的传输和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值