Training

FileUpload ด้วย Servlet

20 Aug 2013

Servlet 3.0 ที่มากับ JavaEE 6 นั้น มีอยู่ฟีเจอร์หนึ่งที่น่าสนใจมาก นั่นก็คือการทำ File Uploading ครับ ฟีเจอร์นี้ทำให้การสร้างโปรแกรมสำหรับอัพโหลดไฟล์ง่ายขึ้นมากๆ แต่ทว่าการจะดาวน์โหลดไฟล์กลับไปใช้นั้น กลับไม่ใช่เรื่องง่ายเลย ดังนั้นวันนี้ผมจะมาพูดถึงฟีเจอร์ใหม่นี้ไปพร้อมๆกับการทำ Virtual Directories ใน Tomcat และ GlassFish เพื่อให้ได้โปรแกรมที่มีความสามารถทั้งการทำอัพโหลดและดาวน์โหลดไฟล์ได้ครับ ว่าแล้วก็ไปดูกันเลย

HTML Form สำหรับการอัพโหลดไฟล์

ผมขอเริ่มต้นบทความด้วยเรื่องของการเตรียมฟอร์มสำหรับให้ผู้ใช้เลือกไฟล์ที่จะอัพโหลดก่อนนะครับ โดยจะเริ่มต้นจากโครงสร้างพื้นฐานของ HTML Form ไปจนกระทั้งฟอร์มสำหรับอัพโหลดไฟล์ แน่นอนครับในการทำฟอร์ม เราย่อมต้องการแท็ก <form> โดยมีโครงสร้างดังนี้

<form action="url" method="GET|POST">
</form>

โดยที่ action ก็คือ URL ปลายทางที่เราจะส่งข้อมูลในฟอร์มไปประมวลผล ส่วน method คือวิธีการส่ง ซึ่งเราก็ส่งได้ทั้งแบบ GET และ POST (รายละเอียดความแตกต่างระหว่าง GET กับ POST ผมขอไม่พูดในบทความนี้นะครับ) เมื่อเราได้แท็ก <form> แล้ว ที่เหลือก็คือการเขียนแท็กคอนโทรล (Control Tags) ต่างๆ เช่น Textfield เป็นต้น ลงไปในแท็ก <form> ตัวอย่างเช่น

<form action="SomeServlet" method="POST">
  First Name: <input type="text" name="firstname" /><br/>
  Last Name: <input type="text" name="lastname" /><br/>
  <input type="submit" value="Submit" />
</form>

ตัวอย่างข้างต้นนี้เราสร้างฟอร์มแบบง่ายๆให้มีการกรอกชื่อและนามสกุลเท่านั้น เมื่อเรากดปุ่ม Submit ข้อมูลที่เรากรอกก็จะถูกส่งไปที่ SomeServlet ปลายทาง (ยังไม่มีอยู่จริงนะครับ) แต่สิ่งที่น่าสนใจสำหรับตัวอย่างนี้ก็คือรูปแบบ (Format) ที่มันถูกส่งออกไปครับ หากเราลองหาโปรแกรมมาตรวจสอบสิ่งที่ถูกส่งออกไป เช่น Firebug เราก็จะเห็นว่ามันมีรูปแบบดังนี้

firstname=James&lastname=P

เจ้ารูปแบบข้างต้นนี้ เราเรียกมันว่า Query String ซึ่งเป็นรูปแบบที่ใช้ในการสร้างฟอร์มทั่วๆไป แล้วผมมาพูดเท้าความถึงมันทำไม??? เพราะว่ารูปแบบนี้ใช้อัพโหลดไฟล์ไม่ได้นั่นเองครับ T__T ถ้าจะสร้างฟอร์มเพื่อให้อัพโหลดไฟล์ได้ เราจะต้องส่งข้อมูลในอีกรูปแบบหนึ่ง ซึ่งก็คือแบบ Multipart ครับ โดยในแท็ก <form> จะต้องมีรูปแบบดังนี้

