Статьи

Использование Asciidoctor с Spring: рендеринг документов Asciidoc с помощью Spring MVC

Asciidoc — это текстовый формат документов, и поэтому он очень полезен, если мы хотим зафиксировать наши документы в системе контроля версий и отслеживать изменения между различными версиями. Это делает Asciidoc идеальным инструментом для написания книг, технических документов, часто задаваемых вопросов или руководств пользователя.

После того, как мы создали документ Asciidoc, есть вероятность, что мы хотим его опубликовать, и один из способов сделать это — опубликовать этот документ на нашем веб-сайте. Сегодня мы узнаем, как мы можем преобразовать документы Asciidoc в HTML с помощью AsciidoctorJ и визуализировать созданный HTML с помощью Spring MVC.

Требования нашего приложения:

  • Он должен поддерживать документы Asciidoc, найденные из пути к классам.
  • Он должен поддерживать разметку Asciidoc, заданную как объект String .
  • Он должен преобразовать документы Asciidoc в HTML и отобразить созданный HTML.
  • Он должен «встроить» созданный HTML-код в макет нашего приложения.

Давайте начнем с получения необходимых зависимостей с Maven.

Получение необходимых зависимостей с Maven

Мы можем получить необходимые зависимости с Maven, выполнив следующие действия:

  1. Включите платформу Spring IO .
  2. Настройте необходимые зависимости.

Во-первых , мы можем включить платформу Spring IO, добавив следующий фрагмент в наш файл POM:

01
02
03
04
05
06
07
08
09
10
11
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.spring.platform</groupId>
            <artifactId>platform-bom</artifactId>
            <version>1.0.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Во-вторых , мы можем настроить необходимые зависимости, выполнив следующие действия:

  1. Настройте зависимости ведения журнала в файле pom.xml .
  2. Добавьте зависимость spring-webmvc в файл pom.xml .
  3. Добавьте зависимость Servlet API в файл POM.
  4. Настройте зависимость Sitemesh (версия 3.0.0) в файле POM. Sitemesh гарантирует, что каждая страница нашего приложения будет выглядеть единообразно.
  5. Добавьте зависимость asciidoctorj (версия 1.5.0) в файл pom.xml . AsciidoctorJ — это Java API для Asciidoctor, и мы используем его для преобразования документов Asciidoc в HTML.

Соответствующая часть нашего файла pom.xml выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<dependencies>
    <!-- Logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
    </dependency>
    <!-- Spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
    </dependency>
    <!-- Java EE -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <scope>provided</scope>
    </dependency>
    <!-- Sitemesh -->
    <dependency>
        <groupId>org.sitemesh</groupId>
        <artifactId>sitemesh</artifactId>
        <version>3.0.0</version>
    </dependency>
    <!-- AsciidoctorJ -->
    <dependency>
        <groupId>org.asciidoctor</groupId>
        <artifactId>asciidoctorj</artifactId>
        <version>1.5.0</version>
    </dependency>
</dependencies>

Поскольку мы используем Spring IO Platform, нам не нужно указывать версии зависимостей артефактов, которые являются частью Spring IO Platform .

Давайте двигаться дальше и начнем реализацию нашего приложения.

Рендеринг документов Asciidoc с помощью Spring MVC

Мы можем выполнить требования нашего приложения, выполнив следующие действия:

  1. Настройте наше веб-приложение и фильтр Sitemesh.
  2. Реализуйте классы представлений, которые отвечают за преобразование документов Asciidoc в HTML и рендеринг созданного HTML.
  3. Реализуйте методы контроллера, которые используют созданные классы представления.

Давайте начнем.

Настройка Sitemesh

Первое, что нам нужно сделать, это настроить Sitemesh. Мы можем настроить Sitemesh, выполнив следующие три шага:

  1. Настройте фильтр Sitemesh в конфигурации веб-приложения.
  2. Создайте декоратор, который используется для создания согласованного внешнего вида нашего приложения.
  3. Настройте декоратор, который используется фильтром Sitemesh.

Сначала мы должны настроить фильтр Sitemesh в конфигурации нашего веб-приложения. Мы можем настроить наше веб-приложение, выполнив следующие действия:

  1. Создайте класс WebAppConfig, который реализует интерфейс WebApplicationInitializer .
  2. Реализуйте метод onStartup () интерфейса WebApplicationInitializer , выполнив следующие действия:
    1. Создайте объект AnnotationConfigWebApplicationContext и настройте его для обработки нашего класса конфигурации контекста приложения.
    2. Настройте диспетчерский сервлет .
    3. Сконфигурируйте фильтр Sitemesh для обработки HTML-кода, возвращаемого JSP-страницами нашего приложения и всеми методами контроллера, использующими шаблон URL ‘/ asciidoctor / *’
    4. Добавьте новый объект ContextLoaderListener в ServletContext . ContextLoaderListener отвечает за запуск и завершение Spring WebApplicationContext .

