中文文件名的文件在下载的时候有文件编码和文件名编码两个问题,最后被证明的是文件编码要采用iso-8859-1,而文件名编码要采用utf-8;
代码如下:
String filename = (String) session.getAttribute("filename");
//String dst_fname = URLEncoder.encode(filename,"utf-8");//这样被证明是不行的
String dst_fname=ConvertCode.toUtf8String(filename);
response.setContentType("application/octet-stream; charset=iso-8859-1");
response.setHeader("Content-disposition", "attachment; filename=\"" + dst_fname + "\"");
我用oracle的BLOB存储附件文件,并保存了附件名称。我用一个servlet和一个jsp联合起来来处理附件文件的下载,servlet负责将附件文件从数据库中去出来存储到本地文件系统,jsp负责将文件从本地文件系统下载到浏览器。
期间我尝试了网上能够找到的多种方法,问题主要集中在下载那里.下面我列举一下我所遇到的下载问题:
- 能够下载执行下载以后的第一个附件下载,后边无法正确下载,只能下载到空文件或者只有一行文本。
- 能够正确下载,但是在文件首行添加了额外的一行。
- 只能下载到空文件。
我采用的方法:
- 采用从response中获得流直接输出。
ServletOutputStream sos = response.getOutputStream();
InputStream pi = resultset.getBinaryStream("DATABLOB");//字段名datablob
byte[] blobbytes = new byte[0x100000]; //照片大小
int bytesRead = 0;
while ((bytesRead = pi.read(blobbytes)) != -1) {
sos.write(blobbytes, 0, bytesRead);
//System.out.println(""+ (bytecount++));
}
pi.close();
sos.flush();
- 采用本地文件流
response.setContentType("application/octet-stream; charset=iso-8859-1");
response.setHeader("Content-disposition", "attachment; filename=\"" + dst_fname + "\"");
FileInputStream fis = null;
int byteRead;
out.clear();
try{
fis=new FileInputStream(filepath);
while ((byteRead = fis.read()) != -1) {
out.write(byteRead);
}
out.flush();
- 采用网络URL流
String src_fname = "http://www.javaworld.com.tw/jute/images_zh_TW/bluetitle.gif";
我的具体代码如下:
String dst_fname = URLEncoder.encode("bluetitle.gif", "Big5");
response.setContentType("application/octet-stream; charset=iso-8859-1");
response.setHeader("Content-disposition", "attachment; filename=\"" + dst_fname + "\"");
URL url = new URL(src_fname);
InputStream is = url.openStream();
DataInputStream fis = null;
int byteRead;
try{
fis = new DataInputStream(is);
while ((byteRead = fis.read()) != -1) {
out.write(byteRead);
}
out.flush();
}catch(Exception e){
out.clearBuffer();
response.setContentType("text/html; charset=big5");
response.setHeader("Content-disposition", "inline");
out.println("<HTML><BODY><P>");
out.println(e.toString());
out.println("</P></BODY></HTML>");
}
if(fis != null){
fis.close();
}
return; // 避免下面多按了 Enter 鍵而輸出多餘的換行字元.
import org.apache.log4j.Logger;
import java.io.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 把指定完整路径的文件存到tzfb的fj字段,时间关系没有设计成可重用类,只能为该表服务
*
* @author yyh 16:31:26
*
* FileImport
*/
public class FileImport {
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(FileImport.class);
private Connection conn;
private Statement querryStm;
private Statement updateStm;
private String theLocalFile;
private String tzid=null;
private String dwdm=null;
public FileImport() throws SQLException
{
getConnection();
}
private int getConnection(){
//获取数据库连接
IDBOperate idbo=new IDBOperate();
DBOperate dbo=idbo.getDBOperate();
this.conn = dbo.getConnection();
try{
this.conn.setAutoCommit(false);
}catch(Exception e){
logger.warn(dwdm+"-无法连接数据库服务器,附件文件导入失败!");
e.printStackTrace();
}
if(conn==null){
return -1;
}
return 0;
}
/**
* 把指定完整路径的文件存到tzfb的fj字段,时间关系没有设计成可重用类,只能为该表服务
*
* Method ‘importFile’
* @param theLocalFolder
* @param tzid
* @param dwdm
* @return
* 0:正常导入
* -1:附件文件导入数据库异常
* -2:附件文件导入数据库时IO异常
* -3:给定id的通知并不存在
* -4:给定附件文件路径不是一个文件
* -5:无法获得数据库连接
* -6:文件导入时无法建立Statement
*/
public int importFile(String theLocalFile,String tzid,String dwdm){
//init
this.theLocalFile = theLocalFile;
this.tzid=tzid;
this.dwdm=dwdm;
if(null==conn){
if(0!=getConnection())
return -5;
}
int result=0;
try{
this.querryStm = this.conn.createStatement();
this.updateStm = this.conn.createStatement();
}catch(Exception e){
logger.warn(dwdm+"-文件导入时无法建立Statement,附件文件导入失败");
e.printStackTrace();
return -6;
}
result=doImport( this.theLocalFile);
if (this.conn != null){
try{
this.querryStm.close();
this.updateStm.close();
this.conn.close();
}catch(Exception e){
System.out.println("数据库连接释放失败");
e.printStackTrace();
}
}
return result;//正常导入
}
/**
* 根据文件路径将文件导入到前边指定tzid的通知数据FJ中
*
* Method ‘goThroughFileTree’
* @param FolderName
* @return
* 0:正常导入
* -1:附件文件导入数据库异常
* -2:附件文件导入数据库时IO异常
* -3:给定id的通知并不存在
* -4:给定附件文件路径不是一个文件
*/
private int doImport(String FolderName)//遍历整个文件树
{
int result=0;
File currentFile = new File(FolderName);
if(currentFile.isFile())
{
try
{
result=doImport(currentFile);
}
catch (SQLException e)
{
logger.warn(dwdm+"附件文件导入数据库异常,附件文件导入失败");
e.printStackTrace();
return -1;
}
catch (IOException e)
{
logger.warn(dwdm+"-附件文件导入数据库时IO异常,附件文件导入失败");
e.printStackTrace();
return -2;
}
}else{
logger.warn(dwdm+"-给定附件文件路径不是一个文件,附件文件导入失败");
return -4;
}
if(-1==result){
return -3;
}
//如果上述错误都没有发生就返回正确值0
return 0;
}
/**
* 将附件文件装载进数据库文件
*
* Method ‘doImport’
* @param file
* @return
* 0:文件正常导入数据库
* -1:给定id的通知并不存在
* @throws SQLException
* @throws IOException
*/
private int doImport(File file) throws SQLException, IOException
{
String queryString;
System.out.println("路径—"+file.getPath() + " 文件名—"+file.getName());
FileInputStream fileIn = new FileInputStream(file);
queryString ="SELECT DLID FROM tzFB WHERE id ="+tzid;
System.out.println(queryString);
ResultSet theRS = this.querryStm.executeQuery(queryString);
if(theRS.next())//假设该id的通知一定存在
{
queryString ="SELECT FJ FROM TZFB WHERE id ="+tzid+" FOR UPDATE";
theRS = this.querryStm.executeQuery(queryString);
System.out.println(queryString);
if(theRS.next())
{
oracle.sql.BLOB blob = (oracle.sql.BLOB)theRS.getBlob("FJ");
BufferedOutputStream out = new BufferedOutputStream(blob.getBinaryOutputStream());
BufferedInputStream in = new BufferedInputStream(fileIn);
int c;
while ((c=in.read())!=-1)
{
out.write(c);
}
in.close();
out.close();
this.conn.commit();
}
return 0;
}
else{//如果没有这个id的通知,那么则报告错误
logger.warn(dwdm+"-通知id错误,数据库中没有该id的通知,附件文件导入失败");
return -1;
}
}
public static void main(String arg[])
{
try
{
FileImport thePI = new FileImport();
thePI.importFile("C:\\tomcat5.5.8\\webapps\\gsmis\\main_images\\button\\000000000.JPG","12","1101′");
}
catch (SQLException e)
{
System.out.print("导入文件发生错误");
e.printStackTrace();
}
}
}
public class ExportAttachmentFile extends LEV1Servlet {
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(ExportAttachmentFile.class);
private String id=null;
/**
* 1.查找当前用户是否是指定id的通知接受者或者发出者,如果不是返回到错误页面
* 2.下载附件文件
*/
public void service(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
String cxp=req.getContextPath();
HttpSession session=req.getSession(true);
String dwdm=(String)session.getAttribute("userID");
String fileSeparator = System.getProperty("file.separator");
ServletContext context=session.getServletContext();
String dbpath=context.getInitParameter("systemPath");
String userPath=dbpath+fileSeparator+dwdm; //like ‘/opt/tomcat/webapps/wb/db/1101′
// String host = "http://" + req.getServerName() + ":" + req.getServerPort() + "/" + req.getContextPath();
String host = "http://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath();
String download_url = host+"/db/"+dwdm+"/";
//验证dwdm
if(null==dwdm){
logger.warn("xxxxx-未登录时试图下载下载通知附件文件,ip:"+req.getRemoteAddr());
req.setAttribute("message", "无权下载通知附件文件,请登录系统!");
forward(req, res, "/pub/failure.jsp");
return;
}
//验证tzid
id=req.getParameter("tzid");
if(null==id){
logger.warn(dwdm+"-下载在附件时未指定通知id!");
req.setAttribute("nextPage", cxp+"/index.jsp");
req.setAttribute("message", "下载错误,请重试或联系客服人员!");
forward(req, res, "/pub/failure.jsp");
return;
}
//验证用户是否可以下载
String sql_tzfb="select dlid from tzfb where id="+id;
String sql_tzfbdx="select count(*) from tzfbdx where tzid="+id+" and dwid=’"+dwdm+"’";
IDBOperate idbo=new IDBOperate();
DBOperate dbo=idbo.getDBOperate();
int count=dbo.queryTotalRowCount(sql_tzfbdx);
if(0==count){//如果不是通知的接受对象
ResultSet rs=null;
try{
rs=dbo.getResultSet(sql_tzfb);
if(rs.next()){//如果存在该id的通知
String dlid=rs.getString("dlid");
if(!dlid.equals(dwdm)){//如果还不是通知的发布对象
logger.warn(dwdm+"-无权下载该通知附件!tzid="+id);
req.setAttribute("nextPage", cxp+"/form/index.jsp");
req.setAttribute("message", "无权下载该通知附件,下载错误,请重试或联系客服人员!");
forward(req, res, "/pub/failure.jsp");
return;
}
}else{//如果不存在该id的通知
logger.warn(dwdm+"-不存在id="+id+"的通知!");
req.setAttribute("nextPage", cxp+"/form/index.jsp");
req.setAttribute("message", "不存在的通知,下载错误,请重试或联系客服人员!");
forward(req, res, "/pub/failure.jsp");
return;
}
}catch(Exception e){
logger.warn(dwdm+"-验证用户下载通知附件权限时候数据库异常,下载失败!");
e.printStackTrace();
return;
}
}
//通过验证
String QerrySting="select * from tzfb where id="+id;
try{
Connection conn = dbo.getConnection();
Statement stat = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
ResultSet rs = stat.executeQuery(QerrySting);
if(rs.next()){
String filename=rs.getString("FJWJMC");;
download_url=download_url+filename;//下载地址
File file = new File(userPath + fileSeparator + filename);//下载到下载附件的该用户的本地路径上
OutputStream fout = new FileOutputStream(file);
//ServletOutputStream sos = res.getOutputStream();
oracle.sql.BLOB blob=(oracle.sql.BLOB)((OracleResultSet)rs).getBLOB("FJ");
InputStream pi = rs.getBinaryStream("FJ");//字段名FJ
//InputStream pii=blob.getBinaryStream();
int blobsize = (int)blob.length();//?????这里可能将来不用
System.out.println("———–blobsize———–"+blobsize);
byte[] blobbytes = new byte[blobsize]; //照片大小0×100000
int bytesRead = 0;
while ((bytesRead = pi.read(blobbytes)) != -1)
{
//sos.write(blobbytes, 0, bytesRead);
fout.write(blobbytes, 0, bytesRead);
}
pi.close();
//sos.flush();
fout.flush();
conn.close();
System.out.println("download_url–"+download_url);
session.setAttribute("filename", filename);
forward(req,res,"/com/downloadAttachmentFile.jsp");
//res.sendRedirect(download_url);
}
}catch(Exception e){
logger.warn(dwdm+"-通知附件下载异常");
req.setAttribute("nextPage", cxp+"/form/index.jsp");
req.setAttribute("message", "下载异常,请重试或联系客服人员!");
forward(req, res, "/pub/failure.jsp");
return;
}
}
}
downloadAttachmentFile.jap:
<%@ page language="java" contentType="text/html; charset=GB2312" pageEncoding="GB2312" import="java.util.*, java.io.*, java.net.*"%>
<%
String filename = (String) session.getAttribute("filename");
String dst_fname = URLEncoder.encode(filename, "GB2312");
String dwdm=(String)session.getAttribute("userID");
ServletContext context=session.getServletContext();
String dbpath=context.getInitParameter("systemPath");
String fileSeparator = System.getProperty("file.separator");
String filepath=dbpath+fileSeparator+dwdm+fileSeparator+filename;
response.setContentType("application/octet-stream; charset=iso-8859-1");
response.setHeader("Content-disposition", "attachment; filename=\"" + dst_fname + "\"");
FileInputStream fis = null;
int byteRead;
out.clear();
try{
fis=new FileInputStream(filepath);
while ((byteRead = fis.read()) != -1) {
out.write(byteRead);
}
out.flush();
}catch(Exception e){
out.clearBuffer();
response.setContentType("text/html; charset=GB2312");
response.setHeader("Content-disposition", "inline");
out.println("<HTML><BODY><P>");
out.println(e.toString());
out.println("</P></BODY></HTML>");
}
if(fis != null){
fis.close();
}
return; // 避免下面多按了 Enter 键而输出多余的换行字元.
%>
| 使用JSP对文件下载的控制 出自孟宪会大大的blog Web开发人员都有过这样的疑问,如何让一个 |
学习web2.0
ZhanBin整理了一份“ web2.0:正在变化中的互联网”的提纲稿。
非常期待他在中文网志年会上关于web2.0的讲演。
————————
jgovernor认为“Web 2.0 is a
manifesto not a technology”(web2.0是一个宣言而不是一个技术)。
(注:括号部分是我的想法)
他对比了1.0和2.0的差别:
web 1.0 – 内容来自某人
web 2.0 – 内容来自用户
(我不同意这个观点。比如说BBS,内容也来自用户。比如Blog,内容来自个人。所以,用这个反倒使web2.0的概念更加混乱。)
web 1.0 – architecture of consumption/消费架构
web 2.0 – architecture of
partipation/参与架构
(这让我想起很早很早时候的ecircles。挺好的创意和服务,如果能借助现在的社会性理念,一定能受欢迎。也就是说,web新阶段的一个最重要的特征是“社会性”。早先,用户所得到的是针对个人的服务,现在,提供得出了服务之外,更使用户能够展现和发展社会性的关联。对于用户来说,它不再是服务,而是一个社会性的平台,从而,用户生产/消费的信息也有了社会性,变成了分享,变成了自我供养。)
web 1.0 – attempts to create walled gardens/创建一个有围墙的花园
web 2.0 – building
value through open fields/建造一个开放的有价值的田园
(开放,当然不只是内容上的,还需要服务上的,围墙是个很好的比喻。不要试图把用户圈在墙内。)
web 1.0 – download culture/下载的文化
web 2.0 – remix culture/混合的文化
web 1.0 – read only/只读
web 2.0 – read/write /读写
(关于读写,我不是很同意,或许在读写所指上需要进一步的辨识)
————————-
受jgovernor启发,Alex Barnett给出了他认为的web2.0的特质:
web 1.0 – 中心化
web 2.0 – 分布式/去中心化
(其实互联网本身,包括Web,就是非中心化的,分布式特征的。为什么那么多人提到2.0的时候强调去中心化呢。我想这时候的中心化,要比互联网的分布式对应的中心化的概念更细化,更深入些。它不对应宏观,而是指微观的站点或者服务:在web1.0,都是资方,站方,技术管理者统治着,阶层/管理与被管理,等级/次序依旧被维护甚至加强。)
web 1.0 – 个人的
web 2.0 – 社会性的( memetic,这是什么?)
(web 1.0根本就没有人。有么??)
web 1.0 – 内容
web 2.0 – 服务和APIs
(这个恐怕可以归到技术层面)
web 1.0 – 可读的
web 2.0 – 可写的
web 1.0 – 传送的
web 2.0 – 聚合的
web 1.0 – 计划的
web 2.0 – 偶发,自发,自然浮现的
web 1.0 – 静态的
web 2.0 – 联接的,动态的
web 1.0 – 刚性的
web 2.0 – 松散耦合的
(或许Flickr的变迁可以成为一个很好的注脚)
———————–
rashmi在“Web 2.0: Data, Metadata and Interface”中说:“对于Web
2.0应用,数据也许来自一个地方,元数据来自另一个地方,而界面则是来自第三方或者是融合的结果。”
他画了一张图(the move
towards web2.0)。
我觉得箭头有些问题。
web2.0:正在变化中的互联网(提纲稿)
谁在炒作web2.0提到我希望继续深入web2.0,虽然这个名词已经传播得较为广泛了,但是我以为还有很多值得说的,而且web2.0只是一个符号,它表明的是正在变化中的互联网,这些变化相辅相成,彼此联系在一起,才促使互联网出现今天的模样,才让社会性、用户、参与和创作浮到表面成为互联网文化的中坚力量并表征了未来。以下的提纲稿算是为中文网志年会准备的,还有很多思考没有成熟和完善的地方。先贴出来,今晚离京16日回来再展开。
一、web2.0的基础
那些认为web2.0是炒作概念的人忽视了互联网在泡沫后沉潜的这几年中发生的大大小小变化,一些应用和商业模式或者概念在这几年里获得了发展,才导致web2.0的出现。我觉得这包括如下内容:
1、咳,咳,首先是用户习惯的改变和用户需求的改变。这句老套的话却明确在发生,我们从上网“冲浪”到自己“织网”,从寻找信息变成分享信息。web1.0创造了一大批网民,从中诞生了web2.0的网民,而web2.0的潮流将会创造更多的织网者。
2、技术与资金的壁垒正在降低。现在我可以120元包月享受速度还算不错的ADSL网络,而且域名和虚拟空间价格也能接受,最关键毫无技术功底的我也能利用建站程序轻松搭建我的blog,并且css模板和js语句方便我组织我的blog。
3、开源程序+开放内容+开放API。开放的精神正在笼罩着互联网,正是这些敲响了技术集中和内容集中以及网站先发壁垒的丧钟。它不仅提供了开放的精神,而且让资源变得非常容易获得,同时开发提供了参与与分享的可能。开源程序众所周知,而开放内容则以MIT开放课程和wiki百科为典型代表,开放API不仅让web有更好的联结,而且方便用户自己创造。
4、GPL、CC和Copyleft版权。是这样一些版权协议确保了web2.0的可能,促进了知识创造与知识传播。这些协议的功劳比想象的要重要得多,而且web2.0会像web1.0伴随火热的版权讨论一样,在未来产生新的版权讨论热潮。我和很多人一样期盼这类版权协议能够深入改变知识的创新与传播。
5、我觉得微支付也比想象中要对web2.0的意义大。因为电子商务在一开始就基于b2c、b2b和c2c的方式并且应用互联网的技术平台,能够促进个人电子商务的发展。而web2.0将加速个人电子商务尤其是c2c交易,这个过程中,微支付起到了很重要的作用。paypal、支付宝等应该算是典型,同时paypal同时还有力支持了开源软件和其它分享行为。
二、web2.0的精神
这些我觉得基本大家都达成共识了。
1、个人、去中心:这个太具有标志性了,基本上web2.0的绝大部分服务都存在一个个人标识明确的页面。
2、社会化:我认为web2.0基本等于社会性网络
3、开放、共享
4、参与、创造
三、web2.0的技术与典型应用
1、rss、xml、ajax、traceback、tag等,这些技术并不是革命,也不一定最新出现,但是web2.0让其广泛应用,代表着技术的应用创新,参考1、技术创新与应用创新:blog、qq群与web2.0,2、应用导向的技术创新
2、blog、wiki、sns、文摘、group
四、web2.0的网站特点
1、分散化,小型站点的发展:类似flickr、delicious、feedburner这样广受欢迎的站点并不需要很大的规模,因为用户参与其中。
2、用户主导、用户参与、用户建设,参考互联网用户自主时代与互联网企业的用户为王策略
3、输入输出与cms的组织方式,可读写,参考1、rss,聚合的无数可能,2、Blog、CMS与网站内容的组织
4、用户忠诚与用户(社区)文化
5、服务型
五、web2.0的商业问题
1、用户付费的可能:这一点在国外已经证实完全可行的模式,但是在国内确实比较难说,只是我个人持比较乐观的态度,还是很看好这种模式在一定范围内是可以实现的。
2、小型网站的可能:成本可以得到很好的控制。
3、web2.0产业链条:比如bsp、rss搜索、rss处理等等。
4、微支付:个人对个人的商务即web2.0电子商务实现的基础。
5、长尾模式的商业理念:这是一种平台化的思路,其实现方法有多种,它和分销等有本质区别,强调小规模交易在技术平台支持下的可能及其利润创造。回头再述。
6、行业应用:我觉得这是最直接的,依旧保持原有的商业模式和利润来源,只是网站组织和与用户的关系改变,而且更强调服务。比如IT行业网站的web2.0化已经比较明显;旅游行业网站的web2.0正在进行;人才招聘方面已经有了不少web2.0的应用等等。
以上只是基于以前思考过的问题的总结,有些东西可以看参考链接,更多可以阅读全部文档。这个提纲仓促而成,没有补充阅读其它内容,等回北京以后补充阅读之后再修改和站开。欢迎讨论。

