I have a method which returns a file object of an image:
public File getPhoto(entryId){...}
I call this method from my action method and set the file to a DTO File variable:
myDto.photo = getPhoto(entryId);
// where entryId refers to the name of the image file
// e.g. ent01 for ent01.gif, ent02 for ent02.gif and so on.
Now, in my JSP file I would like to display the image through a code like this:
<img src = "${myDto.photo}">
However,I realized that the myDto.photo is a file object thus has the absolute path of the file and not the URL needed for the img src in JSP.
Through searching, I understand that I can use a servlet and use something like
<img src = "${pageContext.request.contextPath}/image/ent01.gif"}.
However, I'm a little confused about this one as I wanted the filename part (ent01.gif) to vary based from the input entryId.
I hope anyone can shed light for me on this one. A lot of thanks.
You can Create a Controller Class for you to diplay the image you want.
#Controller
public class ImageReadFile{
// this is for mapping your image related path.
#RequestMapping(value="/image/*")
public void readImage(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc = request.getServletContext();
//here i uploaded my image in this path
// You can set any path here
String imagePath = "/home/somefolder/Workspaces/Images/";
String [] fragmentFilename = request.getServletPath().split("/");
//Check if image isn't set
if(fragmentFilename.length <= 2){
return;
}
String filename = fragmentFilename[2];
String requestedImage = "/"+filename;
if(filename == null){
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
File image = new File(imagePath, URLDecoder.decode(requestedImage, "UTF-8"));
if(!image.exists()){
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
String contentType = sc.getMimeType(image.getName());
response.reset();
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(image.length()));
Files.copy(image.toPath(), response.getOutputStream());
}
}
Servlet Version.
try this.
#WebServlet("/image/*")
public class ImageWriter extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext sc = request.getServletContext();
//here i uploaded my image in this path
// You can set any path here
String imagePath = "/home/somefolder/Workspaces/Images/";
String [] fragmentFilename = request.getServletPath().split("/");
//Check if image isn't set
if(fragmentFilename.length <= 2){
return;
}
String filename = fragmentFilename[2];
String requestedImage = "/"+filename;
if(filename == null){
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
File image = new File(imagePath, URLDecoder.decode(requestedImage, "UTF-8"));
if(!image.exists()){
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
String contentType = sc.getMimeType(image.getName());
response.reset();
response.setContentType(contentType);
response.setHeader("Content-Length", String.valueOf(image.length()));
Files.copy(image.toPath(), response.getOutputStream());
}
}
this is how you gonna set display it in jsp,
<img alt="${imageFilename}" src="${pageContext.request.contextPath}/image/${imageFilename}">
Just pass the Filename to jsp then let the controller read it and display it.
hope this will help you.
Related
This question already has answers here:
Recommended way to save uploaded files in a servlet application
(2 answers)
Closed 1 year ago.
I can able to upload image in database but unable to upload into "files" folder. web
#WebServlet(name="AdminServlet",urlPatterns="/AdminServlet")
#MultipartConfig
public class AdminSevlet extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException, SQLException, SQLException {
try (PrintWriter out = response.getWriter()) {
UserDAO UserDAO = new UserDAO();
User User = new User();
String sid = request.getParameter("aid");
int id = Integer.parseInt(sid);
String userid = request.getParameter("userid");
String password = request.getParameter("password");
String fname = request.getParameter("fname");
String ic = request.getParameter("ic");
String gender = request.getParameter("gender");
String dob = request.getParameter("dob");
String addr = request.getParameter("addr");
String email = request.getParameter("email");
String phoneNo = request.getParameter("phoneNo");
String dept = request.getParameter("dept");
String position = request.getParameter("position");
String eduqual = request.getParameter("eduqual");
String role = request.getParameter("role");
Part part = request.getPart("file"); // Retrieves <input type="file" name="file">
String image = part.getSubmittedFileName();
String path = getServletContext().getRealPath("./"+"web"+File.separator+"files"+File.separator+image);
InputStream is = part.getInputStream();
boolean succs = uploadFile(is, path);//
User.setadmin_id(id);
User.setuser_id(userid);
User.setpassword(password);
User.setuser_name(fname);
User.setIC(ic);
User.setGender(gender);
User.setdob(dob);
User.setAddress(addr);
User.setemail(email);
User.setphoneNo(phoneNo);
User.setDepartment(dept);
User.setPosition(position);
User.setEducationbackground(eduqual);
User.setRole(role);
User.setimage(image);
int result = UserDAO.addUser(User);
RequestDispatcher dispatcher = request.getRequestDispatcher("/view-user");
dispatcher.forward(request, response);
}
}
public boolean uploadFile(InputStream is, String path){
boolean test = false;
try{
byte[] byt = new byte[is.available()];
is.read();
FileOutputStream fops = new FileOutputStream(path);
fops.write(byt);
fops.flush();
fops.close();
test = true;
}catch (Exception e){
e.printStackTrace();
}
return test;
}
This is the image upload servlet. Once the image has been uploaded it should be inserted in the files folder. I don't know what mistake I have done. Could anyone let me know what is the problem? Do I need to add upload directory or the file path C: inside?
Updated answer and changed it
public boolean uploadFile(InputStream is, String path) {
boolean test = false;
try {
File targetFile = new File(path);
Files.copy(is, targetFile.toPath());
test = true;
} catch (Exception e) {
e.printStackTrace();
}
return test;
}
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());
I am uploading files (of different content types) using Apache fileupload API as follows:
FileItemFactory factory = getFileItemFactory(request.getContentLength());
ServletFileUpload uploader = new ServletFileUpload(factory);
uploader.setSizeMax(maxSize);
uploader.setProgressListener(listener);
List<FileItem> uploadedItems = uploader.parseRequest(request);
... saving files to GridFS using the following method:
public String saveFile(InputStream is, String contentType) throws UnknownHostException, MongoException {
GridFSInputFile in = getFileService().createFile(is);
in.setContentType(contentType);
in.save();
ObjectId key = (ObjectId) in.getId();
return key.toStringMongod();
}
... calling saveFile() as follows:
saveFile(fileItem.getInputStream(), fileItem.getContentType())
and reading from GridFS using the following method:
public void writeFileTo(String key, HttpServletResponse resp) throws IOException {
GridFSDBFile out = getFileService().findOne(new ObjectId(key));
if (out == null) {
throw new FileNotFoundException(key);
}
resp.setContentType(out.getContentType());
out.writeTo(resp.getOutputStream());
}
My servlet code to download the file:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uri = req.getRequestURI();
String[] uriParts = uri.split("/"); // expecting "/content/[key]"
// third part should be the key
if (uriParts.length == 3) {
try {
resp.setDateHeader("Expires", System.currentTimeMillis() + (CACHE_AGE * 1000L));
resp.setHeader("Cache-Control", "max-age=" + CACHE_AGE);
resp.setCharacterEncoding("UTF-8");
fileStorageService.writeFileTo(uriParts[2], resp);
}
catch (FileNotFoundException fnfe) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
}
catch (IOException ioe) {
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
}
However; all non-ASCII characters are displayed as '?' on a web page with encoding set to UTF-8 using:
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
Any help would be greatly appreciated!
Apologies for taking your time! This was my mistake. There is nothing wrong with the code or GridFS. My test file's encoding was wrong.
resp.setContentType("text/html; charset=UTF-8");
Reason: only content type, together with a binary InputStream are passed on.
public void writeFileTo(String key, HttpServletResponse resp) throws IOException {
GridFSDBFile out = getFileService().findOne(new ObjectId(key));
if (out == null) {
throw new FileNotFoundException(key);
}
resp.setContentType(out.getContentType()); // This might be a conflict
out.writeTo(resp.getOutputStream());
}
Maybe I do not understand the servlet lifecycle very well, but this is what i want:
I want to display a page generated by a servlet let's say servlet: paginaAmd.
On this page I want to display a list of images stored in folder on web server.
The address of url of the images is something like:
/img/80-80-1-1-1-1-1-1-1-1-1
where /img/* is my servlet for displaying images.
All works well if I want to display one image at a time in browser.
But when I want to put all the list at once, the images are not displayed correctly. Sometimes are not displayed at all, sometimes are displayed in wrong position (the position does not alter in time), and sometimes are displayed only some images.
I suspect that somehow not all the doGet() methods are catched.
Can someone give me some advice?
Here are the servlet code witch is implemented by the tutorial here: http://balusc.blogspot.fr/2007/04/imageservlet.html
#WebServlet(name = "ImgDisplay", urlPatterns = {"/img/*"})
public class ImgDisplay extends HttpServlet
{
private SessionFactory sessionfactory = new AnnotationConfiguration().configure().buildSessionFactory();
private Query query;
private String mesajEroare = "";
private HttpServletRequest _request;
private HttpServletResponse _response;
private int width = 0;
private int height = 0;
private int idImagine = 0;
private int format = 0;
private String titluArticol = "";
private String numeImagine = "";
private boolean imgValida = false;
private int DEFAULT_BUFFER_SIZE = 1024 * 100;
String fileUploadPath = "";
#Override
public void init() throws ServletException {
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
this._request = request;
this._response = response;
this.SetVariabile();
if(imgValida)
{
String nImagine = this.GetImageFromDisk();
this.DisplayImage(nImagine);
}
}
private void SetVariabile()
{
String reqUrl = _request.getRequestURL().toString();
String aUrl[] = reqUrl.split("/");
String urlImg = aUrl[aUrl.length - 1];
aUrl = urlImg.split("-");
try
{
this.width = Integer.parseInt(aUrl[0]);
this.height = Integer.parseInt(aUrl[1]);
this.idImagine = Integer.parseInt(aUrl[2]);
this.format = Integer.parseInt(aUrl[3]);
this.numeImagine = aUrl[aUrl.length - 1];
this.imgValida = true;
}
catch(Exception e)
{
this.imgValida = false;
}
}
private String GetImageFromDisk()
{
String nImagine;
//preiau imaginea
PaginiImagini pa = new PaginiImagini();
Session session;
try
{
session = sessionfactory.openSession();
session.beginTransaction();
query = session.getNamedQuery("PaginiImagini.findByImagineID");
query.setInteger("imagineID", this.idImagine);
pa = (PaginiImagini) query.uniqueResult();
session.getTransaction().commit();
session.close();
}
catch( Exception e )
{
this.mesajEroare = "Nu pot citi din baza de date!";
}
// citesc imagine de pe disk
ServletContext sctx = getServletContext();
this.fileUploadPath = sctx.getInitParameter("file-upload-path");
String pathImagine = this.fileUploadPath + "/" + Setari.pathImaginiMici;
if(this.width > Setari.wImagineMica || this.height > Setari.hImagineMica)
{
pathImagine = this.fileUploadPath + "/" + Setari.pathImaginiMari;
}
nImagine = pathImagine + "/" + pa.getNumeImaginePeDisc();
return nImagine;
}
private void DisplayImage(String imageToRead) throws FileNotFoundException, IOException
{
File image = new File(imageToRead);
String contentType = getServletContext().getMimeType(image.getName());
_response.setContentType(contentType);
_response.setHeader("Content-Length", String.valueOf(image.length()));
_response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");
_response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
_response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
_response.setDateHeader("Expires", 0); // Proxies.
// Prepare streams.
BufferedInputStream input = null;
BufferedOutputStream output = null;
try
{
// Open streams.
input = new BufferedInputStream(new FileInputStream(image), DEFAULT_BUFFER_SIZE);
output = new BufferedOutputStream(_response.getOutputStream(), DEFAULT_BUFFER_SIZE);
// Write file contents to response.
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int length;
while ((length = input.read(buffer)) > 0)
{
output.write(buffer, 0, length);
}
}
finally
{
// Gently close streams.
close(output);
close(input);
}
}
/**
*
* #param resource
*/
private static void close(Closeable resource)
{
if (resource != null)
{
try
{
resource.close();
}
catch (IOException e)
{
// Do your thing with the exception. Print it, log it or mail
// it.
//e.printStackTrace();
}
}
}
}
You have serious concurrency issues in your servlet. A single instance of the servlet is used to serve all the requests to this servlet. So a servlet should be stateless. But the first thing you're doing is
this._request = request;
this._response = response;
This means that if two concurrent requests are made to the servlet, you might have the first one set these two instance variables, then the second one resetting the same instance variables. The first image would thus be sent as a response to the second request, and nothing would be sent as a response to the first request. And this is only one of the strange things that could happen. You could also have exceptions and inconsistent data.
Don't store the request and response (and any other state) in instance variables. Pass them from method to method. I've not analyzed the whole code, but the only instance field that you should have in the servlet is sessionFactory field.
I have next problem... when i submit form and my Post method end. Form(or not)throwing empty alert window. how can I delete this throwing window?
ClienSide
....
final FormPanel form = new FormPanel();
form.setAction(GWT.getModuleBaseURL()+"upload");
form.setEncoding(FormPanel.ENCODING_MULTIPART);
form.setMethod(FormPanel.METHOD_POST);
VerticalPanel panel = new VerticalPanel();
form.setWidget(panel);
FileUpload upload = new FileUpload();
upload.setName("uploadFormElement");
panel.add(upload);
fileButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
form.submit();
}
});
FileUploadServlet
public class FileUploadServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
super.doGet(req, resp);
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
if (ServletFileUpload.isMultipartContent(req)) {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List<FileItem> items = upload.parseRequest(req);
for (FileItem fileItem : items) {
if (fileItem.isFormField()) continue;
String fileName = fileItem.getName();
if (fileName != null) {
fileName = FilenameUtils.getName(fileName);
}
File uploadedFile = new File("test.txt");
if (uploadedFile.createNewFile()) {
fileItem.write(uploadedFile);
}
}
} catch (FileUploadException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Maybe someone knows the reason of this alert?
If it is a simple Javascript alert window you need to track/search for it in three places
Steps - Search for alert string across client code
1) In javascript - third party .js file . String search for `alert` in such js files
2) In third party gwt jar .
a) String search for Window.alert in the GWT java code
b) String search for wnd.alert in GWT jsni code
3) In Your own source code - repeat steps "a" and "b" from Step 2
It is unlikely but also string search you server side code base if in case they are building a string in response and displaying it via some other mechanism.