REST ওয়েব পরিষেবা থেকে ক্লায়েন্টের কাছে কোনও ফাইল প্রেরণের সঠিক উপায় কী?


105

আমি সবেমাত্র REST পরিষেবাদি বিকাশ করা শুরু করেছি, তবে আমি একটি কঠিন পরিস্থিতি পেরিয়ে এসেছি: আমার ক্লায়েন্টের কাছে আমার REST পরিষেবা থেকে ফাইল পাঠানো। এতক্ষণ আমি কীভাবে সহজ ডেটা প্রকারগুলি (স্ট্রিংস, পূর্ণসংখ্যা ইত্যাদি) প্রেরণ করতে পারি তা হ্যাং করে ফেলেছি তবে একটি ফাইল প্রেরণ একটি আলাদা বিষয় কারণ এখানে অনেকগুলি ফরম্যাট রয়েছে যা আমার জানা নেই যে আমারও শুরু হওয়া উচিত। আমার REST পরিষেবাটি জাভাতে তৈরি হয়েছে এবং আমি জার্সি ব্যবহার করছি, আমি JSON ফর্ম্যাট ব্যবহার করে সমস্ত ডেটা প্রেরণ করছি।

আমি বেস 64৪ টি এনকোডিং সম্পর্কে পড়েছি, কিছু লোক বলে এটি একটি ভাল কৌশল, অন্যরা বলে এটি ফাইল আকারের সমস্যার কারণে নয়। সঠিক উপায় কি? আমার প্রকল্পের একটি সাধারণ সংস্থান শ্রেণিটি কীভাবে দেখছে:

import java.sql.SQLException;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.UriInfo;

import com.mx.ipn.escom.testerRest.dao.TemaDao;
import com.mx.ipn.escom.testerRest.modelo.Tema;

@Path("/temas")
public class TemaResource {

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public List<Tema> getTemas() throws SQLException{

        TemaDao temaDao = new TemaDao();        
        List<Tema> temas=temaDao.getTemas();
        temaDao.terminarSesion();

        return temas;
    }
}

আমি ফাইলটি প্রেরণের জন্য কোডটি অনুমান করছি এমন কিছু হবে:

import java.sql.SQLException;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/resourceFiles")
public class FileResource {

    @GET
    @Produces({application/x-octet-stream})
    public File getFiles() throws SQLException{ //I'm not really sure what kind of data type I should return

        // Code for encoding the file or just send it in a data stream, I really don't know what should be done here

        return file;
    }
}

আমার কোন ধরণের টিকা ব্যবহার করা উচিত? আমি দেখেছি কিছু লোক একটি জন্য সুপারিশ @GETব্যবহার @Produces({application/x-octet-stream}), যে সঠিক উপায় আছে কি? আমি যে ফাইলগুলি প্রেরণ করছি তা নির্দিষ্ট ফাইলগুলি যাতে ক্লায়েন্টকে ফাইলগুলির মাধ্যমে ব্রাউজ করার প্রয়োজন হয় না। আমাকে কীভাবে ফাইলটি প্রেরণ করা যায় সে সম্পর্কে কেউ আমাকে গাইড করতে পারেন? আমি এটি JSON অবজেক্ট হিসাবে প্রেরণ করতে বেস 64 ব্যবহার করে এটি এনকোড করব? বা এনকোডিংয়ের এটি JSON অবজেক্ট হিসাবে প্রেরণ করার প্রয়োজন নেই? আপনি যে কোনও সহায়তার জন্য ধন্যবাদ


java.io.Fileআপনার সার্ভারে আপনার কি প্রকৃত (বা ফাইলের পাথ) আছে বা ডেটাবেস, ওয়েব পরিষেবা, পদ্ধতি কল হিসাবে কোনও অন্য উত্স থেকে ডেটা আসছে InputStream?
ফিলিপ রিচার্ট

উত্তর:


142

আমি বেস 64 এ বাইনারি ডেটা এনকোডিং এবং এটি JSON এ মোড়ানোর পরামর্শ দিচ্ছি না। এটি অনাবশ্যকভাবে প্রতিক্রিয়ার আকার বাড়িয়ে দেবে এবং জিনিসগুলি ধীর করবে।

