I need to generate on my GWT application an xls file (generated on server side with apache-poi) from client.
I want that when the user click on a button, appears a file chooser the allow him to save the generated file.
To begin I've created my servlet:
public class DownloadServlet extends HttpServlet
{
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
// What I have to insert here?!
}
public void getXlsFile()
{
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Datatypes in Java");
Object[][] datatypes = { { "Datatype", "Type", "Size(in bytes)" }, { "int", "Primitive", 2 }, { "float", "Primitive", 4 }, { "double", "Primitive", 8 }, { "char", "Primitive", 1 }, { "String", "Non-Primitive", "No fixed size" } };
int rowNum = 0;
for (Object[] datatype : datatypes) {
Row row = sheet.createRow(rowNum++);
int colNum = 0;
for (Object field : datatype) {
Cell cell = row.createCell(colNum++);
if( field instanceof String ) {
cell.setCellValue((String) field);
}
else if( field instanceof Integer ) {
cell.setCellValue((Integer) field);
}
}
}
try {
FileOutputStream outputStream = new FileOutputStream("MyFirstExcel.xlsx");
workbook.write(outputStream);
workbook.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
Now the questions are:
How do I have to fill doGet method?
And how I can call this servlet from client side?
Note that client side I don't know the xls file path because I want to create the xls file "on the fly" on server side.
You have created a servlet and have your xls file ready. All you have to do is to push the data into HttpServletResponse object.
First, you don't need to save the file. Change the getXlsFile() method to return XSSFWorkbook and remove the try / catch block at the end.
Now, doGet method:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HSSFWorkbook workbook = getXlsFile();
String fileName = "MyFirstExcel.xlsx";
resp.setStatus(HttpServletResponse.SC_OK);
resp.setHeader("Content-disposition", "attachment; filename=\"" + fileName + "\"");
resp.setContentType("application/vnd.ms-excel");
resp.getOutputStream().write(workbook.getBytes());
resp.getOutputStream().close();
resp.flushBuffer();
workbook.close();
}
How to call the server?
You need to add a servlet mapping in web.xml file:
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>fully.qualified.className</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/path/to/the/servlet</url-pattern>
</servlet-mapping>
In short: servlet mapping maps the url to the servlet class. So, when you open /path/to/the/servlet the fully.qualified.className servlet is called.
Related
I have the following POST servlet that adds new node under certain resource with parameters(name and last nam) from the request:
#Component(
service = Servlet.class,
property = {
"sling.servlet.paths=/bin/createuser",
"sling.servlet.methods=" + HttpConstants.METHOD_POST
})
public class CreateNodeServlet extends SlingAllMethodsServlet {
/**
* Logger
*/
private static final Logger log = LoggerFactory.getLogger(CreateNodeServlet.class);
#Override
protected void doPost(final SlingHttpServletRequest req, final SlingHttpServletResponse resp) throws IOException {
log.info("Inside CreateNodeServlet");
ResourceResolver resourceResolver = req.getResourceResolver();
final Resource resource = resourceResolver.getResource("/content/test/us/en");
String name = req.getParameter("name");
String lastname = req.getParameter("lastname");
log.info("name :{}",name);
log.info("lastname :{}",lastname);
Node node = resource.adaptTo(Node.class);
try {
log.info("Node {}", node.getName() );
Node newNode = node.addNode(name+lastname, "nt:unstructured");
newNode.setProperty("name", name);
newNode.setProperty("lastname", lastname);
resourceResolver.commit();
} catch (RepositoryException e) {
e.printStackTrace();
} catch (PersistenceException e) {
e.printStackTrace();
}
resp.setStatus(200);
resp.getWriter().write("Simple Post Test");
}
}
I tried creating unit test for this I got this so far:
#ExtendWith(AemContextExtension.class)
class CreateNodeServletTest {
private final AemContext context = new AemContext();
private CreateNodeServlet createNodeServlet = new CreateNodeServlet();
#Test
void doPost() throws IOException, JSONException {
context.currentPage(context.pageManager().getPage("/bin/createuser"));
context.currentResource(context.resourceResolver().getResource("/bin/createuser"));
context.requestPathInfo().setResourcePath("/bin/createuser");
MockSlingHttpServletRequest request = context.request();
MockSlingHttpServletResponse response = context.response();
createNodeServlet.doPost(request, response);
JSONArray output = new JSONArray(context.response().getOutputAsString());
assertEquals("Simple Post Test", output);
}
}
however this is not working I am getting null pointer on this line
Node node = resource.adaptTo(Node.class);
can some one help what I am missing and some tips will be of great help as I am new to AEM, and there is not much resources about unit testing sling servlets ?
I think you need to register JCR_MOCK as resource resolver type
new AemContext(ResourceResolverType.JCR_MOCK);
I built a web application using spring MVC, everything is working fine except the file upload in which I got random FileNotFoundExceptions. I found some solutions online like using a different tmp folder but I keep getting random error.
My code is:
#RequestMapping(value="/upload", method=RequestMethod.POST)
public #ResponseBody String handleFileUpload(#RequestParam("file") final MultipartFile multipartFile,
#RequestHeader("email") final String email, #RequestHeader("password") String password){
if (authenticateUser(email, password)) {
if (!multipartFile.isEmpty()) {
System.out.println("Start processing");
Thread thread = new Thread(){
public void run(){
ProcessCSV obj = new ProcessCSV();
try {
File file = multipartToFile(multipartFile);
if(file !=null) {
obj.extractEvents(file, email, cluster, session);
}
else {
System.out.println("null File");
}
} catch (IOException e) {
System.out.println("File conversion error");
e.printStackTrace();
}
}
};
thread.start();
return "true";
} else {
return "false";
}
}
else {
return "false";
}
}
and:
public File multipartToFile(MultipartFile multipartFile) throws IOException {
File uploadFile = null;
if(multipartFile != null && multipartFile.getSize() > 0) {
uploadFile = new File("/tmp/" + multipartFile.getOriginalFilename());
FileOutputStream fos = null;
try {
uploadFile.createNewFile();
fos = new FileOutputStream(uploadFile);
IOUtils.copy(multipartFile.getInputStream(), fos);
} catch (FileNotFoundException e) {
System.out.println("File conversion error");
e.printStackTrace();
} catch (IOException e) {
System.out.println("File conversion error");
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
System.out.println("File conversion error");
e.printStackTrace();
}
}
}
}
else {
System.out.println("null MultipartFile");
}
return uploadFile;
}
and the configuration file:
multipart.maxFileSize: 100MB
multipart.maxRequestSize: 100MB
multipart.location = ${user.home}
server.port = 8090
I used different versions of the multipartToFile function, one was using multipartfile.transferTo() but I was getting the same random error. Any advice?
Thank you
EDIT stack trace:
java.io.IOException: java.io.FileNotFoundException: /Users/aaa/upload_07720775_4b37_4b86_b370_40280388f3a4_00000003.tmp (No such file or directory)
at org.apache.catalina.core.ApplicationPart.write(ApplicationPart.java:121)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.transferTo(StandardMultipartHttpServletRequest.java:260)
at main.RESTController.multipartToFile(RESTController.java:358)
at main.RESTController$1.run(RESTController.java:241)
Caused by: java.io.FileNotFoundException: /Users/aaa/upload_07720775_4b37_4b86_b370_40280388f3a4_00000003.tmp (No such file or directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.write(DiskFileItem.java:392)
at org.apache.catalina.core.ApplicationPart.write(ApplicationPart.java:119)
... 3 more
I had just had a night of terror with this error. I found out that MultiPartFile is only recognisable to and by the #Controller class. So if you pass it to another bean which is not a controller, Spring will not be able to help you. It somewhat makes sense that the #Controller is tightly bound to the front screen (communication from the browser to the system - Controllers are the entry point from the browser). So any conversation must happen there in the Controller.
In my case, I did something like the following:
#Controller
public class FileUploadingController{
#PostMapping("/uploadHistoricData")
public String saveUploadedDataFromBrowser(#RequestParam("file") MultipartFile file) {
try {
String pathToFile = "/home/username/destination/"
new File(pathToFile).mkdir();
File newFile = new File(pathToFile + "/uploadedFile.csv");
file.transferTo(newFile); //transfer the uploaded file data to a java.io.File which can be passed between layers
dataService.processUploadedFile( newFile);
} catch (IOException e) {
//handle your exception here please
}
return "redirect:/index?successfulDataUpload";
}
}`
I had the same problem, it looks like MultipartFile is using different current dir internally, so all not absolute paths are not working.
I had to convert my path to an absolute path and then it worked.
It is working inside #RestController and in other beans too.
Path path = Paths.get(filename).toAbsolutePath();
fileToImport.transferTo(path.toFile());
fileToImport is MultipartFile.
I see that Java 8 has significantly cleaned up reading the contents of a file into a String:
String contents = new String(Files.readAllBytes(Paths.get(new URI(someUrl))));
I am wondering if there is something similar (cleaner/less code/more concise) for copying directories recursively. In Java 7 land, it's still something like:
public void copyFolder(File src, File dest) throws IOException{
if(src.isDirectory()){
if(!dest.exists()){
dest.mkdir();
}
String files[] = src.list();
for (String file : files) {
File srcFile = new File(src, file);
File destFile = new File(dest, file);
copyFolder(srcFile,destFile);
}
} else {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
in.close();
out.close();
}
}
Any improvements here in Java 8?
In this way the code looks a bit simpler
import static java.nio.file.StandardCopyOption.*;
public void copyFolder(Path src, Path dest) throws IOException {
try (Stream<Path> stream = Files.walk(src)) {
stream.forEach(source -> copy(source, dest.resolve(src.relativize(source))));
}
}
private void copy(Path source, Path dest) {
try {
Files.copy(source, dest, REPLACE_EXISTING);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
Using Files.walkFileTree:
you don't need to worry about closing Streams.
(some other answers here forget that while using Files.walk)
handles IOException elegantly.
(Some other answers here would become more difficult when adding proper exception handling instead of a simple printStackTrace)
public void copyFolder(Path source, Path target, CopyOption... options)
throws IOException {
Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
Files.createDirectories(target.resolve(source.relativize(dir).toString()));
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
Files.copy(file, target.resolve(source.relativize(file).toString()), options);
return FileVisitResult.CONTINUE;
}
});
}
What this does is
walk recursively over all files in the directory.
When a directory is encountered (preVisitDirectory):
create the corresponding one in the target directory.
When a regular file is encountered (visitFile):
copy it.
options can be used to tailor the copy to your needs. For example to overwrite existing files in the target directory, use copyFolder(source, target, StandardCopyOption.REPLACE_EXISTING);
How about the following code
public void copyFolder(File src, File dest) throws IOException {
try (Stream<Path> stream = Files.walk(src.toPath())) {
stream.forEachOrdered(sourcePath -> {
try {
Files.copy(
/*Source Path*/
sourcePath,
/*Destination Path */
src.toPath().resolve(dest.toPath().relativize(sourcePath)));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}
}
This version uses Files.walk and Path parameters as Java 8 suggests.
public static void copyFolder(Path src, Path dest) {
try {
Files.walk( src ).forEach( s -> {
try {
Path d = dest.resolve( src.relativize(s) );
if( Files.isDirectory( s ) ) {
if( !Files.exists( d ) )
Files.createDirectory( d );
return;
}
Files.copy( s, d );// use flag to override existing
} catch( Exception e ) {
e.printStackTrace();
}
});
} catch( Exception ex ) {
ex.printStackTrace();
}
}
and one more version:
static void copyFolder(File src, File dest){
// checks
if(src==null || dest==null)
return;
if(!src.isDirectory())
return;
if(dest.exists()){
if(!dest.isDirectory()){
//System.out.println("destination not a folder " + dest);
return;
}
} else {
dest.mkdir();
}
if(src.listFiles()==null || src.listFiles().length==0)
return;
String strAbsPathSrc = src.getAbsolutePath();
String strAbsPathDest = dest.getAbsolutePath();
try {
Files.walkFileTree(src.toPath(), new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
File dstFile = new File(strAbsPathDest + file.toAbsolutePath().toString().substring(strAbsPathSrc.length()));
if(dstFile.exists())
return FileVisitResult.CONTINUE;
if(!dstFile.getParentFile().exists())
dstFile.getParentFile().mkdirs();
//System.out.println(file + " " + dstFile.getAbsolutePath());
Files.copy(file, dstFile.toPath());
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
//e.printStackTrace();
return;
}
return;
}
its code use java8 Files.walkFileTree function.
my version:
static private void copyFolder(File src, File dest) {
// checks
if(src==null || dest==null)
return;
if(!src.isDirectory())
return;
if(dest.exists()){
if(!dest.isDirectory()){
//System.out.println("destination not a folder " + dest);
return;
}
} else {
dest.mkdir();
}
File[] files = src.listFiles();
if(files==null || files.length==0)
return;
for(File file: files){
File fileDest = new File(dest, file.getName());
//System.out.println(fileDest.getAbsolutePath());
if(file.isDirectory()){
copyFolder(file, fileDest);
}else{
if(fileDest.exists())
continue;
try {
Files.copy(file.toPath(), fileDest.toPath());
} catch (IOException e) {
//e.printStackTrace();
}
}
}
}
Can be used to copy source (file or directory) to target (directory)
void copy(Path source, Path target, boolean override) throws IOException {
Path target = target.resolve(source.toFile().getName());
Files.walkFileTree(source, new FileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
Path targetDir = target.resolve(source.relativize(dir));
if(Files.notExists(targetDir)) {
Files.createDirectory(targetDir);
}
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.copy(file, target.resolve(source.relativize(file))));
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
throw new RuntimeException("Copying file " + file + " failed", exc);
// Consider looking at FileVisitResult options...
}
#Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (exc != null) {
// TODO...
}
return FileVisitResult.CONTINUE; // Or whatever works for you
}
});
}
I need to implement the HttpRequestWrapper and a Filter in order to reuse my request. This is because I firstly need the request to see what the user has selected and secondly to upload a file to the tomcat server. Right now I have a Servlet Upload File "public class UploadFile extends HttpServlet {}" which runs for each user. Once it returns what the user has selected it goes to null and I can't upload a file to the server. Just wondering would I have to alter my code much in order to implement HttpRequestWrapper? Do I change from "public class UploadFile extends HttpServlet {}" to "public class UploadFile extends HttpRequestWrapper {}"?
So firstly I check the parameters to see which checkbox has been ticked :
String ConvertFile = request.getParameter("ConvertFile");
String Powershell = request.getParameter("Powershell");
String LMBackup = request.getParameter("LM_Backup");
String Restful_API = request.getParameter("Restful_API");
if (Powershell != null) {
Powershell = request.getParameter("Powershell");
}
if (LMBackup != null) {
LMBackup = request.getParameter("LM_Backup");
}
if (Restful_API != null) {
Restful_API = request.getParameter("Restful_API");
}
if (ConvertFile != null && LMBackup == null && Powershell != null && Restful_API == null)
{
System.out.println(ConvertFile + " and " + Powershell + " selected");
doUpload(request, response); //Here the request that is being passed is now null because I've used it previously
response.sendRedirect("index.jsp");
}
//Upload Method is as shown
//Items remains null because the request has already been used
protected void doUpload(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try {
System.out.println("Uploading File");
boolean ismultipart = ServletFileUpload.isMultipartContent(request);
System.out.println(request + " <<<<<<<<<<<<<+++++++++++++");
if (ismultipart) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = null;
try {
items = upload.parseRequest(request);
System.out.println(items + "<<<<<<<<<--------------");
} catch (Exception e) {
System.out.println(e);
}
I'm trying to access a XML file from client side in GWT. But it looks like the sendRequest method is not getting fired at all.
I'm able to see the xml in the browser. Do I need to do any thing in the server side?
Any help is appreciated.
Here's my code
String xmlurl = "http://localhost:8888/test.xml";
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(xmlurl));
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
System.out.println(exception);
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
System.out.println(response.getText());
} else {
System.out.println(response.getStatusCode());
}
}
});
} catch (RequestException e) {
System.out.println("exception"+e);
}
I tried the following code too, but have the same problem. The developer tool shows response status as 200 and correct response text. Only, its not working in the code.
String xmlurl = "http://127.0.0.1:8888/test.xml";
httpGetFile(xmlurl, new AsyncCallback<String>() {
public void onFailure(Throwable caught) {
xmlData = "Error";
}
public void onSuccess(String xmlText) {
xmlData = xmlText;
}
});
public static void httpGetFile(final String url, final AsyncCallback<String> callback) {
final RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url);
rb.setCallback(new RequestCallback() {
public void onResponseReceived(Request request, Response response) {
try {
System.out.println("dafadfdf");
final int responseCode = response.getStatusCode() / 100;
if (url.startsWith("file:/") || (responseCode == 2)) {
callback.onSuccess(response.getText());
} else {
callback.onFailure(new IllegalStateException("HttpError#" + response.getStatusCode() + " - " + response.getStatusText()));
}
} catch (Throwable e) {
callback.onFailure(e);
}
}
public void onError(Request request, Throwable exception) {
callback.onFailure(exception);
}
});
try {
rb.send();
} catch (RequestException e) {
callback.onFailure(e);
}
}
Always Use logging instead of System.out.print statements https://developers.google.com/web-toolkit/doc/latest/DevGuideLogging
Step 1 - Add logging statements to failure, success and try catch statements. Clean up the exception.
Step 2 - "Parsing the XML" should be done inside the "onSuccess" method of the rb callback.
You do not need a RequestBuilder at all to access an XML file. You can use an ExternalTextResource for this:
https://developers.google.com/web-toolkit/doc/latest/DevGuideClientBundle#TextResource