I was looking for a way to send a PDF (direct display) file to the browser through Liferay Portal. Found many solutions - the most popular one being writing a Servlet that does the job. I've read about Portlet Resource Serving in JSR 286 Specification, can someone please elaborate on that for Spring 3.0 Portlet MVC?
<servlet>
<display-name>DownloadServlet</display-name>
<servlet-name>DownloadServlet</servlet-name>
<servlet-class>com.liferay.portal.pdf.DownloadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DownloadServlet</servlet-name>
<url-pattern>/DownloadServlet/*</url-pattern>
</servlet-mapping>
And the Servlet Consists of:
private void downloadServlet(HttpServletRequest req,
HttpServletResponse resp) throws ServletException, IOException {
logger.debug(" downloadServlet :: ");
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
ServletOutputStream op = null;
try {
//Something
pdfContentVO=//getpdf VO here
String filename = "PDFFILE_"+pdfNumber+".pdf";
op = resp.getOutputStream();
resp.setContentType("application/pdf");
resp.setHeader("Content-Disposition", "attachment; filename="
+ filename);
resp.setContentLength(pdfContentVO.getPdfData().length);
System.out.println("pdfcontent"+pdfContentVO.getPdfData());
op.write(pdfContentVO.getPdfData());
op.flush();
op.close();
} catch(final IOException e) {
System.out.println ( "IOException." );
throw e;
} finally {
if (bis != null)
{
bis.close();
}
if (bos != null)
{
bos.flush();
bos.close();
}
}
}
I couldn't find anything on Servlet<->Portlet mapping thing. So I used Resource mapping for sending a pdf with Spring Portlet MVC using annotations.
Ref:http://developers.sun.com/portalserver/reference/techart/jsr286/jsr286_2.html
In JSP:
<portlet:resourceURL var="PDFActionURL">
<portlet:param name="reportType" value="pdf" />
<portlet:param name="pdfNumber" value="${pdfNumber}" />
</portlet:resourceURL>
<input type="button" name="viewPDFButton" value="View PDF" onClick="self.location = '${PDFActionURL}';" />
In Spring ApplicationContext.xml of the portlet, include these:
<context:annotation-config />
<context:component-scan base-package="com.xxx" />
Define a new controller:
import java.io.IOException;
import java.io.OutputStream;
import javax.portlet.PortletException;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.portlet.bind.annotation.ResourceMapping;
import com.xxx.pdf.PDFBO;
import com.xxx.PDFDTO;
import com.liferay.portal.kernel.servlet.HttpHeaders;
import com.liferay.portal.kernel.util.ParamUtil;
#Controller("pdfController")
#RequestMapping(value = "view")
public class PDFController {
private final static Logger LOG = LoggerFactory.getLogger(PDFController.class);
//This is using Spring 3.0 Annotation Mapping (Spring Portlet MVC Architecture)
#ResourceMapping
public void serveResource(ResourceRequest resourceRequest, ResourceResponse res) throws PortletException, IOException {
LOG.info("In serveResource: ResourceURL");
String returnType = ParamUtil.getString(resourceRequest, "reportType");
String pdfNumber = ParamUtil.getString(resourceRequest, "pdfNumber");
LOG.info("returnType:" + returnType + " pdfNumber:" + pdfNumber);
String filename = "FILENAME_"+pdfNumber+".pdf";
// HttpServletRequest request =
// PortalUtil.getHttpServletRequest(resourceRequest);
if (returnType != null && returnType.equals("pdf")) {
try {
//GET YOUR PDF HERE
//PDFBO pdfBO = new PDFBO();
//PDFDTO pdfContentVO = null;
//pdfContentVO = pdfBO.getPDF(pdfNumber);
res.setContentType("application/pdf");
res.addProperty(HttpHeaders.CACHE_CONTROL, "max-age=3600, must-revalidate");
res.addProperty(HttpHeaders.CONTENT_DISPOSITION,"filename="+ filename);
//Use this to directly download the file
//res.addProperty(HttpHeaders.CONTENT_DISPOSITION,"attachment");
OutputStream out = res.getPortletOutputStream();
//out.write(pdfContentVO.getPdfData());
out.write(/*get pdf byte[] Array Here */);
out.flush();
out.close();
} catch (Exception e) {
LOG.info("Error in " + getClass().getName() + "\n" + e);
}
}
}
}
Edit: If you are using previous versions of Liferay, this is a great article to implement file download/serving through Liferay - https://www.liferay.com/web/raymond.auge/blog/-/blogs/801426
Related
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.
1) Upgraded our code from wicket 1.4.9 to wicket 6.6 and from jdk 1.6 to Jdk 1.8
2)First time i am able to log in application, if i click logout and click login
link from homepage getting session expired,
Is there any modification is required in wicket 6.6 to work fine in IE and FireFox, old code(wicket 1.4.9) was working fine in all 3 browsers.
3)We are using Jboss-eap-7.0 server
This the servlet class responsible for JSESSIONID
package com.bnaf.servlet;
import static com.bnaf.CLAS.clasConfiguration;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.grlea.log.SimpleLogger;
import org.owasp.esapi.ESAPI;
import com.bnaf.utils.Constants;
import com.bnaf.utils.RedirectUrlBuilder;
public class ReqAuthnServlet extends HttpServlet {
private static final SimpleLogger log = new SimpleLogger(ReqAuthnServlet.class);
private HttpServletResponse response = null;
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
log.info("*********************************************************");
log.info(" Authentication request process initiated ");
log.info("**********************************************************");
this.response = response;
// Valid request parameters
ESAPI.httpUtilities().setCurrentHTTP(request, response);
String sessionIdReq = ServletHelper.getSafeValue(request, "sessionid");
log.debug("Authentication request received. sessionIdReq: [" + sessionIdReq + "]");
if (sessionIdReq == null || sessionIdReq.equals("")) {
log.error("Failed to find requested session ID!");
String message = Constants.ERROR_CODE_ILLEGAL_ARGS + ";" + Constants.ERROR_MSG_ILLEGAL_ARGS;
handleResponse(HttpServletResponse.SC_BAD_REQUEST, message);
return;
}
sessionIdReq = sessionIdReq.trim();
if (request.getSession(false) != null) {
request.getSession(false).invalidate(); // invalidate old session
}
Cookie cookie = new Cookie("JSESSIONID", sessionIdReq);
cookie.setMaxAge(-1);
response.addCookie(cookie);
String authnURL = constructRedirectUrl(request, clasConfiguration().getAuthnURL()) + ";jsessionid=" + sessionIdReq;
log.debug("authnURL = " + authnURL);
response.sendRedirect(response.encodeRedirectURL(authnURL));
log.info(" ****** Generated authentication URL ****** " + authnURL);
log.info(" ****** Authentication request process completed ****** ");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
private String constructRedirectUrl(HttpServletRequest request, String path) {
// construct redirect url base
RedirectUrlBuilder urlBuilder = new RedirectUrlBuilder();
urlBuilder.setScheme(request.getScheme());
urlBuilder.setServerName(request.getServerName());
urlBuilder.setPort(request.getServerPort());
urlBuilder.setContextPath(request.getContextPath());
urlBuilder.setServletPath(path);
return urlBuilder.getUrl();
}
private void handleResponse(int status, String msg) throws IOException {
if (status != HttpServletResponse.SC_OK) {
response.sendError(status, msg);
} else {
this.response.setStatus(status);
PrintWriter out = this.response.getWriter();
out.println(msg);
out.flush();
out.close();
}
}
}
Below code is in wicket6.6 -- you can find log out method, where session is invalidated.
import static com.bnaf.CLAS.clasConfiguration;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang.WordUtils;
import org.apache.wicket.RestartResponseException;
import org.apache.wicket.core.request.handler.PageProvider;
import org.apache.wicket.core.request.handler.RenderPageRequestHandler;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.link.PopupSettings;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.http.WebResponse;//new
import org.apache.wicket.request.http.handler.RedirectRequestHandler;//news
import org.apache.wicket.request.mapper.parameter.PageParameters;//new
import org.apache.wicket.request.resource.CssPackageResource;//new
import org.bouncycastle.ocsp.RespData;
import org.grlea.log.SimpleLogger;
import com.bnaf.exception.AuthenticationServiceException;
import com.bnaf.model.ClasDB;
import com.bnaf.utils.Constants;
import com.bnaf.web.ClasApplication;
import com.bnaf.web.UserSession;
import com.bnaf.web.common.panel.ClasBaseAfterLoginPanel;
import com.bnaf.web.onlineregistration.ui.BnafContactAddress;
import com.bnaf.web.onlineregistration.ui.BnafPrivacyPolicy;
import com.bnaf.web.onlineregistration.ui.BnafServCenter;
public class ClasBaseAfterLogin extends WebPage {
ClasDB user;
String userId;
protected String accountType = "";
private static final SimpleLogger LOG = new SimpleLogger(ClasBaseAfterLogin.class);
public ClasBaseAfterLogin(PageParameters parameters) {
String ticket = parameters.get("ticket").toString();
String clasSessionId = parameters.get("clasSessionId").toString();
Authentication au = new Authentication();
List lst;
try {
lst = au.retrieveAuthnStatus(ticket, clasSessionId);
} catch (AuthenticationServiceException e) {
String locale = getSession().getLocale().toString();
String redirectUrl = clasConfiguration().getUserMgmtHomeUrl() + "?loc=" + locale;
getRequestCycle().scheduleRequestHandlerAfterCurrent(new RedirectRequestHandler(redirectUrl));//new
return;
}
String authStat = (String) lst.get(1);
boolean authStatus = Boolean.valueOf(authStat);
userId = (String) lst.get(0);
}
public ClasBaseAfterLogin() {
PopupSettings popupSettings = new PopupSettings().setHeight(825).setWidth(1000);
add(new BookmarkablePageLink("privacyPolicy", BnafPrivacyPolicy.class).setPopupSettings(new PopupSettings(PopupSettings.RESIZABLE
| PopupSettings.SCROLLBARS).setHeight(1500).setWidth(1000)));
add(new BookmarkablePageLink("contactUs", BnafContactAddress.class).setPopupSettings(new PopupSettings(PopupSettings.RESIZABLE
add(new BookmarkablePageLink("servCenter", BnafServCenter.class).setPopupSettings(new PopupSettings(PopupSettings.RESIZABLE
| PopupSettings.SCROLLBARS).setHeight(1500).setWidth(1000)));
Label label = new Label("pageTitle", getLocalizer().getString("label.title", this));
add(label);
userId = (String) UserSession.get().getMyObject();
if (userId == null) {
setResponsePage(Welcome.class);
} else {
try {
user = ClasApplication.get().getPasswordManagerService().getUserProfileDetails(userId);
} catch (AuthenticationServiceException e) {
LOG.errorException(e);
setResponsePage(new BnafCommonErrorPage(this.getPage(), getLocalizer().getString("label.applicaiton.error.page", this),
getLocalizer().getString("request.process.page.error", this)));
}
}
String nameOfUser = null;
if (user != null && user.getLangPref().equals(Constants.USER_LANG_PREF_ENG)) {
nameOfUser = WordUtils.capitalize(user.getName().concat(" ")
.concat((user.getSixthName() != null || (!user.getSixthName().equals("")) ? user.getSixthName() : "")));
} else if (user != null && user.getLangPref().equals(Constants.USER_LANG_PREF_AR)) {
nameOfUser = user.getNameArb().concat(" ")
.concat((user.getSixthNameArb() != null || (!user.getSixthNameArb().equals("")) ? user.getSixthNameArb() : ""));
}
add(new Label("userName", nameOfUser));
add(new ClasBaseAfterLoginPanel("clasbasepanel", userId));
// addCssToPage();
String accountType ="";
String registrationType =(String) UserSession.get().getRegistrationType();
if(!(registrationType.equals(""))){
if(registrationType.equals(Constants.LABEL_BASIC_EKEY_USER)){
accountType = getLocalizer().getString("standard.ekey.account", this);
}else if(registrationType.equals(Constants.LABEL_ADVANCE_EKEY_USER)){
accountType = getLocalizer().getString("advanced.ekey.account", this);
}
}
LOG.info("account_type:" + accountType);
add(new Label("accountType", accountType));
if (getSession().getId() == null) {
//getRequestCycle().setRedirect(true);
throw new RestartResponseException(new BnafCommonErrorPage(this.getPage(), getLocalizer().getString(
"label.session.expired.heading", this), getLocalizer().getString("label.session.expired.error", this)));
}
add(new Link("logout") {
public void onClick() {
String locale = getSession().getLocale().toString();
String redirectUrl = clasConfiguration().getUserMgmtHomeUrl() + "?loc=" + locale;
getSession().invalidateNow();
// getRequestCycle().setRedirect(true);
//getRequestCycle().setRequestTarget(new RedirectRequestTarget(redirectUrl));//old
getRequestCycle().scheduleRequestHandlerAfterCurrent(new RedirectRequestHandler(redirectUrl));//new
}
});
}
/**************NEW WAY TO ADD css FILE FROM WICKET 6.X ************************/
#Override
public void renderHead(IHeaderResponse response) {
response.render(CssHeaderItem.forUrl("css/$/styles.css".replace("$", getSession().getLocale().toString().toLowerCase())));
response.render(CssHeaderItem.forUrl("css/$/reset.css".replace("$", getSession().getLocale().toString().toLowerCase())));
}
/**************END NEW WAY TO ADD css FILE FROM WICKET 6.X ************************/
#Override
protected void configureResponse(WebResponse responses) {
super.configureResponse(responses);
//WebResponse response = (WebResponse) getRequestCycle().getResponse();// getResponse() use Get the active response at the request cycle.
responses.setHeader("Cache-Control", "no-cache, max-age=0,must-revalidate, no-store");
responses.setHeader("Expires", "-1");
responses.setHeader("Pragma", "no-cache");
// responses.setCharacterEncoding("text/html; charset=utf-8");
getSession().setLocale(new Locale(getSession().getLocale().toString()));
}
}
How can I retrieve and display images from a database in a JSP page?
Let's see in steps what should happen:
JSP is basically a view technology which is supposed to generate HTML output.
To display an image in HTML, you need the HTML <img> element.
To let it locate an image, you need to specify its src attribute.
The src attribute needs to point to a valid http:// URL and thus not a local disk file system path file:// as that would never work when the server and client run at physically different machines.
The image URL needs to have the image identifier in either the request path (e.g. http://example.com/context/images/foo.png) or as request parameter (e.g. http://example.com/context/images?id=1).
In JSP/Servlet world, you can let a Servlet listen on a certain URL pattern like /images/*, so that you can just execute some Java code on specific URL's.
Images are binary data and are to be obtained as either a byte[] or InputStream from the DB, the JDBC API offers the ResultSet#getBytes() and ResultSet#getBinaryStream() for this, and JPA API offers #Lob for this.
In the Servlet you can just write this byte[] or InputStream to the OutputStream of the response the usual Java IO way.
The client side needs to be instructed that the data should be handled as an image, thus at least the Content-Type response header needs to be set as well. You can obtain the right one via ServletContext#getMimeType() based on image file extension which you can extend and/or override via <mime-mapping> in web.xml.
That should be it. It almost writes code itself. Let's start with HTML (in JSP):
<img src="${pageContext.request.contextPath}/images/foo.png">
<img src="${pageContext.request.contextPath}/images/bar.png">
<img src="${pageContext.request.contextPath}/images/baz.png">
You can if necessary also dynamically set src with EL while iterating using JSTL:
<c:forEach items="${imagenames}" var="imagename">
<img src="${pageContext.request.contextPath}/images/${imagename}">
</c:forEach>
Then define/create a servlet which listens on GET requests on URL pattern of /images/*, the below example uses plain vanilla JDBC for the job:
#WebServlet("/images/*")
public class ImageServlet extends HttpServlet {
// content=blob, name=varchar(255) UNIQUE.
private static final String SQL_FIND = "SELECT content FROM Image WHERE name = ?";
#Resource(name="jdbc/yourDB") // For Tomcat, define as <Resource> in context.xml and declare as <resource-ref> in web.xml.
private DataSource dataSource;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String imageName = request.getPathInfo().substring(1); // Returns "foo.png".
try (Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL_FIND)) {
statement.setString(1, imageName);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
byte[] content = resultSet.getBytes("content");
response.setContentType(getServletContext().getMimeType(imageName));
response.setContentLength(content.length);
response.getOutputStream().write(content);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
}
}
} catch (SQLException e) {
throw new ServletException("Something failed at SQL/DB level.", e);
}
}
}
That's it. In case you worry about HEAD and caching headers and properly responding on those requests, use this abstract template for static resource servlet.
See also:
How should I connect to JDBC database / datasource in a servlet based application?
How to upload an image and save it in database?
Simplest way to serve static data from outside the application server in a Java web application
I suggest you address that as two problems. There are several questions and answer related to both.
How to load blob from MySQL
See for instance Retrieve image stored as blob
How to display image dynamically
See for instance Show thumbnail dynamically
I've written and configured the code in JSP using Oracle database.
Hope it will help.
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class displayfetchimage
*/
#WebServlet("/displayfetchimage")
public class displayfetchimage extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public displayfetchimage() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
Statement stmt = null;
String sql = null;
BufferedInputStream bin = null;
BufferedOutputStream bout = null;
InputStream in = null;
response.setContentType("image/jpeg");
ServletOutputStream out;
out = response.getOutputStream();
Connection conn = employee.DbConnection.getDatabaseConnection();
HttpSession session = (HttpSession) request.getSession();
String ID = session.getAttribute("userId").toString().toLowerCase();
try {
stmt = conn.createStatement();
sql = "select user_image from employee_data WHERE username='" + ID + "' and rownum<=1";
ResultSet result = stmt.executeQuery(sql);
if (result.next()) {
in = result.getBinaryStream(1);// Since my data was in first column of table.
}
bin = new BufferedInputStream(in);
bout = new BufferedOutputStream(out);
int ch = 0;
while ((ch = bin.read()) != -1) {
bout.write(ch);
}
} catch (SQLException ex) {
Logger.getLogger(displayfetchimage.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (bin != null)
bin.close();
if (in != null)
in.close();
if (bout != null)
bout.close();
if (out != null)
out.close();
if (conn != null)
conn.close();
} catch (IOException | SQLException ex) {
System.out.println("Error : " + ex.getMessage());
}
}
}
// response.getWriter().append("Served at: ").append(request.getContextPath());
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Statement stmt = null;
String sql = null;
BufferedInputStream bin = null;
BufferedOutputStream bout = null;
InputStream in = null;
response.setContentType("image/jpeg");
ServletOutputStream out;
out = response.getOutputStream();
Connection conn = employee.DbConnection.getDatabaseConnection();
HttpSession session = (HttpSession) request.getSession();
String ID = session.getAttribute("userId").toString().toLowerCase();
try {
stmt = conn.createStatement();
sql = "select user_image from employee_data WHERE username='" + ID + "' and rownum<=1";
ResultSet result = stmt.executeQuery(sql);
if (result.next()) {
in = result.getBinaryStream(1);
}
bin = new BufferedInputStream(in);
bout = new BufferedOutputStream(out);
int ch = 0;
while ((ch = bin.read()) != -1) {
bout.write(ch);
}
} catch (SQLException ex) {
Logger.getLogger(displayfetchimage.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (bin != null)
bin.close();
if (in != null)
in.close();
if (bout != null)
bout.close();
if (out != null)
out.close();
if (conn != null)
conn.close();
} catch (IOException | SQLException ex) {
System.out.println("Error : " + ex.getMessage());
}
}
}
}
Try to flush and close the output stream if it does not display.
Blob image = rs.getBlob(ImageColName);
InputStream in = image.getBinaryStream();
// Output the blob to the HttpServletResponse
response.setContentType("image/jpeg");
BufferedOutputStream o = new BufferedOutputStream(response.getOutputStream());
byte by[] = new byte[32768];
int index = in.read(by, 0, 32768);
while (index != -1) {
o.write(by, 0, index);
index = in.read(by, 0, 32768);
}
o.flush();
o.close();
I used SQL SERVER database and so the answer's code is in accordance. All you have to do is include an <img> tag in your jsp page and call a servlet from its src attribute like this
<img width="200" height="180" src="DisplayImage?ID=1">
Here 1 is unique id of image in database and ID is a variable. We receive value of this variable in servlet. In servlet code we take the binary stream input from correct column in table. That is your image is stored in which column. In my code I used third column because my images are stored as binary data in third column. After retrieving input stream data from table we read its content in an output stream so it can be written on screen. Here is it
import java.io.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.*;
import javax.servlet.http.*;
import model.ConnectionManager;
public class DisplayImage extends HttpServlet {
public void doGet(HttpServletRequest request,HttpServletResponse response)
throws IOException
{
Statement stmt=null;
String sql=null;
BufferedInputStream bin=null;
BufferedOutputStream bout=null;
InputStream in =null;
response.setContentType("image/jpeg");
ServletOutputStream out;
out = response.getOutputStream();
Connection conn = ConnectionManager.getConnection();
int ID = Integer.parseInt(request.getParameter("ID"));
try {
stmt = conn.createStatement();
sql = "SELECT * FROM IMAGETABLE WHERE ID="+ID+"";
ResultSet result = stmt.executeQuery(sql);
if(result.next()){
in=result.getBinaryStream(3);//Since my data was in third column of table.
}
bin = new BufferedInputStream(in);
bout = new BufferedOutputStream(out);
int ch=0;
while((ch=bin.read())!=-1)
{
bout.write(ch);
}
} catch (SQLException ex) {
Logger.getLogger(DisplayImage.class.getName()).log(Level.SEVERE, null, ex);
}finally{
try{
if(bin!=null)bin.close();
if(in!=null)in.close();
if(bout!=null)bout.close();
if(out!=null)out.close();
if(conn!=null)conn.close();
}catch(IOException | SQLException ex){
System.out.println("Error : "+ex.getMessage());
}
}
}
}
After the execution of your jsp or html file you will see the image on screen.
You can also create custom tag for displaying image.
1) create custom tag java class and tld file.
2) write logic to display image like conversion of byte[] to string by Base64.
so it is used for every image whether you are displaying only one image or multiple images in single jsp page.
I am reading a excel file now I want to pass it to the jsp file.
I need to pass the test object to the jsp file so that I can display it to the browser.
import java.io.IOException;
import java.io.*;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
public class Readexcl
{
private String inputFile;
public void setInputFile(String inputFile) {
this.inputFile = inputFile;
}
public void read() throws IOException {
File inputWorkbook = new File(inputFile);
Workbook w;
try {
w = Workbook.getWorkbook(inputWorkbook);
Sheet sheet = w.getSheet(0);
for (int i = 0; i < sheet.getRows(); i++)
{
Cell cell = sheet.getCell(0, i);
System.out.print(cell.getContents()+" ");
cell = sheet.getCell(1, i);
System.out.println(cell.getContents()+" ");
//cell = sheet.getCell(2, i);
//System.out.println(cell.getContents());
}
}
catch (BiffException e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
Readexcl test = new Readexcl();
test.setInputFile("c:\\DATA.xls");
test.read();
}
}
If you are in a servlet (but the same is valid if you are in a jsp) you don't need to pass anything...just set the apptopriate content type in response, get the ServletOutputStream, read the xls and write using that stream
If you are in a main it unusual but not impossible...just create a servlet that accept base64 encoded data. In your main read the file, encode the stream in base64band then make an http post call to that servlet, posting the encoded data. In your servlet doPost() method decode the data and write out using ServletOutputStream
I am prototyping a web application using Spring MVC 3.0 with JasperReports.
I have already done reporting applications using Spring + Jfreechart + iText + Apache POI and been able to use successfully the respective view classes provided by Spring to stream pdfs, xls and images.
This time I want to try to use JasperReports so that I can design my pdfs outside of the application and not have to worry about knowing the underlying api (be that jfreechart, itext, or poi).
Problem
I have a report1.jrxml file that contains a queryString tag with my query with two date parameters. When I test the report through iReport, it compiles and runs successfully. No problems here.
Now I am reading the JasperReports section from the following Spring documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#view-jasper-reports
and I am trying to get the JasperReportsMultiFormatView to work properly, but there is one piece that I am not understanding:
How does JasperReportMultiFormatView know the database to connect to (Recall that I have the query embedded in the report itself) ?
The documentation states to use the reportDataKey property in the view, but I do not see how this is the solution to my problem.
How do you pass parameters?
What can be done
JaperReports provides with a set of xxxManager objects that are responsible for compiling, fiiling, and exporting the report. You could create a custom class that implements the Spring View interface and do something like this:
Connection connection;
ServletOutputStream servletOutputStream = response .getOutputStream();
InputStream reportStream = getServlet().getServletConfig().getServletContext().getResourceAsStream("/reports/report1.jasper");
response.setContentType("application/pdf");
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:
3306/flightstats?user=user&password=secret");
JasperRunManager.runReportToPdfStream(reportStream,
servletOutputStream, new HashMap(), connection);
connection.close();
servletOutputStream.flush();
servletOutputStream.close();
What I need
I need to accomplish what the code above those leveraging the Spring classes such as JasperReportsPdfView, JasperReportsXlsView, or even better JasperReportsMultiFormatView
So in summary I need to be able to pass the following from my controller to the jasper report:
Parameters
Db connection information so that the queryString inside the jasper knows who to run against
This is what I have and the output is a blank PDF document, I am assuming because it does not know how to run the query
#RequestMapping("/reports/**")
#Controller
public class ReportsController {
#RequestMapping(value ="/reports/usage/report", method = RequestMethod.GET)
public ModelAndView handleSimpleReportMulti(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("Made it here");
Map model = new HashMap();
//model.put("format", "pdf");
model.put("START_DATE", new String("09-12-2011"));
model.put("END_DATE", new String("09-17-2011"));
return new ModelAndView("report1", model);
}
}
I found the answer to my question. I have changed my controller above to this:
#RequestMapping(value ="/reports/usage/report/{format}", method = RequestMethod.GET)
public ModelAndView handleSimpleReportMulti(ModelMap modelMap, #PathVariable("format") String format) throws Exception {
//Map model = new HashMap();
modelMap.put("format", format);
modelMap.put("REPORT_CONNECTION", dataSource.getConnection());
modelMap.put("START_DATE", new String("09-12-2011"));
modelMap.put("END_DATE", new String("09-17-2011"));
return new ModelAndView("report1", modelMap);
}
I have changed my view.properties to this:
#report1(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
report1(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsMultiFormatView
report1.url=/WEB-INF/reports/report1.jasper
I hope this helps.
Thanks
I found another way to pass the connection as a parameter, and then close it.
THE PROBLEM:
I implement the solution above an the problem was, that everytime I call a PDF, a new connection was created, so when the app gets to the max limit of open connections it crash.
ReportesDAOJDBC reportes;
public void setReportes(ReportesDAOJDBC reportes) {
this.reportes = reportes;
}
public ModelAndView leoTest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
Map < String, Object > model = new HashMap < String, Object >();
model.put("PARAMCONTRARECIBO", new Integer(1101));
model.put("PARAMDOCTOS", new Integer(1101));
model.put("REPORT_CONNECTION", reportes.getConexion());
return new ModelAndView("leoTest",model);
}
The parameter to pass a connection to a JasperReport is REPORT_CONNECTION, but as I said, doing this way, will cause a lot of trobubles.
MY SOLUTION:
ReportesDAOJDBC reportes;
public void setReportes(ReportesDAOJDBC reportes) {
this.reportes = reportes;
}
public ModelAndView leoTest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
Map < String, Object > model = new HashMap < String, Object >();
model.put("PARAMCONTRARECIBO", new Integer(1101));
model.put("PARAMDOCTOS", new Integer(1101));
model.put("OBJETO_CONEXION", reportes);
return new ModelAndView(new PdfView("leoTest"),model);
}
As you can see, I implement my own PdfView and I pass in the constructor the name of the key define in the view.properties file, and also I pass a reference to my DAO (reportes) as a parameter of the HashMap, the name of the parameter is "OBJETO_CONEXION". Here is the code for ReportesDAOJDBC:
public class ReportesDAOJDBC extends JdbcDaoSupport {
public Connection getConexion() {
Connection con ;
try {
con = getDataSource().getConnection();
}
catch (Exception e) {
e.printStackTrace();
return null;
}
return con;
}
public void closeConecction(Connection con) {
try {
if (con != null) {
con.close();
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Then the next step is to show you the code of my own PdfView implementation.
import java.io.File;
import java.io.OutputStream;
import java.sql.Connection;
import java.util.Map;
import java.util.ResourceBundle;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import mx.com.mexican.leinksy.dao.jdbc.ReportesDAOJDBC;
import mx.com.mexican.leinksy.utils.Utils;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.util.JRLoader;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.ResourceBundleViewResolver;
public class PdfView implements View {
private static final String CONTENT_TYPE = "application/pdf";
private String JASPER_URL;
public PdfView(String jasperUrl){
this.JASPER_URL = jasperUrl+".url";
}
#Override
public String getContentType() {
return CONTENT_TYPE;
}
#Override
public void render(Map model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out.println(Utils.getRealPath(request));
ResourceBundle rb = ResourceBundle.getBundle("view");/* Se lee el archivo view.properties*/
ReportesDAOJDBC reporte = (ReportesDAOJDBC)model.get("OBJETO_CONEXION");/* Se obtiene el objeto de conexion */
Connection con = reporte.getConexion();/* Se genera la conexion a la base de datos*/
String jasperFilePath = Utils.getRealPath(request) + rb.getString( JASPER_URL );/* Se obtiene la ruta fisica del archivo .jasper a ejectuar*/
JasperReport jasperReport = (JasperReport)JRLoader.loadObject(new File(jasperFilePath));/* Se carga el reporte ya compilado*/
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, model, con);/* Se llena el reporte con datos del modelo y con la conexion a la BD*/
try{
OutputStream out = response.getOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint, out);/* Se manda el contenido a la salida estandar*/
out.flush();
out.close();
}catch(Exception e){
e.printStackTrace();
}
reporte.closeConecction(con);/* Cierro la conexion a la base de datos para liberar el pool*/
}
}
As you can see, I read the view.properties file using the ResourceBoundle class to get the path and name of the .jasper file to load, Also notice that I dont compile the .jrxml file I just load the compiled file, I compile the jrxml with IREPORTS. Also I hava a utility to get the path of my .jasper file, here is the code if you dont have idea of how to do it.
public static String getRealPath(HttpServletRequest req) {
ServletContext context = req.getSession().getServletContext();
String path = context.getRealPath("/");
if (path != null) {
if (!path.endsWith(File.separator)) {
path += File.separator;
}
}
return path;
}
With this implementation I can control where to open an close connection, also I respect the MVC model of SPRING, and also I still using the view.properties.
And at this point, maybe you are asking WHAT CAN I DO IF I WANT AN EXCEL FILE, well, I also implement an XlsView, (Ajuuaaaa !!! ). Here is the code:
import java.io.File;
import java.io.OutputStream;
import java.sql.Connection;
import java.util.Map;
import java.util.ResourceBundle;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import mx.com.mexican.leinsky.dao.jdbc.ReportesDAOJDBC;
import mx.com.mexican.leinksy.utils.Utils;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.engine.util.JRLoader;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.ResourceBundleViewResolver;
public class XlsView implements View {
private static final String CONTENT_TYPE = "application/vnd.ms-excel";
private String JASPER_URL;
private String FILE_NAME = "XLSFile";
public XlsView(String jasperUrl){
this.JASPER_URL = jasperUrl+".url";
}
#Override
public String getContentType() {
return CONTENT_TYPE;
}
#Override
public void render(Map model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
if(model.get("FILE_NAME")!=null){
this.FILE_NAME = model.get("FILE_NAME").toString();
}
ResourceBundle rb = ResourceBundle.getBundle("view");/* Se lee el archivo view.properties*/
ReportesDAOJDBC reporte = (ReportesDAOJDBC)model.get("OBJETO_CONEXION");/* Se obtiene el objeto de conexion */
Connection con = reporte.getConexion();/* Se genera la conexion a la base de datos*/
String jasperFilePath = Utils.getRealPath(request) + rb.getString( JASPER_URL );/* Se obtiene la ruta fisica del archivo .jasper a ejectuar*/
JasperReport jasperReport = (JasperReport)JRLoader.loadObject(new File(jasperFilePath));/* Se carga el reporte ya compilado*/
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, model, con);/* Se llena el reporte con datos del modelo y con la conexion a la BD*/
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition","attachment; filename=\""+FILE_NAME+".xls\"");
response.setHeader("Pragma", "No-cache");
response.setDateHeader("Expires", 1);
try{
OutputStream out = response.getOutputStream();
JRXlsExporter exporterXLS = new JRXlsExporter();
exporterXLS.setParameter(JRXlsExporterParameter.JASPER_PRINT,jasperPrint);
exporterXLS.setParameter(JRXlsExporterParameter.OUTPUT_STREAM,out);
exporterXLS.exportReport();
out.flush();
out.close();
}catch(Exception e){
e.printStackTrace();
}
reporte.closeConecction(con);/* Cierro la conexion a la base de datos para liberar el pool*/
}
}
So this is my solution, hope It helps !!!