জিইটি application/octect-streamব্যবহার করে এবং কারখানার একটি পদ্ধতি javax.ws.rs.core.Response(জ্যাকস-আরএস এপিআইয়ের অংশ, যাতে আপনি জার্সিতে লক না হয়ে থাকেন) ব্যবহার করে কেবল আপনার ফাইল ডেটা পরিবেশন করুন :

@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
  File file = ... // Initialize this to the File path you want to serve.
  return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
      .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
      .build();
}

আপনার যদি কোনও আসল Fileঅবজেক্ট না থাকে তবে একটি InputStream, Response.ok(entity, mediaType)এটিও পরিচালনা করতে সক্ষম হওয়া উচিত।


ধন্যবাদ, এটি দুর্দান্ত কাজ করেছে তবে আমি যদি পুরো ফোল্ডারের কাঠামোটি গ্রাস করতে চাই তবে কী হবে? আমি এই জাতীয় কিছু ভাবছিলাম এছাড়াও যেহেতু আমি ক্লায়েন্টের বিভিন্ন ফাইল পাব, এইচটিপিআরস্পোনসের সত্তার প্রতিক্রিয়াটি আমি কীভাবে আচরণ করব?
উরিল

4
এর থেকে ZipOutputStreamফিরে আসার সাথে সাথে একবার দেখুন । এইভাবে আপনি একটি সুপরিচিত মাল্টি-ফাইল ফর্ম্যাট পাবেন যা বেশিরভাগ ক্লায়েন্টকে সহজেই পড়তে পারা উচিত। সংক্ষিপ্তকরণটি কেবল তখনই ব্যবহার করুন যদি এটি আপনার ডেটার জন্য অর্থবোধ করে, অর্থাত্ জেপিইজিগুলির মতো প্রাক-সংকুচিত ফাইলগুলির জন্য নয়। ক্লায়েন্ট পক্ষের, প্রতিক্রিয়া পার্স করার আছে । StreamingOutputgetFile()ZipInputStream
ফিলিপ রেচার্ট

4
এটি সাহায্য করতে পারে: স্ট্যাকওভারফ্লো.com
প্রশ্নগুলি

ফাইল বাইনারি ডেটা সহ প্রতিক্রিয়াতে ফাইলের মেটাডেটা যুক্ত করার কোনও উপায় আছে কি?

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

6

আপনি যদি ডাউনলোড করার জন্য কোনও ফাইল ফিরে আসতে চান, বিশেষত আপনি যদি ফাইল আপলোড / ডাউনলোডের কিছু জাভাস্ক্রিপ্ট লিবের সাথে একীভূত করতে চান তবে কোড বেলোটি এই কাজটি করে:

@GET
@Path("/{key}")
public Response download(@PathParam("key") String key,
                         @Context HttpServletResponse response) throws IOException {
    try {
        //Get your File or Object from wherever you want...
            //you can use the key parameter to indentify your file
            //otherwise it can be removed
        //let's say your file is called "object"
        response.setContentLength((int) object.getContentLength());
        response.setHeader("Content-Disposition", "attachment; filename="
                + object.getName());
        ServletOutputStream outStream = response.getOutputStream();
        byte[] bbuf = new byte[(int) object.getContentLength() + 1024];
        DataInputStream in = new DataInputStream(
                object.getDataInputStream());
        int length = 0;
        while ((in != null) && ((length = in.read(bbuf)) != -1)) {
            outStream.write(bbuf, 0, length);
        }
        in.close();
        outStream.flush();
    } catch (S3ServiceException e) {
        e.printStackTrace();
    } catch (ServiceException e) {
        e.printStackTrace();
    }
    return Response.ok().build();
}

3

লোকালহোস্ট থেকে আইপি ঠিকানায় মেশিনের ঠিকানাটি পরিবর্তন করুন আপনি নীচের পরিষেবাতে কল করতে আপনার ক্লায়েন্টের সাথে সংযোগ স্থাপন করতে চান।

আরআরএসটি ওয়েব সার্ভিস কল করার ক্লায়েন্ট:

package in.india.client.downloadfiledemo;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response.Status;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.multipart.BodyPart;
import com.sun.jersey.multipart.MultiPart;

public class DownloadFileClient {

    private static final String BASE_URI = "http://localhost:8080/DownloadFileDemo/services/downloadfile";

