|
我对表单上传的理解(可能有误): <form action="" method="post" enctype="multipart/form-data"> 最大上传2G. 通过 http 协议上传文件(rfc1867协议概述,jsp 应用举例,客户端发送内容构造) 服务器接收到上传的流,自己其实是不作任何处理的,那个request还是原装的,谁来处理这个request呢,一般采用第三方的工具,这里以commons fileupload为例. DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(4096);// 设置缓冲,这个值决定了是fileinputstream还是bytearrayinputstream factory.setRepository(new File("d:\\temp"));//设置临时存放目录,默认是new File(System.getProperty("java.io.tmpdir")) ServletFileUpload sfu = new ServletFileUpload(factory); sfu.setSizeMax(100*1024*1024);//100M List items = sfu.parseRequest(request);//传入的这个request还是原装的 见上面的代码,commons fielupload通过ServletFileUpload类的 parseRequest(request)方法处理这个原始流。而ServletFileUpload 又会调用其爷爷类FileUploadBase的parseRequest(request)方法,然后又会调return parseRequest(new ServletRequestContext(request)),代码如下
try { FileItemIterator iter = getItemIterator(ctx); List items = new ArrayList(); FileItemFactory fac = getFileItemFactory(); if (fac == null) { throw new NullPointerException( "No FileItemFactory has been set."); } while (iter.hasNext()) { FileItemStream item = iter.next(); FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(), item.isFormField(), item.getName()); try { Streams.copy(item.openStream(), fileItem.getOutputStream(), true); } catch (FileUploadIOException e) { throw (FileUploadException) e.getCause(); } catch (IOException e) { throw new IOFileUploadException(//报错经常在这里 "Processing of " + MULTIPART_FORM_DATA + " request failed. " + e.getMessage(), e); } if (fileItem instanceof FileItemHeadersSupport) { final FileItemHeaders fih = item.getHeaders(); ((FileItemHeadersSupport) fileItem).setHeaders(fih); } items.add(fileItem); } return items; } catch (FileUploadIOException e) { throw (FileUploadException) e.getCause(); } catch (IOException e) { throw new FileUploadException(e.getMessage(), e); }
这里注意,上传的<input type=file>标记一定要有name,如果没有,commons fielupload不作处理。 commons fielupload会把上传的文件以流的方式写入到temp文件夹,临时文件夹可以自己设定,如果不手动设置,则是Servlet容器为web应用分配的临时目录,tomcat可能就是 %TOMCAT_HOME%\temp,我用weblogic时,是 C:\DOCUME~1\yourname\LOCALS~1\Temp\。这些临时文件以"upload"开头,格式是.tmp,例如 "upload_47fdc3_11c9eb678b0__8000_00000043.tmp" 在上传过程中commons fielupload才知道上传的文件的大小,如果你定义允许的最大附件为100M,然后你上传一个200M的文件,那么只有实际传输了100M以后,commons fielupload才知道超过了,然后抛出一个异常( org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException)。 commons fielupload处理完了以后(处理过程全在 parseRequest(request)方法里),返回一个List,里面的每一项已被封装为FileItem,你通过 fileItem.isFormField()判断出是普通的表单属性呢,还是一个文件,如果是文件,你可以从 fileItem.getInputStream()获得输入流,这个输入流其实是一个FileInputStream.当然,如果文件很小,则是ByteArrayInputStream.那么如何区分?这两者的区别是由 factory.setSizeThreshold(4096)确定的。大于4K,为FileInputStream,小于4K为ByteArrayInputStream 这样就可以解释struts用ActionForm的方式处理上传附件的一些问题了,struts接收到enctype="multipart/form-data"的post请求后,会看那个对应的action有没有配置actionform,如果配置了,就会作一些处理,所以你在action里得到的request已经不是一个普通的request了,而是一个被封装过的request。如果想得到原始的request,就不要struts-config.xml里给action类配置actionform tempDir指定的目录中可能会随着时间推移出现很多后缀为"tmp"的垃圾文件,commons-fileupload1.2提供了一个不错的解决方法,就是把下面的代码加入到web.xml中即可。 <listener> <listener-class> org.apache.commons.fileupload.servlet.FileCleanerCleanup </listener-class> </listener> 来源: http://fratemity1314.spaces.live.com/Blog/cns!E3BCC13A1E72BB4F!222.entryQ:I'm using FileUpload in an Action, but it's not working. Why?
A:Struts
recognises multipart requests, and parses them automatically,
presenting the request parameters to your code in the same manner as if
they were regular request parameters. Since struts has already processed the request, and made it available in your form
bean, the input stream is no longer available for parsing, so
attempting to do so with FileUpload will fail.
Q:But I need to parse the request myself. How can I do that?
A:Struts
parses multipart a request as a part of the process of populating your
form bean from that request. If, for some reason, you need to have full
control over the multipart parsing, you can do so by configuring your
action mapping without an associated form bean. (A better way of doing
this, however, is to replace the default multipart handler with your
own. See the struts documentation for details.) 1,直接用commons fileupload而不用struts的ActionForm时,表单里的属性值不能用request.getParameter()获取了,而url里的queryString可以。 2, 获取form里的属性值的代码 String formname = fi.getFieldName();// 获取form中的名字 String formcontent = fi.getString(); if (formname.equals("id")) { id = formcontent; } else if (formname.equals("title")) { title = formcontent; } else if (formname.equals("memo")) { memo = formcontent; } 3, 表单里的file控件的name不能为空。 4,上传大文件(190多M)时报异常 org.apache.commons.fileupload.FileUploadException: Processing of
multipart/form-data request failed. EOF after reading only:
"3567789 " of: "203323339 " promised bytes, out of which at least: "0 " were already buffered http://forums.bea.com/thread.jspa?threadID=200033356 http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=121&threadID=20060&start=0&tstart=0 http://thisisxy.blogcn.com/diary,204014352.shtml http://www.80diy.com/home/20050527/17/4040711.html 5, org.apache.commons.fileupload.FileUploadException: Processing of multipart/form-data request failed. Read timed out HTTP活动超时限制的时间太短 HTTP Keep-Alive Timeout.
6,InputStream is =formFile.getInputStream() ; //formFile是org.apache.struts.upload.FormFile 上传的文件小时这个输入流是java.io.ByteArrayInputStream,上传比较大的文件时这个输入流是FileInputStream
7,设置表单里的上传路径为只读 <input type=file id="uploadfile" name="uploadfile" style="display: none;"> <input type=text id=tempfile readonly="true"> <input type=button onClick="uploadfile.click();tempfile.value=uploadfile.value;" value="浏览..">
10, http://eastpoint.javaeye.com/blog/99084 http://topic.csdn.net/u/20080131/13/649c57c7-204e-4bb6-9b09-49cca39f00b8.html http://blog.niwota.com/nb/chenchuang?cat_self_id=291075
1,hipergate 又是西班牙出的,为什么西班牙和葡萄牙两牙都喜欢ERP开源呢? 口气很大,看他说的:什么使hipergate如此独一无二?
It is completely free.
It is the only Open Source application with such a wide functional coverage.
Runs on multiple databases and operating systems
Has a unitary conceptual design and implementation.
Is adequate for being used by Application Service Providers.
Supports multiple languages.
Has a professional services support network.
Is well documented.
hipergate所有的实体类都继承自com.knowgate.dataobjs.DBPersist,好像增删改查的代码都不用自己写了,值得研究。 2,vtiger 就更狂妄了,竟然声称是"The best OpenSource CRM on the planet"! 看过其demo,做得还真不赖,模块比较齐全,界面上很多细节处理得很精致,比较人性化,可惜不是java做的。为什么很多java做的web系统听起来牛鼻子哄哄的,使用起来却惨不忍睹?真想把vtiger的老虎皮剥下来用在我的java上。 3,oaj ,貌似不错,可惜已经两年多没更新了。 OAJ (OpenAccountingJ) is a free, open-source, web-based Accounting/ERP system. Built in Java using the best-of-breed Open Source components, such as Spring Framework, Acegi Security, Hibernate, Jasper Reports, XDoclet it offers a solid, customizable, secure platform for your business.
4,Openbravo 和Compiere这两个就不说了。
5,ADempiere
6,cream
用turbine开发的,持久用的torque。大概看了下,确实有他的一套。 7,icehrm 用了extgwt,不感兴趣。不过好像也用了torque
8,预算软件 Adaptive Planning Express 可惜太大了,而且好像用的swing http://sourceforge.net/projects/adaptiveplan/files/
1,云网OA 用户名zhao,密码123 http://218.206.128.201:8888/oademo/?
2,极品OA http://www.ijipin.com/VOA/login.jsp源码|打包|软件|黑防|模板|调试|教材|网站:[-w'?+w4l*L#F;`*Q
测试用户:test1到test5 bbs.jzpu.com2k,w/k!u&?'L5f*e0u 密码全部为空 3,http://www.tinzoom.com/phr01.htm#b03 4,orangehrm php开源hr http://sourceforge.net/projects/orangehrm
select fk_col.constraint_name, fk_col.table_name, fk_col.column_name from user_constraints pk, user_constraints fk, user_cons_columns fk_col where pk.table_name = 'TEST' and pk.constraint_type = 'P' and fk.r_constraint_name = pk.constraint_name and fk_col.constraint_name = fk.constraint_name order by 2, 3;
select a.table_name 外键表名,a.column_name 外键列名,b.table_name 主键表名,b.column_name 主键列名 from
(select a.constraint_name,b.table_name,b.column_name,a.r_constraint_name from user_constraints a, user_cons_columns b WHERE a.constraint_type='R' and a.constraint_name=b.constraint_name
) a,
(select distinct a.r_constraint_name,b.table_name,b.column_name from user_constraints a, user_cons_columns b WHERE a.constraint_type='R' and
a.r_constraint_name=b.constraint_name)
b where a.r_constraint_name=b.r_constraint_name
extremetable导出excel,弹出一个下载窗口,这时不点下载而点取消,则报下面的异常: ClientAbortException Caused by: java.net.SocketException: Connection reset by peer: socket write error
查了下TOMCAT的文档,解释如下: Wrap an IOException identifying it as being caused by an abort of a request by a remote client. 在BAIDU和GOOGLE上找了下原因,大概归结为: ClientAbortException: java.net.SocketException: Connection reset by peer: socket write error的原因是由于处理http连接时,正在输出内容时,用户关闭了IE,会出现一个"ClientAbortException",属于I/O处理中出现的一个异常,应用服务器应该会捕捉。 Connection reset by peer的原因: 经常出现的Connection reset by peer: 原因可能是多方面的,不过更常见的原因是: ①:服务器的并发连接数超过了其承载量,服务器会将其中一些连接Down掉; ②:客户关掉了浏览器,而服务器还在给客户端发送数据; ③:浏览器端按了Stop 很多人都说是客户端造成的,没有办法控制,是个比较郁闷的问题。
但是,我担心的是:虽然前台没有任何出错的迹象,但是后台会记录这个异常,日志也会疯狂爆满,时间长了,肯定会DOWN掉的,还没找到好的解决办法 resin有一个参数ignore-client-disconnect tomcat似乎没有
经常出现的Connection reset by peer:
原因可能是多方面的,不过更常见的原因是:①:服务器的并发连接数超过了其承载量,服务器会将其中一些连接Down掉;②:客户关掉了浏览器,而服务器还
在给客户端发送数据;③:浏览器端按了Stop
[10054] Connection reset by peer Connection reset by peer is a
tough one because it can be caused by so many things. In all cases, the
server determines that the socket is no longer good and closes it from
its side. Read Error Scenario: Mary couldn't make out what Joe
was saying anymore, so she hung up rather than lose his messages
(data). A read error occurs when a server cannot successfully read
from a user's client. Servers gather information from the client by
text, setup, and other items.When the server receives an error when
reading from a client, it then disconnects the user, resulting in a read
error quit message. Write Error Scenario: Mary was trying to
talk to Joe but didn't think she was getting through, so she hung
rather than lose his messages (data). A write error occurs when a
server cannot successfully write to a user's client. When the server
receives information, it usually responds with information of its own.
When the server receives an error when writing to a client, it then
disconnects the user, resulting in a write error quit message similar to
the read error format. Ping Timeout Error Scenario: Mary,
having been raised in a household with too many kids and always craving
attention, keeps asking to make sure that Joe is still on the line and
listening. If he doesn't reply fast enough to suit her, she hangs up.
Servers automatically ping users at a preset time. The reason for this
is to ensure the client is still connected to the server. When you see
"PING? PONG!" results in your status window, it means the server has
pinged your client, and it has responded back with a pong to ensure the
server that you are still connected. When this does not happen and you
disconnect without the server's knowledge, the server will automatically
disconnect the user when it does not receive a response, resulting in a
ping timeout. Ping timeouts occur to EVERYONE. Broken pipe Error
Scenario: Mary had picked up a sticky note with a message she needed to
relay to Joe, but somehow between her hand and her mouth, the message
got misplaced. Mary was trying to talk to Joe but didn't think she was
getting through, so she hung up rather than lose his messages (data).
A broken pipe error occurs when the server knows it has a message but
can't seem to use its internal data link to get the data out to the
socket. Miscellaneous Scenario: Lots of other reasons;
perhaps the operator broke in and gave Mary a message that made her
doubt the validity of the call so she hung up
最近写代码时发现用BufferedReader把InputStream包装后,使用BufferedReader读取后,然后再使用 InputStream读取时总是发现问题,好像总是丢数据,由于我在流里面同时混了二进制数据与字符串,所以很不好调度,然后专门写了下面的代码去测试发现原来是. BufferedReader读取数据时会把数据从流里面取出一部分缓存,如果你再转向去用InputStream去读取的话,BufferedReader缓存里面的数据InputStream是读取不到的 . package bytearray; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; public class TestByteArray { public byte[] generateByte() { // 构造一个测试流,这样就不用从文件里面读取了,在这个流里面使用了大量的回车换行("\r\n"),这样方便过会的测试 // 过会,我会通过把字符串转换成byte数组,然后通过ByteArrayInputStream来构造一个数据流 return "a\r\nbc\r\ndef\r\nghi\r\nj\r\nklmn\r\nopqr\r\ns\r\ntuvwxyz " .getBytes(); } public static void main(String[] args) throws IOException { // TODO Auto-generated method stub TestByteArray self = new TestByteArray(); byte[] be = self.generateByte(); InputStream in = new ByteArrayInputStream(be); BufferedReader bufferReader = new BufferedReader(new InputStreamReader( in)); // 使用DataInputStream而不直接使用Inputstream是因为这样方便,因为他提供了读取行 // 不过听说他读取行时把字节转变为字符时会有问题,所以不推荐使用,不过我们在这只做测试就没关系了 DataInputStream dataInputStream = new DataInputStream(in); // 先读取流里面的一行数据 System.out.println("bufferReader=" + bufferReader.readLine()); // 回过头来使用dataInputStream读取数据,会发现什么也读取不到 System.out.println("dataInputStream=" + dataInputStream.readLine()); // 回过头来使用inputstream读取数据,会发现什么也读取不到 System.out.println("in=" + in.read()); // InputStream读取不到数据,然后再使用原来的BufferedReader来读取数据,发现是接着原来读取的. System.out.println("bufferReader=" + bufferReader.readLine()); //我们上面的字符串比较小,我想如果字符串,大到缓存装不下的时候,使用inputstream回头去读取数据,肯定是能读取到的 //这个我就不测试了 } } 转自 http://itspy.spaces.live.com/blog/cns!87AF3B24336DF461!180.entry
|