Upload and display images using thymeleaf and springboot - spring-mvc

This is my upload image code in Spring Boot:
String root = ctx.getRealPath("/");
File dir = new File(root + File.separatorChar + "images");
if (!dir.exists())
dir.mkdir();
String path = dir.getAbsolutePath() + File.separatorChar
+ product.getProductName() + "."
+ file.getContentType().split("/")[1];
System.out.println(path);
File file1 = new File(path);
try {
FileOutputStream fod = new FileOutputStream(file1);
fod.write(file.getBytes());
fod.close();
product.setProductPicture("/images/" + product.getProductName()
+ "." + file.getContentType().split("/")[1]);
} catch (IOException e) {
e.printStackTrace();
}
The uploading of files works fine, only problem with this code is that when i use ctx.getRealPath("/") it returns temporary location and when i restart the spring boot app i loose already existing files which was already uploaded as it creates a new temporary directory.
This causes some problem as i also have to display this pics on my site and now it returns "image not found error".
So I needed a solution which will allow me to upload files in a permanent location and serve files from there on the browser.
Note: I'm using thymeleaf for views.

I found a solution for my problem. I created a new function which will only return bytes[] and sent as response body as follows:
#RequestMapping(value = "image/{imageName}")
#ResponseBody
public byte[] getImage(#PathVariable(value = "imageName") String imageName) throws IOException {
File serverFile = new File("/home/user/uploads/" + imageName + ".jpg");
return Files.readAllBytes(serverFile.toPath());
}
And in html <img alt="Image" th:src="#{image/userprofile}" width="250" height="250"/>

