| 日历 |
|
|
| 网志分类 |
|
|
|
| 站内搜索 |
|
| 友情链接 |
|
0250087
|
|
| 开此博一为经验积累,二为资料收集,三为同道交流,四为资源共享. |
|
| 2007/02/22 - 2007/02/31 |
浏览全部日志 |
出处: http://www.jeedev.com/blog/article.asp?id=182
如果用户对一个html表单多次提交,web应用应该能够判断用户的重复提交行为,并作出相应的处理。
最常见的是新增一条数据,用户已经提交表单并且服务器端已经完成新增成功。此时用户可能有两个误操作:
1.用户通过浏览器的后退功能,返回到录入页面,重复提交(此时浏览器提供回退功能基本上是个邪恶行为)
2.刷新该页面(因为新增成功的提示页面通常是通过请求转发(forward)过来的,所以此操作实际效果通常等同于1)
这样造成的可能结果有:
1.若程序级别和数据库级别限制了重复记录,会提示类似于“xxx字段已存在,请修改后重新保存”的信息
2.若没有此限制,服务器端会再插入一条数据,而这通常不是用户想要的
误操作2和可能结果2的结合就达成了与用户意图相背的结果:服务器端不停地在增加重复记录,用户认为自己只不过是刷新该提示信息页面。
通用的解决思路是:
用户请求录入页面,这个与服务器建立的一次连接过程中,在服务器端①【生成一个session标识,同时返回到客户端一个与此匹配的hidden域】。用户提交了此页面,服务器端首先②【判断此hidden域与session标识是否匹配】,若不匹配,终止保存操作,提示同一表单不能提交两次,同时①【新建一个session标识和hidden域】,返回录入页面;若匹配,执行插入保存操作,同时③【清空(重置reset)session标识】。
Struts正在基于这样的思路在org.apache.struts.action.Action类中提供了内置支持方法:
java代码:
protected void saveToken(HttpServletRequest request) 配合标签对应于①
protected boolean isTokenValid(HttpServletRequest request) 对应于②
protected void resetToken(HttpServletRequest request) 对应于③
这样我们在写程序的时候,结合Struts的html标签,只要
1.在forward到insert.jsp页面前加一个action执行saveToken(request)操作,或干脆在insert.jsp中写
2.保存前加个判断操作isTokenValid(request)
3.若isTokenValid(request)返回false,执行saveToken(request)操作,返回错误提示页面;true则执行resetToken(request)操作,然后进行实际的保存操作
我的代码
// 进入创建前的Action
public final class EnterNewProjectPageAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
saveToken(request);
return (mapping.findForward("createproject_jsp"));
}
}
// 创建Action
public final class CreateProjectAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
if(isTokenValid(request)){
resetToken(request);
CreateProjectForm createProjectForm=(CreateProjectForm)form;
Project newProject=createProjectForm.getProject();
newProject.setCreateTime(Util.getCurrTime());
ProjectService.create(newProject);
}
else{
saveToken(request);
System.out.println("重复提交");
}
ProjectUtil.setupPages(0,request);
return (mapping.findForward("projects_jsp"));
}
}
|
本文翻译自Java年鉴1.4版
创建表格组件(Creating a JTable Component)
The following creates a table that uses an efficient underlying storage implementation. Although cell values can be changed, rows and columns cannot be added or deleted.
下列代码使用了一种有效的方式创建表格。尽管单元格的值能变化,行和列不能被添加或删除。
// Create with initial data
Object[][] cellData = {
{"row1-col1", "row1-col2"},
{"row2-col1", "row2-col2"}};
String[] columnNames = {"col1", "col2"};
JTable table = new JTable(cellData, columnNames);
The following creates tables that allow rows and columns to be added or deleted:
下列代码创建的表格允许增删行或列。
// Create a table with empty cells
int rows = 10;
int cols = 5;
table = new JTable(rows, cols);
// Create a table with initial data
Vector rowData = new Vector();
for (int i=0; i<cellData.length; i++) {
Vector colData = new Vector(Arrays.asList(cellData[i]));
rowData.add(colData);
}
Vector columnNamesV = new Vector(Arrays.asList(columnNames));
table = new JTable(rowData, columnNamesV);
取得表格的行数和列数(Getting the Number of Rows and Columns in a JTable Component)
int rows = table.getRowCount();
int cols = table.getColumnCount();
向表格添加一行(Appending a Row to a JTable Component)
To add a row of data to a JTable component, you need to add it to its table model. A simple implementation of a table model that supports appending row data is DefaultTableModel. By default, a table uses a DefaultTableModel.
如果你想要向表格添加一行数据,你需要把这行数据添加到表格的模块部分。一种支持行添加的简单实现是DefaultTableModel。表格缺省使用的就是DefaultTableModel。
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
// 创建两列(Create a couple of columns)
model.addColumn("Col1");
model.addColumn("Col2");
// 添加一行(Append a row)
model.addRow(new Object[]{"v1", "v2"});
// 现在就有两行两列了(there are now 2 rows with 2 columns)
// 添加比列个数少的数据行(Append a row with fewer values than columns.)
// 这时会从左到右依次添加数据,没有对应数据项的单元格将被赋空The left-most fields in the new row are populated
// with the supplied values (left-to-right) and fields
// without values are set to null.
model.addRow(new Object[]{"v1"});
// 现在有了三行两列there are now 3 rows with 2 columns
// 添加比列个数多的数据行(Append a row with more values than columns.)
// 多余的数据将被忽略(The extra values are ignored.)
model.addRow(new Object[]{"v1", "v2", "v3"});
// 现在有了四行两列(there are now 4 rows with 2 columns)
在表格中插入一行(Inserting a Row in a JTable Component)
To insert a row of data to a JTable component, you need to insert it to its table model. A simple implementation of a table model that supports the insertion of row data is DefaultTableModel.
如果你想要向表格插入一行数据,你需要把这行数据插入到表格的模块部分。一种支持行插入的简单实现是DefaultTableModel。表格缺省使用的就是DefaultTableModel。
When inserting a row using DefaultTableModel.insertRow(), the position of the new row must be specified. Positions are locations between rows. For example, if there are 2 rows in a table, there are 3 possible positions - - 0, 1,and 2. Inserting a row at position 0 makes the new row the first row. Inserting a row at position 2 makes the new row the last row.
当使用DefaultTableModel.insertRow()方法插入数据时,你需要指定新行的位置。位置是行与行之间的定位点。比如说,一个两行的表格就有三个可能的插入位置,0,1和2。在位置0插入时,新数据行会出现在表格的第一行。在位置3插入时,新行会出现在表格的最后一行。
When inserting a row with fewer values than columns, the left-most fields in the new row are populated with the supplied values (left-to-right) and the fields without values are set to null. When inserting a row with more values than columns, the extra values are ignored.
添加比列个数少的数据行时,会从左到右依次添加数据,没有对应数据项的单元格将被赋空;添加比列个数多的数据行时,多余的数据将被忽略。
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
// 新建两列(Create a couple of columns)
model.addColumn("Col1");
model.addColumn("Col2");
// 创建第一行(Create the first row)
model.insertRow(0, new Object[]{"r1"});
// 在第一行插入(Insert a row so that it becomes the first row)
model.insertRow(0, new Object[]{"r2"});
// 在位置2插入一行(Insert a row at position p)
int p = 2;
model.insertRow(p, new Object[]{"r3"});
// 在第二行前插入一行(Insert a row before the second row)
int r = 1;
model.insertRow(r, new Object[]{"r4"});
// 新行将成为第二行(the new row is now the second row)
// 在第二行后插入一行(Insert a row after the second row)
r = 1;
model.insertRow(r+1, new Object[]{"r5"});
// 新行将成为第三行(the new row is now the third row)
// 使用插入的方法添加一行(Append a row)
model.insertRow(model.getRowCount(), new Object[]{"r5"});
从表格中删除一行(Removing a Row from a JTable Component)
To remove a row of data from a JTable component, you need to remove it from its table model. A simple implementation of a table model that supports the removal of row data is DefaultTableModel.
如果你想要从表格删除一行数据,你需要把这行数据从表格的模块部分删除。一种支持行删除的简单实现是DefaultTableModel。表格缺省使用的就是DefaultTableModel。
When removing a row using DefaultTableModel.removeRow(), the index of the row must be specified. Row indices start from 0. For example, if there are 2 rows in a table, the index of the first row is 0 and the index of the second row is 1. Removing a row at index 0 removes the first row.
当使用DefaultTableModel.removeRow()方法删除数据时,你需要指定删除行的序号。行序号从零开始,比如一个两行的表格,它的第一行的序号是0,第二行的序号是1。删除序号零所在的行就是删除第一行。
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
// 建立一些数据(Create some data)
model.addColumn("Col1");
model.addRow(new Object[]{"r1"});
model.addRow(new Object[]{"r2"});
model.addRow(new Object[]{"r3"});
// 删除第一行(Remove the first row)
model.removeRow(0);
// 删除最后一行(Remove the last row)
model.removeRow(model.getRowCount()-1);
在表格中进行行移动(Moving a Row in a JTable Component)
To move a row of data to a JTable component, you need to move it in its table model. A simple implementation of a table model that supports the moving of row data is DefaultTableModel.
如果你想要从表格移动一行数据,应该把这行数据在表格的模块部分移动。一种支持行移动的简单实现是DefaultTableModel。表格缺省使用的就是DefaultTableModel。
When moving one or more rows using DefaultTableModel.moveRow(), the set of the rows to be moved and the destination position must be specified. The contiguous set of rows to be moved is specified with the index of the starting row and the index of the end row. Row indices start from 0. For example, if there are 2 rows in a table, the index of the first row is 0 and the index of the second row is 1.
The destination is also a position. Positions are locations between rows. For example, if there are 2 rows in a table, there are 3 possible positions - - 0, 1,and 2. The important thing to remember about the destination position is that it specifies the position in the row data after the rows to be moved are taken out of the row data. For example, if you want to move the first row to the end of the table, the destination position is not getRowCount(), it is getRowCount()-1. Similarly, if you want to move the first 2 lines to the end of the table, the destination position is getRowCount()-2.
The way in which the parameters are interpreted is somewhat awkward. The more conventional method is to either make the end index exclusive (like String.substring()) or replace end with a length. Also, it is easier to specify the destination as it exists before the operation, and not have to pretend that the rows to be moved are taken out. A version of moveRow() with more conventional parameter interpretation is provided in betterMoveRow().
DefaultTableModel model = new DefaultTableModel();
JTable table = new JTable(model);
// Create some data
model.addColumn("Col1");
model.addRow(new Object[]{"r1"});
model.addRow(new Object[]{"r2"});
model.addRow(new Object[]{"r3"});
// Move the first row to the end of the table
model.moveRow(0, 0, model.getRowCount()-1);
betterMoveRow(model, 0, 1, model.getRowCount());
// Move the last row to the beginning of the table
model.moveRow(model.getRowCount()-1, model.getRowCount()-1, 0);
betterMoveRow(model, model.getRowCount()-1, model.getRowCount(), 0);
// Move the first two rows to the end of the table
model.moveRow(0, 1, model.getRowCount()-2);
betterMoveRow(model, 0, 2, model.getRowCount());
// Move the last two rows to the start of the table
model.moveRow(model.getRowCount()-2, model.getRowCount()-1, 0);
betterMoveRow(model, model.getRowCount()-2, model.getRowCount(), 0);
// A better version of moveRow().
// Moves all rows contained between the positions start and end
// to the position specified by dest.
public static void betterMoveRow(DefaultTableModel model, int start, int end, int dest) {
int count = end - start;
if (count <= 0) {
return;
}
if (dest > start) {
dest = Math.max(start, dest-count);
}
end--;
model.moveRow(start, end, dest);
}
未完待续...
|
本文系原创文章,转载请注明出处(jungleosng.yculblog.com)
在上一讲中我们谈到了使用Split来劈分字符串得到数组的例子,但如果字符串是
这样:
111b222d333f444
需要分成111,222,333,444
这时Split函数就不一定比Mid函数高明高效了。
但借助正则表达式,Split可以挽回败局。
首先当然是在VB中加入对正则表达式的参照(Microsoft VBScript Regular Expressions 5.5)
。
再书写代码如下:
Dim strDest As String
strDest = "111b222d333f444" ‘// 这是目标字符串
Dim reg As New RegExp
reg.IgnoreCase = True
reg.Global = True
reg.MultiLine = True
reg.Pattern = "b|d|f" ‘// 这是劈分字符串的正则表达式
Dim mc As MatchCollection
strDest = reg.Replace(strDest, ",") ’// 将strDest的b,d,f以,取代
Dim strArr() As String
strArr = Split(strDest, ",") ‘// 正式劈分
最后结果就出来了。也可以用replace函数将b,d,f一步步替换成,,但没有这样
做直观方便。
PS:java中String的Split和replace函数可以直接接受正则表达式,省却了上述的
第二步。
|
本文系原创文章,转载请注明出处(jungleosng.yculblog.com)
1.打开标准文件目录对话框.
首先需要引入MicroSoft Common Dialog 6.0,然后把工具栏上多出的图标放置到画
面上,程序中这样写:
'// 显示标准文件对话框
With cdlg
.FileName = ""
.Filter = "Excel File(*.xls)|*.xls" '// 文件描述及类型
.InitDir = App.Path + "\"
.ShowSave '// 显示保存状态,如果是打开
状态则为ShowOpen
If Len(.FileName) > 0 Then '// 如果文件名有效
Screen.MousePointer = 11 '// 鼠标变成等待状态
Call StartMergeFile(.FileName, strArrAllFile)'// 对文件进行
处理
Screen.MousePointer = 1 '// 鼠标变成正常状态
End If
End With
运用上述代码一般在一个按钮的点击事件中.
2.判断文件/目录是否存在
Public Function isFileExist(strFile As String) As Boolean
isFileExist=(Dir(strFile, vbDirectory) <> "")
End Function
这个函数主要使用了Dir函数.
3.以缺省方式打开文件
首先我们需要引入Api函数ShellExecute
Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
然后在代码中这样调用:
Dim lngTmp As Long
lngTmp = ShellExecute(Me.hwnd, "open", strFileName, "", "", 1)
strFileName就是你要打开的文件名,ShellExecute会通知Windows找到strFileName
这个文件的缺省打开方式,再以这个方式打开.大家可以试一试效果.
4.遍历某目录下某类型文件(不遍历子目录)
函数如下:
Public Function getProperFileInDir(strDir As String, _
strFilter As String, _
strArr() As String)
Dim strFileName As String
'// get first file
strFileName = Dir(strDir + "\" + strFilter, vbNormal Or vbArchive Or vbHidden)
Dim intFileCount As Integer
Do While Len(strFileName) > 0
ReDim Preserve strArr(0 To intFileCount)
strArr(intFileCount) = strDir + "\" + strFileName
intFileCount = intFileCount + 1
strFileName = Dir
Loop
End Function
调用方式如下:
Dim strArrAllFile() As String
ReDim Preserve strArrAllFile(0 To 0)
Call getProperFileInDir(txtPath, txtType, strArrAllFile)
|
Kill 语句
Kill语句的功能是从磁盘中删除文件,它的语法结构如下:
Kill pathname
其中参数pathname是用来指定一个文件名的字符串表达式,pathname要包含文件所在的目录或文件夹以及驱动器。Kill支持多字符(*)和单字符(?)的统配来指定多重文件。
FileCopy 语句
FileCopy语句的功能是复制一个文件 ,它的语法结构如下
FileCopy source,destination
在FileCopy语句的语法中包括两个参数,其中soure用来表示要被复制的源文件名,而destination用来指定要复制的目的文件名
在source和destination参数中都要包含文件所在的目录或文件夹以及驱动器。
Shell 函数
Shell函数的功能是执行一个可执行文件,同时返回一个Variant(Double),如果成功的话,代表这个程序的任务ID,若不成功,则会返回0.它的语法结构如下:
Shell(pathname[,windowstyle])
参数说明: pathname为所要执行的应用程序的名称及其路径和必要的参数;
windowstyle表示在程序运行时窗口的样式。其中的参数windowstyle的设置及其说明如表
设置值说明:
0 窗口被隐藏,且焦点会移到隐藏式窗口;
1 窗口具有焦点,且会还原到它原来的大小和位置;
2 窗口会以一个具有焦点的图标来显示;
3 窗口是一个具有焦点的最大化窗口;
4 窗口会被还原到最近使用的大小和位置,而当前活动的窗口仍然保持活动;
6 窗口会以一个图标来显示,而当前活动的窗口仍然保持活动。
RmDir 语句
RmDir 语句的功能是删除一个存在的而且为空的目录或文件夹,它的语法结构如下所示:
Rmdir path
其中参数Path是一个字符串表达式,用来指定要删除的目录或文件夹。如果在参数Path中没有指定驱动器,则Rmdir会在当前驱动器上删除为空的目录或文件夹。
Name语句
Name语句的功能是重新命名一个文件、目录或文件夹,它的语法结构如下:
Name oldpathname As newpathname
其中包括以下两个部分:
oldpathname 为字符串表达式,由它来指定已存在的文件名和位置,在其中包含目录或文件夹以及驱动器。
newpathname也是字符串表达,它指定新的文件名和位置,同样要包含目录或文件夹以及驱动器。
|
|
|
|
|