We have one screen/page in our application where we are showing different columns for different products. These all records in the columns are fetched from database.
Also, We have two export buttons at the bottom of the screen which is meant for showing all those records in the PDF and XLS format.
These functionalities are working fine except under one condition. We have one column name in the screen whose values are fetched from database. when any record under name column has & in it, the export functionality stopped working.
For example :-
for name "BOWOG BEHEER B.V.", the export is working fine for both pdf and xls.
But for the name "BOWOG & BEHEER B.V.", it stopped working. While clicking on export button, pdf and xls is showing as blank page.
Could anyone please help ?
Below is the piece of codes :- (not full code)
public class CVRExportServlet extends HttpServlet {
private final SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");
/** context. */
private ResourceContext context = null;
private Map createParametersFromRequest(final HttpServletRequest request) {
// copy all request parameters
final Map parameters = new HashMap();
final Enumeration names = request.getParameterNames();
while (names.hasMoreElements()) {
final String name = (String) names.nextElement();
final String[] values = request.getParameterValues(name);
if (values.length > 1) {
parameters.put(name, values);
} else {
parameters.put(name, values[0]);
}
}
// parse request uri to get type and format
final String requestURI = request.getRequestURI();
String type = StringUtils.left(requestURI, requestURI.lastIndexOf('.'));
type = StringUtils.substring(type, requestURI.lastIndexOf('/') + 1);
final String format = StringUtils.substring(requestURI, requestURI.lastIndexOf('.') + 1);
parameters.put(Constants.EXPORT_TYPE_PARAMETER, type);
parameters.put(Constants.EXPORT_FORMAT_PARAMETER, format);
// determine themeUrl
final String requestUrl = request.getRequestURL().toString();
final int index = requestUrl.indexOf(request.getContextPath());
String server = "";
if (index > -1) {
server = requestUrl.substring(0, index);
}
private void fillParameters(final HttpServletRequest request, final HttpServletResponse response, final Map parameters)
throws ApplicationException {
parameters.put("props", ResourceBundle.getBundle("messages"));
// Create search request using the search form
final SearchForm form = (SearchForm) request.getSession().getAttribute(
(String) request.getSession().getAttribute(CvrConstants.SESS_ATTR_CVR_SEARCH_FORM_NAME));
final SearchRequest searchRequest = form.getSearchRequest();
searchRequest.setPageNumber(1);
searchRequest.setRowsPerPage(10000);
parameters.put("searchRequest", searchRequest);
}
public void service(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
final long startTime = System.currentTimeMillis();
// create parameters from request
final Map parameters = this.createParametersFromRequest(request);
parameters.put(ResourceContext.class.getName(), this.context);
try {
this.fillParameters(request, response, parameters);
final SearchRequest searchRequest = (SearchRequest) parameters.get("searchRequest");
if (searchRequest == null || searchRequest.getCounterPartyList() == null
|| searchRequest.getCounterPartyList().isEmpty()) {
throw new ExportException("Exception occurred while handling export: empty counterparty list");
} else {
if (searchRequest.getCounterPartyList().size() == 1) {
this.handleSingleReportExport(response, parameters);
} else {
this.handleMutlipleReportExport(response, parameters);
}
}
} catch (final Exception e) {
this.handleException(e, request, response);
}
}
private void handleSingleReportExport(final HttpServletResponse response, final Map parameters) throws Exception {
final XmlExportService exportService = this.getXmlExportService();
final ApplicationContext context = this.getApplicationContext();
final XmlTransformationService xmlTransformationService = (XmlTransformationService) context.getBean("transformationService");
// perform export
exportService.export(parameters);
// perform transformation
final ExportResult exportResult = xmlTransformationService.transform(parameters);
// write result to stream
response.setContentType(exportResult.getContentType());
response.setContentLength(exportResult.getContentLength());
if (parameters.get("format").equals("csv")) {
response.setContentType("text/csv");
response.setHeader("Content-disposition", "attachment; filename=export.csv");
} else if (parameters.get("format").equals("pdf")) {
response.setContentType("application/pdf");
response.setHeader("Content-disposition", "inline; filename=export.pdf");
}
final ServletOutputStream out = response.getOutputStream();
out.write(exportResult.getBytes());
out.flush();
out.close();
}
private void handleMutlipleReportExport(final HttpServletResponse response, final Map parameters) throws Exception {
final SearchRequest searchRequest = (SearchRequest) parameters.get("searchRequest");
response.setContentType("application/force-download");
response.setHeader("Content-Encoding" , "x-compress");
response.setHeader("Content-Disposition", "attachment; filename=export_" + parameters.get("format") + ".zip");
final XmlExportService exportService = this.getXmlExportService();
final ApplicationContext context = this.getApplicationContext();
final XmlTransformationService xmlTransformationService = (XmlTransformationService) context.getBean("transformationService");
// start the zip process
final ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
// create a file for each counterparty and add it to the zip file
for (final String counterPartyId : searchRequest.getCounterPartyList()) {
// make sure to reset the counterparty to the current one in the loop
searchRequest.setCounterPartyList(Arrays.asList(new String[] {counterPartyId}));
// perform export
exportService.export(parameters);
// perform transformation
final ExportResult exportResult = xmlTransformationService.transform(parameters);
// add the file to the zip
final String fileName = counterPartyId + "_" + sdf.format(searchRequest.getRevaluationDate()) + "." + parameters.get("format");
zos.putNextEntry(new ZipEntry(fileName));
zos.write(exportResult.getBytes());
zos.closeEntry();
}
// finish the zip process
zos.flush();
zos.close();
}
I have some idea now. actually the issue is there at vm (velocity template). The "name" column is fetched from vm file and code is something like this :-
$!{result.counterpartyName}
This is in for each loop for multiple records. Could anyone please suggest how can i ignore special characters in the vm file itself. so that we will be able to export correctly even if "name" column has "&" or "-" etc special characters.
It seems based on your code that you are using an XML transformation service.
I'd say it's probably your data in your parameters containing dangling & sign. To be valid XML ready for transformation, & should be &. However, based on the code given it is not possible to say where the XML data is coming from. You say it's coming from the database, so my guess is that the problem should be dealt with by modifying the data in the database.
Edit:
It seems I was partly right, but the database doesn't contain the XML - if I got this correctly, data is coming from database as raw tabular data, but is formatted to XML using velocity templates. If that's it, then XML escaping should be used in velocity template like this.
Related
Goodmorning everyone,
I am creating a web application for my degree and I have been running into a problem for several days related to the loading and retrive of images from the database.
I can upload the photos without major problems, I still leave the controller code:
#PostMapping()
public AckDto handleImagePost(#RequestParam ("file") MultipartFile file, #RequestParam Long userId, #RequestParam Long contestId) throws ServiceException, IOException {
PhotoDto photoDto = new PhotoDto();
photoDto.setTitle("Test Image");
photoDto.setDescription("Test description");
photoDto.setImage(file.getBytes());
return photoService.saveImagineFile(photoDto, userId, contestId);
}
While for the get of the photos I can only take one photo with the following method:
#GetMapping(value = "/image", produces = MediaType.IMAGE_PNG_VALUE)
public Resource downloadImage(#RequestParam Long contestId) throws ServiceException, IOException {
Photo photo = photoService.findByContest_Id(contestId);
byte[] image = photoService.findByContest_Id(contestId).getImage();;
return new ByteArrayResource(image);
}
while if I try to take more photos with the following code obviously changing the Service and Repository:
#GetMapping(value = "/image", produces = MediaType.IMAGE_PNG_VALUE)
public List<Resource> downloadImage(#RequestParam Long contestId) throws ServiceException, IOException {
List<Photo> photo = photoService.findByContest_Id(contestId);
List<Resource> results = new ArrayList<>();
for(Photo p : photo){
results.add(new ByteArrayResource(p.getImage()));
}
return results;
}
it returns me the following errors:
org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.ArrayList] with preset Content-Type 'null'
I also tried to return a PhotoDto list but it doesn't change anything,
Some idea?
If you need any other class, ask and it will be given to you.
Thanks to everyone, I solved the problem was that I had accidentally left some old notes that I assume were in conflict with others.
Not sure if the following works for you, but you can zip all images and then retrieve them in a unique file.
The code example (taken from the reference below):
#GetMapping(value = "/zip-download", produces="application/zip")
public void zipDownload(#RequestParam List<String> name, HttpServletResponse response) throws IOException {
ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());
for (String fileName : name) {
FileSystemResource resource = new FileSystemResource(fileBasePath + fileName);
ZipEntry zipEntry = new ZipEntry(resource.getFilename());
zipEntry.setSize(resource.contentLength());
zipOut.putNextEntry(zipEntry);
StreamUtils.copy(resource.getInputStream(), zipOut);
zipOut.closeEntry();
}
zipOut.finish();
zipOut.close();
response.setStatus(HttpServletResponse.SC_OK);
response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + zipFileName + "\"");
}
Reference: https://www.devglan.com/spring-boot/spring-boot-file-upload-download
Rather than returning a List, return a ResponseEntity<List>.
It MIGHT work.
Problem is that whatever way you're going about it, it's unlikely the frontend will be able to pull out your images.
UUEncoding them manually and putting them in the HTTP headers is probably your best bet. That way the frontend can iterate over the headers containing the images and get them one by one in a format it should be able to decode.
in xpages I can use:
var protocol = context.getUrl().getScheme() + "://";
var url:XSPUrl = new XSPUrl(database.getHttpURL());
var host = url.getHost();
...
to build urls to documents/files in documents
How should I build the URL's equivalent in Java?
I build URL's in Java all the time.
Here are some RANDOM code snippets that I use. This is not a single class, just random snippets that should help you get started at least.
FacesContext facesContext = FacesContext.getCurrentInstance();
XSPContext context = XSPContext.getXSPContext(facesContext);
String entryPage = context.getUrl().getPath() + context.getUrl().getQueryString();
if (entryPage.contains("/home.xsp")) {
this.console("Entry Page contains /home.xsp");
if (this.isBasicMode()) {
entryPage.replace("home.xsp", "basic_Menu.xsp");
}
} else {
this.console("entry page does NOT contain /home.xsp");
}
context.redirectToPage(“/myPage.xsp”);
public void redirectExternal(String url) throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExtenalContext externalContext = fc.getExternalContext();
externalContext.redirect(url);
}
public void redirectToPage(final String pageName) {
// pageName = "/myPage.xsp"
try {
// You'd think this would end all Java processing but that's NOT
// what happens
// It looks like the Java code will finish and only then will the
// redirection happen.
final String entryPage = JSFUtil.getXSPContext().getUrl().getPath() + JSFUtil.getXSPContext().getUrl().getQueryString();
FrameworkUtils.getSessionScope().put("entryPage", entryPage);
this.setEntryPage(entryPage);
JSFUtil.getXSPContext().redirectToPage(pageName);
} catch (final RedirectSignal rs) {
// Ignoring this error. Useless!
}
// Returning false so we can stop the calling code from continuing
// return false;
}
public String getParam(final String key) {
if (!this.getQueryString().containsKey(key)) {
return null;
} else {
return this.getQueryString().get(key);
}
}
#SuppressWarnings("unchecked")
public Map<String, String> getQueryString() {
final Map<String, String> qs = (Map<String, String>) FrameworkUtils.resolveVariable("param");
return qs;
}
depends where your documents files are. It think the best way is create a servlet in the nsf, call that by passing an docUNID and attachmentName. Then you can get the document and write the attachment as stream to the response. If you set the header to attachment, like
response.setHeader("Content-disposition", "attachment; filename=\""+attachment.getName()+"\"");
you will get the attachment as download
I'm facing an issue when I deploy my application on server side (on local machine everything works fine). In my application, a user can use multiupload for uploading files. Here is my controller:
#Controller
public class FileUploadController {
#Autowired
private StoryService storyService;
#Autowired
private PhotoService photoService;
#RequestMapping("/uploader")
public String home() {
// will be resolved to /views/fileUploader.jsp
return "admin/fileUploader";
}
#RequestMapping(value = "/admin/story/upload", method = RequestMethod.POST)
public #ResponseBody
String upload(MultipartHttpServletRequest request,
HttpServletResponse response, HttpServletRequest req) throws IOException {
//get story id
Integer story_id = Integer.valueOf(req.getParameter("story_id"));
Story story = storyService.findById(story_id);
// Getting uploaded files from the request object
Map<String, MultipartFile> fileMap = request.getFileMap();
// Iterate through the map
for (MultipartFile multipartFile : fileMap.values()) {
// Save the file to local disk
String name = Long.toString(System.currentTimeMillis());
//original size
saveFileToLocalDisk(multipartFile, name + ".jpg");
//medium size
Thumbnails.of(convertMultifileToFile(multipartFile)).size(1800, 2400)
.toFile(new File(getDestinationLocation() + "medium_" + name));
//thumbnail size
Thumbnails.of(convertMultifileToFile(multipartFile)).size(600, 800)
.toFile(new File(getDestinationLocation() + "thumb_" + name));
//Save to db
savePhoto(multipartFile, name, story);
}
return "redirect:/admin";
}
private void saveFileToLocalDisk(MultipartFile multipartFile, String name)
throws IOException, FileNotFoundException {
FileCopyUtils.copy(multipartFile.getBytes(), new FileOutputStream(getDestinationLocation() +
name));
}
private String getOutputFilename(MultipartFile multipartFile) {
return getDestinationLocation() + multipartFile.getOriginalFilename();
}
private Photo savePhoto(MultipartFile multipartFile, String name, Story story)
throws IOException {
Photo photo = new Photo();
if (story != null) {
photo.setName(name);
photo.setStory(story);
photoService.addPhoto(photo);
}
return photo;
}
private String getDestinationLocation() {
return "/var/www/static/images/";
}
public File convertMultifileToFile(MultipartFile file) throws IOException
{
File convFile = new File(file.getOriginalFilename());
convFile.createNewFile();
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
return convFile;
}
}
When I try to upload images on the server, I'm getting following exception:
SEVERE: Servlet.service() for servlet [mvc-dispatcher] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NumberFormatException: For input string: ""] with root cause
java.lang.NumberFormatException: For input string: ""
Can't figure out what it means and how to solve it. By the way, I've noticed that when I upload files which are 100-200 KB everything is ok, when files are 4-5 MB I get exception.
Thanks in advance!
It appears that "story_id" is not always set; correlation with the file size may or may not be a coincidence.
You should protect your code from client-side errors like this by treating the "story_id" parameter as optional. This is a good idea for all request parameters, because it prevents your server side from crashing on improperly formed requests:
String storyIdStr = req.getParameter("story_id");
if (storyIdStr == null || storyIdStr.length() == 0) {
// Deal with the error
}
Integer story_id = null;
try {
story_id = Integer.valueOf(storyIdStr);
} catch (NumberFormatException nfe) {
// Deal with the error
}
Integer.valueOf(req.getParameter("story_id")); will give you this exception if req.getParameter("story_id") returns an empty String, since an empty String can't be parsed as an Integer.
I am working on below scenario since last two days,
I have developed a java filter that check whether request is multipart type,
If it is, I want to restrict .php file getting uploaded.
In servlet filter I successfully retrieved type of file, if it's valid one, i have forwarded that request to proceed.
Now my business logic that was working exactly fine without filter is now failed to upload.
My project is using Spring framework.
At business logic, I'm using MultipartRequest(class of spring) as casting in.
Invoking request.getFileNames() which is returning nothing after involving filter.
In filter, I have wrapped request after validating file extensions as follows:
All form fields are set in parameter map that will be passed with request.
And File type field is set as attribute in request object.
Would you guys please help?
Thanks,
Namrata Shah
In doFilter(),
I have checked whether received request is instance of HttpServletRequest. If yes, then it'll be parsed if it's a multipart req using below code:
parseRequest():
{
List<FileItem> multipartItems = null;
try
{ multipartItems = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
}
catch (FileUploadException e)
{
throw new ServletException("Cannot parse multipart request: " + e.getMessage());
}
Map<String, String[]> parameterMap = new HashMap<String, String[]>();
for (FileItem multipartItem : multipartItems)
{
if (multipartItem.isFormField())
processFormField(multipartItem, parameterMap);
else
processFileField(multipartItem, request);
}
return wrapRequest(request, parameterMap);
}
Code for processFileField():
request.setAttribute(fileField.getFieldName(), fileField);
then, I wrap request as follows:
private static HttpServletRequest wrapRequest(
HttpServletRequest request, final Map<String, String[]> parameterMap)
{
return new HttpServletRequestWrapper(request)
{
#Override
public Map<String, String[]> getParameterMap()
{
return parameterMap;
}
public String[] getParameterValues(String name)
{
return parameterMap.get(name);
}
public String getParameter(String name)
{
String[] params = getParameterValues(name);
return params != null && params.length > 0 ? params[0] : null;
}
public Enumeration<String> getParameterNames()
{
return Collections.enumeration(parameterMap.keySet());
}
};
}
Code for processFormField():
String name = formField.getFieldName(),value = formField.getString();
String[] values = parameterMap.get(name);
if (values == null)
{
parameterMap.put(name, new String[]{value});
}
else
{
int length = values.length;
String[] newValues = new String[length + 1];
System.arraycopy(values, 0, newValues, 0, length);
newValues[length] = value;
parameterMap.put(name, newValues);
}
I have implemented servlet which behaves not stable, sometimes it mixes header in content and writing same twice.
and sometimes it is returning file which contains response header mixed by content like this:
Server: Apache-Coyote/1.1
: W/"43-1353687036000"
DatCCoonntenntt--DDiissppoosittiioonn: : atatatacehnmte;n tf;i lfenlaemnea=m20=12201112211127325421_4W1_Wirnkgi_nSgc_Seern.xnlsx
sx
Content-Typ-eT: ype: applaipcatciaoti/on/toctestt-rstare
am
ConCtoententy-pTeype: appalicatcion/oon/octet-setarm
m
CCoonntent-Lnegtht h: 4199
Date: te: FriF,r i2,3 2No vNo2v0 120162: 215:25 :G4M2T
....
File content bytes ...
And again same header and content
UPDATE
*This situation happens on Tomcat7*
I have tested also on Tomcat6 and Jetty, in both cases there is no injection of HTTP-Header to response content but HTTP-Header is wrong and returns wrong file name, the file content is correct file. I have noticed that wrong return from servlet happens when
returns transfer-encoding is chunked.
When I am removing header stuff, and second part of bytes, it is valid file.
Is it possible that is synchronization issue ?
UPDATE
Here is full source of servlet :
public class ExcelDownloadServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
private static final Logger LOG = Logger
.getLogger (ExcelDownloadServlet.class);
#Override
protected void doGet (HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
try
{
TransactionId transactionId = getTransactionId (request);
String fileName =
request.getParameter (GlobalConstants.EXCEL_FILE);
ExcelDownloadType downloadType =
ExcelDownloadType
.valueOf (request
.getParameter (GlobalConstants.EXCEL_DOWNLOAD_TYPE));
ActionContextFactory actionContextFactory =
ApplicationContext.getContext ()
.getActionContextFactory ();
//suppress warning. HttpServletRequest.getLocales does not support generics
#SuppressWarnings("unchecked")
ActionContext actionContext =
actionContextFactory.create (request.getSession ()
.getId (), Collections.<Locale> list (request
.getLocales ()));
GetExcelDataResponse dataResponse =
new GetExcelData (transactionId, fileName, downloadType)
.execute (actionContext);
writeToResponse (response, dataResponse.getFileName (),
dataResponse.getData ());
}
catch (InvalidSessionException e)
{
LOG.error ("Invalid session in Excel download", e);
throw new ServletException (e);
}
catch (ActionException e)
{
LOG.error ("Could not download into excel.", e);
throw new ServletException (e);
}
}
protected TransactionId getTransactionId (HttpServletRequest request)
{
return RequestParameterDeserializer.<TransactionId> deserialize (
request, GlobalConstants.TRANSACTION_ID);
}
protected void writeToResponse (HttpServletResponse response,
String rawFileName, byte[] data) throws IOException
{
ServletOutputStream sout = null;
try
{
response.setContentType ("application/octet-stream");
response.setContentLength (data.length);
// removing blanks from the file name, since FF cuts file names
// otherwise.
String fileNameWithTime = rawFileName.replaceAll (" ", "_");
response.setHeader ("Content-Disposition", "attachment; filename="
+ fileNameWithTime);
sout = response.getOutputStream ();
sout.write (data, 0, data.length);
}
finally
{
if (sout != null)
{
sout.close ();
}
}
}
UPDATE
*The call comes from GWT application when is generating the URL of servlet with required parameters and sets in IFrame, then servlet calls and file is downloading. Are there any suggestions ?*
I had a similar issue a long time ago.
It turned out that closing the ServletOutputStream triggered an unexpected behaviour on the request flow.
Servlets are not supposed to close the container provided OutputStream.
Another issue could be manually setting the content length, it is responsibility of the container producing the correct value.
To summarize, try removing out.close() and response.setContentLength()