今天在处理jar下载被IE自动将后缀修改为zip的时候,写了这么一个servlet;后面才发现原来是jboss中的mime.types中少了jar的配置,走了一大段弯路;这个Servlet在mime.types中即使没有配置的类型,大部份的浏览器都可以支持正常下载的,我的测试过程中使用七个浏览器,只有Opera在下载jar的时候会将其后缀恐怖的修改为exe。要使用这个Servlet,需要做的辅助工作就是要在web.xml中配置它,包括Servlet及servlet-mapping的配置,可参考以下内容:
<servlet> <servlet-name>downloadServer</servlet-name> <servlet-class>***.DownloadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>downloadServer</servlet-name> <url-pattern>/download_center.do</url-pattern> </servlet-mapping>
,下载文件的时候,将链接使用如下形式:
http://****.com/download_center.do?file=myfile.jar
,就可以调用该DownloadServlet进行文件的下载了,详细的可以参考一下网络上其它的资料,以下是DownloadServlet.java的完整源码:
/**
* 类DownloadServlet.java的实现描述:TODO 类实现描述 文件下载Servlet
*
* @author root 2010-7-28 上午11:25:58
*/
/**
*
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class DownloadServlet extends HttpServlet {
private static final long serialVersionUID = 8228591081694973459L;
protected final static Log logger = LogFactory.getLog(DownloadServlet.class);
/*
* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
File path = new File("");
String file = request.getParameter("file");// 通过该参数传入文件名
if (!fileSafeCheck(file)) {
StringBuilder sb = new StringBuilder("filename:").append(file).append(" is invalid");
if (logger.isDebugEnabled()) {
logger.debug(sb.toString());
}
response.setCharacterEncoding("gbk");
response.setContentLength(sb.length());
response.getWriter().write(sb.toString());
}
// 以下是文件名的完整路径,具体根据情况需要自己在这里处理一下了
String filePath = path.getAbsoluteFile().getParent() + file;
if (logger.isDebugEnabled()) {
StringBuilder sb = new StringBuilder("filename:").append(file).append(",file absolute path:").append(
filePath);
logger.debug(sb.toString());
}
if (filePath != null && filePath.length() > 0) {
try {
downloadFile(response, filePath);
} catch (Exception e) {
StringBuilder sb = new StringBuilder("download file exception,filename:").append(file).append(
",file absolute path:").append(
filePath);
logger.error(sb.toString(), e);
sb.delete(0, sb.length());
// sb.append("<script language=\"javascript\">alert('文件下载异常,请确定文件名是否正确.');</script>");
sb.append("<script language=\"javascript\">alert('download file err.');</script>");
response.setCharacterEncoding("gbk");
response.setContentLength(sb.length());
response.getWriter().write(sb.toString());
}
}
}
/*
* (non-Javadoc)
* @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
doGet(request, response);
}
/*
* (non-Javadoc)
* @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
*/
public void init(ServletConfig conf) throws ServletException {
// TODO Auto-generated method stub
super.init(conf);
}
/**
* 下载文件
*
* @param response
* @param filePath
* @throws RuntimeException
* @throws IOException
*/
private void downloadFile(HttpServletResponse response, String filePath) throws RuntimeException, IOException {
File file = new File(filePath);
if (!file.exists() || !file.canRead()) {
throw new RuntimeException("File not exists or can not be read!");
}
FileInputStream fileinputstream = new FileInputStream(file);
String filename = getFileName(filePath);
downloadFile(fileinputstream, null, filename, 2048, response);
fileinputstream.close();
fileinputstream = null;
file = null;
}
/**
* 下载文件
*
* @param filedata 下载数据流
* @param contentType 文件类型
* @param filename (下载后的)文件名称
* @param buffersize 缓冲区大小
* @param m_response
* @throws IOException
* @throws BimisException
*/
private void downloadFile(InputStream filedata, String contentType, String filename, int buffersize,
HttpServletResponse m_response) throws IOException, RuntimeException {
if (filedata == null) {
return;
}
if (buffersize <= 0) {
buffersize = 2048;
}
long contentLengh = filedata.available();
if (contentType == null || contentType.length() == 0) {
m_response.setContentType("application/x-msdownload");
}
else {
m_response.setContentType(contentType);
}
if (contentLengh > 0) {
m_response.setContentLength((int) contentLengh);
}
String m_contentDisposition = "attachment;";
if (filename == null || filename.length() == 0) {
m_response.setHeader("Content-Disposition",m_contentDisposition);
}
else {
m_response.setHeader("Content-Disposition", m_contentDisposition + " filename=" + toUtf8String(filename));
}
ServletOutputStream rspout = m_response.getOutputStream();
copyStream(filedata, rspout, buffersize, true);
}
/**
* 将文件名中的汉字转为UTF8编码的串,以便下载时能正确显示另存的文件名.
*
* @param s 原文件名
* @return 重新编码后的文件名
*/
private String toUtf8String(String s) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= 0 && c <= 255) {
sb.append(c);
} else {
byte[] b;
try {
b = Character.toString(c).getBytes("utf-8");
} catch (Exception ex) {
b = new byte[0];
}
for (int j = 0; j < b.length; j++) {
int k = b[j];
if (k < 0) k += 256;
sb.append("%" + Integer.toHexString(k).toUpperCase());
}
}
}
return sb.toString();
}
private final long copyStream(InputStream source, OutputStream dest, int bufferSize, boolean flush)
throws RuntimeException {
int bytes;
long total;
byte[] buffer;
buffer = new byte[bufferSize];
total = 0;
try {
while ((bytes = source.read(buffer)) != -1) {
// Technically, some read(byte[]) methods may return 0 and we
// cannot
// accept that as an indication of EOF.
if (bytes == 0) {
bytes = source.read();
if (bytes < 0) break;
dest.write(bytes);
if (flush) dest.flush();
++total;
continue;
}
dest.write(buffer, 0, bytes);
if (flush) dest.flush();
total += bytes;
}
} catch (IOException e) {
throw new RuntimeException("IOException caught while copying.", e);
}
return total;
}
/**
* 根据传入的路径,获取文件的名称
*
* @param fullFilePath
* @return
*/
private String getFileName(String fullFilePath) {
if (fullFilePath == null) {
return "";
}
int index1 = fullFilePath.lastIndexOf('/');
int index2 = fullFilePath.lastIndexOf('\\');
// index is the maximum value of index1 and index2
int index = (index1 > index2) ? index1 : index2;
if (index == -1) {
// not found the path separator
return fullFilePath;
}
String fileName = fullFilePath.substring(index + 1);
return fileName;
}
/**
* 文件名的安全检查,以免被人通过"../../../"的方式获取其它文件
*
* @param filename
* @return
*/
private boolean fileSafeCheck(String filename) {
if (filename.indexOf("../") >= 0) {
return false;
}
return true;
}
}