Исходный код класса WebAppConfig выглядит следующим образом (конфигурация Sitemesh выделена):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import org.sitemesh.config.ConfigurableSiteMeshFilter;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
 
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import java.util.EnumSet;
 
public class WebAppConfig implements WebApplicationInitializer {
 
    private static final String DISPATCHER_SERVLET_NAME = "dispatcher";
 
    private static final String SITEMESH3_FILTER_NAME = "sitemesh";
    private static final String[] SITEMESH3_FILTER_URL_PATTERNS = {"*.jsp", "/asciidoctor/*"};
 
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(WebAppContext.class);
 
        configureDispatcherServlet(servletContext, rootContext);
        configureSitemesh3Filter(servletContext);
 
        servletContext.addListener(new ContextLoaderListener(rootContext));
    }
 
    private void configureDispatcherServlet(ServletContext servletContext, WebApplicationContext rootContext) {
        ServletRegistration.Dynamic dispatcher = servletContext.addServlet(
                DISPATCHER_SERVLET_NAME,
                new DispatcherServlet(rootContext)
        );
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }
 
    private void configureSitemesh3Filter(ServletContext servletContext) {
        FilterRegistration.Dynamic sitemesh = servletContext.addFilter(SITEMESH3_FILTER_NAME,
                new ConfigurableSiteMeshFilter()
        );
        EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST,
                DispatcherType.FORWARD
        );
        sitemesh.addMappingForUrlPatterns(dispatcherTypes, true, SITEMESH3_FILTER_URL_PATTERNS);
    }
}
  • Если вы хотите взглянуть на класс конфигурации контекста приложения примера приложения, вы можете получить его от Github .

Во-вторых , мы должны создать декоратор, который обеспечивает единообразный внешний вид нашего приложения. Мы можем сделать это, выполнив следующие действия:

  1. Создайте файл декоратора в каталоге src / main / webapp / WEB-INF . Файл декоратора нашего примера приложения называется layout.jsp .
  2. Добавьте в созданный файл декоратора HTML-код, обеспечивающий согласованный внешний вид.
  3. Убедитесь, что Sitemesh добавляет заголовок, найденный в возвращенном HTML-коде, в HTML-код, отображаемый веб-браузером.
  4. Сконфигурируйте Sitemesh, чтобы добавить элементы HTML, найденные из заголовка возвращаемого HTML, в заголовок отображаемого HTML.
  5. Убедитесь, что Sitemesh добавляет тело, найденное из возвращенного HTML, в HTML, который отображается пользователю.

Исходный код нашего файла декоратора ( layout.jsp ) выглядит следующим образом (выделены части, связанные с Sitemesh):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!doctype html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title><sitemesh:write property="title"/></title>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="${contextPath}/static/css/bootstrap.css"/>
    <link rel="stylesheet" type="text/css" href="${contextPath}/static/css/bootstrap-theme.css"/>
    <script type="text/javascript" src="${contextPath}/static/js/jquery-2.1.1.js"></script>
    <script type="text/javascript" src="${contextPath}/static/js/bootstrap.js"></script>
    <sitemesh:write property="head"/>
</head>
<body>
<nav class="navbar navbar-inverse" role="navigation">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
        </div>
        <div class="collapse navbar-collapse">
            <ul class="nav navbar-nav">
                <li><a href="${contextPath}/">Document list</a></li>
            </ul>
        </div>
    </div>
</nav>
<div class="container-fluid">
    <sitemesh:write property="body"/>
</div>
</body>
</html>

В-третьих , мы должны настроить Sitemesh для использования файла декоратора, который мы создали на втором шаге. Мы можем сделать это, выполнив следующие действия:

  1. Создайте файл sitemesh3.xml в каталоге src / main / webapp / WEB-INF .
  2. Настройте Sitemesh для использования нашего декоратора для всех запросов, которые обрабатываются фильтром Sitemesh.

Файл sitemesh3.xml выглядит следующим образом:

1
2
3
<sitemesh>
    <mapping path="/*" decorator="/WEB-INF/layout/layout.jsp"/>
</sitemesh>

