জেএসএফ ব্যাকিং শিম থেকে একটি ফাইল ডাউনলোড কীভাবে সরবরাহ করবেন?


91

জেএসএফ ব্যাকিং শিম ক্রিয়া পদ্ধতি থেকে কোনও ফাইল ডাউনলোড সরবরাহের কোনও উপায় আছে কি? আমি অনেক চেষ্টা করেছি। প্রধান সমস্যাটি হ'ল OutputStreamফাইলের বিষয়বস্তুটিতে লেখার জন্য প্রতিক্রিয়াটি কীভাবে পাওয়া যায় তা আমি বুঝতে পারি না । এটিকে কীভাবে করবেন তা আমি জানি Servletতবে এটি জেএসএফ ফর্ম থেকে আহ্বান করা যায় না এবং এর জন্য একটি নতুন অনুরোধ প্রয়োজন।

আমি কীভাবে OutputStreamবর্তমান থেকে প্রতিক্রিয়া পেতে পারি FacesContext?

উত্তর:


238

ভূমিকা

আপনি সব মাধ্যমে পেতে পারেন ExternalContext। জেএসএফ 1.x এ আপনি কাঁচা HttpServletResponseবস্তুটি পেতে পারেন ExternalContext#getResponse()। জেএসএফ ২.x এ, আপনি জেএসএফ হুডের অধীনে থেকে ExternalContext#getResponseOutputStream()দখল HttpServletResponseগ্রহণের প্রয়োজন ছাড়াই নতুন প্রতিনিধি পদ্ধতির গুচ্ছ ব্যবহার করতে পারেন ।

প্রতিক্রিয়ায়, আপনার শিরোনামটি সেট করা উচিত Content-Typeযাতে ক্লায়েন্ট জানে যে সরবরাহিত ফাইলটির সাথে কোন অ্যাপ্লিকেশনটি সংযুক্ত করতে হবে। এবং, আপনার Content-Lengthশিরোনাম সেট করা উচিত যাতে ক্লায়েন্টটি ডাউনলোডের অগ্রগতি গণনা করতে পারে, অন্যথায় এটি অজানা। এবং, আপনি যেমন সংরক্ষণ করুন ডায়ালগ চান তবে আপনাকে Content-Dispositionশিরোনামটি সেট করা উচিত , অন্যথায় ক্লায়েন্টটি ইনলাইনটি প্রদর্শন করার চেষ্টা করবে। পরিশেষে কেবল প্রতিক্রিয়া আউটপুট প্রবাহে ফাইল সামগ্রী লিখুন।attachment

সর্বাধিক গুরুত্বপূর্ণ অংশটি FacesContext#responseComplete()জেএসএফকে জানাতে ফোন করা হয়েছে যে আপনি প্রতিক্রিয়াতে ফাইলটি লিখে দেওয়ার পরে এটি নেভিগেশন এবং রেন্ডারিং করা উচিত নয়, অন্যথায় প্রতিক্রিয়াটির শেষ পৃষ্ঠার এইচটিএমএল সামগ্রী বা পুরানো জেএসএফ সংস্করণগুলিতে দূষিত হয়ে যাবে , আপনি যখন জেএসএফ বাস্তবায়ন এইচটিএমএল রেন্ডার করার জন্য কল করেন তখন আপনি IllegalStateExceptionএকটি বার্তা সহ একটি পাবেন ।getoutputstream() has already been called for this responsegetWriter()

এজ্যাক্স বন্ধ করুন / রিমোট কমান্ড ব্যবহার করবেন না!

আপনি শুধুমাত্র নিশ্চিত যে কর্ম পদ্ধতি করতে হবে না একটি AJAX অনুরোধ ডাকা, কিন্তু এটা একটি স্বাভাবিক অনুরোধ ডাকা করছেন যে শুধু আগুন <h:commandLink>এবং <h:commandButton>। অ্যাজাক্স অনুরোধগুলি এবং রিমোট কমান্ডগুলি জাভাস্ক্রিপ্ট দ্বারা পরিচালিত হয় যা সুরক্ষার কারণে, এজ্যাক্স প্রতিক্রিয়াটির বিষয়বস্তুর সাথে কথোপকথন হিসাবে সংরক্ষণের জন্য বাধ্য করার মতো কোনও সুবিধা নেই ।