Here is how I did it.
Step 1: Create a uploads folder in your project directory.
Step 2: Create ResourceConfig file
#Configuration
public class ResourceConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/uploads/**").addResourceLocations("file:uploads/");
}
}
Step 3: Add your html thymleaf
<img th:src="#{'/uploads/' + ${someobject.someAttribute}}"/>

Thanks a lot. I have to do this but with an image storage in my db, as follows:
#GetMapping("/muestra/{idproducto}")
#ResponseBody
public byte[] muestraImagen(Model model,
//id of the product i need to show the picture
#PathVariable("idproducto")Integer idproducto, HttpServletResponse response) {
//object from database
Productos producto = productosRepository.findByIdproducto(idproducto);
logger.info("sal imagen yo te invoco");
//return the attr of my object (blob)
return producto.getArchivo();
}
and in html:
<img alt="Image" th:src="#{/tienda/productos/muestra/{id}(id=${producto.idproducto})}" width="250" height="250"/>

Related

How to show PDF file using Spring Web application

I wish to show this file on page but this code make a direct download
<a th:href="#{/pdf/Manjaro-User-Guide.pdf}">Show Pdf file</a>
I'm using Spring-Thymeleaf
Thanks!
I found the solution by commenting the line below
//response.setHeader("Content-Disposition", "attachment; filename=\"demo.pdf\"");
Here is the code example:
#GetMapping(value = "/pdf")
public void showPDF(HttpServletResponse response) throws IOException {
response.setContentType("application/pdf");
//response.setHeader("Content-Disposition", "attachment; filename=\"demo.pdf\"");
InputStream inputStream = new FileInputStream(new File(rootLocation + "/Manjaro-User-Guide.pdf"));
int nRead;
while ((nRead = inputStream.read()) != -1) {
response.getWriter().write(nRead);
}
}
Source
Thanks!

How to scan dtable drool file if there is any changes in file and load it again using kiescanner drool version 7.4..final

I am working on drool dtable xls file with spring.
i have implemented the business rules in xls file using external location and then with the help of kie services i am executing rules.
Following is the code snippet that's how i am loading rules in engine.
at the start of spring initialization i am calling init() method
see below spring configuration.
<bean id="droolsService" class="com.example.drools.DroolsServiceImpl" init-method="init">
Java Code
public void init() {
LOG.info("inside init");
KieSession kieSession;
for (RequestType type : droolsMap.keySet()) {
try {
kieSession = getKieSession(this.getDroolsMap().get(type));
droolsRules.put(type, kieSession);
} catch (Exception e) {
LOG.error("Failed to load kiesession:", e);
throw new RuntimeException(e);
}
}
}
private KieSession getKieSession(final String file) throws DroolsParserException, IOException, BiffException {
KieServices kieServices = KieServices.Factory.get();
KieFileSystem kfs = kieServices.newKieFileSystem();
InputStream stream = null;
String drl = null;
String RULE_PATH = "src/main/resources/";
SpreadsheetCompiler converter = new SpreadsheetCompiler();
//Workbook workbook = Workbook.getWorkbook(DroolsServiceImpl.class.getResourceAsStream(file));
Workbook workbook = Workbook.getWorkbook(new FileInputStream(file));
LOG.info("Loading rule file " + file);
for (Sheet sheet : workbook.getSheets()) {
LOG.info("Loading Sheet " + sheet.getName());
stream = new FileInputStream(file);
drl = converter.compile(stream, sheet.getName());
//StringReader reader = new StringReader(drl);
String DRL_FILE = RULE_PATH + sheet.getName() + ".drl";
System.out.println("Drool file added ::: " + DRL_FILE);
kfs.write(DRL_FILE, ResourceFactory.newReaderResource(new StringReader(drl)));
stream.close();
}
KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId());
KieSessionConfiguration conf = SessionConfiguration.newInstance();
KieSession ksession = kieContainer.newKieSession(conf);
if (kieBuilder.getResults().hasMessages(Message.Level.ERROR)) {
List<Message> errors = kieBuilder.getResults().getMessages(Message.Level.ERROR);
StringBuilder sb = new StringBuilder("Errors:");
for (Message msg : errors) {
sb.append("\n " + msg);
}
try {
throw new Exception(sb.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null)
stream.close();
if (workbook != null)
workbook.close();
}
}
return ksession;
}
Everything working perfect but the problem is i am not able to scan the file changes. If files is modified then i have to restart the server in order to sync the changes.
I have tried listener to load specific init() method after xls dtable has any changes but its not working , same old result is coming.
I have tried kiescanner but i am not able to get the concept.
KieScanner is loading maven kjar so how do i suppose to create kjar.
I just wanted to kie api scan if any changes in the drool file and try to reload whole changes in kiecontainer without server restarting.
Found the answer myself, Posting because it will help someone who needed.
What I did , I have used apache VFS File Monitor-
DefaultFileMonitor fm = new DefaultFileMonitor(new CustomFileListener());
When file will modified , create or get deleted it will call CustomFileListener.
Following is the implementation of CustomFileListener.
import org.apache.commons.vfs2.FileChangeEvent;
import org.apache.commons.vfs2.FileListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.support.XmlWebApplicationContext;
public class CustomFileListener implements FileListener {
private static final Logger LOG = LoggerFactory.getLogger(CustomFileListener.class);
#Override
public void fileCreated(FileChangeEvent fileChangeEvent) throws Exception {
}
#Override
public void fileDeleted(FileChangeEvent fileChangeEvent) throws Exception {
}
#Override
public void fileChanged(FileChangeEvent fileChangeEvent) throws Exception {
LOG.debug(" Under FileChanged Method");
LOG.debug(" File has been changed hence reinitializing init method = " + fileChangeEvent.getFile().getName().getPath());
XmlWebApplicationContext xmlWebApplicationContext =
(XmlWebApplicationContext) ContextLoader.getCurrentWebApplicationContext();
DefaultListableBeanFactory defaultListableBeanFactory =
(DefaultListableBeanFactory) xmlWebApplicationContext.getBeanFactory();
DroolsServiceImpl droolsService = (DroolsServiceImpl) defaultListableBeanFactory.getBean("droolsService");
droolsService.init();
}
}
What i did when the file will change, It will call fileChanged method.
In that i have fetched cached bean(DroolServiceImpl) from ContextLoader.getCurrentWebApplicationContext(); and called its init() method.
So this it will reload whole process and reinitialize the KieModule,KieRepository.

Download CSV file Using Spring MVC and OpenCSV jar

I am trying to download a .csv file on clicking the Download button in my jsp.The jsp code is like following......
<form:form method="POST" id="poCSVForm"
action="downloadPoCsv" commandName="poCSVcmd" modelAttribute="poCSVcmd">
<div class="content">
<fieldset>
<legend>Page Name</legend>
<div>
<div class="contentpane">
<table>
<tr>
<td><button type="submit" value="Download" id="downId" class="dwnldbtn">Download</button>
<button type="button" class="exit smallbtn" value="Exit">Exit</button></td>
</tr>
</table>
</div>
</div>
</fieldset>
</div>
</form:form>
Then my controller code is like this......
#RequestMapping(value = "/downloadPoCsv", method = RequestMethod.POST)
public void doPoCsvDownload(
#ModelAttribute("poCSVcmd") PurchaseOrderCSVBean poCsvBean,
Map<String, Object> model, HttpServletRequest req,HttpServletResponse response) throws IOException {
CSVWriter writer = null;
String filepath = null;
try {
HttpSession session = req.getSession();
Session hsession = (Session) session
.getAttribute(MOLConstants.HIBERNATE_SESSION_KEY);
filepath = "purchaseOrder" + new Date().getTime() + ".csv";
ServletContext context = req.getServletContext();
String realPath = context.getRealPath("");
System.out.println("appPath = " + realPath);
// construct the complete absolute path of the file
String fullPath = realPath + "\\stuff\\" + filepath;
System.out.println("fullPath = " + fullPath);
File downloadFile = new File(realPath);
try {
if (!downloadFile.exists()) {
if (downloadFile.mkdir()) {
} else {
throw new RuntimeException("Could not create directory");
}
}
} catch (Exception e) {
throw new RuntimeException();
}
String mimeType = context.getMimeType(fullPath); // get MIME type of the file
if (mimeType == null) {
mimeType = "application/octet-stream"; // set to binary type if MIME mapping not found
}
System.out.println("MIME type: " + mimeType);
// set content attributes for the response
response.setContentType(mimeType);
response.setContentLength((int) downloadFile.length());
// set headers for the response
String headerKey = "Content-Disposition";
String headerValue = String.format("attachment; filename=\"%s\"",downloadFile.getName());
response.setHeader(headerKey, headerValue);
List<PoCsvUploadView> csvDataList = poService.getPoCsvData(poCsvBean.getExp_ind(),poCsvBean.getStdt(),poCsvBean.getEnddt());
FileWriter fwriter = new FileWriter(fullPath);
writer = new CSVWriter(fwriter, ',', CSVWriter.NO_QUOTE_CHARACTER);
String[] header = new String[31];
header[0] = "COMPANY_CD";
.......
header[30] = "VENDOR_TYPE";
List<String[]> li = new ArrayList<String[]>();
li.add(header);
for (PoCsvUploadView group : csvDataList)
{
String[] arr = new String[31];
arr[0] = group.getCompany_cd();
.....
arr[30] = group.getVendor_type();
li.add(arr);
}
writer.writeAll(li);
} catch (Exception e) {
e.printStackTrace();
logger.error("Exception >> ", e);
throw new CustomGenericException(
"Error occured while loading report!!");
}finally{
writer.flush();
writer.close();
}
}
Now When I am click on the download button, the csv file is being generated at the specific location ie on fullPath variable. But that file is not downloading through the browser, instead of that browser is downloading some file named downloadPoCsv(which is exactly same as my #RequestMapping in my controller method), which is not desired. Can you guys provides some help on this. Thanx in advance.And yes I am using OpenCsv jar.
To be clear here the issue is spring MVC not openCSV because your problem description is that you are trying to download a file and it is downloading a file with a different name.
CodeJava has a pretty good example of a Spring MVC download. Give that a try.

Vaadin 7: File Upload

I have a Upload component in which I´m supposed to import a xml file in order to parse it.
I´m trying to use the File.createTempFile method to create the file phisically,but something weird is going on.
For example,if I take the file named "test.xml" and use the createTempFile method to create it on the disk,the name of the generate file becomes something like 'test.xml13234xml'.How can I create the file the correct way?
This is expected when using i.e. createTempFile method as it implicitly creates a file with random prefix:
// a part of createTempFile method
private static final SecureRandom random = new SecureRandom();
static File generateFile(String prefix, String suffix, File dir) {
long n = random.nextLong();
if (n == Long.MIN_VALUE) {
n = 0; // corner case
} else {
n = Math.abs(n);
}
return new File(dir, prefix + Long.toString(n) + suffix);
}
which should give something like 'test.xml13234xml'.
If you want to create a file with the correct name and keep it for later use you can rename/move it within uploadSucceeded method.
public class ExampleUpload implements Upload.Receiver, Upload.SucceededListener {
private Upload xmlUpload;
private File tempFile;
public ExampleUpload() {
this.xmlUpload = new Upload("Upload:", this);
this.xmlUpload.addSucceededListener(this);
}
#Override
public OutputStream receiveUpload(String filename, String mimeType) {
try {
tempFile = File.createTempFile(filename, "xml");
tempFile.deleteOnExit();
return new FileOutputStream(tempFile);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
public void uploadSucceeded(SucceededEvent event) {
try {
File destinationFile = new File("c:\\" + event.getFilename());
FileUtils.moveFile(tempFile, destinationFile));
// TODO read and parse destinationFile
} catch (IOException e) {
e.printStackTrace();
}
}
}

TrueZip and MultiPart form

I am currently using TrueZip to add a file to a Zip file that was uploaded to a server via MultiPartFile.
The Problem
Upon appending a file the zip becomes invalid. It can no longer be opened as a zip file.
The Code
Let's start with the relevant code in my upload controller (file is the MultiPartFile):
// Get the file
File dest = null;
TFile zip = null;
try {
// Obtain the file locally, zip, and delete the old
dest = new File(request.getRealPath("") + "/datasource/uploads/" + fixedFileName);
file.transferTo(dest);
// Validate
zip = new TFile(dest);
resp = mls.validateMapLayer(zip);
// Now perform the upload and delete the temp file
FoundryUserDetails userDetails = (FoundryUserDetails) SecurityContextHolder.getContext().getAuthentication()
.getPrincipal();
UserIdentity ui = userDetails.getUserIdentity();
MapLayer newLayer = new MapLayer();
// generate the prj
mls.generateProjection(resp, dest.getAbsolutePath(), projection);
The method "generateProjection" is where the file is added:
public void generateProjection(UploadMapResponse resp, String fLoc, FoundryCRS proj) throws NoSuchAuthorityCodeException,
FactoryException, IOException {
TFile projFile = new TFile(fLoc, resp.getLayerName() + ".prj");
CoordinateReferenceSystem crs = CRS.decode(proj.getEpsg());
String wkt = crs.toWKT();
TConfig config = TConfig.push();
try {
config.setOutputPreferences(config.getOutputPreferences().set(FsOutputOption.GROW));
TFileOutputStream writer = new TFileOutputStream(projFile);
try {
writer.write(wkt.getBytes());
} finally {
writer.close();
}
} finally {
config.close();
}
}
In order to test if this worked at all I tried it in a simple main:
public static void main(String[] args) {
File f = new File("C:/Data/SierritaDec2011TopoContours.zip");
TFile tf = new TFile(f);
tf.listFiles();
TFile proj = new TFile(f, "test.prj");
TConfig config = TConfig.push();
try {
config.setOutputPreferences(config.getOutputPreferences().set(FsOutputOption.GROW));
TFileOutputStream writer = null;
try {
writer = new TFileOutputStream(proj);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
try {
writer.write("Hello Zip world".getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} finally {
// Pop the current configuration off the inheritable thread local
// stack.
config.close();
}
}
Which, of course, works just fine.
The Question
Does anyone have insight into why, in a web server with a MultiPartFile copied to a local file, the TFileOutputStream fails to write properly?
In a long running server app, you may need to add a call to TVFS.sync() or TVFS.umount() in order to sync or umount archive files. In the case of ZIP files, this will trigger to write the Central Directory at the end of the ZIP file, which is required to form a valid ZIP file.
Please check the Javadoc to decide which call is the best for your use case: http://truezip.java.net/apidocs/de/schlichtherle/truezip/file/TVFS.html
Also, please note that calling TFVS.sync() or TVFS.umount() after each append operation will result in a growing Central Directory to be written each time, which results in huge overhead. So it's worth to consider when exactly you need to do this. Generally speaking this is only required when you want a third party to access the ZIP file. A third party is anyone not interacting with the TrueZIP Kernel for accessing the ZIP file.

Resources