Вот и все. Теперь мы настроили Sitemesh, чтобы обеспечить единообразный внешний вид нашего приложения. Давайте продолжим и выясним, как мы можем реализовать классы представления, которые преобразуют разметку Asciidoc в HTML и визуализируют созданный HTML.

Реализация классов представления

Прежде чем мы сможем приступить к реализации классов представления, которые преобразуют разметку Asciidoc в HTML и визуализируют созданный HTML, мы должны быстро взглянуть на наши требования. Требования, которые относятся к этому шагу:

  • Наше решение должно поддерживать документы Asciidoc, найденные из пути к классам.
  • Наше решение должно поддерживать разметку Asciidoc, заданную как объект String.
  • Наше решение должно преобразовать документы Asciidoc в HTML и визуализировать созданный HTML.

Эти требования предполагают, что мы должны создать три класса представления. Эти классы представления описаны ниже:

  • Мы должны создать абстрактный базовый класс, который содержит логику, которая преобразует разметку Asciidoc в HTML и отображает созданный HTML.
  • Мы должны создать класс представления, который может читать разметку Asciidoc из файла, найденного из пути к классам.
  • Мы должны создать класс представления, который может читать разметку Asciidoc из объекта String .

Другими словами, мы должны создать следующую структуру классов:

asciidoctor-HTML-просмотры

Сначала мы должны реализовать класс AbstractAsciidoctorHtmlView . Этот класс является абстрактным базовым классом, который преобразует разметку Asciidoc в HTML и отображает созданный HTML. Мы можем реализовать этот класс, выполнив следующие действия:

  1. Создайте класс AbstractAsciidoctorHtmlView и расширьте класс AbstractView .
  2. Добавьте конструктор в созданный класс и установите тип содержимого представления «text / html».
  3. Добавьте защищенный абстрактный метод getAsciidocMarkupReader () в созданный класс и установите его тип возвращаемого значения Reader . Подклассы этого абстрактного класса должны реализовывать этот метод, а реализация этого метода должна возвращать объект Reader, который можно использовать для чтения визуализированной разметки Asciidoc.
  4. Добавьте закрытый метод getAsciidoctorOptions () в созданный класс и реализуйте его, возвращая параметры конфигурации Asciidoctor.
  5. Переопределите метод renderMergedOutputModel () класса AbstractView и реализуйте его путем преобразования документа Asciidoc в HTML и рендеринга созданного HTML.

Исходный код класса AbstractAsciidoctorHtmlView выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.Options;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.view.AbstractView;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Reader;
import java.io.Writer;
import java.util.Map;
 
public abstract class AbstractAsciidoctorHtmlView extends AbstractView {
 
    public AbstractAsciidoctorHtmlView() {
        super.setContentType(MediaType.TEXT_HTML_VALUE);
    }
 
    protected abstract Reader getAsciidocMarkupReader();
 
    @Override
    protected void renderMergedOutputModel(Map<String, Object> model,
                                           HttpServletRequest request,
                                           HttpServletResponse response) throws Exception {
        //Set the content type of the response to 'text/html'
        response.setContentType(super.getContentType());
 
        Asciidoctor asciidoctor = Asciidoctor.Factory.create();
        Options asciidoctorOptions = getAsciidoctorOptions();
 
        try (
                //Get the reader that reads the rendered Asciidoc document
                //and the writer that writes the HTML markup to the request body
                Reader asciidoctorMarkupReader = getAsciidocMarkupReader();
                Writer responseWriter = response.getWriter();
        ) {
            //Transform Asciidoc markup into HTML and write the created HTML
            //to the response body
            asciidoctor.render(asciidoctorMarkupReader, responseWriter, asciidoctorOptions);
        }
    }
 
    private Options getAsciidoctorOptions() {
        Options asciiDoctorOptions = new Options();
        //Ensure that Asciidoctor includes both the header and the footer of the Asciidoc
        //document when it is transformed into HTML.
        asciiDoctorOptions.setHeaderFooter(true);
        return asciiDoctorOptions;
    }
}