আপনি যদি উদাহরণস্বরূপ প্রাইমফ্রিজ ব্যবহার করছেন <p:commandXxx>তবে আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপনি স্পষ্টরূপে ajax="false"অ্যাট্রিবিটের মাধ্যমে এজাক্স বন্ধ করে দিয়েছেন। আপনি যদি আইসিইফেস ব্যবহার করছেন <f:ajax disabled="true" />তবে কমান্ড উপাদানটিতে আপনাকে বাসা বাঁধতে হবে ।

জেনেরিক জেএসএফ 2.x উদাহরণ

public void download() throws IOException {
    FacesContext fc = FacesContext.getCurrentInstance();
    ExternalContext ec = fc.getExternalContext();

    ec.responseReset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide.
    ec.setResponseContentType(contentType); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ExternalContext#getMimeType() for auto-detection based on filename.
    ec.setResponseContentLength(contentLength); // Set it with the file size. This header is optional. It will work if it's omitted, but the download progress will be unknown.
    ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); // The Save As popup magic is done here. You can give it any file name you want, this only won't work in MSIE, it will use current request URL as file name instead.

    OutputStream output = ec.getResponseOutputStream();
    // Now you can write the InputStream of the file to the above OutputStream the usual way.
    // ...

    fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}

জেনেরিক জেএসএফ 1.x উদাহরণ

public void download() throws IOException {
    FacesContext fc = FacesContext.getCurrentInstance();
    HttpServletResponse response = (HttpServletResponse) fc.getExternalContext().getResponse();

    response.reset(); // Some JSF component library or some Filter might have set some headers in the buffer beforehand. We want to get rid of them, else it may collide.
    response.setContentType(contentType); // Check http://www.iana.org/assignments/media-types for all types. Use if necessary ServletContext#getMimeType() for auto-detection based on filename.
    response.setContentLength(contentLength); // Set it with the file size. This header is optional. It will work if it's omitted, but the download progress will be unknown.
    response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); // The Save As popup magic is done here. You can give it any file name you want, this only won't work in MSIE, it will use current request URL as file name instead.

    OutputStream output = response.getOutputStream();
    // Now you can write the InputStream of the file to the above OutputStream the usual way.
    // ...

    fc.responseComplete(); // Important! Otherwise JSF will attempt to render the response which obviously will fail since it's already written with a file and closed.
}

সাধারণ স্ট্যাটিক ফাইল উদাহরণ

স্থানীয় ডিস্ক ফাইল সিস্টেম থেকে আপনার যদি কোনও স্ট্যাটিক ফাইল প্রবাহিত করতে হয় তবে নীচের মত কোডটি বিকল্পে রাখুন:

File file = new File("/path/to/file.ext");
String fileName = file.getName();
String contentType = ec.getMimeType(fileName); // JSF 1.x: ((ServletContext) ec.getContext()).getMimeType(fileName);
int contentLength = (int) file.length();

// ...

Files.copy(file.toPath(), output);

সাধারণ গতিশীল ফাইল উদাহরণ

যদি আপনাকে গতিশীলভাবে উত্পন্ন ফাইল যেমন পিডিএফ বা এক্সএলএস স্ট্রিমের দরকার হয় তবে কেবল outputসেখানে সরবরাহ করতে হবে যেখানে ব্যবহৃত এপিআই এর প্রত্যাশা করে OutputStream

যেমন আইটেক্সট পিডিএফ:

String fileName = "dynamic.pdf";
String contentType = "application/pdf";

// ...

Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, output);
document.open();
// Build PDF content here.
document.close();

উদাঃ অ্যাপাচি পিওআই এইচএসএসএফ:

