I am writing a android app including a webserver. Therefore I use the Embedded Jetty (8.0.1).
The next step I want to do is implementing a file upload.
The HTML looks like that and I think correct:
<form action=\"fileupload\" method=\"post\" enctype=\"multipart/form-data\">
<table>
<tbody>
<tr>
<td><input type=\"file\" name=\"userfile1\" /></td>
</tr>
<tr>
<td>
<input type=\"submit\" value=\"Submit\" /><input type=\"reset\" value=\"Reset\" />
</td>
</tr>
</tbody>
</table>
</form>
When I use this form, I can see in logcat that I received a file but I can't access this file in my Servlet.
I tried it with
File file1 = (File) request.getAttribute( "userfile1" );
and with the following function:
request.getParameter()
But everytime I receive a NULL Object. What I have to do?
As this is a multipart request, and you are uploading a "file" part, you need to grab the data using
request.getPart("userfile1");
For elements of your request that are not of type "file", for example input type="text", then you can access those properties through request.getParameter.
Just to note, Jetty 8.0.1 is quite old, the newest Jetty version (as of writing, 8.1.12) includes some important bugfixes to multipart handling.
If you upgrade your Jetty version, you will probably have to explicitly enable Multipart handling due to Jetty more strictly enforcing the Servlet 3.0 spec (https://bugs.eclipse.org/bugs/show_bug.cgi?id=395000), use the #MultipartConfig annotation if you are using servlets.
With handlers you have to manually add a Request.__MULTIPART_CONFIG_ELEMENT as an attribute to your request prior to calling getPart(s)
if (request.getContentType() != null && request.getContentType().startsWith("multipart/form-data")) {
baseRequest.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG);
}
This will allow you to parse the multipart requests, but the temp multipart files created will not be cleaned if you inject the config in this way. For servlets it is handled by a ServletRequestListener attached to the Request (see org.eclipse.jetty.server.Request#MultiPartCleanerListener).
So, what we do is have a HandlerWrapper early in our handler chain which adds the multipart config if needed and ensures the multipart files are cleaned after the request has finished. Example:
import java.io.IOException;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.MultiPartInputStreamParser;
/**
* Handler that adds the multipart config to the request that passes through if
* it is a multipart request.
*
* <p>
* Jetty will only clean up the temp files generated by
* {#link MultiPartInputStreamParser} in a servlet event callback when the
* request is about to die but won't invoke it for a non-servlet (webapp)
* handled request.
*
* <p>
* MultipartConfigInjectionHandler ensures that the parts are deleted after the
* {#link #handle(String, Request, HttpServletRequest, HttpServletResponse)}
* method is called.
*
* <p>
* Ensure that no other handlers sit above this handler which may wish to do
* something with the multipart parts, as the saved parts will be deleted on the return
* from
* {#link #handle(String, Request, HttpServletRequest, HttpServletResponse)}.
*/
public class MultipartConfigInjectionHandler extends HandlerWrapper {
public static final String MULTIPART_FORMDATA_TYPE = "multipart/form-data";
private static final MultipartConfigElement MULTI_PART_CONFIG = new MultipartConfigElement(
System.getProperty("java.io.tmpdir"));
public static boolean isMultipartRequest(ServletRequest request) {
return request.getContentType() != null
&& request.getContentType().startsWith(MULTIPART_FORMDATA_TYPE);
}
/**
* If you want to have multipart support in your handler, call this method each time
* your doHandle method is called (prior to calling getParameter).
*
* Servlet 3.0 include support for Multipart data with its
* {#link HttpServletRequest#getPart(String)} & {#link HttpServletRequest#getParts()}
* methods, but the spec says that before you can use getPart, you must have specified a
* {#link MultipartConfigElement} for the Servlet.
*
* <p>
* This is normally done through the use of the MultipartConfig annotation of the
* servlet in question, however these annotations will not work when specified on
* Handlers.
*
* <p>
* The workaround for enabling Multipart support in handlers is to define the
* MultipartConfig attribute for the request which in turn will be read out in the
* getPart method.
*
* #see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=395000#c0">Jetty Bug
* tracker - Jetty annotation scanning problem (servlet workaround) </a>
* #see <a href="http://dev.eclipse.org/mhonarc/lists/jetty-users/msg03294.html">Jetty
* users mailing list post.</a>
*/
public static void enableMultipartSupport(HttpServletRequest request) {
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG);
}
#Override
public void handle(String target, Request baseRequest, HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
boolean multipartRequest = HttpMethod.POST.is(request.getMethod())
&& isMultipartRequest(request);
if (multipartRequest) {
enableMultipartSupport(request);
}
try {
super.handle(target, baseRequest, request, response);
} finally {
if (multipartRequest) {
MultiPartInputStreamParser multipartInputStream = (MultiPartInputStreamParser) request
.getAttribute(Request.__MULTIPART_INPUT_STREAM);
if (multipartInputStream != null) {
try {
// a multipart request to a servlet will have the parts cleaned up correctly, but
// the repeated call to deleteParts() here will safely do nothing.
multipartInputStream.deleteParts();
} catch (MultiException e) {
// LOG.error("Error while deleting multipart request parts", e);
}
}
}
}
}
}
This can be used like:
MultipartConfigInjectionHandler multipartConfigInjectionHandler =
new MultipartConfigInjectionHandler();
HandlerCollection collection = new HandlerCollection();
collection.addHandler(new SomeHandler());
collection.addHandler(new SomeOtherHandler());
multipartConfigInjectionHandler.setHandler(collection);
server.setHandler(multipartConfigInjectionHandler);
The class MultiPartInputStreamParser is deprecated since jetty 9.4.11
it was replaced by MultiPartFormInputStream
the new code looks like this:
import java.io.IOException;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.MultiPartFormInputStream;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.MultiPartInputStreamParser;
/**
* Handler that adds the multipart config to the request that passes through if
* it is a multipart request.
*
* <p>
* Jetty will only clean up the temp files generated by
* {#link MultiPartInputStreamParser} in a servlet event callback when the
* request is about to die but won't invoke it for a non-servlet (webapp)
* handled request.
*
* <p>
* MultipartConfigInjectionHandler ensures that the parts are deleted after the
* {#link #handle(String, Request, HttpServletRequest, HttpServletResponse)}
* method is called.
*
* <p>
* Ensure that no other handlers sit above this handler which may wish to do
* something with the multipart parts, as the saved parts will be deleted on the return
* from
* {#link #handle(String, Request, HttpServletRequest, HttpServletResponse)}.
*/
public class MultipartConfigInjectionHandler extends HandlerWrapper {
public static final String MULTIPART_FORMDATA_TYPE = "multipart/form-data";
private static final MultipartConfigElement MULTI_PART_CONFIG = new MultipartConfigElement(
System.getProperty("java.io.tmpdir"));
public static boolean isMultipartRequest(ServletRequest request) {
return request.getContentType() != null
&& request.getContentType().startsWith(MULTIPART_FORMDATA_TYPE);
}
/**
* If you want to have multipart support in your handler, call this method each time
* your doHandle method is called (prior to calling getParameter).
*
* Servlet 3.0 include support for Multipart data with its
* {#link HttpServletRequest#getPart(String)} & {#link HttpServletRequest#getParts()}
* methods, but the spec says that before you can use getPart, you must have specified a
* {#link MultipartConfigElement} for the Servlet.
*
* <p>
* This is normally done through the use of the MultipartConfig annotation of the
* servlet in question, however these annotations will not work when specified on
* Handlers.
*
* <p>
* The workaround for enabling Multipart support in handlers is to define the
* MultipartConfig attribute for the request which in turn will be read out in the
* getPart method.
*
* #see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=395000#c0">Jetty Bug
* tracker - Jetty annotation scanning problem (servlet workaround) </a>
* #see <a href="http://dev.eclipse.org/mhonarc/lists/jetty-users/msg03294.html">Jetty
* users mailing list post.</a>
*/
public static void enableMultipartSupport(HttpServletRequest request) {
request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, MULTI_PART_CONFIG);
}
#Override
public void handle(String target, Request baseRequest, HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
boolean multipartRequest = HttpMethod.POST.is(request.getMethod())
&& isMultipartRequest(request);
if (multipartRequest) {
enableMultipartSupport(request);
}
try {
super.handle(target, baseRequest, request, response);
} finally {
if (multipartRequest) {
String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
MultiPartFormInputStream multipartInputStream = (MultiPartFormInputStream) request.getAttribute( MULTIPART );
if (multipartInputStream != null) {
multipartInputStream.deleteParts();
}
}
}
}
}
There is also an official example from the Jetty authors.
Related
I'm implementing MVC using JSP and JDBC. I have imported a database class file to my JSP file and I would like to show the data of a DB table. I don't know how I should return the ResultSet from the Java class to the JSP page and embed it in HTML.
How can I achieve this?
In a well designed MVC approach, the JSP file should not contain any line of Java code and the servlet class should not contain any line of JDBC code.
Assuming that you want to show a list of products in a webshop, the following code needs to be created.
A Product class representing a real world entity of a product, it should be just a Javabean.
public class Product {
private Long id;
private String name;
private String description;
private BigDecimal price;
// Add/generate getters/setters/c'tors/equals/hashcode boilerplate.
}
A DAO class which does all the nasty JDBC work and returns a nice List<Product>.
public class ProductDAO {
private DataSource dataSource;
public ProductDAO(DataSource dataSource) {
this.dataSource = dataSource;
}
public List<Product> list() throws SQLException {
List<Product> products = new ArrayList<Product>();
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT id, name, description, price FROM product");
ResultSet resultSet = statement.executeQuery();
) {
while (resultSet.next()) {
Product product = new Product();
product.setId(resultSet.getLong("id"));
product.setName(resultSet.getString("name"));
product.setDescription(resultSet.getString("description"));
product.setPrice(resultSet.getBigDecimal("price"));
products.add(product);
}
}
return products;
}
}
A servlet class which obtains the list and puts it in the request scope.
#WebServlet("/products")
public class ProductsServlet extends HttpServlet {
#Resource(name="jdbc/YourDB") // For Tomcat, define as <Resource> in context.xml and declare as <resource-ref> in web.xml.
private DataSource dataSource;
private ProductDAO productDAO;
#Override
public void init() {
productDAO = new ProductDAO(dataSource);
}
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<Product> products = productDAO.list();
request.setAttribute("products", products); // Will be available as ${products} in JSP
request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response);
} catch (SQLException e) {
throw new ServletException("Cannot obtain products from DB", e);
}
}
}
Finally a JSP file in /WEB-INF/products.jsp which uses JSTL <c:forEach> to iterate over List<Product> which is made available in EL by ${products}, and uses JSTL <c:out> to escape string properties in order to avoid XSS holes when it concerns user-controlled input.
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/format" prefix="fmt" %>
...
<table>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.id}</td>
<td><c:out value="${product.name}" /></td>
<td><c:out value="${product.description}" /></td>
<td><fmt:formatNumber value="${product.price}" type="currency" currencyCode="USD" /></td>
</tr>
</c:forEach>
</table>
To get it to work, just call the servlet by its URL. Provided that the servlet is annotated #WebServlet("/products") or mapped in web.xml with <url-pattern>/products</url-pattern>, then you can call it by http://example.com/contextname/products
See also:
How to avoid Java code in JSP files?
doGet and doPost in Servlets
How should I connect to JDBC database / datasource in a servlet based application?
Design Patterns web based applications
RequestDispatcher.forward() vs HttpServletResponse.sendRedirect()
How to map a ResultSet with unknown amount of columns to a List and display it in a HTML table?
How do I pass current item to Java method by clicking a hyperlink or button in JSP page?
MVC, in a web application context, doesn't consist in using a class from a JSP. It consists in using the following model :
browser sends a request to a web server
the web server is configured so that the request is handled by a servlet or a filter (the controller : Java code, not JSP code)
The servlet/filter usually dispatches the request to a specific class (called an Action, the specific part of the controller), based on configuration/annotations
The action executes the business logic (i.e. fetch the data from the database in your example : the model)
The action forwards the request to a JSP. The role of the JSP is only to generate HTML code (i.e. display your data : the view)
Since the JSP usually uses JSP tags (the JSTL, for example) and the JSP expression language, and since JSP tags and the EL are designed to get information from JavaBeans, you'd better have your data available in the form of JavaBeans or collections of JavaBeans.
The role of the controller (the action class) is thus to fetch the data, to create JavaBean instances containing the data, in a suitable format for the JSP, to put them in request attributes, and then to dispatch to the JSP. The JSP will then iterate through the JavaBean instances and display what they contain.
You should not implement the MVC framework yourself. Use existing ones (Stripes, Struts, etc.)
I don't know how should I return the ResultSet from the class file to the JSP page
Well, you don't.
The point of MVC is to separate your model ( the M DB info in this case ) from your view ( V a jsp, in this case ) in such a way you can change the view without braking to application.
To do this you might use an intermediate object to represent your data ( usually called DTO - after Data Transfer Object -, don't know how they call it these days ), and other object to fetch it ( usually a DAO ).
So basically you have your JSP file, get the request parameters, and then invoke a method from the DAO. The dao, internally has the means to connect to the db and fetch the data and builds a collections of DTO's which are returned to the JSP for rendering.
Something like this extremely simplified ( and insecure ) code:
Employee.java
class Employee {
String name;
int emplid;
}
EmployeeDAO.java
class EmployeeDAO {
... method to connect
etc.
List<Employee> getAllNamed( String name ) {
String query = "SELECT name, emplid FROM employee where name like ?";
ResultSet rs = preparedStatement.executeQuery etc etc.
List<Employee> results = ....
while( rs.hasNext() ) {
results.add( new Employee( rs.getString("name"), rs.getInt("emplid")));
}
// close resources etc
return results;
}
}
employee.jsp
<%
request.setAttribute("employees", dao.getAllNamed( request.getParameter("name") );
%>
<table>
<c:forEach items="${employees}" var="employee">
<tr><td>${employee.emplid}</td><td>${employee.name}</td></tr>
</c:forEach>
</table>
I hope this give you a better idea.
I have a problem. I don't understand clearly the code. I have a similar problem with my code.
I have created database SQL and filled up. Then I want to implement a MainServlet (code below) that richieve data from database and in a different jsp page, I want to insert that data in section like h1, h2 ecc... I must use the ${} sintax but I don't know how do that.
Briefly, In jsp file (code below, I MUST USE ${} SINTAX) I want to "call" MainServlet and there I want to richieve data from database and view in jsp file.
I hope I have explained correctly, thank you very much!
MainServlet.java
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class MainServlet
*/
#WebServlet({ "/MainServlet" })
public class MainServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String PATH_JSP = "/WEB-INF/";
/**
* #see HttpServlet#HttpServlet()
*/
public MainServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
}
/**
* #see Servlet#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String doveAndare = request.getParameter("azione");
if(doveAndare==null)
doveAndare = "index";
try {
String driverString = "com.mysql.cj.jdbc.Driver";
Class.forName(driverString);
String connString = "jdbc:mysql://localhost:3306/ldd_jewels?user=root&password=";
Connection conn = DriverManager.getConnection(connString);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM JEWEL");
while (rs.next() == true) {
System.out.println(rs.getString("Category") + "\t" + rs.getString("Name"));
/* I try that but does not work
request.setAttribute("name", rs.getString("Name"));
javax.servlet.RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/widering_male.jsp");
dispatcher.forward(request, response); */
}
stmt.close();
conn.close();
} catch(Exception e) {
e.printStackTrace();
}
request.getRequestDispatcher(PATH_JSP+doveAndare+".jsp").forward(request, response);
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
doublerow.jsp
<section id="portfolio-details" class="portfolio-details">
<div class="container">
<div class="row gy-4">
<div class="col-lg-8">
<div class="portfolio-details-slider swiper">
<div class="swiper-wrapper align-items-center">
<div class="swiper-slide">
<img src="assets/img/jewels/doublerow_1.jpg" alt="" />
</div>
<div class="swiper-slide">
<img src="assets/img/jewels/doublerow_2.jpg" alt="" />
</div>
<div class="swiper-slide">
<img src="assets/img/jewels/doublerow_3.jpg" alt="" />
</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
<div class="col-lg-4">
<div class="portfolio-info">
<h3>Product details</h3>
<ul>
<li><strong>Code</strong>: 1S3D5</li>
<li><strong>Category</strong>: Bracelets</li>
<li><strong>Name</strong>: Double Row Hinged Bangle</li>
<li><strong>Gender</strong>: Female</li>
<li><strong>Material</strong>: Yellow gold</li>
<li><strong>Size</strong>: 121mm</li>
<li><strong>Price</strong>: €5500</li>
</ul>
</div>
<div class="portfolio-description">
<h2>Description of product</h2>
<p>
The entwined ends of Tiffany Knot’s signature motif symbolize
the power of connections between people. Balancing strength
and elegance, each Tiffany Knot design is a complex feat of
craftsmanship. This bangle is crafted with yellow gold and
polished by hand for high shine. Wear on its own or partnered
with classic silhouettes for an unexpected pairing.
</p>
</div>
</div>
</div>
</div>
</section>
This is my database:
I want to insert each jewel in different pages (each jewel have a jsp file)
You can use the <c:forEach > tag
you can find a detailed example in the following link example use
I think it will be better for you to contain the data of the table into a collection such as list and return the list from the Java class and reuse this collection in the JSP.
The page i crape have removed the ID from their iframe, so I have a problem switching to the iframe, and I can't find any documentation to help me, so maybe there is someone here on Stack?
The url of the page is: http://www.klappen.se/boka/onlinebokning/
I'm using Selenium 1 and my code looks like this:
$this->_driver->switchTo()->getFrameByName("mainframe");
In my TargetLocator.php i have these functions:
<?php
// Copyright 2012-present Nearsoft, Inc
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
namespace SeleniumClient;
require_once 'WebDriver.php';
class TargetLocator
{
private $_driver;
public function __construct(WebDriver $driver)
{
$this->_driver = $driver;
}
#region TargetLocator members
/**
* Move to a different frame using its index
* #param Integer $frameIndex
* #return current WebDriver
*/
public function getFrameByIndex($frameIndex)
{
$this->_driver->getFrame($frameIndex);
return $this->_driver;
}
/**
* Move to different frame using its name
* #param String $frameName
* #return current WebDriver
*/
public function getFrameByName($frameName)
{
//We should validate that frameName is string
/*
if ($frameName == null)
{
throw new ArgumentNullException("frameName", "Frame name cannot be null");
}
*/
$this->_driver->getFrame($frameName);
return $this->_driver;
}
/**
* Move to a frame element.
* #param WebElement $frameElement
* #return current WebDriver
*/
public function getFrameByWebElement(WebElement $frameElement)
{
//We should validate that frameElement is string
/*
if (frameElement == null)
{
throw new ArgumentNullException("frameElement", "Frame element cannot be null");
}
RemoteWebElement convertedElement = frameElement as RemoteWebElement;
if (convertedElement == null)
{
throw new ArgumentException("frameElement cannot be converted to RemoteWebElement", "frameElement");
}
*/
$frameId = $frameElement->getElementId();
$target = array('ELEMENT' => $frameId);
$this->_driver->getFrame($target);
return $this->_driver;
}
/**
* Change to the Window by passing in the name
* #param String $windowName
* #return current WebDriver
*/
public function getWindow($windowName)
{
$this->_driver->getWindow($windowName);
return $this->_driver;
}
/**
* Change the active frame to the default
* #return current WebDriver
*/
public function getDefaultFrame()
{
$this->_driver->getFrame(null);
return $this->_driver;
}
/**
* Finds the active element on the page and returns it
* #return WebElement
*/
public function getActiveElement()
{
$webElement = null;
$webElement = $this->_driver->getActiveElement();
return $webElement;
}
/**
* Switches to the currently active modal dialog for this particular driver instance.
* #return \SeleniumClient\Alert
*/
public function getAlert()
{
// N.B. We only execute the GetAlertText command to be able to throw
// a NoAlertPresentException if there is no alert found.
//$this->_driver->getAlertText();
return new Alert($this->_driver); //validate that the Alert object can be created, if not throw an exception, try to use a factory singleton o depency of injection to only use 1 instance
}
#endregion
}
I have tried them all, but can't get it to work. Is there anybody out there who can help:-)?
Thanks in advance.
As far as i see you are looking for this iFrame:
<iframe src="http://dlbookit3.dlsystems.se/dlbookitKSR/bmlogifilt/logifilt.aspx" style="height:700px; width:100%; border:0;"></iframe>
right? So you have a method like getFrameByWebElement(WebElement) which accepts a WebElement. I think you can use an xpath to find the webElement e.g.:
WebElement element = find(By.xpath("//iframe"));
getFrameByWebElement(element);
so far in theory this could work (this is Java, you have to adapt it for your php code). But if I analyze the HTML code of the page with chrome I cannot locate the webElement by using the xpath //iframe.
Still you can try... but it looks like that the page owner doesn't want its iFrame to be locateable anymore :-)
There is only 1 IFRAME on the page so you can just find it by tag name. The page loaded very slowly for me but I'm in the US so that may have something to do with it. You may have to wait for the IFRAME to become available and then get a handle to it.
I'm able to generate a true report by pre-configuring the (dbconntion + queries and passing parameters) within the prpt and calling it from java. It's working fine.
Problem: I am tring to use report.setQuery("dummyQuery","SELECT NAME,ID FROM test.person");//some query to dynamically generate report. Is this possible?
When I use report.setQuery with same query, my report generates a blank pdf.
I think I should configure an HQL datasource to achieve this.
pre-config PRPT - I'm displaying 2 values, NAME and ID.
I'm able to generate this pdf dynamically through passing parameters.
Please guys help to generate this pdf dynamically thourgh setQuery or "how to use setQuery".
I really want to learn generating pentaho pdf reports.
package com.report;
import java.io.File;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
import org.pentaho.reporting.engine.classic.core.MasterReport;
import org.pentaho.reporting.engine.classic.core.modules.output.pageable.pdf.PdfReportUtil;
import org.pentaho.reporting.libraries.resourceloader.Resource;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
/**
* Servlet implementation class Generate
*/
#WebServlet("/Generate")
public class Generate extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public Generate() {
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
try{
response.reset();
response.setContentType("application/pdf");
ClassicEngineBoot.getInstance().start();
ResourceManager manager = new ResourceManager();
manager.registerDefaults();
String PrptPath ="C:\\Users\\3692902\\Desktop\\pentahoTest.prpt";
//generate report through pre-configured prpt (db connection + query)
Resource res = manager.createDirectly(new File(PrptPath), MasterReport.class);
MasterReport report = (MasterReport) res.getResource();
report.getParameterValues().put("IDValue",101);
//generate report through query?????
//report.setQuery("SELECT ID FROM test.person");
PdfReportUtil.createPDF(report,response.getOutputStream());
}
catch(Exception e){
e.printStackTrace();
}
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
You are loading the report from a PRPT file. So why dont you predefine your query in the Report-Designer by adding a SQL-Data-Source (Menu: Data->Add Data Source->SQL)?
Then, assuming you want to filter by IDValue, you would set your query (inside PRD, NOT your code) to:
SELECT ID FROM test.person WHERE ID = ${IDValue}
That's the "hardest" way to generate a report with reporting engine embedded in java.
Download Pentaho Report Designer matching the version of the engine you are using (eg: Pentaho Report Designer 5.4, Pentaho Reporting Engine 5.4).
From Pentaho Report designer, create a new report, and start creating it (1. Creating your first report)create your connections (or any datasource you need), create your queries, and define your parameters.
Finally, use your own code above to call the report from the servlet and display it.
Remember, Pentaho Report Designer is where you define ALL what you need in the report, then just send parameters and generate it from everywhere!.
I am using jersey to generate http requests and I would like to be able to see the request before it is sent (for debugging purposes).
For example:
WebResource resource = client.resource(url);
resource.header("aa", "bb");
resource.getHeaders(); // Error: how can I do it?
thanks
You can use LoggingFilter, as shown here
You need to add init-params and then implement ContainerRequestFilter
Put it in your web.xml Please note that com.az.jersey.server.AuthFilter is your class that has implemented mentioned above interface.
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter;com.az.jersey.server.AuthFilter</param-value>
</init-param>
public class AuthFilter implements ContainerRequestFilter {
/**
* Apply the filter : check input request, validate or not with user auth
*
* #param containerRequest
* The request from Tomcat server
*/
#Override
public ContainerRequest filter(ContainerRequest containerRequest) throws WebApplicationException {
//GET, POST, PUT, DELETE, ...
String method = containerRequest.getMethod();
// myresource/get/56bCA for example
String path = containerRequest.getPath(true);
return containerRequest;
}
I am using Apache's Velocity templating engine, and I would like to create a custom Directive. That is, I want to be able to write "#doMyThing()" and have it invoke some java code I wrote in order to generate the text.
I know that I can register a custom directive by adding a line
userdirective=my.package.here.MyDirectiveName
to my velocity.properties file. And I know that I can write such a class by extending the Directive class. What I don't know is how to extend the Directive class -- some sort of documentation for the author of a new Directive. For instance I'd like to know if my getType() method return "BLOCK" or "LINE" and I'd like to know what should my setLocation() method should do?
Is there any documentation out there that is better than just "Use the source, Luke"?
On the Velocity wiki, there's a presentation and sample code from a talk I gave called "Hacking Velocity". It includes an example of a custom directive.
Also was trying to come up with a custom directive. Couldn't find any documentation at all, so I looked at some user created directives: IfNullDirective (nice and easy one), MergeDirective as well as velocity build-in directives.
Here is my simple block directive that returns compressed content (complete project with some directive installation instructions is located here):
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.TemplateInitException;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.runtime.log.Log;
import com.googlecode.htmlcompressor.compressor.HtmlCompressor;
/**
* Velocity directive that compresses an HTML content within #compressHtml ... #end block.
*/
public class HtmlCompressorDirective extends Directive {
private static final HtmlCompressor htmlCompressor = new HtmlCompressor();
private Log log;
public String getName() {
return "compressHtml";
}
public int getType() {
return BLOCK;
}
#Override
public void init(RuntimeServices rs, InternalContextAdapter context, Node node) throws TemplateInitException {
super.init(rs, context, node);
log = rs.getLog();
//set compressor properties
htmlCompressor.setEnabled(rs.getBoolean("userdirective.compressHtml.enabled", true));
htmlCompressor.setRemoveComments(rs.getBoolean("userdirective.compressHtml.removeComments", true));
}
public boolean render(InternalContextAdapter context, Writer writer, Node node)
throws IOException, ResourceNotFoundException, ParseErrorException, MethodInvocationException {
//render content to a variable
StringWriter content = new StringWriter();
node.jjtGetChild(0).render(context, content);
//compress
try {
writer.write(htmlCompressor.compress(content.toString()));
} catch (Exception e) {
writer.write(content.toString());
String msg = "Failed to compress content: "+content.toString();
log.error(msg, e);
throw new RuntimeException(msg, e);
}
return true;
}
}
Block directives always accept a body and must end with #end when used in a template. e.g. #foreach( $i in $foo ) this has a body! #end
Line directives do not have a body or an #end. e.g. #parse( 'foo.vtl' )
You don't need to both with setLocation() at all. The parser uses that.
Any other specifics i can help with?
Also, have you considered using a "tool" approach? Even if you don't use VelocityTools to automatically make your tool available and whatnot, you can just create a tool class that does what you want, put it in the context and either have a method you call to generate content or else just have its toString() method generate the content. e.g. $tool.doMyThing() or just $myThing
Directives are best for when you need to mess with Velocity internals (access to InternalContextAdapter or actual Nodes).
Prior to velocity v1.6 I had a #blockset($v)#end directive to be able to deal with a multiline #set($v) but this function is now handled by the #define directive.
Custom block directives are a pain with modern IDEs because they don't parse the structure correctly, assuming your #end associated with #userBlockDirective is an extra and paints the whole file RED. They should be avoided if possible.
I copied something similar from the velocity source code and created a "blockset" (multiline) directive.
import org.apache.velocity.runtime.directive.Directive;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.parser.node.Node;
import org.apache.velocity.context.InternalContextAdapter;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.TemplateInitException;
import java.io.Writer;
import java.io.IOException;
import java.io.StringWriter;
public class BlockSetDirective extends Directive {
private String blockKey;
/**
* Return name of this directive.
*/
public String getName() {
return "blockset";
}
/**
* Return type of this directive.
*/
public int getType() {
return BLOCK;
}
/**
* simple init - get the blockKey
*/
public void init( RuntimeServices rs, InternalContextAdapter context,
Node node )
throws TemplateInitException {
super.init( rs, context, node );
/*
* first token is the name of the block. I don't even check the format,
* just assume it looks like this: $block_name. Should check if it has
* a '$' or not like macros.
*/
blockKey = node.jjtGetChild( 0 ).getFirstToken().image.substring( 1 );
}
/**
* Renders node to internal string writer and stores in the context at the
* specified context variable
*/
public boolean render( InternalContextAdapter context, Writer writer,
Node node )
throws IOException, MethodInvocationException,
ResourceNotFoundException, ParseErrorException {
StringWriter sw = new StringWriter(256);
boolean b = node.jjtGetChild( 1 ).render( context, sw );
context.put( blockKey, sw.toString() );
return b;
}
}