{"id":288514,"date":"2018-08-26T08:30:02","date_gmt":"2018-08-26T04:30:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=288514"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=288514","title":{"rendered":"FreeMarker \u0448\u0430\u0431\u043b\u043e\u043d\u044b"},"content":{"rendered":"\n<div data-io-article-url=\"https:\/\/habr.com\/post\/420549\/\" class=\"post__text post__text-html js-mediator-article\">Apache FreeMarker \u2014 \u044d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432: \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Java \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 (HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, xml, \u0444\u0430\u0439\u043b\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438.\u0442.\u0434. \u041d\u0430 \u0432\u0445\u043e\u0434 \u043f\u043e\u0434\u0430\u0435\u0442\u0441\u044f \u0448\u0430\u0431\u043b\u043e\u043d, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 html \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0435\u0441\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u044d\u0442\u0438\u043c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c, \u0430 Freemarker \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442.<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/7z\/9j\/uj\/7z9jujmfkcbhb_4djpwzutxxh0i.jpeg\" alt=\"image\"><br \/>  <a name=\"habracut\"><\/a><br \/>  \u0412 \u0441\u0442\u0430\u0442\u044c\u0435 FreeMarker<br \/>   Spring boot<br \/>   Macros<br \/>   REST API<\/p>\n<p>  \u0422.\u0435. \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 freemarker \u044d\u0442\u043e \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 ${name}, \u0432 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f, \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f, \u0443\u0441\u043b\u043e\u0432\u0438\u044f, \u0446\u0438\u043a\u043b\u044b, \u0441\u043f\u0438\u0441\u043a\u0438, \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043c\u0430\u043a\u0440\u043e\u0441 \u0438 \u043c\u043d\u043e\u0433\u043e \u0434\u0440. \u041f\u0440\u0438\u043c\u0435\u0440 html \u0441 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c ${name} (\u0448\u0430\u0431\u043b\u043e\u043d test.ftl)  <\/p>\n<pre><code class=\"html\">&lt;!DOCTYPE html&gt; &lt;html lang=\"en\"&gt; &lt;head&gt;     &lt;meta charset=\"UTF-8\"&gt;     &lt;title&gt;${name}!&lt;\/title&gt; &lt;\/head&gt; &lt;body&gt;    &lt;h2&gt;Hello ${name}!&lt;\/h2&gt;     &lt;\/body&gt; &lt;\/html&gt; <\/code><\/pre>\n<p>  \u0415\u0441\u043b\u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432 java \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445   <\/p>\n<pre><code class=\"java\">import freemarker.template.Configuration; import freemarker.template.Template; ... \/\/ \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Configuration cfg = new Configuration(Configuration.VERSION_2_3_27); \/\/ \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445 Map&lt;String, Object&gt; root = new HashMap&lt;&gt;(); root.put(\"name\", \"Freemarker\"); \/\/ \u0448\u0430\u0431\u043b\u043e\u043d Template temp = cfg.getTemplate(\"test.ftl\"); \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 Writer out = new OutputStreamWriter(System.out); \/\/ \u0432\u044b\u0432\u043e\u0434 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c temp.process(root, out); <\/code><\/pre>\n<p>  \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043c html \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0441 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u043c name.<br \/>  \u0415\u0441\u043b\u0438 \u043d\u0430\u0434\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f #list, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0434\u043b\u044f html \u0441\u043f\u0438\u0441\u043a\u0430   <\/p>\n<pre><code class=\"html\">&lt;ul&gt;   &lt;#list father as item&gt;       &lt;li&gt;${item}&lt;\/li&gt;   &lt;\/#list&gt; &lt;\/ul&gt; <\/code><\/pre>\n<p>  \u0412 java, \u0432 \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u0434\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u043c\u043e\u0436\u043d\u043e \u0442\u0430\u043a<br \/>  <code>Map&lt;String, Object&gt; root = new HashMap&lt;&gt;();<br \/>  ....<br \/>  root.put(\"father\", Arrays.asList(\"Alexander\", \"Petrov\", 47));<\/code>  <\/p>\n<h3>\u041f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043a Spring <\/h3>\n<p>  \u0412 Spring boot \u0435\u0441\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 Freemarker. \u041d\u0430 \u0441\u0430\u0439\u0442\u0435 <a href=\"https:\/\/start.spring.io\/\">SPRING INITIALIZR<\/a> \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c pom \u0444\u0430\u0439\u043b \u043f\u0440\u043e\u0435\u043a\u0442\u0430.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">pom \u0444\u0430\u0439\u043b<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"xml\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt; &lt;project xmlns=\"http:\/\/maven.apache.org\/POM\/4.0.0\" xmlns:xsi=\"http:\/\/www.w3.org\/2001\/XMLSchema-instance\" \txsi:schemaLocation=\"http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/xsd\/maven-4.0.0.xsd\"&gt; \t&lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;  \t&lt;groupId&gt;com.example&lt;\/groupId&gt; \t&lt;artifactId&gt;demoFreeMarker&lt;\/artifactId&gt; \t&lt;version&gt;0.0.1-SNAPSHOT&lt;\/version&gt; \t&lt;packaging&gt;jar&lt;\/packaging&gt;  \t&lt;name&gt;demoFreeMarker&lt;\/name&gt; \t&lt;description&gt;Demo project for Spring Boot&lt;\/description&gt;  \t&lt;parent&gt; \t\t&lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; \t\t&lt;artifactId&gt;spring-boot-starter-parent&lt;\/artifactId&gt; \t\t&lt;version&gt;2.0.4.RELEASE&lt;\/version&gt; \t\t&lt;relativePath\/&gt; &lt;!-- lookup parent from repository --&gt; \t&lt;\/parent&gt;  \t&lt;properties&gt; \t\t&lt;project.build.sourceEncoding&gt;UTF-8&lt;\/project.build.sourceEncoding&gt; \t\t&lt;project.reporting.outputEncoding&gt;UTF-8&lt;\/project.reporting.outputEncoding&gt; \t\t&lt;java.version&gt;1.8&lt;\/java.version&gt; \t&lt;\/properties&gt;  \t&lt;dependencies&gt; \t\t&lt;dependency&gt; \t\t\t&lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; \t\t\t&lt;artifactId&gt;spring-boot-starter-freemarker&lt;\/artifactId&gt; \t\t&lt;\/dependency&gt;  \t\t&lt;dependency&gt; \t\t\t&lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; \t\t\t&lt;artifactId&gt;spring-boot-devtools&lt;\/artifactId&gt; \t\t\t&lt;scope&gt;runtime&lt;\/scope&gt; \t\t&lt;\/dependency&gt; \t\t&lt;dependency&gt; \t\t\t&lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; \t\t\t&lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt; \t\t\t&lt;scope&gt;test&lt;\/scope&gt; \t\t&lt;\/dependency&gt; \t&lt;\/dependencies&gt;  \t&lt;build&gt; \t\t&lt;plugins&gt; \t\t\t&lt;plugin&gt; \t\t\t\t&lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; \t\t\t\t&lt;artifactId&gt;spring-boot-maven-plugin&lt;\/artifactId&gt; \t\t\t&lt;\/plugin&gt; \t\t&lt;\/plugins&gt; \t&lt;\/build&gt;   &lt;\/project&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u043a\u043b\u0430\u0441\u0441 DemoFreeMarkerApplication<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@SpringBootApplication public class DemoFreeMarkerApplication {  \tpublic static void main(String[] args) { \t\tSpringApplication.run(DemoFreeMarkerApplication.class, args); \t} } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0412 Spring \u0435\u0441\u0442\u044c \u0443\u0436\u0435 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 Configuration \u0434\u043b\u044f freemarker.<br \/>  \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u043e\u0437\u044c\u043c\u0443 spring \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438(CommandLineRunner) \u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u0430 ftl (hello_test.ftl)  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0428\u0430\u0431\u043b\u043e\u043d hello_test.ftl<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!DOCTYPE html&gt; &lt;html lang=\"en\"&gt; &lt;head&gt;     &lt;meta charset=\"UTF-8\"&gt;     &lt;title&gt;Hello ${name}!&lt;\/title&gt; &lt;\/head&gt; &lt;body&gt;  &lt;input type=\"text\" placeholder=\"${name}\"&gt;  &lt;table&gt;     &lt;#list persons as row&gt;     &lt;tr&gt;         &lt;#list row as field&gt;             &lt;td&gt;${field}&lt;\/td&gt;         &lt;\/#list&gt;     &lt;\/tr&gt;     &lt;\/#list&gt; &lt;\/table&gt;  &lt;\/body&gt; &lt;\/html&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  Java \u043a\u043e\u0434 \u0434\u043b\u044f \u043c\u043e\u0434\u0435\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 hello_test.ftl  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u043a\u043b\u0430\u0441\u0441 CommandLine \u0438 \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Component public class CommandLine implements CommandLineRunner {      @Autowired     private Configuration configuration;      public void run(String... args) {         Map&lt;String, Object&gt; root = new HashMap&lt;&gt;();         \/\/ \u0434\u043b\u044f ${name}         root.put(\"name\", \"Fremarker\");         \/\/ \u0434\u043b\u044f &lt;#list persons         List&lt;List&gt; persons = new ArrayList&lt;&gt;();         persons.add(Arrays.asList(\"Alexander\", \"Petrov\", 47));         persons.add(Arrays.asList(\"Slava\", \"Petrov\", 13));         root.put(\"persons\", persons);          try {             Template template = configuration.getTemplate(\"hello_test.ftl\");             Writer out = new OutputStreamWriter(System.out);             try {                 template.process(root, out);             } catch (TemplateException e) {                 e.printStackTrace();             }         } catch (IOException e) {             e.printStackTrace();         }     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c html \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Output html<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;!DOCTYPE html&gt; &lt;html lang=\"en\"&gt; &lt;head&gt;     &lt;meta charset=\"UTF-8\"&gt;     &lt;title&gt;Hello Fremarker!&lt;\/title&gt; &lt;\/head&gt; &lt;body&gt;  &lt;input type=\"text\" placeholder=\"Fremarker\"&gt;  &lt;table&gt;     &lt;tr&gt;             &lt;td&gt;Alexander&lt;\/td&gt;             &lt;td&gt;Petrov&lt;\/td&gt;             &lt;td&gt;47&lt;\/td&gt;     &lt;\/tr&gt;     &lt;tr&gt;             &lt;td&gt;Slava&lt;\/td&gt;             &lt;td&gt;Petrov&lt;\/td&gt;             &lt;td&gt;13&lt;\/td&gt;     &lt;\/tr&gt; &lt;\/table&gt; &lt;\/body&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<h3>\u041c\u0430\u043a\u0440\u043e\u0441\u044b<\/h3>\n<p>  \u0412 freemarker \u0435\u0441\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432, \u044d\u0442\u043e \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u0430\u044f \u0438 \u0441\u0438\u043b\u044c\u043d\u0430\u044f \u0435\u0433\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u0430 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e. <br \/>  \u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u043c\u0435\u0440:  <\/p>\n<pre><code class=\"html\">&lt;#macro textInput id value=\"\"&gt;   &lt;input type=\"text\" id=\"${id}\" value=\"${value}\"&gt; &lt;\/#macro&gt;<\/code><\/pre>\n<p>  \u042d\u0442\u043e \u043c\u0430\u043a\u0440\u043e\u0441 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c textInput \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 id (\u043e\u043d \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439) \u0438 value (\u043e\u043d \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439, \u0442.\u043a. \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e). \u0414\u0430\u043b\u0435\u0435 \u0438\u0434\u0435\u0442 \u0435\u0433\u043e \u0442\u0435\u043b\u043e \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432. \u0412 \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u0444\u0430\u0439\u043b \u0441 \u043c\u0430\u043a\u0440\u043e\u0441\u0430\u043c\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a:  <\/p>\n<pre><code class=\"xml\">&lt;#import \"ui.ftl\" as ui\/&gt;<\/code><\/pre>\n<p>  \u0418\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u043c\u0430\u043a\u0440\u043e\u0441 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0430\u043a:  <\/p>\n<pre><code class=\"html\">&lt;@ui.textInput id=\"name\" value=\"${name}\"\/&gt;<\/code><\/pre>\n<p>  \u0413\u0434\u0435 ui \u044d\u0442\u043e \u0430\u043b\u0438\u0430\u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u043b\u0438 \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, ${name} \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0432 \u043c\u043e\u0434\u0435\u043b\u0438, \u0434\u0430\u043b\u0435\u0435 \u0447\u0435\u0440\u0435\u0437 \u0430\u043b\u0438\u0430\u0441 \u0441\u0441\u044b\u043b\u0430\u0435\u043c\u0441\u044f \u043d\u0430 \u0438\u043c\u044f \u043c\u0430\u043a\u0440\u043e\u0441\u0430 textInput \u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043a\u0430\u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043b\u044e \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043c\u0430\u043a\u0440\u043e\u0441\u044b \u0434\u043b\u044f html Input \u0438 Table  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0444\u0430\u0439\u043b \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432  ui.ftl<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;#-- textInput macro for html input --&gt; &lt;#macro textInput id placeholder=\"\" value=\"\"&gt;   &lt;input type=\"text\" id=\"${id}\" placeholder=\"${placeholder}\" value=\"${value}\"&gt; &lt;\/#macro&gt;  &lt;#-- table macro for html table --&gt; &lt;#macro table id rows&gt; &lt;table id=\"${id}\"&gt;     &lt;#list rows as row&gt;     &lt;tr&gt;         &lt;td&gt;${row?index + 1}&lt;\/td&gt;         &lt;#list row as field&gt;             &lt;td&gt;${field}&lt;\/td&gt;         &lt;\/#list&gt;     &lt;\/tr&gt;     &lt;\/#list&gt; &lt;\/table&gt; &lt;\/#macro&gt;<\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  ${row?index + 1} \u044d\u0442\u043e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0438\u043d\u0434\u0435\u043a\u0441\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0441\u043f\u0438\u0441\u043a\u0430, \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0445 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043c\u043d\u043e\u0433\u043e. \u0415\u0441\u043b\u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0448\u0430\u0431\u043b\u043e\u043d \u0438 \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0432 \u043d\u0435\u043c input \u0438 table \u043d\u0430 \u043c\u0430\u043a\u0440\u043e\u0441\u044b, \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442<\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0428\u0430\u0431\u043b\u043e\u043d hello.ftl<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;#import \"ui.ftl\" as ui\/&gt;  &lt;!DOCTYPE html&gt; &lt;html lang=\"en\"&gt; &lt;head&gt;     &lt;meta charset=\"UTF-8\"&gt;     &lt;title&gt;Hello ${name}!&lt;\/title&gt; &lt;\/head&gt; &lt;body&gt;  &lt;@ui.textInput id=\"name\" placeholder=\"Enter name\" value=\"${name}\"\/&gt; &lt;@ui.table id=\"table1\" rows=persons\/&gt;  &lt;\/body&gt; &lt;\/html&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<h3>REST<\/h3>\n<p>  \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0442\u0430\u043a\u0443\u044e \u043c\u043e\u0434\u0435\u043b\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 web \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0432 pom   <\/p>\n<pre><code class=\"xml\">\t\t&lt;dependency&gt; \t\t\t&lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt; \t\t\t&lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt; \t\t&lt;\/dependency&gt; <\/code><\/pre>\n<p>  \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u044e REST Controller  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">DemoController.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Controller public class DemoController {      @Autowired     private RepositoryService repositoryService;      @GetMapping(\"\/\")     public String index() {         return \"persons\";     }      @RequestMapping(value = \"\/search\", method = RequestMethod.POST)     public String hello(Model model, @RequestParam(defaultValue = \"\") String searchName) {         List&lt;List&lt;String&gt;&gt; persons = repositoryService.getRepository();         List&lt;List&lt;String&gt;&gt; filterList = persons.stream()                 .filter(p -&gt; p.get(0).contains(searchName))                 .collect(Collectors.toList());         model.addAttribute(\"persons\", filterList);         model.addAttribute(\"lastSearch\", searchName);         return \"persons\";     }      @RequestMapping(value = \"\/save\", method = RequestMethod.POST)     public String save(Model model, @ModelAttribute(\"person\") Person person) {         List&lt;List&lt;String&gt;&gt; persons = repositoryService.addPerson(person);         model.addAttribute(\"persons\", persons);         return \"persons\";     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>   Service \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0434\u043b\u044f \u043b\u0438\u0446  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">RepositoryService.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">@Service public class RepositoryService {      private static List&lt;List&lt;String&gt;&gt; repository = new ArrayList&lt;&gt;();      public List&lt;List&lt;String&gt;&gt; getRepository() {         return repository;     }      public List&lt;List&lt;String&gt;&gt; addPerson(Person person) {         repository.add(Arrays.asList(person.getFirstName(), person.getAge().toString()));         return repository;     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041a\u043b\u0430\u0441\u0441 \u043b\u0438\u0446\u043e  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">Person.java<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"java\">public class Person {      public Person(String firstName, Integer age) {         this.firstName = firstName;         this.age = age;     }      private String firstName;     private Integer age;      public String getFirstName() {         return firstName;     }      public Integer getAge() {         return age;     } } <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0428\u0430\u0431\u043b\u043e\u043d \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">ui.ftl<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;#macro formInput id name label type=\"text\" value=\"\"&gt; &lt;label for=\"${id}\"&gt;${label}&lt;\/label&gt; &lt;input type=\"${type}\" id=\"${id}\" name=\"${name}\" value=\"${value}\"&gt; &lt;\/#macro&gt;  &lt;#macro table id rows&gt; &lt;table id=\"${id}\" border=\"1px\" cellspacing=\"2\" border=\"1\" cellpadding=\"5\"&gt;     &lt;#list rows as row&gt;         &lt;tr&gt;             &lt;td&gt;${row?index + 1}&lt;\/td&gt;             &lt;#list row as field&gt;                 &lt;td&gt;${field}&lt;\/td&gt;             &lt;\/#list&gt;         &lt;\/tr&gt;     &lt;\/#list&gt; &lt;\/table&gt; &lt;\/#macro&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0448\u0430\u0431\u043b\u043e\u043d  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">persons.ftl<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"html\">&lt;#import \"ui.ftl\" as ui\/&gt;  &lt;!DOCTYPE html&gt; &lt;html lang=\"en\"&gt; &lt;head&gt;     &lt;meta charset=\"UTF-8\"&gt;     &lt;title&gt;Person&lt;\/title&gt;     &lt;link href=\"style\/my.css\" rel=\"stylesheet\"&gt; &lt;\/head&gt; &lt;body&gt;  &lt;div&gt;     &lt;fieldset&gt;         &lt;legend&gt;\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u0438\u0446\u043e&lt;\/legend&gt;         &lt;form name=\"person\" action=\"save\" method=\"POST\"&gt;             &lt;@ui.formInput id=\"t1\" name=\"firstName\" label=\"\u0418\u043c\u044f\"\/&gt; &lt;br\/&gt;             &lt;@ui.formInput id=\"t2\" name=\"age\" label=\"\u0412\u043e\u0437\u0440\u0430\u0441\u0442\"\/&gt; &lt;br\/&gt;             &lt;input type=\"submit\" value=\"Save\" \/&gt;         &lt;\/form&gt;     &lt;\/fieldset&gt; &lt;\/div&gt;  &lt;div&gt;     &lt;fieldset&gt;         &lt;legend&gt;\u041f\u043e\u0438\u0441\u043a&lt;\/legend&gt;         &lt;form name=\"searchForm\" action=\"search\" method=\"POST\"&gt;         &lt;@ui.formInput id=\"t3\" name=\"searchName\" label=\"\u041f\u043e\u0438\u0441\u043a\"\/&gt; &lt;br\/&gt;             &lt;input type=\"submit\" value=\"Search\" \/&gt;         &lt;\/form&gt;     &lt;\/fieldset&gt; &lt;\/div&gt; &lt;p&gt;&lt;#if lastSearch??&gt;\u041f\u043e\u0438\u0441\u043a \u0434\u043b\u044f: ${lastSearch}&lt;#else&gt;&lt;\/#if&gt;&lt;\/p&gt;  &lt;@ui.table id=\"table1\" rows=persons![]\/&gt;  &lt;\/body&gt; &lt;\/html&gt; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/v2\/bt\/2x\/v2bt2xhtnzh6b7inih7pmf46czq.jpeg\" alt=\"image\"><\/p>\n<p>  \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0434\u0432\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00absave\u00bb \u0438 \u00absearch\u00bb \u043b\u0438\u0446\u0430 (\u0441\u043c. \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440). \u0412\u0441\u044e \u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435 (\u043c\u0430\u043f\u0438\u043d\u0433\u0443) \u0432\u0445\u043e\u0434\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u0431\u0435\u0440\u0435\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f Spring. <\/p>\n<p>  \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043a \u0448\u0430\u0431\u043b\u043e\u043d\u0443. <br \/>  <code>&lt;#if lastSearch??&gt;\u041f\u043e\u0438\u0441\u043a \u0434\u043b\u044f: ${lastSearch}&lt;#else&gt;&lt;\/#if&gt;<\/code><br \/>  \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f, \u0435\u0441\u043b\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0437\u0430\u0434\u0430\u043d, \u0442\u043e \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0444\u0440\u0430\u0437\u0443 \u00ab\u041f\u043e\u0438\u0441\u043a \u0434\u043b\u044f: ..\u00bb, \u0438\u043d\u0430\u0447\u0435 \u043d\u0438\u0447\u0435\u0433\u043e<br \/>  <code>&lt;@ui.table id=\"table1\" rows=persons![]\/&gt;<\/code><br \/>  \u0437\u0434\u0435\u0441\u044c \u0442\u043e\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430, \u0447\u0442\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u043b\u0438\u0446 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442, \u0438\u043d\u0430\u0447\u0435 \u043f\u0443\u0441\u0442\u043e\u0439. \u042d\u0442\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0432\u0430\u0436\u043d\u044b \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u0438\u043d\u0430\u0447\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u0438\u0445 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 index(), \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430. <\/p>\n<p>  \u0420\u0430\u0431\u043e\u0442\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/qb\/s4\/ht\/qbs4htoamu89rmip6sbg7wsbit0.gif\" alt=\"image\"><\/p>\n<p>  \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b:<br \/>  <a href=\"https:\/\/freemarker.apache.org\/docs\/index.html\">Apache FreeMarker Manual<\/a><\/div>\n<p>        <script class=\"js-mediator-script\">!function(e){function t(t,n){if(!(n in e)){for(var r,a=e.document,i=a.scripts,o=i.length;o--;)if(-1!==i[o].src.indexOf(t)){r=i[o];break}if(!r){r=a.createElement(\"script\"),r.type=\"text\/javascript\",r.async=!0,r.defer=!0,r.src=t,r.charset=\"UTF-8\";var d=function(){var e=a.getElementsByTagName(\"script\")[0];e.parentNode.insertBefore(r,e)};\"[object Opera]\"==e.opera?a.addEventListener?a.addEventListener(\"DOMContentLoaded\",d,!1):e.attachEvent(\"onload\",d):d()}}}t(\"\/\/mediator.mail.ru\/script\/2820404\/\",\"_mediator\")}(window);<\/script>     <br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/post\/420549\/\"> https:\/\/habr.com\/post\/420549\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div data-io-article-url=\"https:\/\/habr.com\/post\/420549\/\" class=\"post__text post__text-html js-mediator-article\">Apache FreeMarker \u2014 \u044d\u0442\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432: \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Java \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 (HTML-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, xml, \u0444\u0430\u0439\u043b\u044b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u043a\u043e\u0434 \u0438.\u0442.\u0434. \u041d\u0430 \u0432\u0445\u043e\u0434 \u043f\u043e\u0434\u0430\u0435\u0442\u0441\u044f \u0448\u0430\u0431\u043b\u043e\u043d, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 html \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0435\u0441\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u044d\u0442\u0438\u043c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u043c, \u0430 Freemarker \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u044d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442.<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/7z\/9j\/uj\/7z9jujmfkcbhb_4djpwzutxxh0i.jpeg\" alt=\"image\">  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-288514","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/288514","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=288514"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/288514\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=288514"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=288514"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=288514"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}