request和response及文件的上传下载
一般在服务器用request.getparameter(“”)获取服务器端form表单传递的数据,在服务器端则通过request.setattribute(“”);来设置将传递的参数,再有客户端通过request.getattribute(“”);来获取服务器传递过来参数。
注意点如下:form表单有get和post两种方式,GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。而POST把提交的数据则放置在是HTTP包的包体中。
1.get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。在传递含有中文时应尽量用post而不是get方式,防止出现乱码。在表单内有<imput type=”file”>属性时,需要设置表单的enctype,且用post方式。如下:
<form action="" method="post" enctype="multipart/form-data">
<input name="fileInPath" type="hidden" value="">
<input name="fileName" type="hidden" value="">
<input id="FI" name="file_id" type="hidden" value="<%=file_id%>"/>
</form>
表单中enctype="multipart/form-data"的意思,是设置表单的MIME编码。默认情况,这个编码格式是application/x-www-form-urlencoded,不能用于文件上传;只有使用了multipart/form-data,才能完整的传递文件数据,进行下面的操作.
enctype="multipart/form-data"是上传二进制数据; form里面的input的值以2进制的方式传过去。因而此时将无法用request.getparameter(“”)获取该表单内的非表单属性(如fileName值)。
解决办法如下
1.在action后添加需要传递的参数值(”&userName=’ss’&fileInPath=’aa’”);考虑到值会动态变化,可在javaScript中操作;
2.分析包体内的数据,将非文件类的参数分离出。核心内容如下:
需要的包有
if(ServletFileUpload.isMultipartContent(request)){
DiskFileItemFactory dff = new DiskFileItemFactory();//创建该对象
ff.setRepository(tmpDir);//指定上传文件的临时目录
dff.setSizeThreshold(1024000);//指定在内存中缓存数据大小,单位为byte
ServletFileUpload sfu = new ServletFileUpload(dff);//创建该对象
sfu.setFileSizeMax(5000000);//指定单个上传文件的最大尺寸
sfu.setSizeMax(10000000);//指定一次上传多个文件的总尺寸
ServletFileUpload sfu1 = new ServletFileUpload(dff);//创建该对象
sfu1.setFileSizeMax(5000000);//指定单个上传文件的最大尺寸
sfu1.setSizeMax(10000000);//指定一次上传多个文件的总尺寸
List<?> items = sfu1.parseRequest(request);
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
//如果是普通表单字段
String name = item.getFieldName();
if(name.equals("fileInPath")){
fileInPath=item.getString();
}else {}
else{//处理表单字段
String fieldName = item.getFieldName(); //文件的idname
String fileName2 = item.getName(); //文件的namefileName2=fileName2.substring(fileName2.lastIndexOf("\\")+1);
System.out.println(fileName2.length());
ile_id=fileName2.substring(0, fileName2.length()-17);
// String contentType = item.getContentType();
// boolean isInMemory = item.isInMemory();
// long sizeInBytes = item.getSize();
// Process a file upload
InputStream uploadedStream = item.getInputStream();
InputStreamReader read = new InputStreamReader(uploadedStream);
...
}
文件的下载如下:
<%
//关于文件下载时采用文件流输出的方式处理:
//加上response.reset(),并且所有的%>后面不要换行,包括最后一个;
response.reset();//可以加也可以不加
response.setContentType("application/x-download");
//application.getRealPath("/main/mvplayer/CapSetup.msi");获取的物理路径
String filedownload = request.getParameter("filePath")+".zip";//文件完整路径
String filedisplay = request.getParameter("file_id")+".zip";//默认文件名
filedisplay = URLEncoder.encode(filedisplay,"UTF-8");
//response.setHeader("Content-disposition","attachment; filename="+URLEncoder.encode(filedisplay, "UTF-8"));
//response.setHeader("Content-disposition","attachment; filename="+new String(filedisplay.getBytes("UTF-8"),"iso8859-1"));
response.addHeader("Content-Disposition","attachment;filename=" + filedisplay);
java.io.OutputStream outp = null;
java.io.FileInputStream in = null;
try
{
outp = response.getOutputStream();
in = new FileInputStream(new File(filedownload));
byte[] b = new byte[1024];
int i = 0;
while((i = in.read(b)) > 0)
{
outp.write(b, 0, i);
}
//
outp.flush();
//要加以下两句话,否则会报错
//java.lang.IllegalStateException: getOutputStream() has already been called for //this response
out.clear();
out = pageContext.pushBody();
}
catch(Exception e)
{
System.out.println("Error!");
e.printStackTrace();
}
finally
{
if(in != null)
{
in.close();
in = null;
}
//这里不能关闭
//if(outp != null)
//{
//outp.close();
//outp = null;
//}
}
%>
注意事项有:1.见代码内的注释。在servlet中,文件的结束会涉及到对内置对象的处理,调用了response.getwrite()方法,此方法与outp = response.getOutputStream();中getOutputStream方法两者只能存一,解决方法是加下
response.reset();//可以加也可以不加
out.clear();
out = pageContext.pushBody();
三句,但是在如此处理后依旧出现getOutputStream() has already been called for 错误,原因发现是由servlet跳转到servlet/jsp出现这样的错误的,处理的方法是downloadServlet跳转到一个中间过度的jsp页面,该页面设定为自动跳转到含有上述代码的jsp页面,解决了上述问题。此外跳转后不知何原因无法自动跳转回来,于是设置form表单的target="_blank",表示为点击按钮后另开一新的窗口显示,该属性默认值target="_self"。今后可以适当使用该属性,使数据流图变得更简单。
关于文件压缩
文件压缩的函数如下:
Strs表示所压缩的多个文件的绝对路径的字符串值;zipname表示压缩文件的默认名
filePath表示压缩后文件的所在目录
private static void writeZip(String[] strs,String zipname,String filePath) throws IOException {
String[] files = strs;
OutputStream os = new BufferedOutputStream( new FileOutputStream( filePath+".zip" ) );
ZipOutputStream zos = new ZipOutputStream( os );
byte[] buf = new byte[8192];
int len;
for (int i=0;i<files.length;i++) {
File file = new File( files[i] );
if ( !file.isFile() ) continue;
ZipEntry ze = new ZipEntry( file.getName() );
zos.putNextEntry( ze );
BufferedInputStream bis = new BufferedInputStream( new FileInputStream( file ) );
while ( ( len = bis.read( buf ) ) > 0 ) {
zos.write( buf, 0, len );
}
zos.closeEntry();
bis.close();//少此条语句文件将无法删除
}
//zos.setEncoding("GBK");
zos.closeEntry();
zos.close();
for(int i=0;i<files.length;i++){
File file= new File(files[i]);
if (file.isFile() && file.exists()) {
file.delete();//文件流若没有关闭将无法删除
}
}
}
读取properties属性文件的方法
Properties pro = new Properties();
InputStream in = this.getClass().getClassLoader().getResourceAsStream("a.properties");
pro.load(in);
String path=pro.getProperty(properName);
//properName为文件内属性的变量//名,若无则放回值为null
多线程处理问题
对于与主线程无关的问题,如日志文件等,可以启动另一线程处理,提高主线程的运行速度
Jdbc操作的问题
插入大量数据时考虑使用批处理,oracle默认是自动提交的,设置
private Connection conn=
DriverManager.getConnection(url,username,password);
conn.setAutoCommit(flase);可关闭自动提交,
通过语句private PreparedStatement pstmt=null;
this.pstmt = this.conn.prepareStatement(sql);
this.pstmt.addBatch();//增加一条批处理语句
最后调用this.pstmt.executeBatch();//处理语句
this.conn.commit();//提交更改到数据库
可大幅度提升插入语句的效率,在实践过程中出现只提交了最后一条语句,没有全部更改,是PreparedStatement pstmt=null;可能这个变量在处理的时候被引用为新的对象了,由于处理的数据不大,找到大致原因,未做修改,提供参考。
关于转发与重定向的小段文章
getRequestDispatcher()与sendRedirect()的区别
1.request.getRequestDispatcher()是请求转发,前后页面共享一个request ;
response.sendRedirect()是重新定向,前后页面不是一个request。request.getRequestDispather();返回的是一个RequestDispatcher对象。2.RequestDispatcher.forward()是在服务器端运行;
HttpServletResponse.sendRedirect()是通过向客户浏览器发送命令来完成.
所以RequestDispatcher.forward()对于浏览器来说是“透明的”;
而HttpServletResponse.sendRedirect()则不是。3.ServletContext.getRequestDispatcher(String url)中的url只能使用绝对路径; 而ServletRequest.getRequestDispatcher(String url)中的url可以使用相对路径。因为ServletRequest具有相对路径的概念;而ServletContext对象无次概念。RequestDispatcher对象从客户端获取请求request,并把它们传递给服务器上的servlet,html或jsp。它有两个方法:
3.1 void forward(ServletRequest request,ServletResponse response)
用来传递request的,可以一个Servlet接收request请求,另一个Servlet用这个request请求来产生response。request传递的请求,response是客户端返回的信息。forward要在response到达客户端之前调用,也就是 before response body output has been flushed。如果不是的话,它会报出异常。
3 void include(ServletRequest request,ServletResponse response)
用来记录保留request和response,以后不能再修改response里表示状态的信息。如果需要把请求转移到另外一个Web App中的某个地址,可以按下面的做法:
1. 获得另外一个Web App的ServletConext对象(currentServletContext.getContext(uripath)).
2. 调用ServletContext.getRequestDispatcher(String url)方法。
关于字符串
如这个字符串“D:\ss\ss.txr”,在java中定义这样的字符串是不合法的,因为\是转移字符,有人会说可以写成“D:\\ss\\ss.txt”但是有时我们得到的却就是这样一个字符串,就不如<inpute type=”file” value=””>选择文件后,该值即为文件的路径,并不给你机会处理该字符串(ps:该value为客户端的文件路径,文件上传时获取后给服务器也没有多大意义,而且得到file的路径有其他相关方法去处理,此处为举例该字符串的特殊性),在该问题中,若需要处理该字符串,可以在强大的JavaScript内处理,处理方法为:document.getElementById("file1").value.replace(/\\/g, "\\\\");
括号内是正则表达式g表示全部替换,相关知识请自行查阅资料。此外还有一点补充:在Windows下的路径分隔符和Linux下的路径分隔符是不一样的,当直接使用绝对路径时,跨平台会暴出“No such file or diretory”的异常。
比如说要在temp目录下建立一个test.txt文件,在Windows下应该这么写:
File file1 = new File ("C:\tmp\test.txt");
在Linux下则是这样的:
File file2 = new File ("/tmp/test.txt");
如果要考虑跨平台,则最好是这么写:
File myFile = new File("C:" + File.separator + "tmp" + File.separator, "test.txt");
注意使用:File.separator