java - تنزيل ملف من وحدات التحكم في الربيع




spring file download controller (9)

كنت قادراً على دفق هذا الخط باستخدام الدعم المضمّن في الربيع مع ResourceHttpMessageConverter. سيؤدي ذلك إلى ضبط طول المحتوى ونوع المحتوى إذا كان يمكنه تحديد نوع المايم

@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
@ResponseBody
public FileSystemResource getFile(@PathVariable("file_name") String fileName) {
    return new FileSystemResource(myService.getFileFor(fileName)); 
}

لدي متطلبات حيث أحتاج إلى تنزيل ملف PDF من موقع الويب. يجب إنشاء ملف PDF داخل الكود ، والذي اعتقدت أنه سيكون مزيجًا من freemarker وإطار إنشاء PDF مثل iText. أي طريقة أفضل؟

ومع ذلك ، فإن مشكلتي الرئيسية هي كيف أسمح للمستخدم بتنزيل ملف من خلال جهاز التحكم في الربيع؟


يجب أن تكون قادراً على كتابة الملف على الاستجابة مباشرة. شيء مثل

response.setContentType("application/pdf");      
response.setHeader("Content-Disposition", "attachment; filename=\"somefile.pdf\""); 

ثم اكتب الملف كدفق ثنائي على response.getOutputStream() . تذكر أن تفعل response.flush() في النهاية والتي ينبغي أن تفعل ذلك.


عملت أدناه رمز لي لتوليد وتنزيل ملف نصي.

@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity<byte[]> getDownloadData() throws Exception {

    String regData = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";
    byte[] output = regData.getBytes();

    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.set("charset", "utf-8");
    responseHeaders.setContentType(MediaType.valueOf("text/html"));
    responseHeaders.setContentLength(output.length);
    responseHeaders.set("Content-disposition", "attachment; filename=filename.txt");

    return new ResponseEntity<byte[]>(output, responseHeaders, HttpStatus.OK);
}

@RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
public void getFile(
    @PathVariable("file_name") String fileName, 
    HttpServletResponse response) {
    try {
      // get your file as InputStream
      InputStream is = ...;
      // copy it to response's OutputStream
      org.apache.commons.io.IOUtils.copy(is, response.getOutputStream());
      response.flushBuffer();
    } catch (IOException ex) {
      log.info("Error writing file to output stream. Filename was '{}'", fileName, ex);
      throw new RuntimeException("IOError writing file to output stream");
    }

}

بصفة عامة ، عندما يكون لديك response.getOutputStream() ، يمكنك كتابة أي شيء هناك. يمكنك تمرير دفق الإخراج هذا كمكان لوضع ملف PDF الذي تم إنشاؤه للمولد الخاص بك. أيضا ، إذا كنت تعرف نوع الملف الذي تقوم بإرساله ، يمكنك ضبطه

response.setContentType("application/pdf");

ما يمكنني التفكير فيه بسرعة هو إنشاء ملف pdf وتخزينه في webapp / downloads / <RANDOM-FILENAME> .pdf من الكود وإرسال توجيه إلى هذا الملف باستخدام HttpServletRequest

request.getRequestDispatcher("/downloads/<RANDOM-FILENAME>.pdf").forward(request, response);

أو إذا كان بإمكانك تهيئة أداة حل مشكلات العرض ،

  <bean id="pdfViewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass"
              value="org.springframework.web.servlet.view.JstlView" />
    <property name="order" value=”2″/>
    <property name="prefix" value="/downloads/" />
    <property name="suffix" value=".pdf" />
  </bean>

ثم عاد للتو

return "RANDOM-FILENAME";

اذا أنت:

  • لا ترغب في تحميل الملف بأكمله إلى byte[] قبل الإرسال إلى الاستجابة ؛
  • تريد / تحتاج إلى إرسال / تنزيله عبر InputStream .
  • ترغب في الحصول على السيطرة الكاملة على نوع Mime واسم الملف المرسلة ؛
  • @ControllerAdvice أخرى تلتقط استثناءات لك.

