java - programa - Flujos binarios de entrada y salida utilizando JERSEY?
decimal a hexadecimal java (10)
Aquí hay otro ejemplo. Estoy creando un QRCode como PNG a través de ByteArrayOutputStream
. El recurso devuelve un objeto Response
, y los datos de la secuencia son la entidad.
Para ilustrar el manejo del código de respuesta, he agregado el manejo de los encabezados del caché ( If-modified-since
, If-none-matches
, etc.).
@Path("{externalId}.png")
@GET
@Produces({"image/png"})
public Response getAsImage(@PathParam("externalId") String externalId,
@Context Request request) throws WebApplicationException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
// do something with externalId, maybe retrieve an object from the
// db, then calculate data, size, expirationTimestamp, etc
try {
// create a QRCode as PNG from data
BitMatrix bitMatrix = new QRCodeWriter().encode(
data,
BarcodeFormat.QR_CODE,
size,
size
);
MatrixToImageWriter.writeToStream(bitMatrix, "png", stream);
} catch (Exception e) {
// ExceptionMapper will return HTTP 500
throw new WebApplicationException("Something went wrong …")
}
CacheControl cc = new CacheControl();
cc.setNoTransform(true);
cc.setMustRevalidate(false);
cc.setNoCache(false);
cc.setMaxAge(3600);
EntityTag etag = new EntityTag(HelperBean.md5(data));
Response.ResponseBuilder responseBuilder = request.evaluatePreconditions(
updateTimestamp,
etag
);
if (responseBuilder != null) {
// Preconditions are not met, returning HTTP 304 ''not-modified''
return responseBuilder
.cacheControl(cc)
.build();
}
Response response = Response
.ok()
.cacheControl(cc)
.tag(etag)
.lastModified(updateTimestamp)
.expires(expirationTimestamp)
.type("image/png")
.entity(stream.toByteArray())
.build();
return response;
}
Por favor, no me stream.toByteArray()
una paliza en caso de que stream.toByteArray()
sea un no-no sabio en memoria :) Funciona para mis archivos <1KB PNG ...
Estoy usando Jersey para implementar una API RESTful que es principalmente recuperar y servir datos codificados JSON. Pero tengo algunas situaciones en las que necesito lograr lo siguiente:
- Exportar documentos descargables, como PDF, XLS, ZIP u otros archivos binarios.
- Recupere datos de varias partes, como JSON más un archivo XLS cargado
Tengo un cliente web basado en JQuery de una sola página que crea llamadas AJAX a este servicio web. Por el momento, no hace envíos de formularios, y usa GET y POST (con un objeto JSON). ¿Debo utilizar una publicación de formulario para enviar datos y un archivo binario adjunto, o puedo crear una solicitud de varias partes con el archivo binario JSON plus?
La capa de servicio de mi aplicación crea actualmente un ByteArrayOutputStream cuando genera un archivo PDF. ¿Cuál es la mejor manera de mostrar esta secuencia al cliente a través de Jersey? Creé un MessageBodyWriter, pero no sé cómo usarlo desde un recurso de Jersey. ¿Ese es el enfoque correcto?
He estado revisando las muestras incluidas con Jersey, pero aún no he encontrado nada que ilustre cómo hacer cualquiera de estas cosas. Si es importante, estoy usando Jersey con Jackson para hacer Object-> JSON sin el paso XML y no estoy realmente utilizando JAX-RS.
Este ejemplo muestra cómo publicar archivos de registro en JBoss a través de un recurso de reposo. Tenga en cuenta que el método get usa la interfaz StreamingOutput para transmitir el contenido del archivo de registro.
@Path("/logs/")
@RequestScoped
public class LogResource {
private static final Logger logger = Logger.getLogger(LogResource.class.getName());
@Context
private UriInfo uriInfo;
private static final String LOG_PATH = "jboss.server.log.dir";
public void pipe(InputStream is, OutputStream os) throws IOException {
int n;
byte[] buffer = new byte[1024];
while ((n = is.read(buffer)) > -1) {
os.write(buffer, 0, n); // Don''t allow any extra bytes to creep in, final write
}
os.close();
}
@GET
@Path("{logFile}")
@Produces("text/plain")
public Response getLogFile(@PathParam("logFile") String logFile) throws URISyntaxException {
String logDirPath = System.getProperty(LOG_PATH);
try {
File f = new File(logDirPath + "/" + logFile);
final FileInputStream fStream = new FileInputStream(f);
StreamingOutput stream = new StreamingOutput() {
@Override
public void write(OutputStream output) throws IOException, WebApplicationException {
try {
pipe(fStream, output);
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
};
return Response.ok(stream).build();
} catch (Exception e) {
return Response.status(Response.Status.CONFLICT).build();
}
}
@POST
@Path("{logFile}")
public Response flushLogFile(@PathParam("logFile") String logFile) throws URISyntaxException {
String logDirPath = System.getProperty(LOG_PATH);
try {
File file = new File(logDirPath + "/" + logFile);
PrintWriter writer = new PrintWriter(file);
writer.print("");
writer.close();
return Response.ok().build();
} catch (Exception e) {
return Response.status(Response.Status.CONFLICT).build();
}
}
}
Esto funcionó bien conmigo url: http://example.com/rest/muqsith/get-file?filePath=C : / Users / I066807 / Desktop / test.xml
@GET
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
@Path("/get-file")
public Response getFile(@Context HttpServletRequest request){
String filePath = request.getParameter("filePath");
if(filePath != null && !"".equals(filePath)){
File file = new File(filePath);
StreamingOutput stream = null;
try {
final InputStream in = new FileInputStream(file);
stream = new StreamingOutput() {
public void write(OutputStream out) throws IOException, WebApplicationException {
try {
int read = 0;
byte[] bytes = new byte[1024];
while ((read = in.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
};
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return Response.ok(stream).header("content-disposition","attachment; filename = "+file.getName()).build();
}
return Response.ok("file path null").build();
}
Estoy usando este código para exportar el archivo excel (xlsx) (Apache Poi) en jersey como un adjunto.
@GET
@Path("/{id}/contributions/excel")
@Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public Response exportExcel(@PathParam("id") Long id) throws Exception {
Resource resource = new ClassPathResource("/xls/template.xlsx");
final InputStream inp = resource.getInputStream();
final Workbook wb = WorkbookFactory.create(inp);
Sheet sheet = wb.getSheetAt(0);
Row row = CellUtil.getRow(7, sheet);
Cell cell = CellUtil.getCell(row, 0);
cell.setCellValue("TITRE TEST");
[...]
StreamingOutput stream = new StreamingOutput() {
public void write(OutputStream output) throws IOException, WebApplicationException {
try {
wb.write(output);
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
};
return Response.ok(stream).header("content-disposition","attachment; filename = export.xlsx").build();
}
He estado componiendo mis servicios de Jersey 1.17 de la siguiente manera:
FileStreamingOutput
public class FileStreamingOutput implements StreamingOutput {
private File file;
public FileStreamingOutput(File file) {
this.file = file;
}
@Override
public void write(OutputStream output)
throws IOException, WebApplicationException {
FileInputStream input = new FileInputStream(file);
try {
int bytes;
while ((bytes = input.read()) != -1) {
output.write(bytes);
}
} catch (Exception e) {
throw new WebApplicationException(e);
} finally {
if (output != null) output.close();
if (input != null) input.close();
}
}
}
GET
@GET
@Produces("application/pdf")
public StreamingOutput getPdf(@QueryParam(value="name") String pdfFileName) {
if (pdfFileName == null)
throw new WebApplicationException(Response.Status.BAD_REQUEST);
if (!pdfFileName.endsWith(".pdf")) pdfFileName = pdfFileName + ".pdf";
File pdf = new File(Settings.basePath, pdfFileName);
if (!pdf.exists())
throw new WebApplicationException(Response.Status.NOT_FOUND);
return new FileStreamingOutput(pdf);
}
Y el cliente, si lo necesita:
Client
private WebResource resource;
public InputStream getPDFStream(String filename) throws IOException {
ClientResponse response = resource.path("pdf").queryParam("name", filename)
.type("application/pdf").get(ClientResponse.class);
return response.getEntityInputStream();
}
Me pareció útil lo siguiente y quise compartirlo en caso de que lo ayude a usted o a alguien más. Quería algo como MediaType.PDF_TYPE, que no existe, pero este código hace lo mismo:
DefaultMediaTypePredictor.CommonMediaTypes.
getMediaTypeFromFileName("anything.pdf")
En mi caso, estaba publicando un documento PDF en otro sitio:
FormDataMultiPart p = new FormDataMultiPart();
p.bodyPart(new FormDataBodyPart(FormDataContentDisposition
.name("fieldKey").fileName("document.pdf").build(),
new File("path/to/document.pdf"),
DefaultMediaTypePredictor.CommonMediaTypes
.getMediaTypeFromFileName("document.pdf")));
Entonces p se pasa como el segundo parámetro para publicar ().
Este enlace fue útil para mí al juntar este fragmento de código: http://jersey.576304.n2.nabble.com/Multipart-Post-td4252846.html
Otro código de muestra donde puede cargar un archivo al servicio REST, el servicio REST cierra el archivo y el cliente descarga el archivo zip del servidor. Este es un buen ejemplo del uso de flujos de entrada y salida binarios usando Jersey.
https://.com/a/32253028/15789
Esta respuesta fue publicada por mí en otro hilo. Espero que esto ayude.
Tuve que devolver un archivo rtf y esto funcionó para mí.
// create a byte array of the file in correct format
byte[] docStream = createDoc(fragments);
return Response
.ok(docStream, MediaType.APPLICATION_OCTET_STREAM)
.header("content-disposition","attachment; filename = doc.rtf")
.build();
Usar Jersey 2.16 La descarga de archivos es muy fácil.
A continuación se muestra el ejemplo del archivo ZIP
@GET
@Path("zipFile")
@Produces("application/zip")
public Response getFile() {
File f = new File(ZIP_FILE_PATH);
if (!f.exists()) {
throw new WebApplicationException(404);
}
return Response.ok(f)
.header("Content-Disposition",
"attachment; filename=server.zip").build();
}
Pude obtener un archivo ZIP o un archivo PDF extendiendo el objeto StreamingOutput
. Aquí hay un código de muestra:
@Path("PDF-file.pdf/")
@GET
@Produces({"application/pdf"})
public StreamingOutput getPDF() throws Exception {
return new StreamingOutput() {
public void write(OutputStream output) throws IOException, WebApplicationException {
try {
PDFGenerator generator = new PDFGenerator(getEntity());
generator.generatePDF(output);
} catch (Exception e) {
throw new WebApplicationException(e);
}
}
};
}
La clase PDFGenerator (mi propia clase para crear el PDF) toma el flujo de salida del método de escritura y lo escribe en lugar de una secuencia de salida recién creada.
No sé si es la mejor manera de hacerlo, pero funciona.