<form enctype="multipart/form-data" action="url" method="GET|POST">
</form>

จากโค้ดข้างต้น เราเพิ่มแอททริบิวต์ (Attribute) enctype="multipart/form-data" เข้าไป เพื่อบอกกับเว็บเบราว์เซอร์ว่า ฟอร์มนี้ใช้วิธีการส่งแบบ Multipart ครับ งั้นมาลองดูตัวอย่างดัดแปลงจากตัวอย่างก่อนหน้านี้กัน

<form enctype="multipart/form-data" action="SomeServlet" method="POST">
  First Name: <input type="text" name="firstname" /><br/>
  Last Name: <input type="text" name="lastname" /><br/>
  <input type="submit" value="Submit" />
</form>

และเมื่อเราดูรูปแบบข้อมูลที่ถูกส่งออกไปด้วย Firebug ก็จะได้ดังนี้

-----------------------------1891129615599308875856648481 Content-Disposition: form-data; name="firstname" James
-----------------------------1891129615599308875856648481 Content-Disposition: form-data; name="lastname" P
-----------------------------1891129615599308875856648481--

เห็นไหมครับว่า มันคนละเรื่องกันเลย เอาหล่ะ เมื่อเราได้แท็ก <form> สำหรับทำอัพโหลดไฟล์แล้ว ที่เหลือก็คือแท็กสำหรับเลือกไฟล์ โดยมีโครงสร้างดังนี้

<input type="file" name="xxx" />

เมื่อได้ทุกอย่างแล้ว เรามาดูตัวอย่างรวมสำหรับทำอัพโหลดไฟล์ในบทความนี้กัน ดังนี้

ตัวอย่างที่ 1: Upload_Form.html
<!DOCTYPE html>
<html>
  <head>
    <title>Upload Form</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <h1>Upload Form</h1>
    <form enctype="multipart/form-data" action="UploadServlet" method="POST">
      Picture: <input type="file" name="picture" /><br/>
      Description: <input type="text" name="description" /><br/>
      <input type="submit" value="Upload" />
    </form>
  </body>
</html>

ตัวอย่างที่ 1 (Upload_Form.html) เป็นตัวอย่างแบบง่ายๆสำหรับการอัพโหลดรูปภาพพร้อมคำบรรยาย โดยมีเพียงสองคอนโทรลเท่านั้นคือ text และ file

ปล. เราสามารถทำฟอร์มแบบ Multipart ได้ แม้จะไม่มีคอนโทรลชนิด file ก็ตาม แต่ทว่าเราไม่นิยมทำกัน เพราะการดึงขัอมูลใน Servlet นั้นค่อนข้างยุ่งยากกว่าแบบปกติ

ปล. หากมีการใช้คอนโทรล file เราต้องใช้การส่งแบบ POST ด้วยนะครับ

Servlet สำหรับการอัพโหลดไฟล์

Servlet สำหรับการอัพโหลดไฟล์นั้น อันที่จริงก็มีโครงสร้างการเขียนที่เหมือนกับ Servlet โดยทั่วไป เพียงแต่ว่าวิธีการดึงข้อมูลที่ถูกส่งมาจากฟอร์มนั้นแตกต่างออกไปครับ (ดึงจากรูปแบบ Query String ย่อมไม่เหมือนกับการดึงจากรูปแบบ Multipart) สิ่งแรกที่เราจะต้องทำคือการตั้งค่า (Configure) ให้กับ Servlet เพื่อให้รองรับการดึงข้อมูลแบบ Multipart ครับ (อันนี้ผมแนะนำให้ทำก่อน เพราะลืมกันบ่อยๆ) โดยเราสามารถทำได้ทั้งแบบการใช้ XML ในไฟล์ web.xml หรือแบบการใช้ Annotation ฝังลงไปในโค้ด Servlet นั้นๆครับ เอาหล่ะมาดูแบบการใช้ XML ก่อน โดยมีโครงสร้างดังนี้

<servlet>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>sample.UploadServlet</servlet-class>
    <multipart-config>
      <location>/home/james/Desktop/images</location>
    </multipart-config>
