官网介绍:JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展、Restful。在拥有Java语言所有优势的同时再拥有ruby、python、php等动态语言的开发效率!为您节约更多时间,去陪恋人、家人和朋友 :)
Jfinal做为后台,进行下载文件服务时,源码中可看到:
Controller中已经提供了,方法:
/*** Render with file
*/
public void renderFile(String fileName) {
render = renderManager.getRenderFactory().getFileRender(fileName)
}
/**
* Render with file, using the new file name to the client
*/
public void renderFile(String fileName, String downloadFileName) {
render = renderManager.getRenderFactory().getFileRender(fileName, downloadFileName)
}
/**
* Render with file
*/
public void renderFile(File file) {
render = renderManager.getRenderFactory().getFileRender(file)
}
/**
* Render with file, using the new file name to the client
file=文件 ,downloadFileName=下载时客户端显示的文件名称 ,很贴心
*/
public void renderFile(File file, String downloadFileName) {
render = renderManager.getRenderFactory().getFileRender(file, downloadFileName)
}
大家可以看到源码中 FileRender 是有处理各个浏览器的兼容问题,所以可以方便的使用
/*** Copyright (c) 2011-2017, James Zhan 詹波 (jfinal@126.com).
*
* Licensed under the Apache License, Version 2.0 (the "License")
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jfinal.render
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.io.UnsupportedEncodingException
import java.net.URLEncoder
import javax.servlet.ServletContext
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import com.jfinal.kit.LogKit
import com.jfinal.kit.StrKit
/**
* FileRender.
*/
public class FileRender extends Render {
protected static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"
protected static String baseDownloadPath
protected static ServletContext servletContext
protected File file
protected String downloadFileName = null
public FileRender(File file) {
if (file == null) {
throw new IllegalArgumentException("file can not be null.")
}
this.file = file
}
public FileRender(File file, String downloadFileName) {
this(file)
if (StrKit.isBlank(downloadFileName)) {
throw new IllegalArgumentException("downloadFileName can not be blank.")
}
this.downloadFileName = downloadFileName
}
public FileRender(String fileName) {
if (StrKit.isBlank(fileName)) {
throw new IllegalArgumentException("fileName can not be blank.")
}
String fullFileName
fileName = fileName.trim()
if (fileName.startsWith("/") || fileName.startsWith("\\")) {
if (baseDownloadPath.equals("/")) {
fullFileName = fileName
} else {
fullFileName = baseDownloadPath + fileName
}
} else {
fullFileName = baseDownloadPath + File.separator + fileName
}
this.file = new File(fullFileName)
}
public FileRender(String fileName, String downloadFileName) {
this(fileName)
if (StrKit.isBlank(downloadFileName)) {
throw new IllegalArgumentException("downloadFileName can not be blank.")
}
this.downloadFileName = downloadFileName
}
static void init(String baseDownloadPath, ServletContext servletContext) {
FileRender.baseDownloadPath = baseDownloadPath
FileRender.servletContext = servletContext
}
public void render() {
if (file == null || !file.isFile()) {
RenderManager.me().getRenderFactory().getErrorRender(404).setContext(request, response).render()
return
}
// ---------
response.setHeader("Accept-Ranges", "bytes")
String fn = downloadFileName == null ? file.getName() : downloadFileName
response.setHeader("Content-disposition", "attachment " + encodeFileName(request, fn))
String contentType = servletContext.getMimeType(file.getName())
response.setContentType(contentType != null ? contentType : DEFAULT_CONTENT_TYPE)
// ---------
if (StrKit.isBlank(request.getHeader("Range"))) {
normalRender()
} else {
rangeRender()
}
}
protected String encodeFileName(String fileName) {
try {
// return new String(fileName.getBytes("GBK"), "ISO8859-1")
return new String(fileName.getBytes(getEncoding()), "ISO8859-1")
} catch (UnsupportedEncodingException e) {
return fileName
}
}
/**
* 依据浏览器判断编码规则
*/
public String encodeFileName(HttpServletRequest request, String fileName) {
String userAgent = request.getHeader("User-Agent")
try {
String encodedFileName = URLEncoder.encode(fileName, "UTF8")
// 如果没有UA,则默认使用IE的方式进行编码
if (userAgent == null) {
return "filename=\"" + encodedFileName + "\""
}
userAgent = userAgent.toLowerCase()
// IE浏览器,只能采用URLEncoder编码
if (userAgent.indexOf("msie") != -1) {
return "filename=\"" + encodedFileName + "\""
}
// Opera浏览器只能采用filename*
if (userAgent.indexOf("opera") != -1) {
return "filename*=UTF-8''" + encodedFileName
}
// Safari浏览器,只能采用ISO编码的中文输出,Chrome浏览器,只能采用MimeUtility编码或ISO编码的中文输出
if (userAgent.indexOf("safari") != -1 || userAgent.indexOf("applewebkit") != -1 || userAgent.indexOf("chrome") != -1) {
return "filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO8859-1") + "\""
}
// FireFox浏览器,可以使用MimeUtility或filename*或ISO编码的中文输出
if (userAgent.indexOf("mozilla") != -1) {
return "filename*=UTF-8''" + encodedFileName
}
return "filename=\"" + encodedFileName + "\""
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e)
}
}
protected void normalRender() {
response.setHeader("Content-Length", String.valueOf(file.length()))
InputStream inputStream = null
OutputStream outputStream = null
try {
inputStream = new BufferedInputStream(new FileInputStream(file))
outputStream = response.getOutputStream()
byte[] buffer = new byte[1024]
for (int len = -1 (len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len)
}
outputStream.flush()
outputStream.close()
} catch (IOException e) {
String n = e.getClass().getSimpleName()
if (n.equals("ClientAbortException") || n.equals("EofException")) {
} else {
throw new RenderException(e)
}
} catch (Exception e) {
throw new RenderException(e)
} finally {
if (inputStream != null)
try {inputStream.close()} catch (IOException e) {LogKit.error(e.getMessage(), e)}
}
}
protected void rangeRender() {
Long[] range = {null, null}
processRange(range)
String contentLength = String.valueOf(range[1].longValue() - range[0].longValue() + 1)
response.setHeader("Content-Length", contentLength)
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT) // status = 206
// Content-Range: bytes 0-499/10000
StringBuilder contentRange = new StringBuilder("bytes ").append(String.valueOf(range[0])).append("-").append(String.valueOf(range[1])).append("/").append(String.valueOf(file.length()))
response.setHeader("Content-Range", contentRange.toString())
InputStream inputStream = null
OutputStream outputStream = null
try {
long start = range[0]
long end = range[1]
inputStream = new BufferedInputStream(new FileInputStream(file))
if (inputStream.skip(start) != start)
throw new RuntimeException("File skip error")
outputStream = response.getOutputStream()
byte[] buffer = new byte[1024]
long position = start
for (int len position <= end && (len = inputStream.read(buffer)) != -1) {
if (position + len <= end) {
outputStream.write(buffer, 0, len)
position += len
}
else {
for (int i=0 i<len && position <= end i++) {
outputStream.write(buffer[i])
position++
}
}
}
outputStream.flush()
outputStream.close()
}
catch (IOException e) {
String n = e.getClass().getSimpleName()
if (n.equals("ClientAbortException") || n.equals("EofException")) {
} else {
throw new RenderException(e)
}
}
catch (Exception e) {
throw new RenderException(e)
}
finally {
if (inputStream != null)
try {inputStream.close()} catch (IOException e) {LogKit.error(e.getMessage(), e)}
}
}
/**
* Examples of byte-ranges-specifier values (assuming an entity-body of length 10000):
* The first 500 bytes (byte offsets 0-499, inclusive): bytes=0-499
* The second 500 bytes (byte offsets 500-999, inclusive): bytes=500-999
* The final 500 bytes (byte offsets 9500-9999, inclusive): bytes=-500
* Or bytes=9500-
*/
protected void processRange(Long[] range) {
String rangeStr = request.getHeader("Range")
int index = rangeStr.indexOf(',')
if (index != -1)
rangeStr = rangeStr.substring(0, index)
rangeStr = rangeStr.replace("bytes=", "")
String[] arr = rangeStr.split("-", 2)
if (arr.length < 2)
throw new RuntimeException("Range error")
long fileLength = file.length()
for (int i=0 i<range.length i++) {
if (StrKit.notBlank(arr[i])) {
range[i] = Long.parseLong(arr[i].trim())
if (range[i] >= fileLength)
range[i] = fileLength - 1
}
}
// Range format like: 9500-
if (range[0] != null && range[1] == null) {
range[1] = fileLength - 1
}
// Range format like: -500
else if (range[0] == null && range[1] != null) {
range[0] = fileLength - range[1]
range[1] = fileLength - 1
}
// check final range
if (range[0] == null || range[1] == null || range[0].longValue() > range[1].longValue())
throw new RuntimeException("Range error")
}
}
EhCachePlugin 如果不指定配置文件,会默认在 classpath 里面去找配置文件,这个行为是 EhCache 默认的。loadPropertyFile 是历史原因,JFinal 在 2011 年开始应用于公司项目中,当时没有使用maven管理项目。
即便如此也很容易解决问题,JFinal 提供了 PathKit.getRootClassPath() 方法可以很方便地得到classPath,在使用 EhCachePlugin 或 loadPropertyFile 时可以这样加载classPath 下的配置文件:
new EhCachePlugin(PathKit.getRootClassPath()+"/ehcache.xml") loadPropertyFile(PathKit.getRootClassPath()+"/config.txt")
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)