SpringBoot整合Velocity实现导出PDF接口文档


前言

SpringBoot+Velocity实现导出PDF接口文档
本文SpringBoot 版本 3.3.0,JDK 21
目录结构
在这里插入图片描述


一、Velocity是什么?

   Velocity类似与JSP,是一种基于Java的模板引擎。它可以在web页面中引用Java代码中定义的数据和对象,而Velocity的作用就是把Web视图和java代码进行组装在一起。

二、Velocity使用

1.引入库Maven

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
 	   <!--pdf相关-->
       <dependency>
           <groupId>org.apache.velocity</groupId>
           <artifactId>velocity-engine-core</artifactId>
           <version>2.3</version>
       </dependency>

       <!-- itext7html转pdf  -->
       <dependency>
           <groupId>com.itextpdf</groupId>
           <artifactId>html2pdf</artifactId>
           <version>3.0.2</version>
       </dependency>

       <!-- 中文字体支持 -->
       <dependency>
           <groupId>com.itextpdf</groupId>
           <artifactId>font-asian</artifactId>
           <version>7.1.13</version>
       </dependency>

2.读入数据

Controller

package org.demo.controller;
 
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.URLUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.velocity.VelocityContext;
import org.demo.utli.PdfUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;


import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
/**
 * PDF生成Controller
 */

@Controller
@RequestMapping("/pdf")
public class PDFController {

 
    @RequestMapping("/file/{userId}")
    public void importFile(HttpServletResponse response, @PathVariable Integer userId) {
        response.reset();
        response.setContentType("application/pdf");
        String filename = "获取用户集合接口文档" + System.currentTimeMillis() + ".pdf";
        response.addHeader("Content-Disposition", "inline; filename=" + URLUtil.encode(filename, CharsetUtil.CHARSET_UTF_8));

 
        VelocityContext context = new VelocityContext();
 
        context.put("apiName","查询用户集合" );
        context.put("method","POST" );
        context.put("apiUrl","http://localhost:8080/user/list" );
        context.put("apiDesc","描述查询用户集合" );
        context.put("serverUrl","http://localhost:2828/" );



        List<Map<String, Object>> apiParamsList = new ArrayList<>();
        Map<String, Object> apiParamsOne = new HashMap<>();
        apiParamsOne.put("name", "name");
        apiParamsOne.put("location",  "query");
        apiParamsOne.put("type", "String");
        apiParamsOne.put("required", "no");
        apiParamsOne.put("example", "张三");
        apiParamsOne.put("desc", "姓名");
        Map<String, Object> apiParamsTwo = new HashMap<>();
        apiParamsTwo.put("name", "age");
        apiParamsTwo.put("location",  "query");
        apiParamsTwo.put("type", "String");
        apiParamsTwo.put("required", "no");
        apiParamsTwo.put("example", "18");
        apiParamsTwo.put("desc", "年龄");
        apiParamsList.add(apiParamsOne);
        apiParamsList.add(apiParamsTwo);

        List<Map<String, Object>> responsesList = new ArrayList<>();
        Map<String, Object> responsesMapOne = new HashMap<>();
        responsesMapOne.put("name", "id");
        responsesMapOne.put("type",  "String");
        responsesMapOne.put("example","1");
        responsesMapOne.put("desc", "主键");
        Map<String, Object> responsesMapTwo = new HashMap<>();
        responsesMapTwo.put("name", "name");
        responsesMapTwo.put("type",  "String");
        responsesMapTwo.put("example","张三");
        responsesMapTwo.put("desc", "姓名");
        responsesList.add(responsesMapOne);
        responsesList.add(responsesMapTwo);

        List<Map<String, Object>> apiDictList = new ArrayList<>();
        Map<String, Object> apiDictOne = new HashMap<>();
        apiDictOne.put("name",  "level");
        apiDictOne.put("type","sys_level");
        apiDictOne.put("desc", "级别");
        apiDictList.add(apiDictOne);

        context.put("apiParams", apiParamsList);
        context.put("responses", responsesList);
        context.put("apiDict",apiDictList );



        PdfUtil.pdfToFile(context, filename, response);
    }