الرمز أدناه هو ما تحتاجه:

@RequestMapping(value = "/stuff/{stuffId}", method = RequestMethod.GET)
public ResponseEntity<InputStreamResource> downloadStuff(@PathVariable int stuffId)
                                                                  throws IOException {
    String fullPath = stuffService.figureOutFileNameFor(stuffId);
    File file = new File(fullPath);

    HttpHeaders respHeaders = new HttpHeaders();
    respHeaders.setContentType("application/pdf");
    respHeaders.setContentLength(12345678);
    respHeaders.setContentDispositionFormData("attachment", "fileNameIwant.pdf");

    InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
    return new ResponseEntity<InputStreamResource>(isr, respHeaders, HttpStatus.OK);
}

لاحظ أيضًا أنه لتجنب قراءة الملف بأكمله فقط لحساب طوله ، فمن الأفضل تخزينه مسبقًا. تأكد من فحص مستندات InputStreamResource .


شيء من هذا القبيل أدناه

@RequestMapping(value = "/download", method = RequestMethod.GET)
public void getFile(HttpServletResponse response) {
    try {
        DefaultResourceLoader loader = new DefaultResourceLoader();
        InputStream is = loader.getResource("classpath:META-INF/resources/Accepted.pdf").getInputStream();
        IOUtils.copy(is, response.getOutputStream());
        response.setHeader("Content-Disposition", "attachment; filename=Accepted.pdf");
        response.flushBuffer();
    } catch (IOException ex) {
        throw new RuntimeException("IOError writing file to output stream");
    }
}

يمكنك عرض PDF أو تنزيل أمثلة here


باستخدام الإصدار 3.0 من Spring ، يمكنك استخدام كائن الإرجاع HttpEntity . إذا كنت تستخدم هذا ، فإن وحدة التحكم الخاصة بك لا تحتاج إلى كائن HttpServletResponse ، وبالتالي فمن السهل اختبار. باستثناء هذا ، هذه الإجابة نسبي يساوي واحدة من Infeligo .

إذا كانت قيمة الإرجاع لإطار pdf الخاص بك عبارة عن صفيف بايت (اقرأ الجزء الثاني من إجابتي لقيم الإرجاع الأخرى) :

@RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
public HttpEntity<byte[]> createPdf(
                 @PathVariable("fileName") String fileName) throws IOException {

    byte[] documentBody = this.pdfFramework.createPdf(filename);

    HttpHeaders header = new HttpHeaders();
    header.setContentType(MediaType.APPLICATION_PDF);
    header.set(HttpHeaders.CONTENT_DISPOSITION,
                   "attachment; filename=" + fileName.replace(" ", "_"));
    header.setContentLength(documentBody.length);

    return new HttpEntity<byte[]>(documentBody, header);
}

إذا كان نوع الإرجاع الخاص بـ PDF Framework ( documentBbody ) ليس بالفعل صفيفًا للبايت (وأي أيضًا ByteArrayInputStream ) ، فمن الحكمة عدم جعله صفيفًا للبايت أولاً. بدلاً من ذلك ، من الأفضل استخدام:

سبيل المثال مع FileSystemResource :

@RequestMapping(value = "/files/{fileName}", method = RequestMethod.GET)
public HttpEntity<byte[]> createPdf(
                 @PathVariable("fileName") String fileName) throws IOException {

    File document = this.pdfFramework.createPdf(filename);

    HttpHeaders header = new HttpHeaders();
    header.setContentType(MediaType.APPLICATION_PDF);
    header.set(HttpHeaders.CONTENT_DISPOSITION,
                   "attachment; filename=" + fileName.replace(" ", "_"));
    header.setContentLength(document.length());

    return new HttpEntity<byte[]>(new FileSystemResource(document),
                                  header);
}

from subprocess import call
call("cp -p <file> <file>", shell=True)




java spring file download controller