String fileName = "dynamic.xls";
String contentType = "application/vnd.ms-excel";

// ...

HSSFWorkbook workbook = new HSSFWorkbook();
// Build XLS content here.
workbook.write(output);
workbook.close();

মনে রাখবেন আপনি এখানে সামগ্রীর দৈর্ঘ্য সেট করতে পারবেন না। সুতরাং প্রতিক্রিয়া সামগ্রীর দৈর্ঘ্য সেট করতে আপনাকে লাইনটি সরিয়ে ফেলতে হবে। এটি প্রযুক্তিগতভাবে কোনও সমস্যা নয়, একমাত্র অসুবিধাটি হ'ল এন্ডুয়েসারকে একটি অজানা ডাউনলোড অগ্রগতি উপস্থাপন করা হবে। যদি এটি গুরুত্বপূর্ণ হয় তবে আপনাকে প্রথমে একটি স্থানীয় (অস্থায়ী) ফাইল লিখতে হবে এবং তারপরে এটি পূর্ববর্তী অধ্যায়ে বর্ণিতভাবে সরবরাহ করতে হবে।

ইউটিলিটি পদ্ধতি

আপনি JSF ইউটিলিটি লাইব্রেরি ব্যবহার করেন, তাহলে OmniFaces , তাহলে আপনি তিনটি সুবিধাজনক একটি ব্যবহার করতে পারেন Faces#sendFile()হয় একটি গ্রহণ পদ্ধতি File, অথবা একটি InputStream, অথবা একটি byte[], এবং উল্লেখ কিনা ফাইল একটি সংযুক্তি (যেমন ডাউনলোড করা উচিত true) অথবা ইনলাইন ( false)।

public void download() throws IOException {
    Faces.sendFile(file, true);
}

হ্যাঁ, এই কোডটি যেমন রয়েছে তেমন সম্পূর্ণ। আপনার responseComplete()নিজের উপর অনুরোধ করার প্রয়োজন নেই । এই পদ্ধতিটি আইই-নির্দিষ্ট হেডারের সাথে এবং ইউটিএফ -8 ফাইলের নামগুলিও যথাযথভাবে ডিল করে। আপনি এখানে সোর্স কোড খুঁজে পেতে পারেন ।


4
খুব সহজ! আমি কিভাবে ডাউনলোড তাদের শোকেস অনুযায়ী PrimeFaces উপলব্ধ করার জন্য আমরা, কারণ এটি প্রয়োজন হতাশ করে থাকেন InputStreamজন্য পরিকাঠামো p:fileDownload, এবং আমি রূপান্তর করতে কিভাবে পরিচালিত করেন নি OutputStreamকরার InputStream। এখন এটি পরিষ্কার হয়ে গেছে যে এমনকি কোনও অ্যাকশন শ্রোতা প্রতিক্রিয়া সামগ্রীটির ধরন পরিবর্তন করতে পারে এবং তারপরে প্রতিক্রিয়াটিকে কোনওভাবেই ব্যবহারকারী-এজেন্টের পক্ষ থেকে ফাইল ডাউনলোড হিসাবে সম্মান করা হবে। ধন্যবাদ!
লাইবুমায়ার শায়দারিভ

4
এইচটিটিপি পোস্টের (এইচ: কমান্ডবটন এবং এইচ: কমান্ডলিংক) পরিবর্তে এইচটিটিপি জিইটি ব্যবহার করে কী করার কোনও উপায় আছে?
আলফ্রেডো ওসোরিও

@ অ্যালফ্রেডো: হ্যাঁ, preRenderViewমার্কআপবিহীন দৃশ্যে শ্রোতাদের ব্যবহার । : (ভাল, ভজনা) ডাউনলোড তাদেরকে JSON উত্তর এখানে দেওয়া হয় একই প্রশ্ন stackoverflow.com/questions/8358006/...
BalusC

w3schools.com/media/media_mimeref.asp লিঙ্কটি নষ্ট হয়ে গেছে। : হয়তো এই এক উপযুক্ত iana.org/assignments/media-types
Zakhar