    @RequestMapping("/page/{userId}")
    public void get(HttpServletResponse response, @PathVariable Integer userId) {
        response.reset();
        response.setContentType("application/pdf");
        String filename = System.currentTimeMillis() + ".pdf";
        response.addHeader("Content-Disposition", "inline; filename=" + URLUtil.encode(filename, CharsetUtil.CHARSET_UTF_8));


        VelocityContext context = new VelocityContext();

        context.put("apiName","查询用户集合" );
        context.put("method","POST" );
        context.put("apiUrl","http://localhost:8080/user/list" );
        context.put("apiDesc","描述查询用户集合" );
        context.put("serverUrl","http://localhost:2828/" );



        List<Map<String, Object>> apiParamsList = new ArrayList<>();

        Map<String, Object> apiParamsOne = new HashMap<>();
        apiParamsOne.put("name", "name");
        apiParamsOne.put("location",  "query");
        apiParamsOne.put("type", "String");
        apiParamsOne.put("required", "no");
        apiParamsOne.put("example", "张三");
        apiParamsOne.put("desc", "姓名");

        Map<String, Object> apiParamsTwo = new HashMap<>();
        apiParamsTwo.put("name", "age");
        apiParamsTwo.put("location",  "query");
        apiParamsTwo.put("type", "String");
        apiParamsTwo.put("required", "no");
        apiParamsTwo.put("example", "18");
        apiParamsTwo.put("desc", "年龄");
        apiParamsList.add(apiParamsOne);
        apiParamsList.add(apiParamsTwo);

        List<Map<String, Object>> responsesList = new ArrayList<>();
        Map<String, Object> responsesMapOne = new HashMap<>();
        responsesMapOne.put("name", "id");
        responsesMapOne.put("type",  "String");
        responsesMapOne.put("example","1");
        responsesMapOne.put("desc", "主键");
        Map<String, Object> responsesMapTwo = new HashMap<>();
        responsesMapTwo.put("name", "name");
        responsesMapTwo.put("type",  "String");
        responsesMapTwo.put("example","张三");
        responsesMapTwo.put("desc", "姓名");
        responsesList.add(responsesMapOne);
        responsesList.add(responsesMapTwo);

        List<Map<String, Object>> apiDictList = new ArrayList<>();
        Map<String, Object> apiDictOne = new HashMap<>();
        apiDictOne.put("name",  "level");
        apiDictOne.put("type","sys_level");
        apiDictOne.put("desc", "级别");
        apiDictList.add(apiDictOne);

        context.put("apiParams", apiParamsList);
        context.put("responses", responsesList);
        context.put("apiDict",apiDictList );

        try {
            PdfUtil.pdfToPage(context, response.getOutputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
 
}

Util

package org.demo.utli;
 
import cn.hutool.core.net.URLEncoder;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.html2pdf.css.apply.impl.DefaultCssApplierFactory;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.styledxmlparser.css.media.MediaDeviceDescription;
import com.itextpdf.styledxmlparser.css.media.MediaType;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.velocity.Template;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
 
/**
 * PDF工具
 *
 *
 */
public class PdfUtil {

    static {
        // Velocity初始化
        Velocity.setProperty(RuntimeConstants.INPUT_ENCODING, StandardCharsets.UTF_8);
        Velocity.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        Velocity.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());

        Velocity.init();
    }



    public static void pdfToFile(Context context, String filename,HttpServletResponse response) {
        Template template = Velocity.getTemplate("/templates/api_template.vm", "UTF-8");
        StringWriter html = new StringWriter();
        template.merge(context, html);
        try {
            response.setCharacterEncoding("utf-8");
            String encodeFileName = URLEncoder.createDefault().encode( filename, StandardCharsets.UTF_8);
            response.setHeader("Content-disposition", "attachment;filename=" + encodeFileName);
            PdfWriter pdfWriter = new PdfWriter(response.getOutputStream());
            PdfDocument pdfDocument = new PdfDocument(pdfWriter);
            // 设置为A4大小
            pdfDocument.setDefaultPageSize(PageSize.A4);
            // 添加中文字体支持
            ConverterProperties properties = new ConverterProperties();
            properties.setMediaDeviceDescription(new MediaDeviceDescription(MediaType.PRINT));
            properties.setCssApplierFactory(new DefaultCssApplierFactory());
            FontProvider fontProvider = new FontProvider();

            PdfFont microsoft = PdfFontFactory.createFont("C:/Windows/Fonts/msyh.ttc" + ",0", PdfEncodings.IDENTITY_H, false);
            fontProvider.addFont(microsoft.getFontProgram(), PdfEncodings.IDENTITY_H);

            properties.setFontProvider(fontProvider);
            HtmlConverter.convertToPdf(html.toString(), pdfDocument, properties);

            pdfWriter.close();
            pdfDocument.close();
        } catch (IOException e) {

        }
    }


    public static void pdfToPage(Context context,OutputStream outputStream) {

        try (PdfWriter pdfWriter = new PdfWriter(outputStream)) {
            PdfDocument pdfDocument = new PdfDocument(pdfWriter);
            pdfDocument.setDefaultPageSize(PageSize.A4);

            ConverterProperties properties = new ConverterProperties();
            FontProvider fontProvider = new FontProvider();
            // 字体设置,解决中文不显示问题
            PdfFont sysFont = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H");
            fontProvider.addFont(sysFont.getFontProgram(), "UniGB-UCS2-H");
            properties.setFontProvider(fontProvider);

            Template pfdTemplate = Velocity.getTemplate("/templates/api_template.vm", "UTF-8");
            StringWriter writer = new StringWriter();
            pfdTemplate.merge(context, writer);
            HtmlConverter.convertToPdf(writer.toString(), pdfDocument, properties);
            pdfDocument.close();
        } catch (Exception e) {
            throw new RuntimeException("PFD文件生成失败", e);
        }
    }

 
}

api_template.vm 模板文件

<!doctype html>
<html>

<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width initial-scale=1'>
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,700,400&subset=latin,latin-ext'
          rel='stylesheet' type='text/css'/>
    <style type='text/css'>
        :root {
            --bg-color: #ffffff;
            --text-color: #333333;
            --select-text-bg-color: #B5D6FC;
            --select-text-font-color: auto;
            --monospace: "Lucida Console", Consolas, "Courier", monospace;
            --title-bar-height: 20px;
        }

        .mac-os-11 {
            --title-bar-height: 28px;
        }

        html {
            font-size: 14px;
            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
            -webkit-font-smoothing: antialiased;
        }

        h1, h2, h3, h4, h5 {
            white-space: pre-wrap;
        }

        body {
            margin: 0px;
            padding: 0px;
            height: auto;
            inset: 0px;
            font-size: 1rem;
            line-height: 1.42857;
            overflow-x: hidden;
            background: inherit;
            tab-size: 4;
        }

        iframe {
            margin: auto;
        }

        table td {
            white-space: pre-wrap;
            word-wrap: break-word;
        }

        table th {
            white-space: pre-wrap;
            word-wrap: break-word;
        }

        table thead tr {
            background-color: #f8f8f8;
        }

        table td span {
            display: block;
            width: 62px;
        }

        a:active, a:hover {
            outline: 0px;
        }

        .in-text-selection, ::selection {
            text-shadow: none;
        }

        #write {
            /*margin: 0px auto;*/
            height: auto;
            width: inherit;
            overflow-wrap: break-word;
            position: relative;
            white-space: normal;
            /*padding-top: 36px;*/
        }

