英文:
ResponseEntity<InputStreamResource> return two service methods
问题
public ResponseEntity<InputStreamResource> getAB(...) {
ResponseEntity<InputStreamResource> responseA = aService.getA(...);
ResponseEntity<InputStreamResource> responseB = bService.getB(...);
// Combine the headers and content from both responses
HttpHeaders combinedHeaders = new HttpHeaders();
combinedHeaders.putAll(responseA.getHeaders());
combinedHeaders.putAll(responseB.getHeaders());
InputStreamResource bodyA = responseA.getBody();
InputStreamResource bodyB = responseB.getBody();
// Combine the input streams from both bodies if needed
InputStream combinedInputStream = combineInputStreams(bodyA.getInputStream(), bodyB.getInputStream());
long combinedContentLength = bodyA.contentLength() + bodyB.contentLength();
return ResponseEntity
.ok()
.headers(combinedHeaders)
.contentType(MediaType.APPLICATION_PDF)
.contentLength(combinedContentLength)
.body(new InputStreamResource(combinedInputStream));
}
private InputStream combineInputStreams(InputStream inputStreamA, InputStream inputStreamB) {
// Implement the logic to combine two input streams into one
// For example, you can use SequenceInputStream or any other suitable approach
}
Please replace the comment // Implement the logic to combine two input streams into one
with the actual implementation to combine two input streams if needed. This example assumes that both services return PDF content, so it sets the content type accordingly. You should adapt the logic and content type based on your actual use case.
英文:
I have two services returning two different ResponseEntity<InputStreamResource>.
public ResponseEntity<InputStreamResource> getA(...) {
return ResponseEntity
.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.contentLength(out.size())
.body(new InputStreamResource(bis)); }
public ResponseEntity<InputStreamResource> getB(...) {
return ResponseEntity
.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.contentLength(out.size())
.body(new InputStreamResource(bis)); }
Each service has a controller that calls and returns.
public ResponseEntity<InputStreamResource> getA(...) {
return aService.getA(...) }
public ResponseEntity<InputStreamResource> getB(...) {
return bService.getB(...) }
I'm trying to create another controller which does and return both services at once.
public ResponseEntity<InputStreamResource> getAB(...) {
return aService.getA(...) *and* bService.getB(...) ?????? }
not sure how to combine two ResponseEntities returns into one.
答案1
得分: 2
从Service方法返回ResponseEntity不是一个好主意。
应该由Controller层负责生成ResponseEntity对象。这是Controller的职责,不是Service层的职责。同样,Service层的责任是根据给定的输入准备某种DTO对象,然后Controller将包装该DTO并将其作为响应发送。
因此,我建议在这里进行一些结构上的更改。
Service层
public InputStreamResource getA(...) {
return A
}
public InputStreamResource getB(...) {
return B
}
Controller层
public ResponseEntity<InputStreamResource> getA(...) {
return new ResponseEntity<>(aService.getA(...));
}
public ResponseEntity<InputStreamResource> getB(...) {
return new ResponseEntity<>(bService.getB(...));
}
合并两个流
如果您的目标是逐个流式传输2个不同的PDF文档,那么我认为选项是首先在内存中合并PDF文档,无论您使用什么PDF库。然后创建单个InputStreamResource作为响应。
但是,如果流可以按顺序运行,那么以下是使用SequenceInputStream合并2个流的工作示例 -
@RequestMapping(
path = "/sayHello",
method = RequestMethod.GET,
produces = MediaType.TEXT_PLAIN_VALUE
)
public ResponseEntity<InputStreamResource> get() {
byte[] inputBytes1 = "Hello".getBytes();
// 第一个流包含"Hello"文本
ByteArrayInputStream baos1 = new ByteArrayInputStream(inputBytes1);
byte[] inputBytes2 = "World".getBytes();
// 第二个流包含"World"文本
ByteArrayInputStream baos2 = new ByteArrayInputStream(inputBytes2);
// 合并后的流将包含"HelloWorld"文本
SequenceInputStream combinedStream = new SequenceInputStream(baos1, baos2);
InputStreamResource inputStreamResource = new InputStreamResource(combinedStream);
return ResponseEntity.ok().body(inputStreamResource);
}
输出 ->
curl -X GET http://localhost:8083/sayHello
HelloWorld
英文:
Returning ResponseEntity from a Service method is not a good idea.
It's the Controller layer which should be responsible for generating ResponseEntity Object. That is his business not of the Service Layer. Similarly, the responsibility of the Service Layer is to prepare some kind of a DTO object based on the given input and then the Controller will wrap around that DTO and send it as a response.
So, I suggest to do some structural change here.
Service Layer
public InputStreamResource getA(...) {
return A
}
public InputStreamResource getB(...) {
return B
}
Controller Layer
public ResponseEntity<InputStreamResource> getA(...) {
return new ResponseEntity<>(aService.getA(...) (
}
public ResponseEntity<InputStreamResource> getB(...) {
return new ResponseEntity<>(bService.getB(...) )
}
To merge 2 streams
If you are targeting to stream 2 different pdf documents one by one, then I think the option will be to merge pdf documents in memory first with whatever pdf library you might be using. Then create a single InputStreamResource as Response.
But, If the streams can be run in sequence, then below is a working example to merge 2 streams using SequenceInputStream -
@RequestMapping(
path = "/sayHello",
method = RequestMethod.GET,
produces = MediaType.TEXT_PLAIN_VALUE
)
public ResponseEntity<InputStreamResource> get() {
byte[] inputBytes1 = "Hello".getBytes();
// 1st stream has "Hello" text
ByteArrayInputStream baos1 = new ByteArrayInputStream(inputBytes1);
byte[] inputBytes2 = "World".getBytes();
// 2nd stream has "World" text
ByteArrayInputStream baos2 = new ByteArrayInputStream(inputBytes2);
// combined stream will have "HelloWorld" text
SequenceInputStream combinedStream = new SequenceInputStream(baos1, baos2);
InputStreamResource inputStreamResource = new InputStreamResource(combinedStream);
return ResponseEntity.ok().body(inputStreamResource);
}
Output ->
curl -X GET http://localhost:8083/sayHello
HelloWorld
答案2
得分: 0
你可以尝试通过以下方式:
public ResponseEntity<List<InputStreamResource>> getAAndB(...) {
private List<InputStreamResource> result = new ArrayList<>();
result.add(aService.getA(...));
result.add(bService.getB(...));
return ResponseEntity.ok().body(result));
}
英文:
You can try via this way:
public ResponseEntity<List<InputStreamResource> getAAndB(...) {
private List<InputStreamResource> result = new ArrayList<>();
result.add(aService.getA(...));
result.add(bService.getB(...));
return ResponseEntity.ok().body(result)); }
}
答案3
得分: 0
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
@RestController
public class ReportController {
private static final Logger LOGGER = ...;
@Autowired
private ReportManager manager;
@GetMapping("/reportcard/students")
public ResponseEntity<InputStreamResource> getStudentReportCard(parameters...) throws ServiceException {
List<InputStream> studentReportList = manager.getStudentReports(parameters.... );
HttpHeaders headers = getHeaders(Constants.STUDENTS_REPORT_CARD);
Document document = new Document(PageSize.LETTER);
ByteArrayOutputStream outputStream = null;
try {
outputStream = new ByteArrayOutputStream();
PdfCopy copy = new PdfCopy(document, outputStream);
document.open();
for (InputStream file : studentReportList) {
copy.addDocument(new PdfReader(file)); // writes directly to the output stream
}
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen()) {
document.close();
}
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
InputStreamResource inputStreamResource = new InputStreamResource(new ByteArrayInputStream(outputStream.toByteArray()));
return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_PDF).body(inputStreamResource);
}
private HttpHeaders getHeaders(String fileName) {
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
headers.set("Content-disposition", "attachment; filename=" + fileName);
return headers;
}
}
public class ReportManagerImpl implements ReportManager {
private static final Logger LOGGER = ...;
@Autowired
private HttpClient httpClient;
@Override
public List<InputStream> getStudentReports(parameters...) throws ServiceException {
List<InputStream> studentReportList = new Vector<InputStream>();
List<String> learnersList = //list of students
String reportUrl = //url
for (String learner : learnersList) {
studentReportList.add(getHttpResponse(reportUrl + learner));
}
return studentReportList;
}
private InputStream getHttpResponse(String url) throws ServiceException {
try {
HttpResponse response = httpClient.execute(new HttpGet(url));
HttpEntity entity = response.getEntity();
return entity.getContent();
} catch (IOException e) {
throw new ServiceException(e.getMessage());
}
}
}
英文:
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfReader;
@RestController
public class ReportController {
private static final Logger LOGGER = ...
@Autowired
private ReportManager manager;
@GetMapping("/reportcard/students")
public ResponseEntity<InputStreamResource> getStudentReportCard(parameters...) throws ServiceException {
List<InputStream> studentReportList = manager.getStudentReports(parameters.... );
HttpHeaders headers = getHeaders(Constants.STUDENTS_REPORT_CARD);
Document document = new Document(PageSize.LETTER);
ByteArrayOutputStream outputStream = null;
try {
outputStream = new ByteArrayOutputStream();
PdfCopy copy = new PdfCopy(document, outputStream);
document.open();
for (InputStream file : studentReportList) {
copy.addDocument(new PdfReader(file)); // writes directly to the output stream
}
outputStream.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document.isOpen()) {
document.close();
}
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
InputStreamResource inputStreamResource = new InputStreamResource(new ByteArrayInputStream(outputStream.toByteArray()));
return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_PDF).body(inputStreamResource);
}
private HttpHeaders getHeaders(String fileName) {
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
headers.set("Content-disposition", "attachment; filename=" + fileName);
return headers;
}
public class ReportManagerImpl implements ReportManager {
private static final Logger LOGGER = ...
@Autowired
private HttpClient httpClient;
@Override
public List<InputStream> getStudentReports(parameters...)
throws ServiceException {
List<InputStream> studentReportList = new Vector<InputStream>();
List<String> learnersList = //list of students
String reportUrl = //url
for (String learner : learnersList) {
studentReportList.add(getHttpResponse(reportUrl + learner));
}
return studentReportList;
}
private InputStream getHttpResponse(String url) throws ServiceException {
try {
HttpResponse response = httpClient.execute(new HttpGet(url));
HttpEntity entity = response.getEntity();
return entity.getContent();
} catch (IOException e) {
throw new ServiceException(e.getMessage());
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论