Web Sunucuya Dosya Gönderelim
lib, tomcat, java June 12th, 2007
Web Sunucuya Dosya Gönderelim
Java ile yazdığınız sitede kullanıcıların dosya yüklemesini sağlamak için, gönderilen verinin akım olarak alınıp işlenmesi gerekir. J2EE henüz bu konuya yer vermemiş olduğundan ya kendiniz yazmalı, ki bu astarın yüzden pahalıya gelmesi demektir, ya da hazır bileşenleri kullanmalısınız. Bu kategorideki ürünleri incelediğimizde karşımıza ücretli ürünlerin yanısıra ücretsiz tek bir seçenek çıkıyor: Apache Commons FileUpload
Tabii ki büfemizin yapısı gereği incelediğimiz konu Commons FileUpload olsa da diğer bileşenleri de kısaca tanımakta fayda var. Ücretli olmalarının bazı getirileri de yok değil.
Alternatiflerden ilki servlets.com adresinde bulunan com.oreilly.servlet paketi. Bu paket ticari olmayan uygulamalar için ücretsiz; fakat para işin içine girince yazar projede geliştirme yapan herkesin kitabın (Java Servlet Programming) son halinin satın alınmış olmasını şart koşuyor, fakat pazarlık konusunda da açık kapı bırakıyor. Eğer pazarlık gücünüze güveniyorsanız e.posta adresi de lisans anlaşmasında bulunuyor. java manyaklari gönderdi derseniz size birşeyler yapabilir(FAQ sayfasinin sonunda da görüldüğü gibi bu tip şeyler programcılar arasında olur).
Ücretli bir diğer ürün ise www.javazoom.net sitesinde bulunan ve özellikleri ile göz dolduran UploadBean. UploadBean dosya limiti, karaliste, yükleme yapıldığında çalışan eklentiler (örneğin e.posta gönderen eklenti) gibi özellikler sunuyor, bunun yaninda neredeyse bütün servlet motorlarında testleri yapılmış, güvenli bir seçim olarak karşımıza çıkıyor. Profesyonel(bir sunucu-limitsiz işlemci) ve Kurumsal(limitsiz kullanım) sürümleri bulunuyor.
Ücretli başka bir bileşen de birçok yararlı etikete sahip olan dotj çatısı içinde bulunan dotj:upload etiketi. Bu etiket dosya limiti ve belirli dosya tiplerini yüklenmesine izin verme gibi özelliklere sahip ve tüm etiket kütüphanesine sahip olmak için ödenecek ücret sadece UploadBean Profesyonel için istenen ile aynı. Çatı içerisindeki diğer özellikler de ilginizi çekiyorsa ücretli ürünler arasında seçim kesinlikle bu olmalı.
Gelelim konumuz olan Commons FileUpload kütüphanesine. Tabii ki bu Apache ürününü kullanmak ücretsiz fakat olmazsa olmaz maksimum dosya boyutu dışında diğer ücretli ürünlerde olan özelliklerin hiçbiri yok. Eğer siz de fazlasına ne gerek var diyorsaniz örnegimize geçebiliriz.
Programlamaya başlamadan önce FileUpload paketinin ikili(binary)sürümünü jakarta commons sitesinden indirmemiz gerekiyor. Paket içinde az sayıda sınıf bulunuyor, hatta programımızı yazarken bizi ilgilendiren sadece 2 sınıf olacak. Bunlar DiskFileUpload ve arayüz olan FileItem sınıfları.
Manyak Not:
Makale yazıldığı zaman en son kararlı sürüm 1.0 idi, uzun süre de bu şekilde kalacak gibi görünüyor. Şu an geliştirilmekte olan sürümde birçok yeni sınıf geliyor ve servlet için de kullanılmak üzere yeni kodlar yazılmış durumda. DiskFileUpload ise kullanımdan kaldırılacak fakat sınıflar değişse de kullanım tarzı aynı kalacak.
Dosya yükleme işleminde unutulmaması gereken konu dosya gönderisinin kodlaması. Bunun için yükleme yapacağımız forma bakalım.
<form method="post" action="/upload" enctype="multipart/form-data"> <!-- enctype özelliğine dikkat --> <input type="text" name="text" /> <input type="file" name="file" /> <input type="submit" value="Gonder" /> </form>
Burada dikkat etmemiz gereken kısım formun enctype özelliği. Bu belirtilmediği zaman öntanımlı olarak application/x-www-form-urlencoded tipinde olur. Bunun anlamı gönderilen verinin
text=deneme&file=deneme.zip
şeklinde olmasıdır. Bu şekilde baktığımızda bir text alanı ile file alanı arasinda fark olmadığını ve sadece dosya adının gönderilmekte olduğunu görürüz.
multipart/form-data tipinde kodladığımızda ise veri
-----------------------------15559246345855 Content-Disposition: form-data; name="text" deneme -----------------------------15559246345855 Content-Disposition: form-data; name="file"; filename="deneme.zip" Content-Type: multipart/x-zip <ZIP dosya verisi>
gibi daha karışık bir formatta ve zip dosyasi içeriği de eklenerek gönderilir ki bu yapı e.posta mesajlarımızın içine komik resimler ya da gereksiz Powerpoint dosyalari gömmemizi sağlayan MIME(Multipurpose Internet Mail Extensions) formatıdır.
Kullanacağımız sınıfların iki tane olduğundan bahsetmiştik. Bunlardan ilki olan DiskFileUpload’ı kullanmak için her defasında bu sınıftan bir örnek yaratmamız gerekiyor. Bunun nedeni sınıfın thread-safe bir sınıf olduğunua dair bir belirti gerek java dökümanlarında gerekse kullanım kılavuzunda bulunmamasıdır.
Manyak Not:
Makale yazıldığı zaman FileUpload sitesinde bulunan program örnekleri son kararlı sürüm olan 1.0′a, java dökümanları ise o anda geliştirilmekte olan sürümün java dökümanlarıydı. Dolayısı ile bir tutarsızlık görülebilir.
DiskFile upload sınıfının parse metodu ile request parametresini işlemeden önce bazı parametreleri belirtmemiz gerekli. setMaxSize parametresi yükleme yapılırken yaklaşık olarak dosyanın boyutunun kaç byte olabileceğini belirtmek için kullanılıyor, eğer belirtilmemişse sınırsız boyutta dosya yüklenebilir anlamına geliyor. Dosya yüklenmesi sırasında setSizeThreshold ile belirtilen boyutu geçtiği anda diskte geçici olarak setRepositoryPath ile belirtilen dizine yazılıyor. Bu bilgiler ışığında örnek servletimizin doPost metodunu şu şekilde yazıyoruz.
DiskFileUpload fu;
fu = new DiskFileUpload();
fu.setSizeMax(20 * 1024 * 1024);
fu.setRepositoryPath("/home/vinnie/");
PrintWriter out = response.getWriter();
String text = null;
String filename = null;
parse metodu FileItem listesi döndürmektedir. Bir for döngüsü ile liste içindeki FileItem nesnelerini işlemeye başlıyoruz. Sınıf adı yanıltıcı olmasın, text alanına yazmış olduğumuz değer de bir FileItem olarak elde ediliyor. Farkı anlamak için isFormField metodunu kullanıyoruz. Form alanları ve dosyaların özelliklerini edinmek için farklı metodlar mevcut.
try {
List items = fu.parseRequest(request);
FileItem item;
for (int i=0; i<items.size(); i++) {
item = (FileItem) items.get(i);
if (item.isFormField()) {
if ("text".equals(item.getFieldName())) {
text = item.getString();
}
} else {
filename = item.getName();
File fp = new File(storageBase + filename);
item.write(fp);
}
}
out.println("girilen text alanı: '" + text + "' / file alanı: " + filename);
} catch (FileUploadBase.SizeLimitExceededException ex) {
out.println("Dosya boyutu en fazla 20 MB olabilir.");
} catch (FileUploadException ex) {
throw new ServletException(ex);
} catch (Exception ex) {
throw new ServletException(ex);
}
Manyak Not:
File Upload paketi henüz desteklemese de Java5.0′ın Generics özelliğini kullanarak yukarıdaki for döngüsü foreach döngüsü haline getirilebilir, bu hem sınıf tiplerinde hata yapılmasını engeller hem de kodu basitleştirir.
List<FileItem> items = fu.parseRequest(request);
for (FileItem item : items) {
..
}
FileItem gerçekten bir dosya ise FileItem sınıfının write metodu ile disk üzerinde saklamak istediğimiz yere yazıyoruz. Bir hata ile karşılaşılmadıysa text alanı ve dosya adları sayfamızda yerini alacak fakat boyut aşıldı ise hata mesajı görünecektir. Diğer hata durumlarında ise ServletException oluşacaktır.
Commons Upload paketi çok basit bir şekilde dosya yüklemesi yapmamızı sağladı, buna rağmen bu örnek daha da geliştirilmeye açıktır. Örneğin yüklenen dosya ile aynı dizinde, aynı ada sahip dosya varsa bunun üzerine yazacaktır. Bunu önlemek için önce aynı adlı dosyanın bulunup bulunmadığı kontrol edilebilir, ayrıca değişen ihtiyaçlar doğrultusunda maksimum dosya boyutunu değiştirmek istersek servlet sınıfını yeniden derlemiz gerekeceği açıktır. Bu değerin bir init parametresi yoluyla alınması daha uygun olur.
Daha fazla bilgi edinmek için Apache Jakarta Commons FileUpload sitesine başvurulabilir.
Hepimize afiyet olsun
——————–
Social Bookmarking
April 18th, 2008 at 9:30
merhabalar, bir sorum olacaktı bu kod firefox da çalışıyor fakat ie 6 ve ie 7 de çalışmıyor, bu konuda bir bilginiz var mı? veya bunun bir çözümü mevcut mu? kolay gelsin…
April 18th, 2008 at 10:17
selam Cagatay,
dosya ismini alırken ie ve firefox farklı davranır. Sanırım problemin ondan kaynaklı. File ismini duzgun parse etmen lazım.