참고 URL#

pom.xml#

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-oxm</artifactId>
    <scope>compile</scope>
</dependency>
<!-- PDF Generator -->
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>fop</artifactId>
    <version>2.4</version>
</dependency>
<dependency>
    <groupId>avalon-framework</groupId>
    <artifactId>avalon-framework</artifactId>
    <version>4.1.5</version>
</dependency>
<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.25</version>
</dependency>

MarshallerConfiguration.java#

@Configuration
@RequiredArgsConstructor
public class MarshallerConfiguration {
    @Bean
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setClassesToBeBound(new Class[] {
            PdfResponse.class
        });
        marshaller.setMarshallerProperties(new HashMap<String, Object>() {{
            put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        }});

        return marshaller;
    }
}

FopFontMetricsGenerator.java#

public class FopFontMetricsGenerator {
    private static final String PATH = "src/main/resources/fop";
    public static enum FontTTF {
        NANUMGOTHIC("NanumGothic", PATH + "NanumGothic.ttf", PATH + "NanumGothic.xml"),
        NANUMGOTHIC_BOLD("NanumGothicBold",PATH + "NanumGothicBold.ttf", PATH + "NanumGothicBold.xml");

        private String name;
        private String ttfPath;
        private String matrixPath;

        FontTTF(String name, String ttfPath, String matrixPath) {
            this.name = name;
            this.ttfPath = ttfPath;
            this.matrixPath = matrixPath;
        }

        public String getName() {
            return name;
        }

        public String getTtfPath() {
            return ttfPath;
        }

        public String getMatrixPath() {
            return matrixPath;
        }
    }

    /**
     * java org.apache.fop.fonts.apps.TTFReader -fn "새굴림" C:\WINNT\Fontsngulim.ttf ngulim.xml
     *
     * @param args command-line arguments
     */
    public static void main(String[] args) {
        //
        // ttf
        makeFontTTF();
    }

    private static void makeFontTTF() {
        for (FontTTF font : FontTTF.values()) {
            String[] params = new String[] {"-fn", font.getName(), font.getTtfPath(), font.getMatrixPath()};
            TTFReader.main(params);
        }
    }
}

FopPdfService.java#

@Slf4j
@Service
public class FopPdfService implements InitializingBean {
    private static final String TEMPLATE_FILE = "/fop/pdf.xsl";
    private static final String XCONF_FILE = "/fop/fop.xconf";
    private static final String VERSION = "2.4";

    @Autowired
    private Jaxb2Marshaller jaxb2Marshaller;

    private FopFactory fopFactory;
    private FOUserAgent foUserAgent;
    private Transformer transformer;

