提示:此次文章主要记录关于使用FOP导出PDF的一个实例整理
前言
主要内容就是FOP的Example中的对象输出PDF
`提示:以下为实例中的代码和一部分注解
具体代码
1.pom.xml
代码如下(示例):
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>Demo1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/fop -->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId>
<version>2.7</version>
</dependency>
</dependencies>
</project>
2.AbstractObjectReader
代码如下(示例):
import org.xml.sax.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
//SAX
/**
* This class can be used as base class for XMLReaders that generate SAX
* events from Java objects.
* 此类可用作生成 SAX 的 XML 读取器的基类来自 Java 对象的事件。
* @author Administrator
*/
//抽象类只有被继承才可以使用
public abstract class AbstractObjectReader implements XMLReader {
private static final String NAMESPACES =
"http://xml.org/sax/features/namespaces";
private static final String NS_PREFIXES =
"http://xml.org/sax/features/namespace-prefixes";
private Map features = new HashMap();
private ContentHandler orgHandler;
/** Proxy for easy SAX event generation */
protected EasyGenerationContentHandlerProxy handler;
/** Error handler */
protected ErrorHandler errorHandler;
//以上就是定义所需的一些方法名
/**
* Constructor for the AbstractObjectReader object
* AbstractObjectReader对象的构造函数
*/
public AbstractObjectReader() {
setFeature(NAMESPACES, false);
setFeature(NS_PREFIXES, false);
}
/* ============ XMLReader interface ============ */
/* ============ XMLReader 接口 ==================*/
/**
* @see org.xml.sax.XMLReader#getContentHandler()
* /@see可以实现跳转并且指向包.类等
*/
@Override
public ContentHandler getContentHandler() {
return this.orgHandler;
}
//调用XMLReader中的getContentHandler进行重写
//return this. 代表返回当前对象
/**
* @see org.xml.sax.XMLReader#setContentHandler(ContentHandler)
*/
@Override
public void setContentHandler(ContentHandler handler) {
this.orgHandler = handler;
this.handler = new EasyGenerationContentHandlerProxy(handler);
//当前对象赋值
}
/**
* @see org.xml.sax.XMLReader#getErrorHandler()
*/
@Override
public ErrorHandler getErrorHandler() {
return this.errorHandler;
}
//错误处理器方法
/**
* @see org.xml.sax.XMLReader#setErrorHandler(ErrorHandler)
*/
@Override
public void setErrorHandler(ErrorHandler handler) {
this.errorHandler = handler;
}
/**
* @see org.xml.sax.XMLReader#getDTDHandler()
*/
@Override
public DTDHandler getDTDHandler() {
return null;
}
/**
* @see org.xml.sax.XMLReader#setDTDHandler(DTDHandler)
*/
@Override
public void setDTDHandler(DTDHandler handler) {
}
/**
* @see org.xml.sax.XMLReader#getEntityResolver()
*/
@Override
public EntityResolver getEntityResolver() {
return null;
}
/**
* @see org.xml.sax.XMLReader#setEntityResolver(EntityResolver)
*/
@Override
public void setEntityResolver(EntityResolver resolver) {
}
/**
* @see org.xml.sax.XMLReader#getProperty(String)
*/
@Override
public Object getProperty(String name) {
return null;
}
/**
* @see org.xml.sax.XMLReader#setProperty(String, Object)
*/
@Override
public void setProperty(String name, Object value) {
}
/**
* @see org.xml.sax.XMLReader#getFeature(String)
*/
@Override
public boolean getFeature(String name) {
return (Boolean) features.get(name);
}
/**
* Returns true if the NAMESPACES feature is enabled.
* 如果NAMESPACES功能启用那么就返回True
* @return boolean true if enabled
*/
protected boolean isNamespaces() {
return getFeature(NAMESPACES);
}
/**
* Returns true if the MS_PREFIXES feature is enabled.
* 同上
* @return boolean true if enabled
*/
protected boolean isNamespacePrefixes() {
return getFeature(NS_PREFIXES);
}
/**
* @see org.xml.sax.XMLReader#setFeature(String, boolean)
*/
@Override
public void setFeature(String name, boolean value) {
this.features.put(name, value);
}
/**
* @see org.xml.sax.XMLReader#parse(String)
*/
@Override
public void parse(String systemId) throws IOException, SAXException {
throw new SAXException(
this.getClass().getName()
+ " cannot be used with system identifiers (URIs)");
}
/**
* @see org.xml.sax.XMLReader#parse(InputSource)
*/
@Override
public abstract void parse(InputSource input)
throws IOException, SAXException;
}
3.EasyGenerationContentHandlerProxy
代码如下(示例):
//SAX
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
/**
* This class is an implementation of ContentHandler which acts as a proxy to
* another ContentHandler and has the purpose to provide a few handy methods
* that make life easier when generating SAX events.
* 此类是 ContentHandler 的实现,它充当另一个内容处理程序,目的是提供一些方便的方法在生成SAX事件时使生活更轻松。
* <br>
* Note: This class is only useful for simple cases with no namespaces.
* 注意:此类仅对没有命名空间的简单情况有用。
* @author Administrator
*/
public class EasyGenerationContentHandlerProxy implements ContentHandler {
/* An empty Attributes object used when no attributes are needed. */
/** 在不需要任何属性时使用的空属性对象*/
public static final Attributes EMPTY_ATTS = new AttributesImpl();
//私有变量target
private ContentHandler target;
/**
* Main constructor.
* 主构造
* @param forwardTo ContentHandler to forward the SAX event to.
*/
public EasyGenerationContentHandlerProxy(ContentHandler forwardTo) {
this.target = forwardTo;
}
/**
* Sends the notification of the beginning of an element.
* 发送元素开始通知
* @param name Name for the element.元素名称
* @throws SAXException Any SAX exception, possibly wrapping another exception.
* 任何的SAX异常都可能包含另一个异常
*/
public void startElement(String name) throws SAXException {
startElement(name, EMPTY_ATTS);
}
/**
* Sends the notification of the beginning of an element.
* @param name Name for the element.
* @param atts The attributes attached to the element. If there are no
* attributes, it shall be an empty Attributes object.附加到元素属性,如果没有属性那么应当是一个空属性对象
* @throws SAXException Any SAX exception, possibly wrapping another exception.
* 其余同上
*/
//与上一个startElement看似是同样的命名,但其实是两种不同的方法,因为它里面的属性数量并不相同
public void startElement(String name, Attributes atts) throws SAXException {
startElement(null, name, name, atts);
}
/**
* Send a String of character data.
* 发送一个角色数据字符串
* @param s The content String
* @throws SAXException Any SAX exception, possibly wrapping another exception.
*/
public void characters(String s) throws SAXException {
target.characters(s.toCharArray(), 0, s.length());
}
/**
* Send the notification of the end of an element.
* 发送元素结束信息
* @param name Name for the element.
* @throws SAXException Any SAX exception, possibly wrapping another exception.
*/
public void endElement(String name) throws SAXException {
endElement(null, name, name);
//方法
}
/**
* Sends notifications for a whole element with some String content.
* 发送包含某些字符串内容的整个元素的通知。
* @param name Name for the element.
* @param value Content of the element.
* @throws SAXException Any SAX exception, possibly wrapping another exception.
*/
public void element(String name, String value) throws SAXException {
element(name, value, EMPTY_ATTS);
}
/**
* Sends notifications for a whole element with some String content.
* @param name Name for the element.
* @param value Content of the element.
* @param atts The attributes attached to the element. If there are no
* attributes, it shall be an empty Attributes object.
* @throws SAXException Any SAX exception, possibly wrapping another exception.
*/
public void element(String name, String value, Attributes atts) throws SAXException {
startElement(name, atts);
if (value != null) {
characters(value.toCharArray(), 0, value.length());
}
endElement(name);
}
/* =========== ContentHandler interface =========== */
/**
* @see org.xml.sax.ContentHandler#setDocumentLocator(Locator)
*/
@Override
public void setDocumentLocator(Locator locator) {
target.setDocumentLocator(locator);
}
/**
* @see org.xml.sax.ContentHandler#startDocument()
*/
@Override
public void startDocument() throws SAXException {
target.startDocument();
}
/**
* @see org.xml.sax.ContentHandler#endDocument()
*/
@Override
public void endDocument() throws SAXException {
target.endDocument();
}
/**
* @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
*/
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
target.startPrefixMapping(prefix, uri);
}
/**
* @see org.xml.sax.ContentHandler#endPrefixMapping(String)
*/
@Override
public void endPrefixMapping(String prefix) throws SAXException {
target.endPrefixMapping(prefix);
}
/**
* @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
*/
@Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts) throws SAXException {
target.startElement(namespaceURI, localName, qName, atts);
}
/**
* @see org.xml.sax.ContentHandler#endElement(String, String, String)
*/
@Override
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
target.endElement(namespaceURI, localName, qName);
}
/**
* @see org.xml.sax.ContentHandler#characters(char[], int, int)
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
target.characters(ch, start, length);
}
/**
* @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
*/
@Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
target.ignorableWhitespace(ch, start, length);
}
/**
* @see org.xml.sax.ContentHandler#processingInstruction(String, String)
*/
@Override
public void processingInstruction(String target, String data) throws SAXException {
this.target.processingInstruction(target, data);
}
/**
* @see org.xml.sax.ContentHandler#skippedEntity(String)
*/
@Override
public void skippedEntity(String name) throws SAXException {
target.skippedEntity(name);
}
}
4.ExampleObj2PDF
代码如下(示例):
import org.apache.fop.apps.*;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
public class ExampleObj2PDF {
// configure fopFactory as desired
private final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
/**
* Converts a ProjectTeam object to a PDF file.
* @param team the ProjectTeam object
* @param xslt the stylesheet file
* @param pdf the target PDF file
* @throws IOException In case of an I/O problem
* @throws FOPException In case of a FOP problem
* @throws TransformerException In case of a XSL transformation problem
*/
public void convertProjectTeam2PDF(ProjectTeam team, File xslt, File pdf)
throws IOException, FOPException, TransformerException, SAXNotRecognizedException, SAXNotSupportedException {
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// configure foUserAgent as desired
// Setup output
OutputStream out = new java.io.FileOutputStream(pdf);
out = new java.io.BufferedOutputStream(out);
try {
// Construct fop with desired output format
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
// Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(xslt));
// Setup input for XSLT transformation
Source src = team.getSourceForProjectTeam();
// Resulting SAX events (the generated FO) must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
transformer.transform(src, res);
} finally {
out.close();
}
}
/**
* Main method.
* @param args command-line arguments
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleObj2PDF\n");
System.out.println("Preparing...");
// Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();
// Setup input and output
File xsltfile = new File(baseDir, "projectteam2fo.xsl");
File pdffile = new File(outDir, "ResultObj2PDF.pdf");
System.out.println("Input: a ProjectTeam object");
System.out.println("Stylesheet: " + xsltfile);
System.out.println("Output: PDF (" + pdffile + ")");
System.out.println();
System.out.println("Transforming...");
ExampleObj2PDF app = new ExampleObj2PDF();
app.convertProjectTeam2PDF(ExampleObj2XML.createSampleProjectTeam(), xsltfile, pdffile);
System.out.println("Success!");
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-1);
}
}
}
4.ExampleObj2XM
代码如下(示例):
//Hava
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;
//JAXP
/**
* This class demonstrates the conversion of an arbitrary object file to an
* XML file.
*/
public class ExampleObj2XML {
/**
* Converts a ProjectTeam object to XML.
* @param team the ProjectTeam object
* @param xml the target XML file
* @throws IOException In case of an I/O problem
* @throws TransformerException In case of a XSL transformation problem
*/
public void convertProjectTeam2XML(ProjectTeam team, File xml)
throws IOException, TransformerException, SAXNotRecognizedException, SAXNotSupportedException {
//Setup XSLT
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
/* Note:
We use the identity transformer, no XSL transformation is done.
The transformer is basically just used to serialize the
generated document to XML. */
//Setup input
Source src = team.getSourceForProjectTeam();
//Setup output
Result res = new StreamResult(xml);
//Start XSLT transformation
transformer.transform(src, res);
}
/**
* Creates a sample ProjectTeam instance for this demo.
* @return ProjectTeam the newly created ProjectTeam instance
*/
public static ProjectTeam createSampleProjectTeam() {
ProjectTeam team = new ProjectTeam();
team.setProjectName("Rule the Galaxy");
team.addMember(new ProjectMember(
"Emperor Palpatine", "lead", "palpatine@empire.gxy"));
team.addMember(new ProjectMember(
"Lord Darth Vader", "Jedi-Killer", "vader@empire.gxy"));
team.addMember(new ProjectMember(
"Grand Moff Tarkin", "Planet-Killer", "tarkin@empire.gxy"));
team.addMember(new ProjectMember(
"Admiral Motti", "Death Star operations", "motti@empire.gxy"));
return team;
}
/**
* Main method.
* @param args command-line arguments
*/
public static void main(String[] args) {
try {
System.out.println("FOP ExampleObj2XML\n");
System.out.println("Preparing...");
//Setup directories
File baseDir = new File(".");
File outDir = new File(baseDir, "out");
outDir.mkdirs();
//Setup input and output
File xmlfile = new File(outDir, "ResultObj2XML.xml");
System.out.println("Input: a ProjectTeam object");
System.out.println("Output: XML (" + xmlfile + ")");
System.out.println();
System.out.println("Serializing...");
ExampleObj2XML app = new ExampleObj2XML();
app.convertProjectTeam2XML(createSampleProjectTeam(), xmlfile);
System.out.println("Success!");
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-1);
}
}
}
5.ProjectMember
代码如下(示例):
/**
* This bean represents a project member.
*/
public class ProjectMember {
private String name;
private String function;
private String email;
/**
* Default no-parameter constructor.
*/
public ProjectMember() {
}
/**
* Convenience constructor.
* @param name name of the project member
* @param function function in the team
* @param email email address
*/
public ProjectMember(String name, String function, String email) {
setName(name);
setFunction(function);
setEmail(email);
}
/**
* Returns the name.
* @return String the name
*/
public String getName() {
return name;
}
/**
* Returns the function.
* @return String the function
*/
public String getFunction() {
return function;
}
/**
* Returns the email address.
* @return String the email address
*/
public String getEmail() {
return email;
}
/**
* Sets the name.
* @param name The name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* Sets the function.
* @param function The function to set
*/
public void setFunction(String function) {
this.function = function;
}
/**
* Sets the email address.
* @param email The email address to set
*/
public void setEmail(String email) {
this.email = email;
}
}
6.ProjectTeam
代码如下(示例):
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import java.util.List;
/**
* This bean represents a ProjectTeam.
*/
public class ProjectTeam {
private String projectName;
private List members = new java.util.ArrayList();
/**
* Returns a list of project members.
* @return List a list of ProjectMember objects
*/
public List getMembers() {
return this.members;
}
/**
* Adds a ProjectMember to this project team.
* @param member the member to add
*/
public void addMember(ProjectMember member) {
this.members.add(member);
}
/**
* Returns the name of the project
* @return String the name of the project
*/
public String getProjectName() {
return projectName;
}
/**
* Sets the name of the project.
* @param projectName the project name to set
*/
public void setProjectName(String projectName) {
this.projectName = projectName;
}
/**
* Resturns a Source object for this object so it can be used as input for
* a JAXP transformation.
* @return Source The Source object
*/
public Source getSourceForProjectTeam() throws SAXNotRecognizedException, SAXNotSupportedException {
return new SAXSource(new ProjectTeamXMLReader(),
new ProjectTeamInputSource(this));
}
}
7.ProjectTeamInputSource
代码如下(示例):
import org.xml.sax.InputSource;
/**
* This class is a special InputSource decendant for using ProjectTeam
* instances as XML sources.
*/
public class ProjectTeamInputSource extends InputSource {
private ProjectTeam projectTeam;
/**
* Constructor for the ProjectTeamInputSource
* @param projectTeam The ProjectTeam object to use
*/
public ProjectTeamInputSource(ProjectTeam projectTeam) {
this.projectTeam = projectTeam;
}
/**
* Returns the projectTeam.
* @return ProjectTeam
*/
public ProjectTeam getProjectTeam() {
return projectTeam;
}
/**
* Sets the projectTeam.
* @param projectTeam The projectTeam to set
*/
public void setProjectTeam(ProjectTeam projectTeam) {
this.projectTeam = projectTeam;
}
}
8.ProjectTeamXMLReader
代码如下(示例):
//Java
import org.xml.sax.DTDHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import java.io.IOException;
//SAX
/**
* XMLReader implementation for the ProjectTeam class. This class is used to
* generate SAX events from the ProjectTeam class.
*/
public class ProjectTeamXMLReader extends AbstractObjectReader {
@Override
public DTDHandler getDTDHandler() {
return super.getDTDHandler();
}
/**
* @see org.xml.sax.XMLReader#parse(InputSource)
*/
@Override
public void parse(InputSource input) throws IOException, SAXException {
if (input instanceof ProjectTeamInputSource) {
parse(((ProjectTeamInputSource)input).getProjectTeam());
} else {
throw new SAXException("Unsupported InputSource specified. "
+ "Must be a ProjectTeamInputSource");
}
}
/**
* Starts parsing the ProjectTeam object.
* @param projectTeam The object to parse
* @throws SAXException In case of a problem during SAX event generation
*/
public void parse(ProjectTeam projectTeam) throws SAXException {
if (projectTeam == null) {
throw new NullPointerException("Parameter projectTeam must not be null");
}
if (handler == null) {
throw new IllegalStateException("ContentHandler not set");
}
//Start the document
handler.startDocument();
//Generate SAX events for the ProjectTeam
generateFor(projectTeam);
//End the document
handler.endDocument();
}
/**
* Generates SAX events for a ProjectTeam object.
* @param projectTeam ProjectTeam object to use
* @throws SAXException In case of a problem during SAX event generation
*/
protected void generateFor(ProjectTeam projectTeam) throws SAXException {
if (projectTeam == null) {
throw new NullPointerException("Parameter projectTeam must not be null");
}
if (handler == null) {
throw new IllegalStateException("ContentHandler not set");
}
handler.startElement("projectteam");
handler.element("projectname", projectTeam.getProjectName());
for (Object o : projectTeam.getMembers()) {
ProjectMember member = (ProjectMember) o;
generateFor(member);
}
handler.endElement("projectteam");
}
/**
* Generates SAX events for a ProjectMember object.
* @param projectMember ProjectMember object to use
* @throws SAXException In case of a problem during SAX event generation
*/
protected void generateFor(ProjectMember projectMember) throws SAXException {
if (projectMember == null) {
throw new NullPointerException("Parameter projectMember must not be null");
}
if (handler == null) {
throw new IllegalStateException("ContentHandler not set");
}
handler.startElement("member");
handler.element("name", projectMember.getName());
handler.element("function", projectMember.getFunction());
handler.element("email", projectMember.getEmail());
handler.endElement("member");
}
}
9.projectteam2fo.xsl
代码如下(示例):
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id$ -->
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" exclude-result-prefixes="fo">
<xsl:output method="xml" version="1.0" omit-xml-declaration="no" indent="yes"/>
<xsl:param name="versionParam" select="'1.0'"/>
<!-- ========================= -->
<!-- root element: projectteam -->
<!-- ========================= -->
<xsl:template match="projectteam">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simpleA4" page-height="29.7cm" page-width="21cm" margin-top="2cm" margin-bottom="2cm" margin-left="2cm" margin-right="2cm">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simpleA4">
<fo:flow flow-name="xsl-region-body">
<fo:block font-size="16pt" font-weight="bold" space-after="5mm">Project: <xsl:value-of select="projectname"/>
</fo:block>
<fo:block font-size="12pt" space-after="5mm">Version <xsl:value-of select="$versionParam"/>
</fo:block>
<fo:block font-size="10pt">
<fo:table table-layout="fixed" width="100%" border-collapse="separate">
<fo:table-column column-width="4cm"/>
<fo:table-column column-width="4cm"/>
<fo:table-column column-width="5cm"/>
<fo:table-body>
<xsl:apply-templates select="member"/>
</fo:table-body>
</fo:table>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<!-- ========================= -->
<!-- child element: member -->
<!-- ========================= -->
<xsl:template match="member">
<fo:table-row>
<xsl:if test="function = 'lead'">
<xsl:attribute name="font-weight">bold</xsl:attribute>
</xsl:if>
<fo:table-cell>
<fo:block>
<xsl:value-of select="name"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="function"/>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block>
<xsl:value-of select="email"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
</xsl:stylesheet>
总结
以上就是本次PDF输出功能的实例代码(其实就是一次样例的整理和学习),希望大家可以一起讨论学习