jfinalclub源碼
㈠ 如何評價Jfinal,Jpress
首先,我是從qbasic開始編程,經歷了qb到vb,vb到asp(不帶.net),asp到jsp,jsp到php,再回頭學習j2ee。這個過程可能導致我的觀點可能跟主流觀點不同,希望各位理解。
j2ee並不等於spring struts hibernate,還有各種其他的選擇,ssh不是唯一甚至不是最好的選擇,這里按下不表。
先問一個問題,什麼是jsp/servlet不能做,而ssh能做的?沒有ssh之前,就沒有web應用了么?
有人會覺得servlet傻,可是你看看struts的核心入口Dispatcher,不就是一個Servlet么。你覺得jdbc難用,hibernate的功能最後還是用jdbc實現的,而且不少批量處理的情況,還是原生sql好用,以至於hibernate不得不提供原生sql介面,mybatis正是從這里挖走不少用戶。
在很多情況下,ssh做的,只不過是把java/jsp/servlet/jdbc本來就具有的功能,封裝成不一樣的API,把原先用Java編寫的代碼變成用XML編寫,然後在用java寫的解釋器在jvm裡面去運行這些XML。所以,我覺得ssh其實就是面向web開發這個領域創造出來的一組DSL(領域特定語言)。而這套語言以XML開始,現在轉移到java的註解annotation,慢慢的又回歸java語言本身。
不太全面的說,struts就是給不熟悉html/css/js的web程序員擺脫它們寫業務邏輯用的,hibernate就是給不熟悉SQL的程序員擺脫SQL寫資料庫程序用的,spring就是給不熟悉java的介面、反射的程序員擺脫介面反射寫AOP用的。而上面被代替的這些,恰恰是相關領域的原生DSL,這裡面多少有一點諷刺的意味,對么?
如果struts的開發者沒有在jsp混雜java片段的各種<%="'"+xx.yy()+"'"%>嵌套括弧引號海裡面摸爬滾打過來,你覺得他們會想到要做struts么?
如果hibernate的開發者沒有在SQL的join鏈中繞暈過,他們會搞hibernate?
如果spring的開發者沒有對java反射的異常數量吐過槽,會有spring?
如果你只想做一個平庸的碼農,去學ssh能讓你找到一份不錯的入門工作。
如果你希望能深入的理解系統、語言、框架,去學習語言本身提供的功能,去學習servlet、jdbc、java,去看看如何用他們構造通用的復雜的系統,也許未來5-10年,人們再提起j2ee,說的就是你創造的框架的名字,而不再是什麼spring struts hibernate。
我們總是希望高內聚低耦合,但兩者通常是矛盾的;如果你願意放棄其中的一個,就可以在另一個上面走的更遠。
㈡ 現在JFinal越來越火,它的發展趨勢怎麼樣
JFinal 採用微內核全方位擴展架構,全方位是指其擴展方式在空間上的表現形式。JFinal由Handler、Interceptor、Controller、Render、Plugin五大部分組成。
看過源碼的都知道, JFinal 是輕薄封裝, 原理還是javax.servlet.http.HttpServletRequest等, 所以學好原理, 是最靠譜的, JFinal是為我們快速開發業務實現用的, 新手最好先學會javax.servlet 再來上手JFinal ,
發展趨勢 ? 當做一個工具就好了, Java項目都可以放入JFinal , 小巧方便的, 招聘JFinal 也挺多的
㈢ jfinal框架下 分頁採取的是freemark 現在要加個下拉框 ,用戶根據下拉框的數字,選擇頁面顯示多少條 數據
這個框架我沒用過。
加下拉框根據框中的數字 每頁顯示多少條 這點就可以判斷是用SQL分頁的。
/**
正序分頁 每頁20條、第3頁 **/
Select * from ( select top 20 * FROM TableName b
WHERE (time <= (SELECT max(time) FROM (
SELECT TOP 60 time FROM TableName b where 1=1 ORDER BY time ) AS T )) 1=1 ORDER BY time desc ) AS T ORDER BY time /**
倒敘分頁 每頁30條、第2頁 **/
Select * from ( select top 30 * FROM TableName b
WHERE (time >= (SELECT min(time) FROM (
SELECT TOP 60 time FROM TableName b where 1=1 ORDER BY time desc ) AS T )) 1=1 ORDER BY time ) AS T ORDER BY time desc
㈣ JFinal 集成kisso怎麼使用裡面的shiro
這個你需要看kisso的代碼了。
推薦一套完整的Shiro Demo,免費的。
推薦一套完整的ShiroDemo,免費的。
ShiroDemo:http://www.sojson.com/shiro
Demo已經部署到線上,地址是http://shiro.itboy.net
管理員帳號:admin,密碼:sojson.com如果密碼錯誤,請用sojson。PS:你可以注冊自己的帳號,然後用管理員賦許可權給你自己的帳號,但是,每20分鍾會把數據初始化一次。建議自己下載源碼,讓Demo跑起來,然後跑的更快。
管理員帳號:admin,密碼:sojson.com 如果密碼錯誤,請用sojson。PS:你可以注冊自己的帳號,然後用管理員賦許可權給你自己的帳號,但是,每20分鍾會把數據初始化一次。建議自己下載源碼,讓Demo跑起來,然後跑的更快。
㈤ JAVA SSH和JFinal框架 有什麼區別(優缺點)
1.SSHIntroction
SSH不是一個框架,而是多個框架(struts+spring+hibernate)的集成,是目前較流行的一種Web應用程序開源集成框架,用於構建靈活、易於擴展的多層Web應用程序。如下圖1所示為SSH的架構圖.
Web層,就是MVC模式裡面的「C」(controller)與「V」(View),負責控制業務邏輯層與頁面的交互與展現,在SSH架構中,Struts充當controller,JSP充當View。
Service層(就是業務邏輯層),負責實現業務邏輯。業務邏輯層以DAO層為基礎,通過對DAO組件的正面模式包裝,完成系統所要求的業務邏輯。
DAO層,負責與持久化對象交互。該層封裝了數據的增、刪、查、改的操作。
PO,持久化對象。通過實體關系映射工具將關系型資料庫的數據映射成對象,很方便地實現以面向對象方式操作資料庫,該系統採用Hibernate作為ORM框架。Spring的作用貫穿了整個中間層,將Web層、Service層、DAO層及PO無縫整合,其數據服務層用來存放數據。
1.1 Struts的優劣勢
1.2 Spring的優劣勢
Spring是一個輕量級的控制反轉(IOC)和面向切面(AOP)的容器框架。
1.3 Hibernate的優劣勢
Hibernate是一個開放源代碼的對象關系映射框架,它對JDBC進行了非常輕量級的對象封裝,使得Java程序員可以隨心所欲的使用對象編程思維來操縱資料庫。Hibernate可以應用在任何使用JDBC的場合,既可以在Java的客戶端程序使用,也可以在Servlet/JSP的Web應用中使用,最具革命意義的是,Hibernate可以在應用EJB的J2EE架構中取代CMP,完成數據持久化的重任。
優點:
1)
Hibernate是JDBC的輕量級的對象封裝,它是一個獨立的對象持久層框架。Hibernate可以用在任何JDBC可以使用的場合,例如Java應用程序的資料庫訪問代碼,DAO介面的實現類,甚至可以是BMP裡面的訪問資料庫的代碼。
2)
Hibernate是一個和JDBC密切關聯的框架,所以Hibernate的兼容性和JDBC驅動,和資料庫都有一定的關系,但是和使用它的Java程序,和AppServer 沒有任何關系,也不存在兼容性問題。
3)
Hibernate不能用來直接和EntityBean 做對比,只有放在整個J2EE項目的框架中才能比較。並且即使是放在軟體整體框架中來看,Hibernate也是做為JDBC的替代者出現的,而不是EntityBean 的替代者出現的,
4)
Hibernate是一個開放源代碼的對象關系映射框架,它對JDBC進行了非常輕量級的對象封裝,使得Java程序員可以隨心所欲的使用對象編程思維來操縱資料庫。
5)
Hibernate可以應用在任何使用JDBC的場合。
6)
Hibernate使用Java反射機制而不是位元組碼增強程序來實現透明性。
7)
Hibernate的性能非常好,因為它是個輕量級框架。映射的靈活性很出色。
8)
它支持各種關系資料庫,從一對一到多對多的各種復雜關系。
缺點:
1)
它限制所使用的對象模型。(例如,一個持久性類不能映射到多個表)。
2)
較JDBC,Hibernate更消耗內存。
3)
對於小型項目,Hibernate開發效率低。
2.jFinal Introction
jFinal的相關介紹,請參閱http://code.google.com/p/jfinal/
3.TheComparison
不可否認,SSH與jFinal都是非常優秀的架構,兩者都有各自的優點,如何進行取捨取決於項目與項目組成員的實際情況!
註:*表示所在項具有相對優勢
原文地址:http://blog.csdn.net/daijin888888/article/details/50800887
㈥ jfinal .findById 與.find誰的效率高
findById :是按照主鍵查詢,肯定只能查詢一條或者0條記錄,一般資料庫默認主鍵為索引,使用索引速度肯定快的
find:按照你的sql語句的where條件查詢,查詢0-N條。
按照你的需求,如果要按照主鍵查詢建議用findById,如果查詢多條只能用find。
如果要查詢1條記錄,硬是要比較速度,還是findById比較快,看源碼find要進行很多list的實例化。
必須是可以的啊, 配合 jsch.jar(ftp文件上傳使用) 使用。
Controller 源碼中已經提供兩個獲取 批量上傳的文件 方法
publicList<UploadFile>getFiles(StringuploadPath,intmaxPostSize){
if(==false)
request=newMultipartRequest(request,uploadPath,maxPostSize);
return((MultipartRequest)request).getFiles();
}
publicList<UploadFile>getFiles(StringuploadPath){
if(==false)
request=newMultipartRequest(request,uploadPath);
return((MultipartRequest)request).getFiles();
}
獲取 到 List<UploadFile> 文件集合之後, 再使用 jsch.jar 進行ftp文件上傳到其他伺服器
JSchjsch=newJSch();
SessionsshSession=jsch.getSession(this.username,this.host,this.port);
sshSession.setPassword(password);
PropertiessshConfig=newProperties();
sshConfig.put("StrictHostKeyChecking","no");
sshSession.setConfig(sshConfig);
sshSession.connect(20000);
Channelsftp=sshSession.openChannel("sftp");
sftp.connect();
。。。這個網路搜一下,代碼很多,這里就不在啰嗦了
㈧ jfinal什麼時候出web版的後台管理
可以加入Jfinal俱樂部,
引用官網的:
俱樂部當前發放的福利是本社區 jfinal.com 的源代碼,並取名為
jfinal-club。jfinal-club 在核心功能上相當於一個迷你的 OSChina 社區,newsfeed
信息流模塊整合了整站動態數據,交互性極好。重要功能:動態消息、@提到我、remind提醒、關注、好友、粉絲、私信、發貼、回貼、點贊、收藏、定時任務等功能。常見的功能也很全面:文件下載、圖片上傳、用戶頭像裁剪、登錄、注冊、郵件激活、找回密碼、XSS過濾、緩存、後台管理、以及一些常用工具類等等。
jfinal-club 是官方出品的唯一 JFinal 最佳實踐,絕無僅有的極簡設計,獲得 jfinal-club 也就獲得了作者本人對
JFinal 的使用精髓。基於 jfinal 3.3 開發,獲得 jfinal-club 將以令人難以想像的速度掌握新版本功能。
jfinal-club 是一個長期進化的,不斷添加實用功能的項目,加入俱樂部以後,將隨之長期享受該福利。
---------------
web版的後台管理社區做的比較好的有:
JfinalUIB , EOVA ,JPress, ... 等很多都非常的好
http://www.jfinal.com/project 相關項目http://www.jfinal.com/club 俱樂部
㈨ 如何使用python爬蟲jfinal
一、gzip/deflate支持
現在的網頁普遍支持gzip壓縮,這往往可以解決大量傳輸時間,以VeryCD的主頁為例,未壓縮版本247K,壓縮了以後45K,為原來的1/5。這就意味著抓取速度會快5倍。
然而python的urllib/urllib2默認都不支持壓縮,要返回壓縮格式,必須在request的header裡面寫明』accept-
encoding』,然後讀取response後更要檢查header查看是否有』content-encoding』一項來判斷是否需要解碼,很繁瑣瑣
碎。如何讓urllib2自動支持gzip, defalte呢?其實可以繼承BaseHanlder類,然後build_opener的方式來處理:
import urllib2
from gzip import GzipFile
from StringIO import StringIO
class ContentEncodingProcessor(urllib2.BaseHandler):
"""A handler to add gzip capabilities to urllib2 requests """
# add headers to requests
def http_request(self, req):
req.add_header("Accept-Encoding", "gzip, deflate")
return req
# decode
def http_response(self, req, resp):
old_resp = resp
# gzip
if resp.headers.get("content-encoding") == "gzip":
gz = GzipFile(
fileobj=StringIO(resp.read()),
mode="r"
)
resp = urllib2.addinfourl(gz, old_resp.headers, old_resp.url, old_resp.code)
resp.msg = old_resp.msg
# deflate
if resp.headers.get("content-encoding") == "deflate":
gz = StringIO( deflate(resp.read()) )
resp = urllib2.addinfourl(gz, old_resp.headers, old_resp.url, old_resp.code) # 'class to add info() and
resp.msg = old_resp.msg
return resp
# deflate support
import zlib
def deflate(data): # zlib only provides the zlib compress format,not the deflate format;
try: # so on top of all there's this workaround:
return zlib.decompress(data, -zlib.MAX_WBITS)
except zlib.error:
return zlib.decompress(data)然後就簡單了,
encoding_support = ContentEncodingProcessor
opener = urllib2.build_opener( encoding_support, urllib2.HTTPHandler )
#直接用opener打開網頁,如果伺服器支持gzip/defalte則自動解壓縮
content = opener.open(url).read()二、更方便地多線程
總結一文的確提及了一個簡單的多線程模板,但是那個東東真正應用到程序裡面去只會讓程序變得支離破碎,不堪入目。在怎麼更方便地進行多線程方面我也動了一番腦筋。先想想怎麼進行多線程調用最方便呢?
1、用twisted進行非同步I/O抓取
事實上更高效的抓取並非一定要用多線程,也可以使用非同步I/O法:直接用twisted的getPage方法,然後分別加上非同步I/O結束時的callback和errback方法即可。例如可以這么干:
from twisted.web.client import getPage
from twisted.internet import reactor
links = [ 'http://www.verycd.com/topics/%d/'%i for i in range(5420,5430) ]
def parse_page(data,url):
print len(data),url
def fetch_error(error,url):
print error.getErrorMessage(),url
# 批量抓取鏈接
for url in links:
getPage(url,timeout=5)
.addCallback(parse_page,url) #成功則調用parse_page方法
.addErrback(fetch_error,url) #失敗則調用fetch_error方法
reactor.callLater(5, reactor.stop) #5秒鍾後通知reactor結束程序
reactor.run()twisted人如其名,寫的代碼實在是太扭曲了,非正常人所能接受,雖然這個簡單的例子看上去還好;每次寫twisted的程序整個人都扭曲了,累得不得了,文檔等於沒有,必須得看源碼才知道怎麼整,唉不提了。
如果要支持gzip/deflate,甚至做一些登陸的擴展,就得為twisted寫個新的HTTPClientFactory類諸如此類,我這眉頭真是大皺,遂放棄。有毅力者請自行嘗試。
這篇講怎麼用twisted來進行批量網址處理的文章不錯,由淺入深,深入淺出,可以一看。
2、設計一個簡單的多線程抓取類
還是覺得在urllib之類python「本土」的東東裡面折騰起來更舒服。試想一下,如果有個Fetcher類,你可以這么調用
f = Fetcher(threads=10) #設定下載線程數為10
for url in urls:
f.push(url) #把所有url推入下載隊列
while f.taskleft(): #若還有未完成下載的線程
content = f.pop() #從下載完成隊列中取出結果
do_with(content) # 處理content內容這么個多線程調用簡單明了,那麼就這么設計吧,首先要有兩個隊列,用Queue搞定,多線程的基本架構也和「技巧總結」一文類似,push方法和
pop方法都比較好處理,都是直接用Queue的方法,taskleft則是如果有「正在運行的任務」或者」隊列中的任務」則為是,也好辦,於是代碼如
下:import urllib2
from threading import Thread,Lock
from Queue import Queue
import time
class Fetcher:
def __init__(self,threads):
self.opener = urllib2.build_opener(urllib2.HTTPHandler)
self.lock = Lock() #線程鎖
self.q_req = Queue() #任務隊列
self.q_ans = Queue() #完成隊列
self.threads = threads
for i in range(threads):
t = Thread(target=self.threadget)
t.setDaemon(True)
t.start()
self.running = 0
def __del__(self): #解構時需等待兩個隊列完成
time.sleep(0.5)
self.q_req.join()
self.q_ans.join()
def taskleft(self):
return self.q_req.qsize()+self.q_ans.qsize()+self.running
def push(self,req):
self.q_req.put(req)
def pop(self):
return self.q_ans.get()
def threadget(self):
while True:
req = self.q_req.get()
with self.lock: #要保證該操作的原子性,進入critical area
self.running += 1
try:
ans = self.opener.open(req).read()
except Exception, what:
ans = ''
print what
self.q_ans.put((req,ans))
with self.lock:
self.running -= 1
self.q_req.task_done()
time.sleep(0.1) # don't spam
if __name__ == "__main__":
links = [ 'http://www.verycd.com/topics/%d/'%i for i in range(5420,5430) ]
f = Fetcher(threads=10)
for url in links:
f.push(url)
while f.taskleft():
url,content = f.pop()
print url,len(content)
㈩ jfinal 如何導出zip壓縮文件
官網介紹:JFinal 是基於 Java 語言的極速 WEB + ORM 框架,其核心設計目標是開發迅速、代碼量少、學習簡單、功能強大、輕量級、易擴展、Restful。在擁有Java語言所有優勢的同時再擁有ruby、python、php等動態語言的開發效率!為您節約更多時間,去陪戀人、家人和朋友 :)
Jfinal做為後台,進行下載文件服務時,源碼中可看到:
Controller中已經提供了,方法:
/**
*Renderwithfile
*/
publicvoidrenderFile(StringfileName){
render=renderManager.getRenderFactory().getFileRender(fileName);
}
/**
*Renderwithfile,
*/
publicvoidrenderFile(StringfileName,StringdownloadFileName){
render=renderManager.getRenderFactory().getFileRender(fileName,downloadFileName);
}
/**
*Renderwithfile
*/
publicvoidrenderFile(Filefile){
render=renderManager.getRenderFactory().getFileRender(file);
}
/**
*Renderwithfile,
file=文件,downloadFileName=下載時客戶端顯示的文件名稱,很貼心
*/
publicvoidrenderFile(Filefile,StringdownloadFileName){
render=renderManager.getRenderFactory().getFileRender(file,downloadFileName);
}
大家可以看到源碼中 FileRender 是有處理各個瀏覽器的兼容問題,所以可以方便的使用
/**
*Copyright(c)2011-2017,JamesZhan詹波([email protected]).
*
*LicensendertheApacheLicense,Version2.0(the"License");
*.
*YoumayobtainaoftheLicenseat
*
*http://www.apache.org/licenses/LICENSE-2.0
*
*,software
*"ASIS"BASIS,
*,eitherexpressorimplied.
*
*limitationsundertheLicense.
*/
packagecom.jfinal.render;
importjava.io.BufferedInputStream;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.io.OutputStream;
importjava.io.UnsupportedEncodingException;
importjava.net.URLEncoder;
importjavax.servlet.ServletContext;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importcom.jfinal.kit.LogKit;
importcom.jfinal.kit.StrKit;
/**
*FileRender.
*/
{
_CONTENT_TYPE="application/octet-stream";
;
;
protectedFilefile;
=null;
publicFileRender(Filefile){
if(file==null){
("filecannotbenull.");
}
this.file=file;
}
publicFileRender(Filefile,StringdownloadFileName){
this(file);
if(StrKit.isBlank(downloadFileName)){
("downloadFileNamecannotbeblank.");
}
this.downloadFileName=downloadFileName;
}
publicFileRender(StringfileName){
if(StrKit.isBlank(fileName)){
("fileNamecannotbeblank.");
}
StringfullFileName;
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=newFile(fullFileName);
}
publicFileRender(StringfileName,StringdownloadFileName){
this(fileName);
if(StrKit.isBlank(downloadFileName)){
("downloadFileNamecannotbeblank.");
}
this.downloadFileName=downloadFileName;
}
staticvoidinit(StringbaseDownloadPath,ServletContextservletContext){
FileRender.baseDownloadPath=baseDownloadPath;
FileRender.servletContext=servletContext;
}
publicvoidrender(){
if(file==null||!file.isFile()){
RenderManager.me().getRenderFactory().getErrorRender(404).setContext(request,response).render();
return;
}
//---------
response.setHeader("Accept-Ranges","bytes");
Stringfn=downloadFileName==null?file.getName():downloadFileName;
response.setHeader("Content-disposition","attachment;"+encodeFileName(request,fn));
StringcontentType=servletContext.getMimeType(file.getName());
response.setContentType(contentType!=null?contentType:DEFAULT_CONTENT_TYPE);
//---------
if(StrKit.isBlank(request.getHeader("Range"))){
normalRender();
}else{
rangeRender();
}
}
protectedStringencodeFileName(StringfileName){
try{
//returnnewString(fileName.getBytes("GBK"),"ISO8859-1");
returnnewString(fileName.getBytes(getEncoding()),"ISO8859-1");
}catch(UnsupportedEncodingExceptione){
returnfileName;
}
}
/**
*依據瀏覽器判斷編碼規則
*/
publicStringencodeFileName(HttpServletRequestrequest,StringfileName){
StringuserAgent=request.getHeader("User-Agent");
try{
StringencodedFileName=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=""+newString(fileName.getBytes("UTF-8"),"ISO8859-1")+""";
}
//FireFox瀏覽器,可以使用MimeUtility或filename*或ISO編碼的中文輸出
if(userAgent.indexOf("mozilla")!=-1){
return"filename*=UTF-8''"+encodedFileName;
}
return"filename=""+encodedFileName+""";
}catch(UnsupportedEncodingExceptione){
thrownewRuntimeException(e);
}
}
protectedvoidnormalRender(){
response.setHeader("Content-Length",String.valueOf(file.length()));
InputStreaminputStream=null;
OutputStreamoutputStream=null;
try{
inputStream=newBufferedInputStream(newFileInputStream(file));
outputStream=response.getOutputStream();
byte[]buffer=newbyte[1024];
for(intlen=-1;(len=inputStream.read(buffer))!=-1;){
outputStream.write(buffer,0,len);
}
outputStream.flush();
outputStream.close();
}catch(IOExceptione){
Stringn=e.getClass().getSimpleName();
if(n.equals("ClientAbortException")||n.equals("EofException")){
}else{
thrownewRenderException(e);
}
}catch(Exceptione){
thrownewRenderException(e);
}finally{
if(inputStream!=null)
try{inputStream.close();}catch(IOExceptione){LogKit.error(e.getMessage(),e);}
}
}
protectedvoidrangeRender(){
Long[]range={null,null};
processRange(range);
StringcontentLength=String.valueOf(range[1].longValue()-range[0].longValue()+1);
response.setHeader("Content-Length",contentLength);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//status=206
//Content-Range:bytes0-499/10000
StringBuildercontentRange=newStringBuilder("bytes").append(String.valueOf(range[0])).append("-").append(String.valueOf(range[1])).append("/").append(String.valueOf(file.length()));
response.setHeader("Content-Range",contentRange.toString());
InputStreaminputStream=null;
OutputStreamoutputStream=null;
try{
longstart=range[0];
longend=range[1];
inputStream=newBufferedInputStream(newFileInputStream(file));
if(inputStream.skip(start)!=start)
thrownewRuntimeException("Fileskiperror");
outputStream=response.getOutputStream();
byte[]buffer=newbyte[1024];
longposition=start;
for(intlen;position<=end&&(len=inputStream.read(buffer))!=-1;){
if(position+len<=end){
outputStream.write(buffer,0,len);
position+=len;
}
else{
for(inti=0;i<len&&position<=end;i++){
outputStream.write(buffer[i]);
position++;
}
}
}
outputStream.flush();
outputStream.close();
}
catch(IOExceptione){
Stringn=e.getClass().getSimpleName();
if(n.equals("ClientAbortException")||n.equals("EofException")){
}else{
thrownewRenderException(e);
}
}
catch(Exceptione){
thrownewRenderException(e);
}
finally{
if(inputStream!=null)
try{inputStream.close();}catch(IOExceptione){LogKit.error(e.getMessage(),e);}
}
}
/**
*Examplesofbyte-ranges-specifiervalues(assuminganentity-bodyoflength10000):
*Thefirst500bytes(byteoffsets0-499,inclusive):bytes=0-499
*Thesecond500bytes(byteoffsets500-999,inclusive):bytes=500-999
*Thefinal500bytes(byteoffsets9500-9999,inclusive):bytes=-500
*Orbytes=9500-
*/
protectedvoidprocessRange(Long[]range){
StringrangeStr=request.getHeader("Range");
intindex=rangeStr.indexOf(',');
if(index!=-1)
rangeStr=rangeStr.substring(0,index);
rangeStr=rangeStr.replace("bytes=","");
String[]arr=rangeStr.split("-",2);
if(arr.length<2)
thrownewRuntimeException("Rangeerror");
longfileLength=file.length();
for(inti=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;
}
}
//Rangeformatlike:9500-
if(range[0]!=null&&range[1]==null){
range[1]=fileLength-1;
}
//Rangeformatlike:-500
elseif(range[0]==null&&range[1]!=null){
range[0]=fileLength-range[1];
range[1]=fileLength-1;
}
//checkfinalrange
if(range[0]==null||range[1]==null||range[0].longValue()>range[1].longValue())
thrownewRuntimeException("Rangeerror");
}
}