4
@ বালাসসি আপনি প্রতিটি জেএসএফের বিষয় কভার করেছেন - আমার জীবনকে আরও সহজ করার জন্য আপনাকে ধন্যবাদ স্যার!
বাটিংগার জাভের

5
public void download() throws IOException
{

    File file = new File("file.txt");

    FacesContext facesContext = FacesContext.getCurrentInstance();

    HttpServletResponse response = 
            (HttpServletResponse) facesContext.getExternalContext().getResponse();

    response.reset();
    response.setHeader("Content-Type", "application/octet-stream");
    response.setHeader("Content-Disposition", "attachment;filename=file.txt");

    OutputStream responseOutputStream = response.getOutputStream();

    InputStream fileInputStream = new FileInputStream(file);

    byte[] bytesBuffer = new byte[2048];
    int bytesRead;
    while ((bytesRead = fileInputStream.read(bytesBuffer)) > 0) 
    {
        responseOutputStream.write(bytesBuffer, 0, bytesRead);
    }

    responseOutputStream.flush();

    fileInputStream.close();
    responseOutputStream.close();

    facesContext.responseComplete();

}

3

এটিই আমার পক্ষে কাজ করেছে:

public void downloadFile(String filename) throws IOException {
    final FacesContext fc = FacesContext.getCurrentInstance();
    final ExternalContext externalContext = fc.getExternalContext();

    final File file = new File(filename);

    externalContext.responseReset();
    externalContext.setResponseContentType(ContentType.APPLICATION_OCTET_STREAM.getMimeType());
    externalContext.setResponseContentLength(Long.valueOf(file.lastModified()).intValue());
    externalContext.setResponseHeader("Content-Disposition", "attachment;filename=" + file.getName());

    final HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

    FileInputStream input = new FileInputStream(file);
    byte[] buffer = new byte[1024];
    final ServletOutputStream out = response.getOutputStream();

    while ((input.read(buffer)) != -1) {
        out.write(buffer);
    }

    out.flush();
    fc.responseComplete();
}

4
2 কার্যদিবসের পরে, এটি আমার সমস্যাটিকে কিছুটা পরিবর্তন দিয়ে সমাধান করেছে :) আপনাকে অনেক ধন্যবাদ।
Tএমআর টিএসিসিআই

@ ER মিরতাŞসিআই: কী পরিবর্তন হয়
কুকল্টজে

-3

এখানে সম্পূর্ণ কোড স্নিপেট http://bharatonjava.wordpress.com/2013/02/01/downloading-file-in-jsf-2/

 @ManagedBean(name = "formBean")
 @SessionScoped
 public class FormBean implements Serializable
 {
   private static final long serialVersionUID = 1L;

   /**
    * Download file.
    */
   public void downloadFile() throws IOException
   {
      File file = new File("C:\\docs\\instructions.txt");
      InputStream fis = new FileInputStream(file);
      byte[] buf = new byte[1024];
      int offset = 0;
      int numRead = 0;
      while ((offset < buf.length) && ((numRead = fis.read(buf, offset, buf.length -offset)) >= 0)) 
      {
        offset += numRead;
      }
      fis.close();
      HttpServletResponse response =
         (HttpServletResponse) FacesContext.getCurrentInstance()
        .getExternalContext().getResponse();

     response.setContentType("application/octet-stream");
     response.setHeader("Content-Disposition", "attachment;filename=instructions.txt");
     response.getOutputStream().write(buf);
     response.getOutputStream().flush();
     response.getOutputStream().close();
     FacesContext.getCurrentInstance().responseComplete();
   }
 }

আপনি রানটাইমের সময় ফাইলটি তৈরি করতে চান এমন ক্ষেত্রে আপনি ফাইল পড়ার যুক্তি পরিবর্তন করতে পারেন।


এটি কেবলমাত্র ইনপুট ফাইলের অংশ পাবে, যদি এটির চেয়ে বড় এটি 1024 বাইট হয়!
hinneLinks
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.