Во-вторых , мы должны реализовать класс ClasspathFileAsciidoctorHtmlView . Этот класс может читать разметку Asciidoc из файла, найденного из пути к классам. Мы можем реализовать этот класс, выполнив следующие действия:

  1. Создайте класс ClasspathFileAsciidoctorHtmlView и расширьте класс AbstractAsciidoctorHtmlView .
  2. Добавьте личное поле String с именем asciidocFileLocation в созданный класс. Это поле содержит местоположение файла Asciidoc, который преобразуется в HTML. Это местоположение должно быть задано в формате, понятном для метода getResourceAsStream () класса Class .
  3. Создайте конструктор, который принимает местоположение расположения файла Asciidoc в качестве аргумента конструктора. Реализуйте конструктор, вызвав конструктор суперкласса и сохранив местоположение отображаемого файла Asciidoc в поле asciidocFileLocation .
  4. Переопределите метод getAsciidocMarkupReader () и реализуйте его, возвращая новый объект InputStreamReader, который используется для чтения файла Asciidoc, найденного из пути к классам.

Исходный код класса ClasspathFileAsciidoctorHtmlView выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
import java.io.InputStreamReader;
import java.io.Reader;
 
public class ClasspathFileAsciidoctorHtmlView extends AbstractAsciidoctorHtmlView {
 
    private final String asciidocFileLocation;
 
    public ClasspathFileAsciidoctorHtmlView(String asciidocFileLocation) {
        super();
        this.asciidocFileLocation = asciidocFileLocation;
    }
 
    @Override
    protected Reader getAsciidocMarkupReader() {
        return new InputStreamReader(this.getClass().getResourceAsStream(asciidocFileLocation));
    }
}

В-третьих , мы должны реализовать класс StringAsciidoctorHtmlView, который может читать разметку Asciidoc из объекта String. Мы можем реализовать этот класс, выполнив следующие действия:

  1. Создайте класс StringAsciidoctorHtmlView и расширьте класс AbstractAsciidoctorHtmlView .
  2. Добавьте личное поле String с именем asciidocMarkup к созданному классу. Это поле содержит разметку Asciidoc, которая преобразуется в HTML.
  3. Создайте конструктор, который принимает визуализированную разметку Asciidoc в качестве аргумента конструктора. Реализуйте этот конструктор, вызвав конструктор суперкласса и установив визуализированную разметку Asciidoc в поле asciidocMarkup .
  4. Переопределите метод getAsciidocMarkupReader () и реализуйте его, возвращая новый объект StringReader, который используется для чтения разметки Asciidoc, сохраненной в поле asciidocMarkup .

Исходный код StringAsciidoctorHtmlView выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
import java.io.Reader;
import java.io.StringReader;
 
public class StringAsciidoctorHtmlView extends AbstractAsciidoctorHtmlView {
 
    private final String asciidocMarkup;
 
    public StringAsciidoctorHtmlView(String asciidocMarkup) {
        super();
        this.asciidocMarkup = asciidocMarkup;
    }
 
    @Override
    protected Reader getAsciidocMarkupReader() {
        return new StringReader(asciidocMarkup);
    }
}

Теперь мы создали необходимые классы представления. Давайте продолжим и выясним, как мы можем использовать эти классы в веб-приложении Spring MVC.

Использование созданных классов просмотра

Нашим последним шагом является создание методов контроллера, которые используют созданные классы представлений.

Мы должны реализовать два метода контроллеров, которые описаны ниже:

  • Метод renderAsciidocDocument () обрабатывает запросы GET, отправленные на URL-адрес «/ asciidoctor / document», преобразует документ Asciidoc в HTML и отображает созданный HTML.
  • Метод renderAsciidocString () обрабатывает запросы на получение GET, отправленные на URL-адрес «/ asciidoctor / string», преобразует строку Asciidoc в HTML и отображает созданный HTML.

Исходный код класса AsciidoctorController выглядит следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
  
@Controller
public class AsciidoctorController {
  
    private static final String ASCIIDOC_FILE_LOCATION = "/asciidoctor/document.adoc";
  
    private static final String ASCIIDOC_STRING = "= Hello, AsciiDoc (String)!\n" +
            "Doc Writer <[email protected]>\n" +
            "\n" +
            "An introduction to http://asciidoc.org[AsciiDoc].\n" +
            "\n" +
            "== First Section\n" +
            "\n" +
            "* item 1\n" +
            "* item 2\n" +
            "\n" +
            "1\n" +
            "puts \"Hello, World!\"";
  
    @RequestMapping(value = "/asciidoctor/document", method = RequestMethod.GET)
    public ModelAndView renderAsciidocDocument() {
        //Create the view that transforms an Asciidoc document into HTML and
        //renders the created HTML.
        ClasspathFileAsciidoctorHtmlView docView = new ClasspathFileAsciidoctorHtmlView(ASCIIDOC_FILE_LOCATION);
        return new ModelAndView(docView);
    }
  