        #write.first-line-indent p {
            text-indent: 2em;
        }

        #write.first-line-indent li p, #write.first-line-indent p * {
            text-indent: 0px;
        }

        #write.first-line-indent li {
            margin-left: 2em;
        }

        .for-image #write {
            padding-left: 8px;
            padding-right: 8px;
        }

        body.typora-export {
            padding-left: 30px;
            padding-right: 30px;
        }

        .typora-export .footnote-line, .typora-export li, .typora-export p {
            white-space: pre-wrap;
        }

        .typora-export .task-list-item input {
            pointer-events: none;
        }

        #write li > figure:last-child {
            margin-bottom: 0.5rem;
        }

        #write ol, #write ul {
            position: relative;
        }

        img {
            max-width: 100%;
            vertical-align: middle;
            image-orientation: from-image;
        }

        button, input, select, textarea {
            color: inherit;
            font: inherit;
        }

        input[type="checkbox"], input[type="radio"] {
            line-height: normal;
            padding: 0px;
        }

        *, ::after, ::before {
            box-sizing: border-box;
        }

        #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre {
            width: inherit;
        }

        #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p {
            position: relative;
        }

        p {
            line-height: inherit;
        }

        h1, h2, h3, h4, h5, h6 {
            break-after: avoid-page;
            break-inside: avoid;
            orphans: 4;
        }

        p {
            orphans: 4;
        }

        h1 {
            font-size: 2rem;
        }

        h2 {
            font-size: 1.8rem;
        }

        h3 {
            font-size: 1.6rem;
        }

        h4 {
            font-size: 1.4rem;
        }

        h5 {
            font-size: 1.2rem;
        }

        h6 {
            font-size: 1rem;
        }

        .md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p {
            margin-top: 1rem;
            margin-bottom: 1rem;
        }

        .hidden {
            display: none;
        }

        .md-blockmeta {
            color: rgb(204, 204, 204);
            font-weight: 700;
            font-style: italic;
        }

        a {
            cursor: pointer;
        }

        sup.md-footnote {
            padding: 2px 4px;
            background-color: rgba(238, 238, 238, 0.7);
            color: rgb(85, 85, 85);
            border-radius: 4px;
            cursor: pointer;
        }

        sup.md-footnote a, sup.md-footnote a:hover {
            color: inherit;
            text-transform: inherit;
            text-decoration: inherit;
        }

        #write input[type="checkbox"] {
            cursor: pointer;
            width: inherit;
            height: inherit;
        }

        figure {
            margin: 1.2em 0px;
            max-width: calc(100% + 16px);
            padding: 0px;
        }

        figure > table {
            margin: 0px;
        }

        thead, tr {
            break-inside: avoid;
            break-after: auto;
        }

        thead {
            display: table-header-group;
        }

        table {
            border-collapse: collapse;
            border-spacing: 0px;
            width: 100%;
            break-inside: auto;
            text-align: left;
        }

        table.md-table td {
            min-width: 32px;
        }

        .CodeMirror-gutters {
            border-right: 0px;
            background-color: inherit;
        }

        .CodeMirror-linenumber {
            user-select: none;
        }

        .CodeMirror {
            text-align: left;
        }

        .CodeMirror-placeholder {
            opacity: 0.3;
        }

        .CodeMirror pre {
            padding: 0px 4px;
        }

        .CodeMirror-lines {
            padding: 0px;
        }

        div.hr:focus {
            cursor: none;
        }

        #write pre {
            white-space: pre-wrap;
        }

        #write.fences-no-line-wrapping pre {
            white-space: pre;
        }

        #write pre.ty-contain-cm {
            white-space: normal;
        }

        .CodeMirror-gutters {
            margin-right: 4px;
        }

        .md-fences {
            font-size: 0.9rem;
            display: block;
            break-inside: avoid;
            text-align: left;
            overflow: visible;
            white-space: pre;
            background: inherit;
            position: relative !important;
        }

        .md-fences-adv-panel {
            width: 100%;
            margin-top: 10px;
            text-align: center;
            padding-top: 0px;
            padding-bottom: 8px;
        }

        #write .md-fences.mock-cm {
            white-space: pre-wrap;
        }

        .md-fences.md-fences-with-lineno {
            padding-left: 0px;
        }

        #write.fences-no-line-wrapping .md-fences.mock-cm {
            white-space: pre;
        }

        .md-fences.mock-cm.md-fences-with-lineno {
            padding-left: 8px;
        }

        .CodeMirror-line, twitterwidget {
            break-inside: avoid;
        }

        svg {
            break-inside: avoid;
        }

        .footnotes {
            opacity: 0.8;
            font-size: 0.9rem;
            margin-top: 1em;
            margin-bottom: 1em;
        }

        .footnotes + .footnotes {
            margin-top: 0px;
        }

        .md-reset {
            margin: 0px;
            padding: 0px;
            border: 0px;
            outline: 0px;
            vertical-align: top;
            background: 0px 0px;
            text-decoration: none;
            text-shadow: none;
            float: none;
            position: static;
            width: auto;
            height: auto;
            white-space: nowrap;
            cursor: inherit;
            -webkit-tap-highlight-color: transparent;
            line-height: normal;
            font-weight: 400;
            text-align: left;
            box-sizing: content-box;
            direction: ltr;
        }

        li div {
            padding-top: 0px;
        }

        blockquote {
            margin: 1rem 0px;
        }

        li .mathjax-block, li p {
            margin: 0.5rem 0px;
        }

        li blockquote {
            margin: 1rem 0px;
        }

        li {
            margin: 0px;
            position: relative;
        }

        blockquote > :last-child {
            margin-bottom: 0px;
        }

        blockquote > :first-child, li > :first-child {
            margin-top: 0px;
        }

        .footnotes-area {
            color: rgb(136, 136, 136);
            margin-top: 0.714rem;
            padding-bottom: 0.143rem;
            white-space: normal;
        }

        #write .footnote-line {
            white-space: pre-wrap;
        }

        .footnote-line {
            margin-top: 0.714em;
            font-size: 0.7em;
        }

        a img, img a {
            cursor: pointer;
        }

        pre.md-meta-block {
            font-size: 0.8rem;
            min-height: 0.8rem;
            white-space: pre-wrap;
            background: rgb(204, 204, 204);
            display: block;
        }

        #write .MathJax_Display {
            margin: 0.8em 0px 0px;
        }

        .md-math-block {
            width: 100%;
        }

        .md-math-block:not(:empty)::after {
            display: none;
        }

        .MathJax_ref {
            fill: currentcolor;
        }

        [contenteditable="true"]:active, [contenteditable="true"]:focus, [contenteditable="false"]:active, [contenteditable="false"]:focus {
            outline: 0px;
            box-shadow: none;
        }

        .md-task-list-item {
            position: relative;
            list-style-type: none;
        }

        .task-list-item.md-task-list-item {
            padding-left: 0px;
        }

        .md-task-list-item > input {
            position: absolute;
            top: 0px;
            left: 0px;
            margin-left: -1.2em;
            margin-top: calc(1em - 10px);
            border: none;
        }

        .math {
            font-size: 1rem;
        }

        .md-toc {
            min-height: 3.58rem;
            position: relative;
            font-size: 0.9rem;
            border-radius: 10px;
        }

        .md-toc-content {
            position: relative;
            margin-left: 0px;
        }

        .md-toc-content::after, .md-toc::after {
            display: none;
        }

        .md-toc-item {
            display: block;
            color: rgb(65, 131, 196);
        }

        .md-toc-item a {
            text-decoration: none;
        }

        .md-toc-inner:hover {
            text-decoration: underline;
        }

        .md-toc-inner {
            display: inline-block;
            cursor: pointer;
        }

        .md-toc-h1 .md-toc-inner {
            margin-left: 0px;
            font-weight: 700;
        }

        .md-toc-h2 .md-toc-inner {
            margin-left: 2em;
        }

        .md-toc-h3 .md-toc-inner {
            margin-left: 4em;
        }

        .md-toc-h4 .md-toc-inner {
            margin-left: 6em;
        }

        .md-toc-h5 .md-toc-inner {
            margin-left: 8em;
        }

        .md-toc-h6 .md-toc-inner {
            margin-left: 10em;
        }

        @media screen and (max-width: 48em) {
            .md-toc-h3 .md-toc-inner {
                margin-left: 3.5em;
            }

            .md-toc-h4 .md-toc-inner {
                margin-left: 5em;
            }

            .md-toc-h5 .md-toc-inner {
                margin-left: 6.5em;
            }

            .md-toc-h6 .md-toc-inner {
                margin-left: 8em;
            }
        }

        a.md-toc-inner {
            font-size: inherit;
            font-style: inherit;
            font-weight: inherit;
            line-height: inherit;
        }

        .footnote-line a:not(.reversefootnote) {
            color: inherit;
        }

        .reversefootnote {
            font-family: ui-monospace, sans-serif;
        }

        .md-attr {
            display: none;
        }

        .md-fn-count::after {
            content: ".";
        }

        code, pre, samp, tt {
            font-family: var(--monospace);
        }

        kbd {
            margin: 0px 0.1em;
            padding: 0.1em 0.6em;
            font-size: 0.8em;
            color: rgb(36, 39, 41);
            background: rgb(255, 255, 255);
            border: 1px solid rgb(173, 179, 185);
            border-radius: 3px;
            box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset;
            white-space: nowrap;
            vertical-align: middle;
        }

        .md-comment {
            color: rgb(162, 127, 3);
            opacity: 0.6;
            font-family: var(--monospace);
        }

        code {
            text-align: left;
            vertical-align: initial;
        }

        a.md-print-anchor {
            white-space: pre !important;
            border-width: initial !important;
            border-style: none !important;
            border-color: initial !important;
            display: inline-block !important;
            position: absolute !important;
            width: 1px !important;
            right: 0px !important;
            outline: 0px !important;
            background: 0px 0px !important;
            text-decoration: initial !important;
            text-shadow: initial !important;
        }

        .os-windows.monocolor-emoji .md-emoji {
            font-family: "Segoe UI Symbol", sans-serif;
        }

        .md-diagram-panel > svg {
            max-width: 100%;
        }

        [lang="flow"] svg, [lang="mermaid"] svg {
            max-width: 100%;
            height: auto;
        }

        [lang="mermaid"] .node text {
            font-size: 1rem;
        }

        table tr th {
            border-bottom: 0px;
        }

        video {
            max-width: 100%;
            display: block;
            margin: 0px auto;
        }

        iframe {
            max-width: 100%;
            width: 100%;
            border: none;
        }

        .highlight td, .highlight tr {
            border: 0px;
        }

        mark {
            background: rgb(255, 255, 0);
            color: rgb(0, 0, 0);
        }

        .md-html-inline .md-plain, .md-html-inline strong, mark .md-inline-math, mark strong {
            color: inherit;
        }

        .md-expand mark .md-meta {
            opacity: 0.3 !important;
        }

        mark .md-meta {
            color: rgb(0, 0, 0);
        }

        @media print {
            .typora-export h1, .typora-export h2, .typora-export h3, .typora-export h4, .typora-export h5, .typora-export h6 {
                break-inside: avoid;
            }
        }

        .md-diagram-panel .messageText {
            stroke: none !important;
        }

        .md-diagram-panel .start-state {
            fill: var(--node-fill);
        }

        .md-diagram-panel .edgeLabel rect {
            opacity: 1 !important;
        }

        .md-fences.md-fences-math {
            font-size: 1em;
        }

        .md-fences-advanced:not(.md-focus) {
            padding: 0px;
            white-space: nowrap;
            border: 0px;
        }

        .md-fences-advanced:not(.md-focus) {
            background: inherit;
        }

        .typora-export-show-outline .typora-export-content {
            max-width: 1440px;
            margin: auto;
            display: flex;
            flex-direction: row;
        }

        .typora-export-sidebar {
            width: 300px;
            font-size: 0.8rem;
            margin-top: 80px;
            margin-right: 18px;
        }

        .typora-export-show-outline #write {
            --webkit-flex: 2;
            flex: 2 1 0%;
        }

        .typora-export-sidebar .outline-content {
            position: fixed;
            top: 0px;
            max-height: 100%;
            overflow: hidden auto;
            padding-bottom: 30px;
            padding-top: 60px;
            width: 300px;
        }

        @media screen and (max-width: 800px) {
            .typora-export-sidebar {
                display: none;
            }
        }

        .outline-content li, .outline-content ul {
            margin-left: 0px;
            margin-right: 0px;
            padding-left: 0px;
            padding-right: 0px;
            list-style: none;
            overflow-wrap: anywhere;
        }

        .outline-content ul {
            margin-top: 0px;
            margin-bottom: 0px;
        }

        .outline-content strong {
            font-weight: 400;
        }

        .outline-expander {
            width: 1rem;
            height: 1.42857rem;
            position: relative;
            display: table-cell;
            vertical-align: middle;
            cursor: pointer;
            padding-left: 4px;
        }

        .outline-expander::before {
            content: "";
            position: relative;
            font-family: Ionicons;
            display: inline-block;
            font-size: 8px;
            vertical-align: middle;
        }

        .outline-item {
            padding-top: 3px;
            padding-bottom: 3px;
            cursor: pointer;
        }

        .outline-expander:hover::before {
            content: "";
        }

        .outline-h1 > .outline-item {
            padding-left: 0px;
        }

        .outline-h2 > .outline-item {
            padding-left: 1em;
        }

        .outline-h3 > .outline-item {
            padding-left: 2em;
        }

        .outline-h4 > .outline-item {
            padding-left: 3em;
        }

        .outline-h5 > .outline-item {
            padding-left: 4em;
        }

        .outline-h6 > .outline-item {
            padding-left: 5em;
        }

        .outline-label {
            cursor: pointer;
            display: table-cell;
            vertical-align: middle;
            text-decoration: none;
            color: inherit;
        }

        .outline-label:hover {
            text-decoration: underline;
        }

        .outline-item:hover {
            border-color: rgb(245, 245, 245);
            background-color: var(--item-hover-bg-color);
        }

        .outline-item:hover {
            margin-left: -28px;
            margin-right: -28px;
            border-left: 28px solid transparent;
            border-right: 28px solid transparent;
        }

        .outline-item-single .outline-expander::before, .outline-item-single .outline-expander:hover::before {
            display: none;
        }

        .outline-item-open > .outline-item > .outline-expander::before {
            content: "";
        }

        .outline-children {
            display: none;
        }

        .info-panel-tab-wrapper {
            display: none;
        }

        .outline-item-open > .outline-children {
            display: block;
        }

        .typora-export .outline-item {
            padding-top: 1px;
            padding-bottom: 1px;
        }

        .typora-export .outline-item:hover {
            margin-right: -8px;
            border-right: 8px solid transparent;
        }

        .typora-export .outline-expander::before {
            content: "+";
            font-family: inherit;
            top: -1px;
        }

        .typora-export .outline-expander:hover::before, .typora-export .outline-item-open > .outline-item > .outline-expander::before {
            content: "−";
        }

        .typora-export-collapse-outline .outline-children {
            display: none;
        }

        .typora-export-collapse-outline .outline-item-open > .outline-children, .typora-export-no-collapse-outline .outline-children {
            display: block;
        }

        .typora-export-no-collapse-outline .outline-expander::before {
            content: "" !important;
        }

        .typora-export-show-outline .outline-item-active > .outline-item .outline-label {
            font-weight: 700;
        }

        .md-inline-math-container mjx-container {
            zoom: 0.95;
        }

        mjx-container {
            break-inside: avoid;
        }


        .CodeMirror {
            height: auto;
        }

        .CodeMirror.cm-s-inner {
            background: inherit;
        }

        .CodeMirror-scroll {
            overflow: auto hidden;
            z-index: 3;
        }

        .CodeMirror-gutter-filler, .CodeMirror-scrollbar-filler {
            background-color: rgb(255, 255, 255);
        }

        .CodeMirror-gutters {
            border-right: 1px solid rgb(221, 221, 221);
            background: inherit;
            white-space: nowrap;
        }

        .CodeMirror-linenumber {
            padding: 0px 3px 0px 5px;
            text-align: right;
            color: rgb(153, 153, 153);
        }

        .cm-s-inner .cm-keyword {
            color: rgb(119, 0, 136);
        }

        .cm-s-inner .cm-atom, .cm-s-inner.cm-atom {
            color: rgb(34, 17, 153);
        }

        .cm-s-inner .cm-number {
            color: rgb(17, 102, 68);
        }

        .cm-s-inner .cm-def {
            color: rgb(0, 0, 255);
        }

        .cm-s-inner .cm-variable {
            color: rgb(0, 0, 0);
        }

        .cm-s-inner .cm-variable-2 {
            color: rgb(0, 85, 170);
        }

        .cm-s-inner .cm-variable-3 {
            color: rgb(0, 136, 85);
        }

        .cm-s-inner .cm-string {
            color: rgb(170, 17, 17);
        }

        .cm-s-inner .cm-property {
            color: rgb(0, 0, 0);
        }

        .cm-s-inner .cm-operator {
            color: rgb(152, 26, 26);
        }

        .cm-s-inner .cm-comment, .cm-s-inner.cm-comment {
            color: rgb(170, 85, 0);
        }

        .cm-s-inner .cm-string-2 {
            color: rgb(255, 85, 0);
        }

        .cm-s-inner .cm-meta {
            color: rgb(85, 85, 85);
        }

        .cm-s-inner .cm-qualifier {
            color: rgb(85, 85, 85);
        }

        .cm-s-inner .cm-builtin {
            color: rgb(51, 0, 170);
        }

        .cm-s-inner .cm-bracket {
            color: rgb(153, 153, 119);
        }

        .cm-s-inner .cm-tag {
            color: rgb(17, 119, 0);
        }

        .cm-s-inner .cm-attribute {
            color: rgb(0, 0, 204);
        }

        .cm-s-inner .cm-header, .cm-s-inner.cm-header {
            color: rgb(0, 0, 255);
        }

        .cm-s-inner .cm-quote, .cm-s-inner.cm-quote {
            color: rgb(0, 153, 0);
        }

        .cm-s-inner .cm-hr, .cm-s-inner.cm-hr {
            color: rgb(153, 153, 153);
        }

        .cm-s-inner .cm-link, .cm-s-inner.cm-link {
            color: rgb(0, 0, 204);
        }

        .cm-negative {
            color: rgb(221, 68, 68);
        }

        .cm-positive {
            color: rgb(34, 153, 34);
        }

        .cm-header, .cm-strong {
            font-weight: 700;
        }

        .cm-del {
            text-decoration: line-through;
        }

        .cm-em {
            font-style: italic;
        }

        .cm-link {
            text-decoration: underline;
        }

        .cm-error {
            color: red;
        }

        .cm-invalidchar {
            color: red;
        }

        .cm-constant {
            color: rgb(38, 139, 210);
        }

        .cm-defined {
            color: rgb(181, 137, 0);
        }

        div.CodeMirror span.CodeMirror-matchingbracket {
            color: rgb(0, 255, 0);
        }

        div.CodeMirror span.CodeMirror-nonmatchingbracket {
            color: rgb(255, 34, 34);
        }

        .cm-s-inner .CodeMirror-activeline-background {
            background: inherit;
        }

        .CodeMirror {
            position: relative;
            overflow: hidden;
        }

        .CodeMirror-scroll {
            height: 100%;
            outline: 0px;
            position: relative;
            box-sizing: content-box;
            background: inherit;
        }

        .CodeMirror-sizer {
            position: relative;
        }

        .CodeMirror-gutter-filler, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar {
            position: absolute;
            z-index: 6;
            display: none;
            outline: 0px;
        }

        .CodeMirror-vscrollbar {
            right: 0px;
            top: 0px;
            overflow: hidden;
        }

        .CodeMirror-hscrollbar {
            bottom: 0px;
            left: 0px;
            overflow: auto hidden;
        }

        .CodeMirror-scrollbar-filler {
            right: 0px;
            bottom: 0px;
        }

        .CodeMirror-gutter-filler {
            left: 0px;
            bottom: 0px;
        }

        .CodeMirror-gutters {
            position: absolute;
            left: 0px;
            top: 0px;
            padding-bottom: 10px;
            z-index: 3;
            overflow-y: hidden;
        }

        .CodeMirror-gutter {
            white-space: normal;
            height: 100%;
            box-sizing: content-box;
            padding-bottom: 30px;
            margin-bottom: -32px;
            display: inline-block;
        }

        .CodeMirror-gutter-wrapper {
            position: absolute;
            z-index: 4;
            background: 0px 0px !important;
            border: none !important;
        }

        .CodeMirror-gutter-background {
            position: absolute;
            top: 0px;
            bottom: 0px;
            z-index: 4;
        }

        .CodeMirror-gutter-elt {
            position: absolute;
            cursor: default;
            z-index: 4;
        }

        .CodeMirror-lines {
            cursor: text;
        }

        .CodeMirror pre {
            border-radius: 0px;
            border-width: 0px;
            background: 0px 0px;
            font-family: inherit;
            font-size: inherit;
            margin: 0px;
            white-space: pre;
            overflow-wrap: normal;
            color: inherit;
            z-index: 2;
            position: relative;
            overflow: visible;
        }

        .CodeMirror-wrap pre {
            overflow-wrap: break-word;
            white-space: pre-wrap;
        }

        .CodeMirror-code pre {
            border-right: 30px solid transparent;
            width: fit-content;
        }

        .CodeMirror-wrap .CodeMirror-code pre {
            border-right: none;
            width: auto;
        }

        .CodeMirror-linebackground {
            position: absolute;
            inset: 0px;
            z-index: 0;
        }

        .CodeMirror-linewidget {
            position: relative;
            z-index: 2;
            overflow: auto;
        }

        .CodeMirror-measure {
            position: absolute;
            width: 100%;
            height: 0px;
            overflow: hidden;
            visibility: hidden;
        }

        .CodeMirror-measure pre {
            position: static;
        }

        .CodeMirror div.CodeMirror-cursor {
            position: absolute;
            visibility: hidden;
            border-right: none;
            width: 0px;
        }

        .CodeMirror div.CodeMirror-cursor {
            visibility: hidden;
        }

        .CodeMirror-focused div.CodeMirror-cursor {
            visibility: inherit;
        }

        .cm-searching {
            background: rgba(255, 255, 0, 0.4);
        }

        span.cm-underlined {
            text-decoration: underline;
        }

        span.cm-strikethrough {
            text-decoration: line-through;
        }

        .cm-tw-syntaxerror {
            color: rgb(255, 255, 255);
            background-color: rgb(153, 0, 0);
        }

        .cm-tw-deleted {
            text-decoration: line-through;
        }

        .cm-tw-header5 {
            font-weight: 700;
        }

        .cm-tw-listitem:first-child {
            padding-left: 10px;
        }

        .cm-tw-box {
            border-style: solid;
            border-right-width: 1px;
            border-bottom-width: 1px;
            border-left-width: 1px;
            border-color: inherit;
            border-top-width: 0px !important;
        }

        .cm-tw-underline {
            text-decoration: underline;
        }


        :root {
            --side-bar-bg-color: #fafafa;
            --control-text-color: #777;
        }

        /* open-sans-regular - latin-ext_latin */
        /* open-sans-italic - latin-ext_latin */
        /* open-sans-700 - latin-ext_latin */
        /* open-sans-700italic - latin-ext_latin */
        html {
            font-size: 16px;
            -webkit-font-smoothing: antialiased;
        }

        body {
            font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, 'Segoe UI Emoji', sans-serif;
            color: rgb(51, 51, 51);
            line-height: 1.6;
        }

        #write {
            max-width: 655px;
            /*margin: 0 auto;*/
            /*padding: 30px;*/
            /*padding-bottom: 100px;*/
        }

        #write > ul:first-child,
        #write > ol:first-child {
            margin-top: 30px;
        }

        a {
            color: #4183C4;
        }

        h1,
        h2,
        h3,
        h4,
        h5,
        h6 {
            position: relative;
            margin-top: 1rem;
            margin-bottom: 1rem;
            font-weight: bold;
            line-height: 1.4;
            cursor: text;
        }

        h1:hover a.anchor,
        h2:hover a.anchor,
        h3:hover a.anchor,
        h4:hover a.anchor,
        h5:hover a.anchor,
        h6:hover a.anchor {
            text-decoration: none;
        }

        h1 tt,
        h1 code {
            font-size: inherit;
        }

        h2 tt,
        h2 code {
            font-size: inherit;
        }

        h3 tt,
        h3 code {
            font-size: inherit;
        }

        h4 tt,
        h4 code {
            font-size: inherit;
        }

        h5 tt,
        h5 code {
            font-size: inherit;
        }

        h6 tt,
        h6 code {
            font-size: inherit;
        }

        h1 {
            font-size: 2.25em;
            line-height: 1.2;
            border-bottom: 1px solid #eee;
        }

        h2 {
            font-size: 1.75em;
            line-height: 1.225;
            border-bottom: 1px solid #eee;
        }

        /*@media print {
            .typora-export h1,
            .typora-export h2 {
                border-bottom: none;
                padding-bottom: initial;
            }

            .typora-export h1::after,
            .typora-export h2::after {
                content: "";
                display: block;
                height: 100px;
                margin-top: -96px;
                border-top: 1px solid #eee;
            }
        }*/

        h3 {
            font-size: 1.5em;
            line-height: 1.43;
        }

        h4 {
            font-size: 1.25em;
        }

        h5 {
            font-size: 1em;
        }

        h6 {
            font-size: 1em;
            color: #777;
        }

        p,
        blockquote,
        ul,
        ol,
        dl,
        table {
            margin: 0.8em 0;
        }

        li > ol,
        li > ul {
            margin: 0 0;
        }

        hr {
            height: 2px;
            padding: 0;
            margin: 16px 0;
            background-color: #e7e7e7;
            border: 0 none;
            overflow: hidden;
            box-sizing: content-box;
        }

        li p.first {
            display: inline-block;
        }

        ul,
        ol {
            padding-left: 30px;
        }

        ul:first-child,
        ol:first-child {
            margin-top: 0;
        }

        ul:last-child,
        ol:last-child {
            margin-bottom: 0;
        }

        blockquote {
            border-left: 4px solid #dfe2e5;
            padding: 0 15px;
            color: #777777;
        }

        blockquote blockquote {
            padding-right: 0;
        }

        table {
            padding: 0;
        }

        table tr {
            border: 1px solid #dfe2e5;
            margin: 0;
            padding: 0;
        }

        table tr:nth-child(2n),
        thead {
            background-color: #f8f8f8;
        }

        table th {
            font-weight: bold;
            border: 1px solid #dfe2e5;
            border-bottom: 0;
            margin: 0;
            padding: 6px 13px;
        }

        table td {
            border: 1px solid #dfe2e5;
            margin: 0;
            padding: 6px 13px;
        }

        table th:first-child,
        table td:first-child {
            margin-top: 0;
        }

        table th:last-child,
        table td:last-child {
            margin-bottom: 0;
        }

        .CodeMirror-lines {
            padding-left: 4px;
        }

        .code-tooltip {
            box-shadow: 0 1px 1px 0 rgba(0, 28, 36, .3);
            border-top: 1px solid #eef2f2;
        }

        .md-fences,
        code,
        tt {
            border: 1px solid #e7eaed;
            background-color: #f8f8f8;
            border-radius: 3px;
            padding: 0;
            padding: 2px 4px 0px 4px;
            font-size: 0.9em;
        }

        code {
            background-color: #f3f4f4;
            padding: 0 2px 0 2px;
        }

        .md-fences {
            margin-bottom: 15px;
            margin-top: 15px;
            padding-top: 8px;
            padding-bottom: 6px;
        }


        .md-task-list-item > input {
            margin-left: -1.3em;
        }

        @media print {
            html {
                font-size: 13px;
            }

            pre {
                page-break-inside: avoid;
                word-wrap: break-word;
            }
        }

        .md-fences {
            background-color: #f8f8f8;
        }

        #write pre.md-meta-block {
            padding: 1rem;
            font-size: 85%;
            line-height: 1.45;
            background-color: #f7f7f7;
            border: 0;
            border-radius: 3px;
            color: #777777;
            margin-top: 0 !important;
        }

        .mathjax-block > .code-tooltip {
            bottom: .375rem;
        }

        .md-mathjax-midline {
            background: #fafafa;
        }

        #write > h3.md-focus:before {
            left: -1.5625rem;
            top: .375rem;
        }

        #write > h4.md-focus:before {
            left: -1.5625rem;
            top: .285714286rem;
        }

        #write > h5.md-focus:before {
            left: -1.5625rem;
            top: .285714286rem;
        }

        #write > h6.md-focus:before {
            left: -1.5625rem;
            top: .285714286rem;
        }

        .md-image > .md-meta {
            /*border: 1px solid #ddd;*/
            border-radius: 3px;
            padding: 2px 0px 0px 4px;
            font-size: 0.9em;
            color: inherit;
        }

        .md-tag {
            color: #a7a7a7;
            opacity: 1;
        }

        .md-toc {
            margin-top: 20px;
            padding-bottom: 20px;
        }

        .sidebar-tabs {
            border-bottom: none;
        }

        #typora-quick-open {
            border: 1px solid #ddd;
            background-color: #f8f8f8;
        }

        #typora-quick-open-item {
            background-color: #FAFAFA;
            border-color: #FEFEFE #e5e5e5 #e5e5e5 #eee;
            border-style: solid;
            border-width: 1px;
        }

        /** focus mode */
        .on-focus-mode blockquote {
            border-left-color: rgba(85, 85, 85, 0.12);
        }

        header, .context-menu, .megamenu-content, footer {
            font-family: "Segoe UI", "Arial", sans-serif;
        }

        .file-node-content:hover .file-node-icon,
        .file-node-content:hover .file-node-open-state {
            visibility: visible;
        }

        .mac-seamless-mode #typora-sidebar {
            background-color: #fafafa;
            background-color: var(--side-bar-bg-color);
        }

        .md-lang {
            color: #b4654d;
        }

        /*.html-for-mac {
            --item-hover-bg-color: #E6F0FE;
        }*/

        #md-notification .btn {
            border: 0;
        }

        .dropdown-menu .divider {
            border-color: #e5e5e5;
            opacity: 0.4;
        }

        .ty-preferences .window-content {
            background-color: #fafafa;
        }

        .ty-preferences .nav-group-item.active {
            color: white;
            background: #999;
        }

        .menu-item-container a.menu-style-btn {
            background-color: #f5f8fa;
            background-image: linear-gradient(180deg, hsla(0, 0%, 100%, 0.8), hsla(0, 0%, 100%, 0));
        }


    </style>
    <title>$apiName+接口文档</title>