    public ByteArrayInputStream getPdfInputStream(PdfResponse document) {
        try {
            OutputStream out = new ByteArrayOutputStream();

            try {
                Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
                Source src = new StreamSource(new StringReader(this.jaxbObjectToXML(document)));
                Result res = new SAXResult(fop.getDefaultHandler());
                transformer.transform(src, res);
            } finally {
                out.close();
            }

            ByteArrayOutputStream buffer = (ByteArrayOutputStream)out;
            byte[] bytes = buffer.toByteArray();

            return new ByteArrayInputStream(bytes);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private String jaxbObjectToXML(PdfResponse response) {
        StringWriter sw = new StringWriter();
        Result result = new StreamResult(sw);
        jaxb2Marshaller.marshal(response, result);
        return sw.toString();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        File xconfFile = new ClassPathResource(XCONF_FILE).getFile();
        File xslFile = new ClassPathResource(TEMPLATE_FILE).getFile();

        this.fopFactory = FopFactory.newInstance(xconfFile);
        this.foUserAgent = fopFactory.newFOUserAgent();
        TransformerFactory factory = TransformerFactory.newInstance();
        this.transformer = factory.newTransformer(new StreamSource(xslFile));
        transformer.setParameter("versionParam", VERSION);
    }
}

PdfDownloadController.java#

@Controller
@RequestMapping()
@Slf4j
public class PdfDownloadController {
    @Autowired
    private FopPdfService fopPdfService;

    @RequestMapping(value = "/download")
    public void downloadPdf(@RequestHeader(value = "User-Agent", defaultValue = "") String userAgent, HttpServletResponse response) {
        try {
            ByteArrayInputStream generator = fopPdfService.getPdfInputStream(this.makeSampleData());

            String fileName = getPdfFileName(userAgent, "pdf");
            response.setContentType(MediaType.APPLICATION_PDF.getType());
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".pdf");

            IOUtils.copy(generator, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private String getPdfFileName(String userAgent, String fileName) {
        try {
            if (StringUtils.contains(userAgent, "MSIE") || StringUtils.contains(userAgent, "Trident")) {
                return URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            } else {
                return new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
            }
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
        }

        return StringUtils.EMPTY;
    }
}

PdfResponse.java#

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;

@XmlRootElement(name = "prices")
@XmlAccessorType(XmlAccessType.FIELD)
public class PdfResponse {
    @XmlElement(name = "year")
    private String year;    // 기준년
    @XmlElement(name = "name")
    private String name;    // 성명

    @XmlElement(name = "price")
    private List<Price> prices;

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @XmlRootElement(name = "price")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class Price {
        private String price1;
        private String price2;
        private String price3;

        public Price() {
        }

        public String getPrice1() {
            return price1;
        }

        public void setPrice1(String price1) {
            this.price1 = price1;
        }

        public String getPrice2() {
            return price2;
        }

        public void setPrice2(String price2) {
            this.price2 = price2;
        }

        public String getPrice3() {
            return price3;
        }

        public void setPrice3(String price3) {
            this.price3 = price3;
        }
    }
}

fop.xconf#

<?xml version="1.0"?>
<fop version="1.0">
  <!-- Base URL for resolving relative URLs -->
  <base>.</base>
  <source-resolution>72</source-resolution>
  <target-resolution>72</target-resolution>
  <default-page-settings height="11in" width="8.26in"/>

  <renderers>
    <renderer mime="application/pdf">
      <filterList>
        <value>flate</value>
      </filterList>

      <fonts>
        <auto-detect />
        <font metrics-url="NanumGothic.xml" embed-url="NanumGothic.ttf" kerning="yes">
          <font-triplet name="나눔고딕" style="normal" weight="normal"/>
        </font>
        <font metrics-url="NanumGothicBold.xml" embed-url="NanumGothicBold.ttf" kerning="yes">
          <font-triplet name="나눔고딕 Bold" style="normal" weight="normal"/>
        </font>
      </fonts>
    </renderer>
  </renderers>

  <!-- etc. etc..... -->
</fop>

template.xsl#

<?xml version="1.0" encoding="UTF-8"?>
<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:template match="prices">
        <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
            <fo:layout-master-set>
                <fo:simple-page-master master-name="simpleA4" 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" font-family="나눔고딕">
                    <fo:block font-size="12pt">
                        <fo:table table-layout="fixed" width="100%" border-collapse="separate">
                            <fo:table-column column-width="4cm"/>
                            <fo:table-column column-width="5cm"/>
                            <fo:table-column column-width="4cm"/>
                            <fo:table-column column-width="4cm"/>
                            <fo:table-body end-indent="0in">
                                <fo:table-row>
                                    <fo:table-cell border="1pt solid black" background-color="#C9EA7A"><fo:block>test1</fo:block></fo:table-cell>
                                    <fo:table-cell border="1pt solid black"><fo:block><xsl:value-of select="name"/></fo:block></fo:table-cell>
                                    <fo:table-cell border="1pt solid black" background-color="#C9EA7A"><fo:block>test2</fo:block></fo:table-cell>
                                    <fo:table-cell border="1pt solid black"><fo:block><xsl:value-of select="birthday"/></fo:block></fo:table-cell>
                                </fo:table-row>
                                <fo:table-row>
                                    <fo:table-cell border="1pt solid black" background-color="#C9EA7A"><fo:block>test3</fo:block></fo:table-cell>
                                    <fo:table-cell border="1pt solid black" number-columns-spanned="3">
                                        <fo:block linefeed-treatment="preserve">
                                            test3333
                                        </fo:block>
                                    </fo:table-cell>
                                </fo:table-row>
                            </fo:table-body>
                        </fo:table>
                    </fo:block>

                    <fo:block font-size="10pt">
                        <fo:table table-layout="fixed" width="100%" border-collapse="separate">
                            <fo:table-column column-width="3cm"/>
                            <fo:table-column column-width="5cm"/>
                            <fo:table-column column-width="3cm"/>
                            <fo:table-column column-width="3cm"/>
                            <fo:table-column column-width="3cm"/>
                            <fo:table-header>
                                <fo:table-row>
                                    <fo:table-cell number-columns-spanned="2" border="1pt solid black" text-align="center" background-color="#C9EA7A"><fo:block>test11</fo:block></fo:table-cell>
                                    <fo:table-cell border="1pt solid black" text-align="center" background-color="#C9EA7A"><fo:block>test12</fo:block></fo:table-cell>
                                    <fo:table-cell border="1pt solid black" text-align="center" background-color="#C9EA7A"><fo:block>test13</fo:block></fo:table-cell>
                                    <fo:table-cell border="1pt solid black" text-align="center" background-color="#C9EA7A"><fo:block>test14</fo:block></fo:table-cell>
                                </fo:table-row>
                            </fo:table-header>
                            <fo:table-body end-indent="0in">
                                <xsl:apply-templates select="price"/>
                            </fo:table-body>
                        </fo:table>
                    </fo:block>

                    <fo:block font-size="12pt">
                        <fo:table table-layout="fixed" width="100%" border-collapse="separate">
                            <fo:table-column column-width="3cm"/>
                            <fo:table-column column-width="14cm"/>
                            <fo:table-body end-indent="0in">
                                <fo:table-row>
                                    <fo:table-cell border="1pt solid black" background-color="#C9EA7A"><fo:block>test21</fo:block></fo:table-cell>
                                    <fo:table-cell border="1pt solid black"><fo:block>test22</fo:block></fo:table-cell>
                                </fo:table-row>
                            </fo:table-body>
                        </fo:table>
                    </fo:block>
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
    <xsl:template match="price">
        <fo:table-row>          
            <fo:table-cell border="1pt solid black"><fo:block><xsl:value-of select="val1"/></fo:block>
            </fo:table-cell><fo:table-cell border="1pt solid black"><fo:block><xsl:value-of select="val2"/></fo:block></fo:table-cell>
            <fo:table-cell border="1pt solid black"><fo:block><xsl:value-of select="val3"/></fo:block></fo:table-cell>
            <fo:table-cell border="1pt solid black"><fo:block><xsl:value-of select="val4"/></fo:block></fo:table-cell>
            <fo:table-cell border="1pt solid black"><fo:block><xsl:value-of select="val5"/></fo:block></fo:table-cell>
        </fo:table-row>
    </xsl:template>
</xsl:stylesheet>

기타설정은 첨부파일로..#

Add new attachment

Only authorized users are allowed to upload new attachments.

List of attachments

Kind Attachment Name Size Version Date Modified Author Change note
ttf
NanumGothic.ttf 4,691.8 kB 1 12-Dec-2019 11:09 DongGukLee
xml
NanumGothic.xml 1,469.4 kB 1 12-Dec-2019 11:09 DongGukLee
ttf
NanumGothicBold.ttf 4,642.2 kB 1 12-Dec-2019 11:09 DongGukLee
xml
NanumGothicBold.xml 1,486.6 kB 1 12-Dec-2019 11:09 DongGukLee
« This page (revision-5) was last changed on 17-Dec-2019 09:51 by DongGukLee  
G’day (anonymous guest) My Prefs

Referenced by
Java

JSPWiki v2.8.4