    @RequestMapping(value = "/asciidoctor/string", method = RequestMethod.GET)
    public ModelAndView renderAsciidocString() {
        //Create the view that transforms an Asciidoc String into HTML and
        //renders the created HTML.
        StringAsciidoctorHtmlView stringView = new StringAsciidoctorHtmlView(ASCIIDOC_STRING);
        return new ModelAndView(stringView);
    }
}

Дополнительная информация:

Теперь мы создали методы контроллера, которые используют наши классы представления. Когда пользователь нашего приложения вызывает GET-запрос к URL-адресу ‘/ asciidoctor / document’, исходный код отображаемой HTML-страницы выглядит следующим образом (части, созданные Asciidoctor, подсвечиваются):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<!doctype html>
 
<html>
<head>
    <title>Hello, AsciiDoc (File)!</title>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="/static/css/bootstrap.css"/>
    <link rel="stylesheet" type="text/css" href="/static/css/bootstrap-theme.css"/>
    <script type="text/javascript" src="/static/js/jquery-2.1.1.js"></script>
    <script type="text/javascript" src="/static/js/bootstrap.js"></script>
     
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.0">
<meta name="author" content="Doc Writer">
 
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic|Noto+Serif:400,400italic,700,700italic|Droid+Sans+Mono:400">
<link rel="stylesheet" href="./asciidoctor.css">
 
</head>
<body>
<nav class="navbar navbar-inverse" role="navigation">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
        </div>
        <div class="collapse navbar-collapse">
            <ul class="nav navbar-nav">
                <li><a href="/">Document list</a></li>
            </ul>
        </div>
    </div>
</nav>
<div class="container-fluid">
     
<div id="header">
<h1>Hello, AsciiDoc (File)!</h1>
<div class="details">
<span id="author" class="author">Doc Writer</span><br>
<span id="email" class="email"><a href="mailto:[email protected]">[email protected]</a></span><br>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>An introduction to <a href="http://asciidoc.org">AsciiDoc</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_first_section">First Section</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>item 1</p>
</li>
<li>
<p>item 2</p>
</li>
</ul>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-ruby" data-lang="ruby">puts "Hello, World!"</code></pre>
</div>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2014-09-21 14:21:59 EEST
</div>
</div>
 
</div>
</body>
</html>

Как мы видим, HTML, созданный Asciidoctor, встроен в наш макет, который обеспечивает согласованное взаимодействие с пользователями нашего приложения.

Давайте продолжим и оценим плюсы и минусы этого решения.

Плюсы и минусы

Плюсы нашего решения:

  • Представленные документы HTML имеют такой же внешний вид, как и другие страницы нашего приложения. Это означает, что мы можем обеспечить постоянное взаимодействие с пользователями нашего приложения.
  • Мы можем отображать как статические файлы, так и строки, которые можно загрузить из базы данных.

Минусы нашего решения:

  • Файл войны нашего простого приложения огромен (51,9 МБ). Причина этого в том, что, хотя Asciidoctor имеет Java API, он написан на Ruby. Таким образом, нашему приложению нужны два больших jar-файла:
    • Размер файла asciidoctorj-1.5.0.jar составляет 27,5 МБ.
    • Размер файла jruby-complete-1.7.9.jar составляет 21,7 МБ.
  • Наше приложение преобразует документы Asciidoc в HTML, когда пользователь запрашивает их. Это отрицательно влияет на время отклика наших методов контроллера, потому что чем больше документ, тем дольше он обрабатывается.
  • Первый запрос, который отображает документ Asciidoc в виде HTML, в 4-5 раз медленнее, чем следующие запросы. Я не профилировал приложение, но я предполагаю, что JRuby как-то связан с этим.
  • В настоящее время невозможно использовать эту технику, если мы хотим преобразовать документы Asciidoc в документы PDF.

Давайте продолжим и подведем итог тому, что мы узнали из этого блога.

Резюме

Этот пост научил нас трем вещам:

  • Мы узнали, как мы можем настроить Sitemesh, чтобы обеспечить единообразный внешний вид нашего приложения.
  • Мы узнали, как мы можем создавать классы представлений, которые преобразуют документы Asciidoc в HTML и визуализируют созданный HTML.
  • Хотя наше решение работает, оно имеет много недостатков, которые могут сделать его непригодным для использования в реальных приложениях.

Следующая часть этого руководства описывает, как мы можем решить проблемы с производительностью этого решения.

PS Если вы хотите поиграть с примером приложения из этого поста в блоге, вы можете получить его от Github .