I have a method which takes the string as input, filters for specific key and value, returns the value as String output. I have a requirement to append input param to output string. The input is array int id. Here is the method code snippet:
private static String headerstomap(String headers) {
String sHeaders = headers.replace("[", "");
sHeaders = sHeaders.replace("]", "");
String res = Arrays.stream(sHeaders.split(", "))
.filter(s->s.contains("Uniquename"))
.findFirst()
.map(name->name.split(":")[1])
.orElse("Not Present");
return res;
}
Input is: [DomainValue:MYSQL,Oracle,SAP, Uniquename:jvmErrors_v1]
There is a rest API which takes the input param, gets the relevant data. Calls the above method to create a filename. The REST resource is:
public void downloadRecords(#PathVariable Long[] ids, HttpServletResponse response) throws Exception {
I need the method to return: jvmErrors_v1_1
Essentially, add an underscore at the end and append the input param.
Here is the REST resource:
public void downloadRecords(#PathVariable Long[] ids, HttpServletResponse response) throws Exception {
List<IDZip> iDZip = messageRepository.findbyId(ids);
IDZip iDZip = iDZip.get(0);
String xml = new ObjectMapper().writeValueAsString(iDZip);
String fileName = "id.zip";
String xmlname = messageController.headerstomap(iDZip.getheaders());
byte[] data = xml.getBytes();
byte[] bytes;
try (ByteOutputStream bout = new ByteOutputStream(); ZipOutputStream zout = new ZipOutputStream(bout)) {
for (Long id : ids) {
zout.setLevel(1);
ZipEntry ze = new ZipEntry(xmlname);
ze.setSize(data.length);
ze.setTime(System.currentTimeMillis());
zout.putNextEntry(ze);
zout.write(data);
zout.closeEntry();
}
bytes = bout.getBytes();
}
response.setContentType("application/zip");
response.setContentLength(bytes.length);
response.setHeader("Content-Disposition", "attachment; " + String.format("filename=" + fileName));
ServletOutputStream outputStream = response.getOutputStream();
FileCopyUtils.copy(bytes, outputStream);
outputStream.close();
}
There is IDZip class which holds getters and setters...
public String getheaders() {
return headers;
}
public void setheaders(String headers) {
this.headers = headers;
}
I will give you a gift today only if you will accept it, first debugs the process into small section system.out.println("step 1"); in each of the line then i will take it from that point
Related
I have an 3 array of strings ( actually it's an ArrayList ) and I would like to create an InputStream from it, each element of the array being a line in the stream.
String[] business = ['CONSUMER', 'TELUS'];
String[] position = ['Business', 'SMB','THPS'];
String isDone = "Yes";
need to convert the above data into and pass it to InputStream so i can upload the data to ftp server
Business_Unit: 'TELUS', 'CONSUMER'
Position_Group: 'Business', 'SMB', 'THPS'
On-Cycle_Schedule: 'Yes' or 'No
ftp server method as follows
private boolean fileUpload(InputStream isUploadFile, String dirName, String fileName){
boolean storeRetVal = false;
//File submission method
return storeRetVal;
}
the above method gets called from action class
public ActionForward generatePayroll(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
SessionInfoForm _form = (SessionInfoForm) form;
String isDone = "Yes";
String[] business = request.getParameterValues("selectedBusinessValues");
String[] position = request.getParameterValues("selectedPositionValues");
String fileName = "result.csv";
InputStream isUploadFile;
fileUpload(isUploadFile, fileName);
return mapping.findForward("success");
}
You can do something like
String[] business = { "CONSUMER", "TELUS" };
StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter(sw);
for (String s : business) {
out.println(s);
}
InputStream in = new ByteArrayInputStream(sw.toString().getBytes());
I have a java/spring boot application where I want to build an API endpoint that creates and returns a downloadable excel file. Here is my controller endpoint:
#RestController
#RequestMapping("/Foo")
public class FooController {
private final FooService fooService;
#GetMapping("/export")
public ResponseEntity export() {
Resource responseFile = fooService.export();
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="+responseFile.getFilename())
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(responseFile);
}
}
Then the service class
public class FooService {
public Resource export() throws IOException {
StringBuilder filename = new StringBuilder("Foo Export").append(" - ")
.append("Test 1.xlsx");
return export(filename);
}
private ByteArrayResource export(String filename) throws IOException {
byte[] bytes = new byte[1024];
try (Workbook workbook = generateExcel()) {
FileOutputStream fos = write(workbook, filename);
fos.write(bytes);
fos.flush();
fos.close();
}
return new ByteArrayResource(bytes);
}
private Workbook generateExcel() {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet();
//create columns and rows
return workbook;
}
private FileOutputStream write(final Workbook workbook, final String filename) throws IOException {
FileOutputStream fos = new FileOutputStream(filename);
workbook.write(fos);
fos.close();
return fos;
}
}
This code successfully creates the proper excel file using the Apache POI library. But this won't return it out of the controller properly because ByteArrayResource::getFilename always returns null:
/**
* This implementation always returns {#code null},
* assuming that this resource type does not have a filename.
*/
#Override
public String getFilename() {
return null;
}
What type of resource can I use to return the generated excel file?
Since you are using ByteArrayResource, you can use the below controller code assuming that the FooService is autowired in the controller class.
#RequestMapping(path = "/download_excel", method = RequestMethod.GET)
public ResponseEntity<Resource> download(String fileName) throws IOException {
ByteArrayResource resource = fooService.export(fileName);
return ResponseEntity.ok()
.headers(headers) // add headers if any
.contentLength(resource.contentLength())
.contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
.body(resource);
}
Basically , there are few points that you first need to understand & then decide what you want to do ,
1.Is excel creation on disk needed or can you stream it from memory?
If its a download pop up, user might keep it open for long time & memory be occupied during that period ( disadvantage of in memory approach ) .
Secondly, if generated file has to be new for each request ( i.e. data to be exported is different ) then there is no point in keeping it at disk ( disadvantage of in disk approach ) .
Thirdly, it will be hard for an API code to do disk clean up because you never know in advance as when user will finish up his down load ( disadvantage of in disk approach ) .
Answer by Fizik26 is this In - Memory approach where you don't create a file on disk. . Only thing from that answer is that you need to keep track of length of array out.toByteArray() & that can easily be done via a wrapper class.
2.While downloading a file , your code needs to stream a file chunk by chunk - thats what Java streams are for.
Code like below does that.
return ResponseEntity.ok().contentLength(inputStreamWrapper.getByteCount())
.contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
.cacheControl(CacheControl.noCache())
.header("Content-Disposition", "attachment; filename=" + "SYSTEM_GENERATED_FILE_NM")
.body(new InputStreamResource(inputStreamWrapper.getByteArrayInputStream()));
and inputStreamWrapper is like ,
public class ByteArrayInputStreamWrapper {
private ByteArrayInputStream byteArrayInputStream;
private int byteCount;
public ByteArrayInputStream getByteArrayInputStream() {
return byteArrayInputStream;
}
public void setByteArrayInputStream(ByteArrayInputStream byteArrayInputStream) {
this.byteArrayInputStream = byteArrayInputStream;
}
public int getByteCount() {
return byteCount;
}
public void setByteCount(int byteCount) {
this.byteCount = byteCount;
}
}
Regarding file name, if file name is not an input to end point - that means ..its system generated ( a combination of constant string plus a variable part per user ). I am not sure why you need to get that from resource.
You won't need this wrapper if use - org.springframework.core.io.ByteArrayResource
Letting controller know is always better what it is going to write using ReponseEntity. At service level just create and play around the objects. #RestController or #Controller doesn't matter here.
What you are looking forward for in your controller is somewhat like this (sample) -
#GetMapping(value = "/alluserreportExcel")
public ResponseEntity<InputStreamResource> excelCustomersReport() throws IOException {
List<AppUser> users = (List<AppUser>) userService.findAllUsers();
ByteArrayInputStream in = GenerateExcelReport.usersToExcel(users);
// return IO ByteArray(in);
HttpHeaders headers = new HttpHeaders();
// set filename in header
headers.add("Content-Disposition", "attachment; filename=users.xlsx");
return ResponseEntity.ok().headers(headers).body(new InputStreamResource(in));
}
Generate Excel Class -
public class GenerateExcelReport {
public static ByteArrayInputStream usersToExcel(List<AppUser> users) throws IOException {
...
...
//your list here
int rowIdx = 1;
for (AppUser user : users) {
Row row = sheet.createRow(rowIdx++);
row.createCell(0).setCellValue(user.getId().toString());
...
}
workbook.write(out);
return new ByteArrayInputStream(out.toByteArray());
and finally, somewhere, in your view -
<a href="<c:url value='/alluserreportExcel' />"
target="_blank">Export all users to MS-Excel</a>
For full example, take a peek -
here, here and here.
You have to set the file name to the response header using Content-disposition. Try this
#GetMapping("/export")
public ResponseEntity export(HttpServletResponse response) {
fooService.export(response);
}
Change your service method like this
public Resource export(HttpServletResponse response) throws IOException {
StringBuilder filename = new StringBuilder("Foo Export").append(" - ")
.append("Test 1.xlsx");
return export(filename, response);
}
private void export(String filename, HttpServletResponse response) throws IOException {
try (Workbook workbook = generateExcel()) {
FileOutputStream fos = write(workbook, filename);
IOUtils.copy(new FileInputStream(fos.getFD()),
servletResponse.getOutputStream());//IOUtils is from apache commons io
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-disposition", "attachment; filename=" + filename);
}catch(Exception e) {
//catch if any checked exception
}finally{
//Close all the streams
}
}
You can use this :
headers.add("Content-Disposition", "attachment; filename=NAMEOFYOURFILE.xlsx");
ByteArrayInputStream in = fooService.export();
return ResponseEntity
.ok()
.headers(headers)
.body(new InputStreamResource(in));
It will download the Excel file when you call this endpoint.
In your export method in your service, you have to return something like that :
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
workbook.write(out);
} catch (IOException e) {
e.printStackTrace();
}
return new ByteArrayInputStream(out.toByteArray());
Still super new to REST, but close to finishing my first program.
I am attempting to create a CSV with the value of the POST URL Parameter being passed into it each time I POST.
Is there a way of setting my variable to be equal to my POST URL Parameter?
Code below (value is temporarily set to 10 while I figure this out):
#Path("/values")
public class values {
int totalSum = 0;
List<String> list = new ArrayList<String>();
#GET
#Produces(MediaType.TEXT_PLAIN)
public int getSum() throws IOException {
CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
List<String[]> read = reader.readAll();
return sum.sum(read, totalSum);
}
#POST
public String addValue() throws IOException {
int value = 10;
String valueString = Integer.toString(value);
CSVWriter writer = new CSVWriter(new FileWriter("yourfile.csv", true), ',');
String[] entries = valueString.split(",");
writer.writeNext(entries);
writer.close();
return "ok";
}
#DELETE
#Produces(MediaType.TEXT_PLAIN)
public String deleteList() throws IOException {
FileWriter fw = new FileWriter("yourfile.csv", false);
PrintWriter pw = new PrintWriter(fw, false);
pw.flush();
pw.close();
fw.close();
return "ok";
}
}
So now you need the base url, and when you add /{some_value} it gets mapped via PathVariable to String value test
Like so?
#Path("/{test}")
#POST
// Javax.ws.rs.PathParam
public String addValue(#PathParam("test") final String test) throws
// SpringFramework
//public String addValue(#PathVariable("test") final String test) throws IOException {
final String value = test;
CSVWriter writer = new CSVWriter(new FileWriter(value, true), ',');
String[] entries = valueString.split(",");
writer.writeNext(entries);
writer.close();
return "ok";
}
See link for more information
I've written a transformer class that takes an HttpServletRequest and transforms it into another type that holds a pointer to the InputStream from the servlet request. (The idea is to abstract the incoming transport protocol from the request handling, so I could also write a similar transformer from FTP, for instance.)
Now I'm trying to write a unit test for this, and I'm having problems. I've managed to figure out the correct boilerplate to create a valid Multipart HTTP request (using the Spring classes MockMultipartHttpServletRequest and MockMultipartFile), but now I get a NullPointerException in the initialize() method of my UploadRequest class. I'm guessing the problem is that somehow the stream inside the MockMultipartHttpServletRequest isn't being initialized correctly, but I can't figure out what I should do differently.
Any suggestions would be gratefully accepted!
This is the stack trace:
java.lang.NullPointerException
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:976)
at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:886)
at java.io.InputStream.read(InputStream.java:82)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:96)
at org.apache.commons.fileupload.util.Streams.copy(Streams.java:66)
at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:592)
at org.apache.commons.fileupload.MultipartStream.discardBodyData(MultipartStream.java:618)
at org.apache.commons.fileupload.MultipartStream.skipPreamble(MultipartStream.java:637)
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:984)
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:965)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.servlet.ServletFileUpload.getItemIterator(ServletFileUpload.java:148)
at com.ooyala.UploadRequest.initialize(UploadRequest.java:51)
at com.ooyala.UploadRequestTest.testCreateFromServletRequest(UploadRequestTest.java:57)
Here's an abbreviated version of my transformer class:
public class UploadRequest {
private Map<String, String> params;
private InputStream strIn;
private Logger Log = Logger.getLogger(UploadRequest.class.getName());
public UploadRequest()
{
params = new HashMap<String, String>();
}
public void initialize(HttpServletRequest sRequest,
ServletFileUpload upload)
throws IOException, FileUploadException
{
Enumeration<String> paramNames = sRequest.getParameterNames();
while (paramNames.hasMoreElements()) {
String pName = paramNames.nextElement();
params.put(pName, sRequest.getParameter(pName));
}
params.put("request_uri", sRequest.getRequestURI());
FileItemIterator iter = upload.getItemIterator(sRequest);
while (iter.hasNext()) {
FileItemStream item = iter.next();
try {
if (!item.isFormField()) {
// Skip form fields
params.put("original_file_name", item.getName());
strIn = item.openStream();
}
} catch (IOException ex) {
Log.severe("File uploading exception: " + ex.getMessage());
throw ex;
}
}
}
And here's the unit test:
import org.springframework.mock.web.MockMultipartHttpServletRequest;
import org.springframework.mock.web.MockMultipartFile;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
// etc.... other imports
#RunWith(JMock.class)
public class UploadRequestTest {
private UploadRequest upRequest;
#Before
public void setUp()
{
context.setImposteriser(ClassImposteriser.INSTANCE);
upRequest = new UploadRequest();
}
#Test
public void testCreateFromServletRequest()
throws IOException, FileUploadException
{
String text_contents = "hello world";
MockMultipartHttpServletRequest sRequest =
new MockMultipartHttpServletRequest();
sRequest.setMethod("POST");
String boundary = generateBoundary();
String contentType = "multipart/form-data; boundary="+boundary;
sRequest.setContentType(contentType);
sRequest.setRequestURI("/foo");
sRequest.addParameter("test_param","test_value");
sRequest.addFile(
new MockMultipartFile("file1","test_upload.txt","text/plain",
text_contents.getBytes()));
ServletFileUpload upload = new ServletFileUpload();
assertTrue(upload.isMultipartContent(sRequest));
upRequest.initialize(sRequest, upload);
}
}
I have the same issue and I googled but no answer. I plugged in the source code from the library, You need to send content, whatever. The library might need to check if it is null in the skip method
MockMultipartHttpServletRequest request
request.setContent("whatever".getBytes());
Posted here for others
Add boundary condition
Generate contents as follows
MockMultipartHttpServletRequest request =
this.generateMockMultiPartHttpServletRequest(true);
MockMultipartFile mockMultipartFile = null;
try {
request.setContentType("multipart/form-data; boundary=-----1234");
request.setCharacterEncoding("text/plain");
String endline = "\r\n";
String bondary = "-----1234";
String textFile = this.encodeTextFile("-----1234", "\r\n", "file","test.csv",
"text/UTF-8", FileUtils.readFileToString((new File(csvFilePath)), "UTF-8"));
StringBuilder content = new StringBuilder(textFile.toString());
content.append(endline);
content.append(endline);
content.append(endline);
content.append("--");
content.append(bondary);
content.append("--");
content.append(endline);
request.setContent(content.toString().getBytes());
request.setMethod("POST");
mockMultipartFile = new MockMultipartFile("file",
FileUtils.readFileToByteArray(new File(csvFilePath)));
} catch (Exception e1) {
e1.printStackTrace();
}
request.addFile(mockMultipartFile);
Function to encode text
private String encodeTextFile(String bondary, String endline, String name,
String filename, String contentType, String content) {
final StringBuilder sb = new StringBuilder(64);
sb.append(endline);
sb.append("--");
sb.append(bondary);
sb.append(endline);
sb.append("Content-Disposition: form-data; name=\"");
sb.append(name);
sb.append("\"; filename=\"");
sb.append(filename);
sb.append("\"");
sb.append(endline);
sb.append("Content-Type: ");
sb.append(contentType);
sb.append(endline);
sb.append(endline);
sb.append(content);
return sb.toString();
}
I went through the same problem, after searching lot I got this post in which I answered with code that solved my problem.
The Shriprasad's solution works well for text file. But I had some problems with binary files.
https://stackoverflow.com/a/30541653/2762092
I want to upload a file, store it in the Blobstore and then later access it (via the BlobKey) but this won't work.
Here is my Code:
public class CsvToBlobstoreUploadServlet extends HttpServlet {
private final BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
#Override
public void doPost(final HttpServletRequest request, final HttpServletResponse res) throws ServletException, IOException {
final Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(request);
final BlobKey blobKey = blobs.get("upload");
final BlobInfo info = new BlobInfoFactory().loadBlobInfo(blobstoreService.getUploadedBlobs(request).get("upload"));
if (blobKey == null) {
res.sendRedirect("/");
} else {
res.sendRedirect("/csvupload?blob-key=" + blobKey.getKeyString());
}
}
#Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
final BlobInfo blobInfo = new BlobInfoFactory().loadBlobInfo(new BlobKey(req.getParameter("blob-key")));
resp.setContentType("text/html");
resp.setHeader("Content-Language", "en");
resp.getWriter().println("<blob-key>" + blobInfo.getBlobKey().getKeyString() + "</blob-key>"); // Here I get no NullPointerException, blobInfo is NOT null, everything es as expected....
}
This works! Means the File ist stored in the Blobstore, and I get something like <blob-key>jA_W_jiKoTpXAe9QjeFlrg</blob-key> back from Post request.
Now I want to access this Blob with this key, but following Code results in NullPointerException, because blobInfo is null.... but why???
// A method from another Servlet....
private String getData(final String blobKey) {
//at this point blobKey is exactly that one returned previously for example jA_W_jiKoTpXAe9QjeFlrg
try {
final BlobInfo blobInfo = new BlobInfoFactory().loadBlobInfo(new BlobKey(blobKey));
final BlobstoreInputStream bis = new BlobstoreInputStream(blobInfo.getBlobKey()); // Here I got NullPointerException, because BlobInfo is null
final InputStreamReader isr = new InputStreamReader(bis);
final BufferedReader br = new BufferedReader(isr);
final StringBuffer sb = new StringBuffer();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} catch (final IOException e) {
e.printStackTrace();
}
return "";
}
I would be very very glad if someone could figure out what the problem is....
The following works for me it need only one helper class, called FileObject, which is a named dynamic byte buffer to append byte arrays:
public class FileObject {
private String name;
byte [] bufferArray = null;
public FileObject(String name, byte[] data) {
this.name = name;
this.bufferArray = data;
}
public FileObject(String name) {
this.name = name;
}
public void appendData(byte[] data, int numberOfBytes) {
if (bufferArray == null)
{
this.bufferArray = new byte [numberOfBytes];
System.arraycopy(data, 0, bufferArray, 0, numberOfBytes);
}
else
{
byte[] tempArray = new byte[bufferArray.length + numberOfBytes];
System.arraycopy(bufferArray, 0, tempArray, 0, bufferArray.length);
System.arraycopy(data, 0, tempArray, bufferArray.length, numb erOfBytes);
bufferArray = tempArray;
}
}
public byte[] getData() {
return bufferArray;
}
public void setData(byte[] data) {
this.bufferArray = data;
}
public String getName() {
return name;
}
}
This is the core method to write into the file object:
public synchronized static byte[] readBlob(BlobKey blobKey) throws BlobServiceException{
int bufferSize = MAX_READ_BUFFER_SIZE;
FileObject fileObject = new FileObject("");
try{
AppEngineFile file = fileService.getBlobFile(blobKey);
FileReadChannel readChannel = fileService.openReadChannel(file, false);
// write the files to the disk
ByteBuffer byteBuffer = ByteBuffer.allocate(bufferSize);
int numberOfBytes;
while ((numberOfBytes = readChannel.read(byteBuffer)) != -1) {
fileObject.appendData(byteBuffer.array(), numberOfBytes);
byteBuffer = ByteBuffer.allocate(bufferSize);
}
readChannel.close();
}catch(Exception e){
BlobServiceException blobIoException = new BlobServiceException("Failure while reading blob.\n" + e.getMessage());
blobIoException.setStackTrace(e.getStackTrace());
throw blobIoException;
}
return fileObject.getData();
}