    public DownloadFileClient() {

        try {
            Client client = Client.create();
            WebResource objWebResource = client.resource(BASE_URI);
            ClientResponse response = objWebResource.path("/")
                    .type(MediaType.TEXT_HTML).get(ClientResponse.class);

            System.out.println("response : " + response);
            if (response.getStatus() == Status.OK.getStatusCode()
                    && response.hasEntity()) {
                MultiPart objMultiPart = response.getEntity(MultiPart.class);
                java.util.List<BodyPart> listBodyPart = objMultiPart
                        .getBodyParts();
                BodyPart filenameBodyPart = listBodyPart.get(0);
                BodyPart fileLengthBodyPart = listBodyPart.get(1);
                BodyPart fileBodyPart = listBodyPart.get(2);

                String filename = filenameBodyPart.getEntityAs(String.class);
                String fileLength = fileLengthBodyPart
                        .getEntityAs(String.class);
                File streamedFile = fileBodyPart.getEntityAs(File.class);

                BufferedInputStream objBufferedInputStream = new BufferedInputStream(
                        new FileInputStream(streamedFile));

                byte[] bytes = new byte[objBufferedInputStream.available()];

                objBufferedInputStream.read(bytes);

                String outFileName = "D:/"
                        + filename;
                System.out.println("File name is : " + filename
                        + " and length is : " + fileLength);
                FileOutputStream objFileOutputStream = new FileOutputStream(
                        outFileName);
                objFileOutputStream.write(bytes);
                objFileOutputStream.close();
                objBufferedInputStream.close();
                File receivedFile = new File(outFileName);
                System.out.print("Is the file size is same? :\t");
                System.out.println(Long.parseLong(fileLength) == receivedFile
                        .length());
            }
        } catch (UniformInterfaceException e) {
            e.printStackTrace();
        } catch (ClientHandlerException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static void main(String... args) {
        new DownloadFileClient();
    }
}

প্রতিক্রিয়া ক্লায়েন্ট পরিষেবা:

package in.india.service.downloadfiledemo;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.sun.jersey.multipart.MultiPart;

@Path("downloadfile")
@Produces("multipart/mixed")
public class DownloadFileResource {

    @GET
    public Response getFile() {

        java.io.File objFile = new java.io.File(
                "D:/DanGilbert_2004-480p-en.mp4");
        MultiPart objMultiPart = new MultiPart();
        objMultiPart.type(new MediaType("multipart", "mixed"));
        objMultiPart
                .bodyPart(objFile.getName(), new MediaType("text", "plain"));
        objMultiPart.bodyPart("" + objFile.length(), new MediaType("text",
                "plain"));
        objMultiPart.bodyPart(objFile, new MediaType("multipart", "mixed"));

        return Response.ok(objMultiPart).build();

    }
}

জেআর দরকার:

jersey-bundle-1.14.jar
jersey-multipart-1.14.jar
mimepull.jar

ওয়েব.এক্সএমএল:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <display-name>DownloadFileDemo</display-name>
    <servlet>
        <display-name>JAX-RS REST Servlet</display-name>
        <servlet-name>JAX-RS REST Servlet</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
             <param-name>com.sun.jersey.config.property.packages</param-name> 
             <param-value>in.india.service.downloadfiledemo</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>JAX-RS REST Servlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

-2

যেহেতু আপনি জেএসএন ব্যবহার করছেন, আমি তারের জুড়ে প্রেরণের আগে এটি বেস64 এ এনকোড করব।

যদি ফাইলগুলি বড় হয় তবে BSON, বা বাইনারি স্থানান্তরগুলির সাথে আরও ভাল এমন কোনও অন্য ফর্ম্যাট দেখার চেষ্টা করুন।

বেস 64 টি এনকোডিংয়ের আগে আপনি ফাইলগুলি ভালভাবে সংকুচিত করতে পারলে আপনি জিপ করতে পারেন।


পুরো ফাইল আকারের কারণে তাদের প্রেরণের আগে আমি সেগুলিকে জিপ করার পরিকল্পনা করছিলাম তবে আমি যদি এটিকে এনকোড করে বেস 64 করি তবে আমার টীকায় কী @Producesথাকতে হবে?
ইউরিয়েল

আপনি এটিতে যাই থাকুক না কেন, JSON স্পেস অনুসারে অ্যাপ্লিকেশন / জসন। ( ietf.org/rfc/rfc4627.txt?number=4627 ) মনে রাখবেন যে বেস 64 এনকোডেড ফাইলটি এখনও
জেএসএন

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