</servlet>
<servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/UploadServlet</url-pattern>
</servlet-mapping>

ตัวอย่างข้างต้นเราเตรียมการตั้งค่าให้กับคลาส UploadServlet ที่เรากำลังจะสร้างขึ้นมา โดยใช้แท็ก <multipart-config> เพื่อบอกกับเซิร์ฟเวอร์ว่า คลาส UploadServlet นี้ รองรับโปรโตคอลรูปแบบ Multipart ส่วนแท็ก <location> ก็ไว้บอกไดเรกทอรี่ที่ใช้เก็บไฟล์ที่ถูกอัพโหลดมา และควรเป็น Absolute Path ด้วย เช่น ขึ้นต้นด้วย c:\ ใน Windows หรือ / ใน Unix-based เอาหล่ะทีนี้มาดูการตั้งค่าด้วย Annoatation บ้าง โดย Annoation ที่เราจะใช้คือ @MultipartConfig โดยมีโครงสร้างดังนี้

@MultipartConfig(location = "/home/james/Desktop/images")

โค้ดใน Annoation จะดูน้อยกว่าแบบ XML นะครับ เนื่องจากการตั้งค่า Servlet อื่นๆถูกยกไปไว้ Annoation อีกตัวหนึ่ง รายละเอียดจะสรุปรวมตอนท้ายอีกทีหนึ่งครับ เมื่อเราได้การตั้งค่าแล้ว คราวนี้เรามาดูการดึงข้อมูลจากรูปแบบ Multipart ขึ้นมาบ้าง โดยการดึงข้อมูลขึ้นมานั้นแบ่งออกเป็น 2 รูปแบบด้วยกัน คือ i) การดึงข้อมูลไฟล์ และ ii) การดึงข้อมูล Text อย่าลืมนะครับว่า ฟอร์มที่เราสร้างนอกจากจะให้เลือกไฟล์ได้แล้ว ยังมีส่วนที่เป็น Text ให้กรอกอีกด้วย งั้นเรามาดูการดึงข้อมูลไฟล์กันก่อน โดยมีรายละเอียดดังนี้

Part picturePart = request.getPart("picture");
picturePart.write("picture1.png");

ตัวอย่างข้างต้นเราดึงข้อมูลในส่วน (Part) ของรูปภาพขึ้นมา จากนั้นเราก็บันทึกลงไปในไดเรกทอรี่ที่เราตั้งค่าไว้ก่อนหน้านี้ เห็นมั้ยครับไม่ยากเลย แต่!!! แต่ชื่อรูปนี่ซิตัวปัญหาเลย เพราะ Servlet มันดันไม่มี API สำหรับดึงชื่อรูปซะงั้น?!!! ถ้าเราสามารถตั้งชื่อเองได้ก็จบไป แต่ถ้าเราต้องใช้ชื่อเดิมที่ถูกส่งออกมาจากเว็บเบราว์เซอร์ล่ะก็ ต้องเขียนโค้ดเพิ่มกันอีกซักนิดครับ เราต้องรู้ก่อนว่า เมื่อข้อมูลไฟล์ถูกส่งมา มันมีชื่อติดมาด้วย ดังเช่นตัวอย่างต่อไปนี้