</head>

<body class='typora-export os-windows'>
<div class='typora-export-content'>
    <div id='write' class=''>
        <h2 id='apiname'><span>$apiName</span></h2>
        <blockquote><p><span>Description</span></p>
            <p><span>$apiDesc</span></p></blockquote>
        <h2 id='url'><span>URL</span></h2>
        <p><span>$method $apiUrl</span></p>
        <h2 id='parameters'><span>Parameters</span></h2>
        <figure class='table-figure'>
            <table>
                <thead>
                <tr>
                    <th style="text-align:left; font-weight: bold; width: 110px"><span style="display: block; width: 110px">名称</span></th>
                    <th style="text-align:left; font-weight: bold; width:  60px"><span style="display: block; width:  60px">位置</span></th>
                    <th style="text-align:left; font-weight: bold; width:  50px"><span style="display: block; width:  50px">类型</span></th>
                    <th style="text-align:left; font-weight: bold; width:  40px"><span style="display: block; width:  40px">必填</span></th>
                    <th style="text-align:left; font-weight: bold; width: 110px"><span style="display: block; width: 110px">示例值</span></th>
                    <th style="text-align:left; font-weight: bold; width: 110px"><span style="display: block; width: 110px">描述</span></th>
                </tr>
                </thead>
                <tbody>
                <tr>
                    <td style="width: 110px"><span style="width: 110px">AccessKey</span></td>
                    <td style="width:  60px"><span style="width:  60px">header</span></td>
                    <td style="width:  50px"><span style="width:  50px">string</span></td>
                    <td style="width:  40px"><span style="width:  40px">yes</span></td>
                    <td style="width: 110px"><span style="width: 110px">h6***qF</span></td>
                    <td style="width: 110px"><span style="width: 110px">AccessKey</span></td>
                </tr>
                <tr>
                    <td style="width: 110px"><span style="width: 110px">SecretKey</span></td>
                    <td style="width:  60px"><span style="width:  60px">header</span></td>
                    <td style="width:  50px"><span style="width:  50px">string</span></td>
                    <td style="width:  40px"><span style="width:  40px">yes</span></td>
                    <td style="width: 110px"><span style="width: 110px">h6***qF***3f</span></td>
                    <td style="width: 110px"><span style="width: 110px">SecretKey</span></td>
                </tr>
                    #foreach($param in $apiParams)
                    <tr>
                        <td style="width: 110px"><span style="width: 110px">$param.name</span></td>
                        <td style="width:  60px"><span style="width:  60px">$param.location</span></td>
                        <td style="width:  50px"><span style="width:  50px">#if($param.type)${param.type}#else string#end</span></td>
                        <td style="width:  40px"><span style="width:  40px">#if($param.required)$param.required#else no#end</span></td>
                        <td style="width: 110px"><span style="width: 110px">#if($param.example)$param.example#end</span></td>
                        <td style="width: 110px"><span style="width: 110px">$param.desc</span></td>
                    </tr>
                    #end
                </tbody>
            </table>
        </figure>
        #if(!$apiDict.isEmpty())
            <h2 id='api-dict-parameters'><span>Dictionary</span></h2>
            <figure class='table-figure'>
                <table>
                    <thead>
                    <tr>
                        <th style="text-align:left; font-weight: bold"><span>Field</span></th>
                        <th style="text-align:left; font-weight: bold"><span>Dict Type</span></th>
                        <th style="text-align:left; font-weight: bold"><span>Description</span></th>
                    </tr>
                    </thead>
                    <tbody>
                        #foreach($dict in $apiDict)
                        <tr>
                            <td><span>$dict.name</span></td>
                            <td><span>$dict.type</span></td>
                            <td><span>$dict.desc</span></td>
                        </tr>
                        #end
                    </tbody>
                </table>
            </figure>
        #end
        <h2 id='responses'><span>Responses</span></h2>
        #if(!$responses.isEmpty() && $responses.size() > 0)
            <figure class='table-figure'>
                <table>
                    <thead>
                    <tr>
                        <th style="text-align:left; font-weight: bold"><span>名称</span></th>
                        <th style="text-align:left; font-weight: bold"><span>类型</span></th>
                        <th style="text-align:left; font-weight: bold"><span>示例值</span></th>
                        <th style="text-align:left; font-weight: bold"><span>描述</span></th>
                    </tr>
                    </thead>
                    <tbody>
                        #foreach($param in $responses)
                        <tr>
                            <td><span>$param.name</span></td>
                            <td><span>$param.type</span></td>
                            <td><span>$param.example</span></td>
                            <td><span>$param.desc</span></td>
                        </tr>
                        #end
                    </tbody>
                </table>
            </figure>
        #else
            <blockquote><p>Response Examples</p></blockquote>
            <pre class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" lang="json"><div
                    class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap" lang="json"><div
                    style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 9.51562px; left: 8px;"><textarea
                    autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0"
                    style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div
                    class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler"
                                                                                         cm-not-content="true"></div><div
                    class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer"
                                                                 style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div
                    style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div
                    role="presentation" style="position: relative; outline: none;"><div
                    class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div
                    class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline"
                                                                              style="position: relative;"><div
                    class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div
                    class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre
                    class=" CodeMirror-line " role="presentation"><span role="presentation"
                                                                        style="padding-right: 0.1px;">{</span></pre></div><pre
                    class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">  <span
                    class="cm-string cm-property">"code"</span>: <span class="cm-number">200</span>,</span></pre><pre
                    class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">  <span
                    class="cm-string cm-property">"msg"</span>: <span class="cm-string">"操作成功"</span>,</span></pre><pre
                    class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">  <span
                    class="cm-string cm-property">"data"</span>: [</span></pre><pre class=" CodeMirror-line "
                                                                                    role="presentation"><span
                    role="presentation" style="padding-right: 0.1px;">      {</span></pre><div class=""
                                                                                                         style="position: relative;"><pre
                    class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span
                    class="cm-meta">......</span></span></pre></div><div class="" style="position: relative;"><pre
                    class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">      }</span></pre></div><div
                    class="" style="position: relative;"><pre class=" CodeMirror-line " role="presentation"><span
                    role="presentation" style="padding-right: 0.1px;">  ]</span></pre></div><div class=""
                                                                                                 style="position: relative;"><pre
                    class=" CodeMirror-line " role="presentation"><span role="presentation"
                                                                        style="padding-right: 0.1px;">}</span></pre></div></div></div></div></div></div><div
                    style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 207px;"></div><div
                    class="CodeMirror-gutters" style="display: none; height: 207px;"></div></div></div></pre>
        #end
        #if(!$apiDict.isEmpty())
            <div style="padding-top: 32px">
                <h2 id='dict-name'><span>数据字典</span></h2>
                <blockquote><p><span>Description</span></p>
                    <p><span>根据字典类型查询字典数据信息</span></p></blockquote>
                <h2 id='dict-url'><span>URL</span></h2>
                <p><span>GET ${serverUrl}api/system/dict/{dictType}</span></p>
                <h2 id='dict-parameters'><span>Parameters</span></h2>
                <figure class='table-figure'>
                    <table>
                        <thead>
                        <tr>
                            <th style="text-align:left; font-weight: bold"><span>Name</span></th>
                            <th style="text-align:left; font-weight: bold"><span>Location</span></th>
                            <th style="text-align:left; font-weight: bold"><span>Type</span></th>
                            <th style="text-align:left; font-weight: bold"><span>Required</span></th>
                            <th style="text-align:left; font-weight: bold"><span>Description</span></th>
                        </tr>
                        </thead>
                        <tbody>
                        <tr>
                            <td><span>AccessKey</span></td>
                            <td><span>header</span></td>
                            <td><span>string</span></td>
                            <td><span>yes</span></td>
                            <td><span>AccessKey</span></td>
                        </tr>
                        <tr>
                            <td><span>SecretKey</span></td>
                            <td><span>header</span></td>
                            <td><span>string</span></td>
                            <td><span>yes</span></td>
                            <td><span>SecretKey</span></td>
                        </tr>
                        <tr>
                            <td><span>dictType</span></td>
                            <td><span>path</span></td>
                            <td><span>string</span></td>
                            <td><span>yes</span></td>
                            <td><span>字典类型</span></td>
                        </tr>
                        </tbody>
                    </table>
                </figure>
                <h2 id='dict-responses'><span>Responses</span></h2>
                <blockquote><p>Response Examples</p></blockquote>
                <pre class="md-fences md-end-block ty-contain-cm modeLoaded md-focus" spellcheck="false" lang="json" style="break-inside: unset;">
                   <div class="CodeMirror cm-s-inner cm-s-null-scroll CodeMirror-wrap CodeMirror-focused" lang="json">
                       ##
                    <div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 470.141px; left: 16.6771px;">
                     <textarea autocorrect="off"
                               autocapitalize="off"
                               spellcheck="false"
                               tabindex="0"
                               style="position: absolute;  padding: 0px; width: 1000px; height: 1em; outline: none;">

                     </textarea>
                        ## bottom: -1em;
                    </div>
                    <div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div>
                    <div class="CodeMirror-gutter-filler" cm-not-content="true"></div>
                    <div class="CodeMirror-scroll" tabindex="-1">
                     <div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;">
                      <div style="position: relative; top: 0px;">
                       <div class="CodeMirror-lines" role="presentation">
                        <div role="presentation" style="position: relative; outline: none;">
                         <div class="CodeMirror-measure">
                          <pre><span>xxxxxxxxxx</span></pre>
                         </div>
                         <div class="CodeMirror-measure"></div>
                         <div style="position: relative; z-index: 1;"></div>
                        <div class="CodeMirror-code" role="presentation" style="">
                          <div class="" style="position: relative;">
                           <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">{</span></pre>
                          </div>
                          <pre class=" CodeMirror-line " role="presentation">
                              <span role="presentation" style="padding-right: 0.1px;">  <span class="cm-string cm-property">"code"</span>: <span class="cm-number">200</span>,</span>
                          </pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">  <span class="cm-string cm-property">"msg"</span>: <span class="cm-string">"操作成功"</span>,</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">  <span class="cm-string cm-property">"data"</span>: [</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">      {</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictType"</span>: <span class="cm-string">"sys_user_sex"</span>,</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictLabel"</span>: <span class="cm-string">"男"</span>,</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictDesc"</span>: <span class="cm-atom">null</span></span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">      },</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">      {</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictType"</span>: <span class="cm-string">"sys_user_sex"</span>,</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictLabel"</span>: <span class="cm-string">"女"</span>,</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictDesc"</span>: <span class="cm-atom">null</span></span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">      },</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">      {</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictType"</span>: <span class="cm-string">"sys_user_sex"</span>,</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictLabel"</span>: <span class="cm-string">"未知"</span>,</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">          <span class="cm-string cm-property">"dictDesc"</span>: <span class="cm-atom">null</span></span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">      }</span></pre>
                          <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">  ]</span></pre>
                          <div class="CodeMirror-activeline" style="position: relative;">
                           <div class="CodeMirror-activeline-background CodeMirror-linebackground"></div>
                           <div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div>
                           <pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">}</span></pre>
                          </div>
                         </div>
                       </div>
                       </div>
                     </div>
                     </div>
                     <div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 484px;"></div>
                     <div class="CodeMirror-gutters" style="display: none; height: 484px;"></div>
                    </div>
                   </div>
                </pre>
            </div>
        #end
    </div>
</div>
</body>
</html>

效果图
在这里插入图片描述


总结

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在 Spring Boot整合 Velocity 并使用自定义标签,可以按照以下步骤进行: 1. 导入相关依赖 在 `pom.xml` 文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-velocity</artifactId> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-tools</artifactId> <version>2.0</version> </dependency> ``` 2. 配置 Velocity 在 `application.properties` 文件中添加以下配置: ```properties spring.velocity.resource-loader-path=classpath:/templates/ spring.velocity.toolbox-config-location=velocity.toolbox.xml ``` 其中,`resource-loader-path` 配置 Velocity 模板所在的目录,`toolbox-config-location` 配置 Velocity 工具箱的配置文件路径。 3. 定义自定义标签 在 `velocity.toolbox.xml` 文件中定义自定义标签,例如: ```xml <tools> <toolbox scope="application"> <tool key="myTag" class="com.example.MyTag"/> </toolbox> </tools> ``` 其中,`key` 是标签名,`class` 是标签类的完整路径。 4. 实现自定义标签类 在项目中创建 `MyTag` 类,并实现 `org.apache.velocity.tools.generic.SafeConfig` 接口和 `org.apache.velocity.tools.generic.Tool` 接口,例如: ```java public class MyTag implements SafeConfig, Tool { private String name; @Override public void configure(Map<String, Object> map) { this.name = (String) map.get("name"); } public String execute() { return "Hello, " + name + "!"; } } ``` 其中,`configure` 方法用于获取配置信息,`execute` 方法用于执行标签的逻辑。 5. 在模板中使用自定义标签 在模板中使用自定义标签,例如: ``` <myTag name="world"/> ``` 这样就可以在模板中使用自定义标签了。 以上就是 Spring Boot 整合 Velocity 并使用自定义标签的步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值