-----------------------------141303705117508355362109524228 
Content-Disposition: form-data; name="picture"; filename="alice.png"
Content-Type: image/png PNG ��� IHDR���–���–���<q?���bKGD�?�?�? ??“��� pHYs�� ?�� ?B(›x���tIME? 58‰ �� �IDATx??wx“????I?&M??{?E m??ldˆ ?p!*.DNP@A”?8????^…???{e?$ ?@G’–?|?+\Mrrž?|Ÿ?

ปล. ส่วนที่เหลือของไฟล์ถูกตัดทิ้งนะครับ

เห็นไหมครับ มันมีชื่อไฟล์ติดมากับ Part ด้วย อยู่ในพร็อพเพอร์ตี้ Content-Disposition ดังนั้นเราจะดึงมันขึ้นดัวยโค้ดดังต่อไปนี้

String pictureName = "";
for (String cd : part.getHeader("content-disposition").split(";")) {
  if (cd.trim().startsWith("filename")) {
    pictureName = cd.substring(cd.indexOf('=') + 1).trim().replace("\"", "");
  }
}

เพียงเท่านี้เราก็ได้ชื่อรูปเอาไปใช้ตั้งชื่อไฟล์แล้ว ทีนี้เรามาดูวิธีการดึงข้อมูลชนิด Text ขึ้นมาบ้าง โดยมีรายละเอียดดังนี้

Part descriptionPart = request.getPart("description");
BufferedReader r = new BufferedReader(new InputStreamReader(descriptionPart.getInputStream()));
String description = r.readLine();

จะเห็นได้ว่าการเขียนโค้ดค่อนข้างยุ่งยากแต่ไม่ถึงกับยากนะครับ อ้าว แล้วถ้ามีการอัพโหลดไฟล์ได้ทีละหลายๆไฟล์และมีข้อมูลชนิด Text มากๆหล่ะ การเขียนโค้ดคงจะเยิ่นเย้อน่าดู ถ้าอย่างนั้นเรามาทำเป็นเมธอดสำหรับเก็บไว้เรียกใช้เพื่อความสะดวกกันดีกว่า ตัวอย่างที่ 2 (UploadServlet.java) แสดงโค้ดรวมทั้งหมดพร้อมทั้งการประยุกต์โค้ดในลักษณะเมธอดด้วย

ตัวอย่างที่ 2: UploadServlet.java
package sample;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@WebServlet(name = "UploadServlet", urlPatterns = {"/UploadServlet"})
@MultipartConfig(location = "/home/james/Desktop/images")
public class UploadServlet extends HttpServlet {

  protected void doPost(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {

    request.setCharacterEncoding("UTF-8");
    response.setCharacterEncoding("UTF-8");

    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();

    Part picturePart = request.getPart("picture");
    String pictureName = this.getFileName(picturePart);
    picturePart.write(pictureName);
    picturePart.delete();

    Part descriptionPart = request.getPart("description");
    String description = this.getStringFromPart(descriptionPart);

    out.println("We have received: " + pictureName + "<br/>");
    out.println("With this description: " + description);

    out.close();

  } // end of doPost()

  private String getStringFromPart(Part part) throws IOException {
    BufferedReader r = new BufferedReader(new InputStreamReader(part.getInputStream()));
    return r.readLine();
  } // end of getStringFromPart()

  private String getFileName(Part part) {
    for (String cd : part.getHeader("content-disposition").split(";")) {
      if (cd.trim().startsWith("filename")) {
        return cd.substring(cd.indexOf('=') + 1).trim()
                .replace("\"", "");
      }
    }
    return null;
  } // end of getFileName()
}

คำสั่ง picturePart.delelte() หรือ Part.delete() ใช้สำหรับเคลียร์ Temporary ไฟล์ต่างๆที่ Server อาจสร้างขึ้นได้ครับ เช่นในกรณีของ GlassFish เท่านี้เราก็ได้ Servlet สำหรับการอัพโหลดไฟล์แล้ว ^__^ ในหัวข้อถัดไปเราจะมาดูการทำดาวน์โหลดไฟล์บ้าง

Virtual Directories ใน Tomcat และ GlassFish

ในหัวข้อที่ผ่านมา ถ้าเราสังเกตให้ดีเราจะเห็นว่า เราเลือกบันทึกไฟล์ลงในไดเรกทอรี่นอกเว็บแอพพลิเคชันของเรา (ของผมเป็น /home/james/Desktop/images) ถ้าเช่นนั้นหากเราจะดึงมันมาใช้ในเว็บของเรา เช่นผ่านแท็ก <img> เราจะระบุแอททริบิวต์ src อย่างไร? ถ้าอย่างนั้นทำไมเราไม่บันทึกไฟล์อัพโหลดลงในไดเรกทอรี่ภายใต้เว็บแอพพลิเคชันของเราหล่ะ? คำตอบคือไม่ควรทำและทำไม่ได้ครับ ทั้งนี้เพราะถ้าเรา Re-Deploy ระบบใหม่ ไฟล์เหล่านั้นจะหายไปทันที ถูกไหมครับ เพราะเรา Deploy ด้วยไฟล์ .war และนอกจากนี้เรายังไม่รู้ด้วยซ้ำว่าเมื่อ Deploy แล้ว Server แต่ละยี่ห้อมัน Deploy ที่ไดเรกทอรี่ไหนกันแน่ (ถึงเราจะหาจนเจอ เราก็ไม่ควรไป Re-Deploy แบบแปะทับแบบนั้น เพราะจะทำให้เกิดปัญหาในภายหลังได้) แล้วทางแก้คืออะไร? อันที่จริงก็มีทางแก้ไขอยู่หลายวิธีด้วยกัน ทั้งนี้ทั้งนั้นขึ้นอยู่กับลักษณะการใช้งานด้วย โดยเราอาจเขียน Servlet สำหรับอ่านไฟล์ขึ้นมาผ่าน I/O ก็ได้ เทคนิคนี้เหมาะกับการที่เราให้ผู้ใช้ดาวน์โหลดไฟล์ได้บางกรณีเท่านั้น หรือตรวจสอบสิทธิ์ก่อนดาวน์โหลดไฟล์ อาทิเช่น Login เข้ามาแล้วเท่านั้น หรือเป็นผู้ใช้ที่เป็นเจ้าของไฟล์จริงๆ เป็นต้น แต่หากเราอยากให้ไฟล์เหล่านั้น เปิดเป็น Public สามารถเข้าถึงได้ทุกคน หรือเข้าถึงได้ทุกคนที่ Login แล้ว (อ้างผ่านแท็ก <img> ได้เหมือนปกติ) เราสามารถทำ Virtual Directories เพื่อแมพ (Map) กับไดเรกทอรี่ที่เราใช้เก็บไฟล์อัพโหลดของเราได้ครับ ยกตัวอย่างเช่น

→ http://localhost:8080/SampleApp/images/alice.png → /home/james/Desktop/images/alice.png

ตัวอย่างข้างต้นนี้ SampleApp คือชื่อ Context Root ของเรา (หรือคุณจะใช้ชื่ออื่นก็ได้) และหากมีรีเควสต์เข้ามาที่ /SampleApp/images/ ก็ให้ไปหยิบไฟล์ที่ /home/james/Desktop/images/ อย่างไรก็ตามการทำ Virtual Directories นั้น แตกต่างกันไปตามแต่ละ Server มีการตั้งค่าไม่เหมือนกัน ในบทความนี้ผมจะพูดถึงการตั้งค่าใน Tomcat และ GlassFish ครับ

การทำ Virtual Directories ใน Tomcat

ใน Tomcat เราต้องสร้างไฟล์ XML ขึ้นมา โดยมีรูปแบบการตั้งชื่อดังนี้

ContextRoot#folderName.xml

โดยที่ ContextRoot คือชื่อ Context Root ของเว็บแอพพลิเคชันของเรา และ folderName คือชื่อไดเรกทอรี่เสมือนที่อยู่ภายใต้เว็บแอพพลิเคชันของเรา และควรให้ชื่อตรงกับที่ใช้เก็บไฟล์อัพโหลดด้วย เพื่อป้องกันปัญหายุ่งยากในการตั้งค่ากับ Server จากค่ายต่างๆ ในกรณีของเราก็จะได้ไฟล์ดังนี้ครับ

SampleApp#images.xml

อย่าลืมว่า Java นี่ตัวอักษรพิมพ์เล็กพิมพ์ใหญ่มีผลแตกต่างด้วยนะครับ ทีนี้ภายในไฟล์ก็ให้เขียนโค้ดดังต่อไปนี้ลงไป

<Context docBase="/home/james/Desktop/images"></Context>

จากนั้นให้บันทึกไฟล์นี้ลงไปในไดเรกทอรี่ที่เราติดตั้ง Tomcat โดยบันทึกไว้ภายใต้ไดเรกทอรี่ดังต่อไปนี้

[TOMCAT_HOME]/conf/Catalina/localhost

โดยที่ [TOMCAT_HOME] ก็คือไดเรกทอรี่ที่เราติดตั้ง Tomcat ครับ หากคุณเพิ่งติดตั้ง Tomcat ใหม่ โดยยังไม่เคยสตาร์ท Tomcat คุณจะไม่เห็นไดเรกทอรี่ Catalina นอกจากนี้หากคุณเขียนโค้ดผ่าน IDE เช่น NetBeans คุณจะไปบันทึกไฟล์ที่ไดเรกทอรี่ข้างต้นไม่ได้ เพราะ IDE มักจะใช้ไฟล์ Configuration สำหรับ Tomcat แยกต่างหาก ในกรณีของ NetBeans ให้เข้าไปดูว่ามันใช้ไฟล์ Configuration และไดเรกทอรี่ใด โดยไปที่ Tools → Servers → Apache Tomcat → Connection Tab และดูที่ Catalina Base จากนั้นให้บันทึกไฟล์ SampleApp#images.xml ไว้ภายใต้ไดเรกทอรี่นั้นตามนี้ครับ

[CATALINA_BASE]/conf/Catalina/localhost

การทำ Virtual Directories ใน GlassFish

ต่อไปเรามาดูการตั้งค่าใน GlassFish กันบ้าง สำหรับ GlassFish เราต้องสร้างไฟล์ glassfish-web.xml ขึ้นมา (ในเวอร์ชันเก่าๆใช้ชื่อ sun-web.xml ครับ - ก่อน Oracle ซื้อไป) โดยเขียนโค้ดลงไปตามนี้

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
  <class-loader delegate="true"/>
  <jsp-config>
    <property name="keepgenerated" value="true">
      <description>Keep a copy of the generated servlet class' java code.</description>
    </property>
  </jsp-config>
  <property name="alternatedocroot_1" value="from=/images/* dir=/home/james/Desktop">
  </property>
</glassfish-web-app>

โปรดสังเกตที่ผมทำตัวหนาไว้นะครับ นั่นแหละคือการตั้งค่าที่จำเป็นในการทำ Virtual Directories ครับ (แท็กอื่นๆ NetBeans สร้างให้โดยอัตโนมัติครับ อาจจะลบทิ้งได้ ซึ่งผมไม่แน่ใจ) โดยมีรายละเอียดที่สำคัญดังต่อไปนี้

  • แอททริบิวต์ name ต้องมีค่าเป็น alternatedocroot_X เท่านั้น โดยที่ X คือเลข Running No. 1, 2, 3, 4 . . .
  • การกำหนดค่าในแอททริบิวต์ value แยกออกเป็นสองส่วนย่อยด้วยช่องว่าง โดยแบ่งออกเป็นส่วนของ from และ dir ใน from ให้กำหนด Path เสมือนในเว็บของเรา และต้องเริ่มต้น Path ด้วย / ซึ่งก็คือ Context Root ครับ อีกทั้งชื่อไดเรกทอรี่เสมือนนี้ต้องใช้ชื่อเดียวกับที่มีตัวตนอยู่จริงในไดเรกทอรี่เก็บไฟล์อัพโหลดด้วย ส่วน dir บอก Path ไปยังไดเรกทอรี่ (โปรดสังเกตนะครับว่าลงท้ายแค่ Desktop)

จากนั้นก็ให้เราบันทึกไฟล์ glassfish-web.xml ไว้ในไดเรกทอรี่ WEB-INF เป็นอันจบครับ อ้อ หากคุณใช้ NetBeans ก็ให้มันสร้างไฟล์ขึ้นมาให้เราเองได้ครับ โดยไปที่ File → New File → GlassFish แล้วเลือก GlassFish Descriptor นะครับ จากนั้นก็เพิ่มแท็กที่จำเป็นเข้าไป

ปล. ถึงเราจะทำ Virtual Directories เราก็สามารถกำหนดสิทธิ์ในการเข้าถึงไฟล์ที่อัพโหลดต่างๆได้ เช่น แยกไดเรกทอรี่ย่อยสำหรับแต่ละผู้ใช้ แล้วสร้าง Filter ขึ้นมาเพื่อตรวจสอบสิทธิ์ โดยตรวจสอบว่า Username ตรงกับชื่อไดเรกทอรี่ย่อยหรือไม่ เป็นต้น แต่ในกรณีนี้การบันทึกไฟล์จำเป็นต้องเขียนโค้ด I/O เองนะครับ ใช้ Part.write() ไม่ได้ !!! เพราะต้องเก็บแยกย่อย หรือจะเก็บชื่อไฟล์และตรวจสอบสิทธิ์ผ่านระบบฐานข้อมูลก็ได้เช่นกันครับ แล้วแต่จะประยุกต์

File Listing Servlet

เมื่อเราทำ Virtual Directories ได้เรียบร้อยแล้ว คราวนี้เราจะมาดูการนำเอาไฟล์ในไดเรกทอรี่ที่เก็บไฟล์อัพโหลดมาใช้บ้าง โดยเราจะลิสท์รายชื่อไฟล์ทั้งหมดที่มีและทำเป็นลิงค์เอาไว้ดังแสดงในตัวอย่างที่ 3 (FileListServlet.java)

ตัวอย่างที่ 3: FileListServlet.java
package sample;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "FileListServlet", urlPatterns = {"/FileListServlet"})
public class FileListServlet extends HttpServlet {

  protected void doGet(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();

    // Directory path here
    String path = "/home/james/Desktop/images";

    String fileName;
    File folder = new File(path);
    File[] listOfFiles = folder.listFiles();

    for (int i = 0; i < listOfFiles.length; i++) {

      if (listOfFiles[i].isFile()) {
        fileName = listOfFiles[i].getName();
        out.println("<a href='/SampleApp/images/" + fileName + "'>" + fileName + "</a><br/>" );
      }
    }

  } // end of doGet()
}

รูปที่ 1, 2, และ 3 แสดงตัวอย่างการรันเว็บแอพพลิเคชันนี้ อ้อ อย่าลืมสร้างหน้า index ด้วยนะครับ เวลารันจะได้เรียกใช้ง่ายๆ

รูปที่ 1: หน้า index
รูปที่ 2: หน้าฟอร์มสำหรับการอัพโหลดไฟล์
รูปที่ 3: หน้าลิสท์รายชื่อไฟล์ในไดเรกทอรี่ที่ใช้เก็บไฟล์อัพโหลด

จบแล้วนะครับกับการทำไฟล์อัพโหลดและการทำ Virtual Direcotories เพื่อเข้าถึงไฟล์ที่ได้อัพโหลดมา ไม่ยากเกินไปใช่ไหมครับ ลองเอาไปประยุกต์ดัดแปลงกับงานของคุณดู ขอให้สนุกกับการเขียน Java นะครับ ^^


Books By Me

JavaScript Programming Guide book cover

JavaScript Programming Guide
Thai language
Kontentblue Publishing

About This Site

I use this site to share my knowledge in form of articles. I also use it as an experimental space, trying and testing things. If you have any problems viewing this site, please tell me.

→ More about me

→ Contact me

→ Me on facebook

Creative Commons Attribution License

creative commons logo

This license lets you distribute, remix, tweak my articles, even commercially, as long as you credit me for the original creation.

ด้วยสัญญาอนุญาตินี้ คุณสามารถเผยแพร่ ดัดแปลง แก้ไขและนำบทความของผมไปใช้ แม้ในเชิงธุรกิจ ตราบใดที่คุณได้อ้างอิงกลับมาและให้เครดิตกับผม