app side article viewing, static freemaker, distributed file system minIO

Posted by morgan on Mon, 10 Jan 2022 07:11:40 +0100

app side article viewing, static freemaker, distributed file system minIO

1) Article list loading

1.1) demand analysis

Article layout display

Table 1.2) structural analysis

ap_article article basic information table

ap_article_config article configuration table

ap_article_content article content table

Relationship analysis of three tables

1.3) import article database

1.3.1) import database

View the data folder of the day and execute leadnews in the database connection tool_ article. sql

1.3.2) import the corresponding entity class

ap_ Corresponding entity of article table

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">model</span>.<span style="color:#000000">article</span>.<span style="color:#000000">pojos</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">IdType</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableField</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableId</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableName</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">Data</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">Serializable</span>;
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">Date</span>;
​
<span style="color:#aa5500">/**</span>
 <span style="color:#aa5500">* <p></span>
 <span style="color:#aa5500">* Article information table to store published articles</span>
 <span style="color:#aa5500">* </p></span>
 <span style="color:#aa5500">*</span>
 <span style="color:#aa5500">* @author itheima</span>
 <span style="color:#aa5500">*/</span>
​
<span style="color:#555555">@Data</span>
<span style="color:#555555">@TableName</span>(<span style="color:#aa1111">"ap_article"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ApArticle</span> <span style="color:#770088">implements</span> <span style="color:#000000">Serializable</span> {
​
    <span style="color:#555555">@TableId</span>(<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"id"</span>,<span style="color:#000000">type</span> <span style="color:#981a1a">=</span> <span style="color:#000000">IdType</span>.<span style="color:#000000">ID_WORKER</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">id</span>;
​
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Title</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">title</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Author ID</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"author_id"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">authorId</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Author name</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"author_name"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">authorName</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Channel ID</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"channel_id"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">channelId</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Channel name</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"channel_name"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">channelName</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Article layout 0 no picture Article 1 single picture Article 2 multi picture article</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">Short</span> <span style="color:#000000">layout</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Article tag 0 ordinary articles 1 hot articles 2 top Articles 3 boutique Articles 4 big V articles</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">Byte</span> <span style="color:#000000">flag</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Multiple comma separated article cover pictures</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">images</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Label</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">labels</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Number of likes</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">likes</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Collection quantity</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">collection</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Number of comments</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">comment</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Number of readings</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">views</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Provinces and cities</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"province_id"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">provinceId</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Urban area</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"city_id"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">cityId</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* District and county</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"county_id"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Integer</span> <span style="color:#000000">countyId</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Creation time</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"created_time"</span>)
    <span style="color:#770088">private</span> <span style="color:#000000">Date</span> <span style="color:#000000">createdTime</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Release time</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"publish_time"</span>)
    <span style="color:#770088">private</span> <span style="color:#000000">Date</span> <span style="color:#000000">publishTime</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Synchronization status</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"sync_status"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Boolean</span> <span style="color:#000000">syncStatus</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Source</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">Boolean</span> <span style="color:#000000">origin</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Static page address</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"static_url"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">staticUrl</span>;
}</span></span>

ap_ article_ The config article configures the corresponding entity class

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">model</span>.<span style="color:#000000">article</span>.<span style="color:#000000">pojos</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">IdType</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableField</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableId</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableName</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">Data</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">Serializable</span>;
​
<span style="color:#aa5500">/**</span>
 <span style="color:#aa5500">* <p></span>
 <span style="color:#aa5500">* APP Published article configuration table</span>
 <span style="color:#aa5500">* </p></span>
 <span style="color:#aa5500">*</span>
 <span style="color:#aa5500">* @author itheima</span>
 <span style="color:#aa5500">*/</span>
​
<span style="color:#555555">@Data</span>
<span style="color:#555555">@TableName</span>(<span style="color:#aa1111">"ap_article_config"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ApArticleConfig</span> <span style="color:#770088">implements</span> <span style="color:#000000">Serializable</span> {
​
    <span style="color:#555555">@TableId</span>(<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"id"</span>,<span style="color:#000000">type</span> <span style="color:#981a1a">=</span> <span style="color:#000000">IdType</span>.<span style="color:#000000">ID_WORKER</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">id</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Article ID</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"article_id"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">articleId</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Can I comment</span>
     <span style="color:#aa5500">* true: Can comment 1</span>
     <span style="color:#aa5500">* false: Non commentable 0</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"is_comment"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Boolean</span> <span style="color:#000000">isComment</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Forward</span>
     <span style="color:#aa5500">* true: Can forward {1</span>
     <span style="color:#aa5500">* false: Cannot forward 0</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"is_forward"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Boolean</span> <span style="color:#000000">isForward</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Off the shelf</span>
     <span style="color:#aa5500">* true: Remove the rack 1</span>
     <span style="color:#aa5500">* false: No offline 0</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"is_down"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Boolean</span> <span style="color:#000000">isDown</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Deleted</span>
     <span style="color:#aa5500">* true: Delete {1</span>
     <span style="color:#aa5500">* false: 0 was not deleted</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"is_delete"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Boolean</span> <span style="color:#000000">isDelete</span>;
}</span></span>

ap_article_content the entity class corresponding to the article content

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">model</span>.<span style="color:#000000">article</span>.<span style="color:#000000">pojos</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">IdType</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableField</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableId</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">TableName</span>;
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">Data</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">io</span>.<span style="color:#000000">Serializable</span>;
​
<span style="color:#555555">@Data</span>
<span style="color:#555555">@TableName</span>(<span style="color:#aa1111">"ap_article_content"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ApArticleContent</span> <span style="color:#770088">implements</span> <span style="color:#000000">Serializable</span> {
​
    <span style="color:#555555">@TableId</span>(<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"id"</span>,<span style="color:#000000">type</span> <span style="color:#981a1a">=</span> <span style="color:#000000">IdType</span>.<span style="color:#000000">ID_WORKER</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">id</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Article ID</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@TableField</span>(<span style="color:#aa1111">"article_id"</span>)
    <span style="color:#770088">private</span> <span style="color:#008855">Long</span> <span style="color:#000000">articleId</span>;
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Article content</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#770088">private</span> <span style="color:#008855">String</span> <span style="color:#000000">content</span>;
}</span></span>

1.4) implementation ideas

1. Display 10 article information in the default channel

2. You can switch channels to view different kinds of articles

3. When the user drops down, the latest articles can be loaded (paged). The time of publication in the article list on this page is based on the maximum time

4. When the user pulls up, more article information can be loaded (according to the publishing time) based on the time with the smallest publishing time in the article list on this page

5. If it is the home page of the current channel, the front end passes the default parameters:

  • maxBehotTime: 0 (MS)

  • minBehotTime: 20000000000000 (milliseconds) - > 2063

1.5) interface definition

Load home pageLoad moreLoad latest
Interface path/api/v1/article/load/api/v1/article/loadmore/api/v1/article/loadnew
Request modePOSTPOSTPOST
parameterArticleHomeDtoArticleHomeDtoArticleHomeDto
Response resultsResponseResultResponseResultResponseResult

ArticleHomeDto

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">model</span>.<span style="color:#000000">article</span>.<span style="color:#000000">dtos</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">lombok</span>.<span style="color:#000000">Data</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">Date</span>;
​
<span style="color:#555555">@Data</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ArticleHomeDto</span> {
​
    <span style="color:#Aa5500 "> / / maximum time</span>
    <span style="color:#000000">Date</span> <span style="color:#000000">maxBehotTime</span>;
    <span style="color:#Aa5500 "> / / minimum time</span>
    <span style="color:#000000">Date</span> <span style="color:#000000">minBehotTime</span>;
    <span style="color:#Aa5500 "> / / paging size</span>
    <span style="color:#008855">Integer</span> <span style="color:#000000">size</span>;
    <span style="color:#Aa5500 "> / / channel ID</span>
    <span style="color:#008855">String</span> <span style="color:#000000">tag</span>;
}</span></span>

1.6) function realization

1.6.1): import Heima leadnews article micro service, and the data is in the folder of the day

Note: you need to add sub module information in the pom folder of Heima leadnews service, as follows:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#117700"><</span><span style="color:#117700">modules</span><span style="color:#117700">></span>
    <span style="color:#117700"><</span><span style="color:#117700">module</span><span style="color:#117700">></span>heima-leadnews-user<span style="color:#117700"></</span><span style="color:#117700">module</span><span style="color:#117700">></span>
    <span style="color:#117700"><</span><span style="color:#117700">module</span><span style="color:#117700">></span>heima-leadnews-article<span style="color:#117700"></</span><span style="color:#117700">module</span><span style="color:#117700">></span>
<span style="color:#117700"></</span><span style="color:#117700">modules</span><span style="color:#117700">></span></span></span>

Update maven in idea. If the project is still gray, you need to add the pom file of the article micro service again. The operation steps are as follows:

You need to add the corresponding configuration in nacos

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">spring</span><span style="color:#555555">:</span>
<span style="color:#221199">  datasource</span><span style="color:#555555">:</span>
<span style="color:#221199">    driver-class-name</span><span style="color:#555555">: </span>com.mysql.jdbc.Driver
<span style="color:#221199">    url</span><span style="color:#555555">: </span>jdbc<span style="color:#555555">:</span>mysql<span style="color:#555555">:</span>//localhost<span style="color:#555555">:</span>3306/leadnews_article?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
<span style="color:#221199">    username</span><span style="color:#555555">: </span>root
<span style="color:#221199">    password</span><span style="color:#555555">: </span>root
<span style="color:#aa5500"># Set the XML file location corresponding to the Mapper interface. If you have a custom method in the Mapper interface, you need to configure it</span>
<span style="color:#221199">mybatis-plus</span><span style="color:#555555">:</span>
<span style="color:#221199">  mapper-locations</span><span style="color:#555555">: </span>classpath*<span style="color:#555555">:</span>mapper/*.xml
  <span style="color:#aa5500"># Set the alias package scanning path, and use this property to register aliases for classes in the package</span>
<span style="color:#221199">  type-aliases-package</span><span style="color:#555555">: </span>com.heima.model.article.pojos</span></span>

1.6.2): define interface

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">article</span>.<span style="color:#000000">controller</span>.<span style="color:#000000">v1</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">model</span>.<span style="color:#000000">article</span>.<span style="color:#000000">dtos</span>.<span style="color:#000000">ArticleHomeDto</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">model</span>.<span style="color:#000000">common</span>.<span style="color:#000000">dtos</span>.<span style="color:#000000">ResponseResult</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">PostMapping</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">RequestBody</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">RequestMapping</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">web</span>.<span style="color:#000000">bind</span>.<span style="color:#000000">annotation</span>.<span style="color:#000000">RestController</span>;
​
<span style="color:#555555">@RestController</span>
<span style="color:#555555">@RequestMapping</span>(<span style="color:#aa1111">"/api/v1/article"</span>)
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ArticleHomeController</span> {
​
​
    <span style="color:#555555">@PostMapping</span>(<span style="color:#aa1111">"/load"</span>)
    <span style="color:#770088">public</span> <span style="color:#000000">ResponseResult</span> <span style="color:#000000">load</span>(<span style="color:#555555">@RequestBody</span> <span style="color:#000000">ArticleHomeDto</span> <span style="color:#000000">dto</span>) {
        <span style="color:#770088">return</span> <span style="color:#221199">null</span>;
    }
​
    <span style="color:#555555">@PostMapping</span>(<span style="color:#aa1111">"/loadmore"</span>)
    <span style="color:#770088">public</span> <span style="color:#000000">ResponseResult</span> <span style="color:#000000">loadMore</span>(<span style="color:#555555">@RequestBody</span> <span style="color:#000000">ArticleHomeDto</span> <span style="color:#000000">dto</span>) {
        <span style="color:#770088">return</span> <span style="color:#221199">null</span>;
    }
​
    <span style="color:#555555">@PostMapping</span>(<span style="color:#aa1111">"/loadnew"</span>)
    <span style="color:#770088">public</span> <span style="color:#000000">ResponseResult</span> <span style="color:#000000">loadNew</span>(<span style="color:#555555">@RequestBody</span> <span style="color:#000000">ArticleHomeDto</span> <span style="color:#000000">dto</span>) {
        <span style="color:#770088">return</span> <span style="color:#221199">null</span>;
    }
}</span></span>

1.6.3): prepare mapper file

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#770088">package</span> <span style="color:#0000ff">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">article</span>.<span style="color:#000000">mapper</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">baomidou</span>.<span style="color:#000000">mybatisplus</span>.<span style="color:#000000">core</span>.<span style="color:#000000">mapper</span>.<span style="color:#000000">BaseMapper</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">model</span>.<span style="color:#000000">article</span>.<span style="color:#000000">dtos</span>.<span style="color:#000000">ArticleHomeDto</span>;
<span style="color:#770088">import</span> <span style="color:#000000">com</span>.<span style="color:#000000">heima</span>.<span style="color:#000000">model</span>.<span style="color:#000000">article</span>.<span style="color:#000000">pojos</span>.<span style="color:#000000">ApArticle</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">apache</span>.<span style="color:#000000">ibatis</span>.<span style="color:#000000">annotations</span>.<span style="color:#000000">Mapper</span>;
<span style="color:#770088">import</span> <span style="color:#000000">org</span>.<span style="color:#000000">apache</span>.<span style="color:#000000">ibatis</span>.<span style="color:#000000">annotations</span>.<span style="color:#000000">Param</span>;
​
<span style="color:#770088">import</span> <span style="color:#000000">java</span>.<span style="color:#000000">util</span>.<span style="color:#000000">List</span>;
​
<span style="color:#555555">@Mapper</span>
<span style="color:#770088">public</span> <span style="color:#770088">interface</span> <span style="color:#0000ff">ApArticleMapper</span> <span style="color:#770088">extends</span> <span style="color:#000000">BaseMapper</span><span style="color:#981a1a"><</span><span style="color:#000000">ApArticle</span><span style="color:#981a1a">></span> {
​
    <span style="color:#770088">public</span> <span style="color:#000000">List</span><span style="color:#981a1a"><</span><span style="color:#000000">ApArticle</span><span style="color:#981a1a">></span> <span style="color:#000000">loadArticleList</span>(<span style="color:#555555">@Param</span>(<span style="color:#aa1111">"dto"</span>) <span style="color:#000000">ArticleHomeDto</span> <span style="color:#000000">dto</span>, <span style="color:#555555">@Param</span>(<span style="color:#aa1111">"type"</span>) <span style="color:#008855">Short</span> <span style="color:#000000">type</span>);
​
}</span></span>

Corresponding mapping file

In resources, create a new mapper / aparticlemapper XML is configured as follows:

<span style="background-color:#f8f8f8"><span style="color:#333333"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.heima.article.mapper.ApArticleMapper">

    <resultMap id="resultMap" type="com.heima.model.article.pojos.ApArticle">
        <id column="id" property="id"/>
        <result column="title" property="title"/>
        <result column="author_id" property="authorId"/>
        <result column="author_name" property="authorName"/>
        <result column="channel_id" property="channelId"/>
        <result column="channel_name" property="channelName"/>
        <result column="layout" property="layout"/>
        <result column="flag" property="flag"/>
        <result column="images" property="images"/>
        <result column="labels" property="labels"/>
        <result column="likes" property="likes"/>
        <result column="collection" property="collection"/>
        <result column="comment" property="comment"/>
        <result column="views" property="views"/>
        <result column="province_id" property="provinceId"/>
        <result column="city_id" property="cityId"/>
        <result column="county_id" property="countyId"/>
        <result column="created_time" property="createdTime"/>
        <result column="publish_time" property="publishTime"/>
        <result column="sync_status" property="syncStatus"/>
        <result column="static_url" property="staticUrl"/>
    </resultMap>
    <select id="loadArticleList" resultMap="resultMap">
        SELECT
        aa.*
        FROM
        `ap_article` aa
        LEFT JOIN ap_article_config aac ON aa.id = aac.article_id
        <where>
            and aac.is_delete != 1
            and aac.is_down != 1
            <!-- loadmore -->
            <if test="type != null and type == 1">
                and aa.publish_time <![CDATA[<]]> #{dto.minBehotTime}
            </if>
            <if test="type != null and type == 2">
                and aa.publish_time <![CDATA[>]]> #{dto.maxBehotTime}
            </if>
            <if test="dto.tag != '__all__'">
                and aa.channel_id = #{dto.tag}
            </if>
        </where>
        order by aa.publish_time desc
        limit #{dto.size}
    </select>

</mapper></span></span>

1.6.4): writing business layer code

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.article.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.common.dtos.ResponseResult;

import java.io.IOException;

public interface ApArticleService extends IService<ApArticle> {

    /**
     * Load article list according to parameters
     * @param loadtype 1 To load more 2 to load the latest
     * @param dto
     * @return
     */
    ResponseResult load(Short loadtype, ArticleHomeDto dto);

}</span></span>

Implementation class:

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.article.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.common.constants.ArticleConstants;
import com.heima.model.article.dtos.ArticleHomeDto;

import com.heima.model.article.pojos.ApArticle;
import com.heima.model.common.dtos.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;


@Service
@Transactional
@Slf4j
public class ApArticleServiceImpl  extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {

    // Number of maximum loads per page
    private final static short MAX_PAGE_SIZE = 50;

    @Autowired
    private ApArticleMapper apArticleMapper;

    /**
     * Load article list according to parameters
     * @param loadtype 1 To load more 2 to load the latest
     * @param dto
     * @return
     */
    @Override
    public ResponseResult load(Short loadtype, ArticleHomeDto dto) {
        //1. Calibration parameters
        Integer size = dto.getSize();
        if(size == null || size == 0){
            size = 10;
        }
        size = Math.min(size,MAX_PAGE_SIZE);
        dto.setSize(size);

        //Type parameter inspection
        if(!loadtype.equals(ArticleConstants.LOADTYPE_LOAD_MORE)&&!loadtype.equals(ArticleConstants.LOADTYPE_LOAD_NEW)){
            loadtype = ArticleConstants.LOADTYPE_LOAD_MORE;
        }
        //Article channel verification
        if(StringUtils.isEmpty(dto.getTag())){
            dto.setTag(ArticleConstants.DEFAULT_TAG);
        }

        //Time verification
        if(dto.getMaxBehotTime() == null) dto.setMaxBehotTime(new Date());
        if(dto.getMinBehotTime() == null) dto.setMinBehotTime(new Date());
        //2. Query data
        List<ApArticle> apArticles = apArticleMapper.loadArticleList(dto, loadtype);

        //3. Result encapsulation
        ResponseResult responseResult = ResponseResult.okResult(apArticles);
        return responseResult;
    }
    
}</span></span>

Defining constant classes

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.common.constants;

public class ArticleConstants {
    public static final Short LOADTYPE_LOAD_MORE = 1;
    public static final Short LOADTYPE_LOAD_NEW = 2;
    public static final String DEFAULT_TAG = "__all__";

}</span></span>

1.6.5): write controller code

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.article.controller.v1;

import com.heima.article.service.ApArticleService;
import com.heima.common.constants.ArticleConstants;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v1/article")
public class ArticleHomeController {


    @Autowired
    private ApArticleService apArticleService;

    @PostMapping("/load")
    public ResponseResult load(@RequestBody ArticleHomeDto dto) {
        return apArticleService.load(ArticleConstants.LOADTYPE_LOAD_MORE,dto);
    }

    @PostMapping("/loadmore")
    public ResponseResult loadMore(@RequestBody ArticleHomeDto dto) {
        return apArticleService.load(ArticleConstants.LOADTYPE_LOAD_MORE,dto);
    }

    @PostMapping("/loadnew")
    public ResponseResult loadNew(@RequestBody ArticleHomeDto dto) {
        return apArticleService.load(ArticleConstants.LOADTYPE_LOAD_NEW,dto);
    }
}</span></span>

1.6.6): swagger test or front and rear end joint commissioning test

First, add the article micro service route in the nacos configuration center of the micro service of the app gateway. The complete configuration is as follows:

<span style="background-color:#f8f8f8"><span style="color:#333333">spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': # Match all requests
            allowedOrigins: "*" #Cross domain processing allows all domains
            allowedMethods: # Supported methods
              - GET
              - POST
              - PUT
              - DELETE
      routes:
        # User micro service
        - id: user
          uri: lb://leadnews-user
          predicates:
            - Path=/user/**
          filters:
            - StripPrefix= 1
        # Article micro service
        - id: article
          uri: lb://leadnews-article
          predicates:
            - Path=/article/**
          filters:
            - StripPrefix= 1</span></span>

Second: start nginx, directly use the front-end project test, and start the article micro service, user micro service and app gateway micro service

2)freemarker

2.1) freemaker introduction

FreeMarker is a template engine: a general tool based on templates and data to be changed and used to generate output text (HTML web pages, e-mail, configuration files, source code, etc.). It is not for end users, but a Java class library. It is a component that programmers can embed in the products they develop.

The template is written as FreeMarker Template Language (FTL). It is a simple, specialized language, not a mature programming language like PHP. That means preparing data for display in real programming language, such as database query and business operation, and then displaying the prepared data in the template. In the template, you can focus on how to display the data, while outside the template, you can focus on what data to display.

What other java template engines are commonly used?

Jsp, Freemarker, Thymeleaf, Velocity, etc.

1.Jsp is dedicated to servlets and cannot be used alone.

2.Thymeleaf is a new technology with powerful functions, but its execution efficiency is relatively low.

3.Velocity has not been updated since version 2.0 was updated in 2010. Spring Boot officially does not support this after version 1.4. Although velocity was iterated in 2017, it was too late.

2.2) environment construction & & quick start

Freemaker is a view format of spring MVC. By default, spring MVC supports freemaker view format.

You need to create a Spring Boot+Freemarker project to test the template.

2.2.1) create test project

Create a freemaker demo test project, which is specially used for freemaker function test and template test.

pom. The XML is as follows

<span style="background-color:#f8f8f8"><span style="color:#333333"><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>heima-leadnews-test</artifactId>
        <groupId>com.heima</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>freemarker-demo</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- apache yes java io Packaging tool library -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>

</project></span></span>

2.2.2) configuration file

Configure application yml

<span style="background-color:#f8f8f8"><span style="color:#333333">server:
  port: 8881 #Service port
spring:
  application:
    name: freemarker-demo #Specify the service name
  freemarker:
    cache: false  #Close the template cache to facilitate testing
    settings:
      template_update_delay: 0 #Check the template update delay time. Setting it to 0 means checking immediately. If the time is greater than 0, there will be a cache, which is inconvenient for template testing
    suffix: .ftl               #Specifies the suffix of the Freemarker template file</span></span>

2.2.3) create model class

Create model types for testing under freemaker's test project

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.freemarker.entity;

import lombok.Data;

import java.util.Date;

@Data
public class Student {
    private String name;//full name
    private int age;//Age
    private Date birthday;//birthday
    private Float money;//wallet
}</span></span>

2.2.4) create template

Create templates under resources, which is the default template storage directory of freemaker.

Create the template file 01 basic under templates FTL, the interpolation expression in the template will eventually be replaced with specific data by freemaker.

<span style="background-color:#f8f8f8"><span style="color:#333333"><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<b>Plain text String Exhibition:</b><br><br>
Hello ${name} <br>
<hr>
<b>object Student Data display in:</b><br/>
full name: ${stu.name}<br/>
Age: ${stu.age}
<hr>
</body>
</html></span></span>

2.2.5) create controller

Create the Controller class, add name to the Map, and finally return the template file.

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.xuecheng.test.freemarker.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

@Controller
public class HelloController {

    @GetMapping("/basic")
    public String test(Model model) {


        //1. Parameters in plain text
        model.addAttribute("name", "freemarker");
        //2. Entity class related parameters
        
        Student student = new Student();
        student.setName("Xiao Ming");
        student.setAge(18);
        model.addAttribute("stu", student);

        return "01-basic";
    }
}</span></span>

01-basic.ftl, filling data with interpolation expressions

<span style="background-color:#f8f8f8"><span style="color:#333333"><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<b>Plain text String Exhibition:</b><br><br>
Hello ${name} <br>
<hr>
<b>object Student Data display in:</b><br/>
full name: ${stu.name}<br/>
Age: ${stu.age}
<hr>
</body>
</html></span></span>

2.2.6) create startup class

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.freemarker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class FreemarkerDemotApplication {
    public static void main(String[] args) {
        SpringApplication.run(FreemarkerDemotApplication.class,args);
    }
}</span></span>

2.2.7) test

Request: http://localhost:8881/basic

2.3) freemaker Foundation

2.3.1) basic grammar types

1. Comments, i.e. < #--- >, are ignored by freemaker

<span style="background-color:#f8f8f8"><span style="color:#333333"><#--I'm a freemaker comment -- ></span></span>

2. Interpolation: i.e. ${..} In part, freemaker replaces ${..} with a real value

<span style="background-color:#f8f8f8"><span style="color:#333333">Hello ${name}</span></span>

3. FTL instruction: similar to HTML tags, the name is prefixed # to distinguish it. Freemarker will parse the expression or logic in the tag.

<span style="background-color:#f8f8f8"><span style="color:#333333"><# >FTL instructions</#> </span></span>

4. Text, only text information, which are not freemaker's comments, interpolation and FTL instructions, will be ignored and parsed by freemaker and output directly.

<span style="background-color:#f8f8f8"><span style="color:#333333"><#--Plain text in freemaker -- >
I am an ordinary text</span></span>

2.3.2) set instructions (List and Map)

1. Data model:

Add the following methods in HelloController:

<span style="background-color:#f8f8f8"><span style="color:#333333">@GetMapping("/list")
public String list(Model model){

    //------------------------------------
    Student stu1 = new Student();
    stu1.setName("cockroach");
    stu1.setAge(18);
    stu1.setMoney(1000.86f);
    stu1.setBirthday(new Date());

    //Xiaohong object model data
    Student stu2 = new Student();
    stu2.setName("Xiao Hong");
    stu2.setMoney(200.1f);
    stu2.setAge(19);

    //Store the two object model data in the List collection
    List<Student> stus = new ArrayList<>();
    stus.add(stu1);
    stus.add(stu2);

    //Store List collection data into model
    model.addAttribute("stus",stus);

    //------------------------------------

    //Create Map data
    HashMap<String,Student> stuMap = new HashMap<>();
    stuMap.put("stu1",stu1);
    stuMap.put("stu2",stu2);
    // 3.1 store Map data in the model
    model.addAttribute("stuMap", stuMap);

    return "02-list";
}</span></span>

2. Template:

Add 02 list in templates FTL file

<span style="background-color:#f8f8f8"><span style="color:#333333"><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
    
<#--Display of list data -- >
<b>Exhibition list Medium stu data:</b>
<br>
<br>
<table>
    <tr>
        <td>Serial number</td>
        <td>full name</td>
        <td>Age</td>
        <td>wallet</td>
    </tr>
</table>
<hr>
    
<#--Display of Map data -- >
<b>map Display of data:</b>
<br/><br/>
<a href="###"> method 1: through map ['keyname ']. Property < / a > < br / >
output stu1 Student information:<br/>
full name:<br/>
Age:<br/>
<br/>
<a href="###"> method 2: through map.keyname.property < / a > < br / >
output stu2 Student information:<br/>
full name:<br/>
Age:<br/>

<br/>
<a href="###"> traverse two student information in the map: < / a > < br / >
<table>
    <tr>
        <td>Serial number</td>
        <td>full name</td>
        <td>Age</td>
        <td>wallet</td> 
    </tr>
</table>
<hr>
 
</body>
</html></span></span>

Example code:

<span style="background-color:#f8f8f8"><span style="color:#333333"><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
    
<#--Display of list data -- >
<b>Exhibition list Medium stu data:</b>
<br>
<br>
<table>
    <tr>
        <td>Serial number</td>
        <td>full name</td>
        <td>Age</td>
        <td>wallet</td>
    </tr>
    <#list stus as stu>
        <tr>
            <td>${stu_index+1}</td>
            <td>${stu.name}</td>
            <td>${stu.age}</td>
            <td>${stu.money}</td>
        </tr>
    </#list>

</table>
<hr>
    
<#--Display of Map data -- >
<b>map Display of data:</b>
<br/><br/>
<a href="###"> method 1: through map ['keyname ']. Property < / a > < br / >
output stu1 Student information:<br/>
full name: ${stuMap['stu1'].name}<br/>
Age: ${stuMap['stu1'].age}<br/>
<br/>
<a href="###"> method 2: through map.keyname.property < / a > < br / >
output stu2 Student information:<br/>
full name: ${stuMap.stu2.name}<br/>
Age: ${stuMap.stu2.age}<br/>

<br/>
<a href="###"> traverse two student information in the map: < / a > < br / >
<table>
    <tr>
        <td>Serial number</td>
        <td>full name</td>
        <td>Age</td>
        <td>wallet</td>
    </tr>
    <#list stuMap?keys as key >
        <tr>
            <td>${key_index}</td>
            <td>${stuMap[key].name}</td>
            <td>${stuMap[key].age}</td>
            <td>${stuMap[key].money}</td>
        </tr>
    </#list>
</table>
<hr>
 
</body>
</html></span></span>

👆 The above code explanation:

${k_index}: index: get the subscript of the loop by adding "_index" after stu, and its value starts from 0

2.3.3) if instruction

The if instruction is a judgment instruction. It is a commonly used FTL instruction. Freemaker will judge if it encounters if during parsing. If the condition is true, the content in the middle of if will be output. Otherwise, the skipped content will not be output.

  • Instruction format

<span style="background-color:#f8f8f8"><span style="color:#333333"><#if ></if></span></span>

1. Data model:

Use the list command to test the data model and judge that the data font with the name of small red is displayed in red.

2. Template:

<span style="background-color:#f8f8f8"><span style="color:#333333"><table>
    <tr>
        <td>full name</td>
        <td>Age</td>
        <td>wallet</td>
    </tr>
    <#list stus as stu>
        <tr>
            <td >${stu.name}</td>
            <td>${stu.age}</td>
            <td >${stu.mondy}</td>
        </tr>
    </#list>

</table></span></span>

Example code:

<span style="background-color:#f8f8f8"><span style="color:#333333"><table>
    <tr>
        <td>full name</td>
        <td>Age</td>
        <td>wallet</td>
    </tr>
    <#list stus as stu >
        <#if stu.name = 'Xiaohong' >
            <tr style="color: red">
                <td>${stu_index}</td>
                <td>${stu.name}</td>
                <td>${stu.age}</td>
                <td>${stu.money}</td>
            </tr>
            <#else >
            <tr>
                <td>${stu_index}</td>
                <td>${stu.name}</td>
                <td>${stu.age}</td>
                <td>${stu.money}</td>
            </tr>
        </#if>
    </#list>
</table></span></span>

3. Output:

If the name is "Xiaoqiang", the font color is displayed in red.

2.3.4) operator

1. Arithmetic operator

FreeMarker expression fully supports arithmetic operations. The arithmetic operators supported by FreeMarker include:

  • Addition:+

  • Subtraction:-

  • Multiplication:*

  • Division:/

  • Modulus (remainder):%

Template code

<span style="background-color:#f8f8f8"><span style="color:#333333 "> < b > arithmetic operator</b>
<br/><br/>
    100+5 Operation:  ${100 + 5 }<br/>
    100 - 5 * 5 Operation: ${100 - 5 * 5}<br/>
    5 / 2 Operation: ${5 / 2}<br/>
    12 % 10 Operation: ${12 % 10}<br/>
<hr></span></span>

Except for the + operation, other operations can only be combined with the calculation of number type.

2. Comparison operator

  • =Or = =: judge whether the two values are equal

  • !=: Judge whether the two values are unequal

  • >Or gt: judge whether the left value is greater than the right value

  • >=Or gte: judge whether the left value is greater than or equal to the right value

  • < or lt: judge whether the left value is less than the right value

  • < = or lte: judge whether the left value is less than or equal to the right value

=And = = template code

<span style="background-color:#f8f8f8"><span style="color:#333333"><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>

    <b>Comparison operator</b>
    <br/>
    <br/>

    <dl>
        <dt> =/== and != Comparison:</dt>
        <dd>
            <#if "xiaoming" == "xiaoming">
                String comparison "xiaoming" == "xiaoming"
            </#if>
        </dd>
        <dd>
            <#if 10 != 100>
                Comparison of values 10 != 100
            </#if>
        </dd>
    </dl>



    <dl>
        <dt>Other comparison</dt>
        <dd>
            <#if 10 gt 5 >
                Form 1: use special characters to compare values 10 gt 5
            </#if>
        </dd>
        <dd>
            <#--date comparison needs to pass? date can be compared only when the attribute is converted to data type -- >
            <#if (date1?date >= date2?date)>
                Form 2: compare time in parentheses date1?date >= date2?date
            </#if>
        </dd>
    </dl>

    <br/>
<hr>
</body>
</html></span></span>

Data model code of Controller

<span style="background-color:#f8f8f8"><span style="color:#333333">@GetMapping("operation")
public String testOperation(Model model) {
    //Build Date data
    Date now = new Date();
    model.addAttribute("date1", now);
    model.addAttribute("date2", now);
    
    return "03-operation";
}</span></span>

Comparison operator note

  • =And= You can use strings, numbers, and dates to compare equality

  • =And= Both sides must be values of the same type, otherwise an error will occur

  • The string "X", "X", "X" comparison is unequal Because FreeMarker is an accurate comparison

  • Other runes can act on numbers and dates, but not on strings

  • It is better to use letter operators such as gt instead of > because FreeMarker will interpret > as the end character of FTL label

  • You can avoid this by using parentheses, such as: < #if (x > y) >

3. Logical operator

  • Logic and:&&

  • Logical or:||

  • Logical non:!

Logical operators can only act on Boolean values, otherwise an error will be generated.

Template code

<span style="background-color:#f8f8f8"><span style="color:#333333 "> < b > logical operator</b>
    <br/>
    <br/>
    <#if (10 lt 12 )&&( 10  gt  5 )  >
        (10 lt 12 )&&( 10  gt  5 )  Display as true
    </#if>
    <br/>
    <br/>
    <#if !false>
        false Take the inverse as true
    </#if>
<hr></span></span>

2.3.5) null value processing

1. To judge whether a variable exists, use "?"

Usage: variable??, If the variable exists, return true; otherwise, return false

For example, to prevent stus from being null and reporting errors, the following judgment can be added:

<span style="background-color:#f8f8f8"><span style="color:#333333">    <#if stus??>
    <#list stus as stu>
    	......
    </#list>
    </#if></span></span>

2. Missing variable default use '!'

  • use! To specify a default value in, the default value is displayed when the variable is empty

    Example: ${name! '} indicates that if name is empty, an empty string will be displayed.

  • If it is a nested object, it is recommended to enclose it with ()

    Example: ${(stu.bestFriend.name)! ''} means that if stu or bestFriend or name is empty, an empty string will be displayed by default.

2.3.6) built in function

Syntax format of built-in function: variable ++ Function name

1. And the size to a collection

${collection name? size}

2. Date formatting

Display year, month and day: ${today?date} display hour, minute and second: ${today?time} display date + time: ${today?datetime} custom format: ${today?string("yyyy year, MM and month")}

3. Built in function c

model.addAttribute("point", 102920122);

Point is numeric. Using ${point} will display the value of this number, and every three digits are separated by commas.

If you do not want to display numbers separated by every three digits, you can use the c function to convert the numeric type to string output

${point?c}

4. Convert json string to object

An example:

The assign tag is used to define a variable.

<span style="background-color:#f8f8f8"><span style="color:#333333"><#assign text="{'bank': 'ICBC', 'account': '10101920201212'}" / >
<#assign data=text?eval />
Bank of deposit: ${data.bank}  account number: ${data.account}</span></span>

Template code:

<span style="background-color:#f8f8f8"><span style="color:#333333"><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>inner Function</title>
</head>
<body>

    <b>Get collection size</b><br>

    Collection size:
    <hr>


    <b>Date obtained</b><br>

    Display date:      <br>

    Display hours, minutes and seconds:<br>

    Display date+Time:<br>

    Custom formatting:  <br>

    <hr>

    <b>Built in function C</b><br>
    No, C Value displayed by function: <br>

    have C Value displayed by function:

    <hr>

    <b>Declare variable assign</b><br>


<hr>
</body>
</html></span></span>

Built in function template page:

<span style="background-color:#f8f8f8"><span style="color:#333333"><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>inner Function</title>
</head>
<body>

    <b>Get collection size</b><br>

    Collection size: ${stus?size}
    <hr>


    <b>Date obtained</b><br>

    Display date: ${today?date}       <br>

    Display hours, minutes and seconds: ${today?time}<br>

    Display date+Time: ${today?datetime}<br>

    Custom formatting:  ${today?string("yyyy year MM month")}<br>

    <hr>

    <b>Built in function C</b><br>
    No, C Value displayed by function: ${point} <br>

    have C Value displayed by function: ${point?c}

    <hr>

    <b>Declare variable assign</b><br>
    <#assign text="{'bank': 'ICBC', 'account': '10101920201212'}" / >
    <#assign data=text?eval />
    Bank of deposit: ${data.bank}  account number: ${data.account}

<hr>
</body>
</html></span></span>

Built in function Controller data model:

<span style="background-color:#f8f8f8"><span style="color:#333333">@GetMapping("innerFunc")
public String testInnerFunc(Model model) {
    //1.1 Xiaoqiang object model data
    Student stu1 = new Student();
    stu1.setName("cockroach");
    stu1.setAge(18);
    stu1.setMoney(1000.86f);
    stu1.setBirthday(new Date());
    //1.2 Xiaohong object model data
    Student stu2 = new Student();
    stu2.setName("Xiao Hong");
    stu2.setMoney(200.1f);
    stu2.setAge(19);
    //1.3 store the data of two object models in the List set
    List<Student> stus = new ArrayList<>();
    stus.add(stu1);
    stus.add(stu2);
    model.addAttribute("stus", stus);
    // 2.1 add date
    Date date = new Date();
    model.addAttribute("today", date);
    // 3.1 adding values
    model.addAttribute("point", 102920122);
    return "04-innerFunc";
}</span></span>

2.4) static test

In previous tests, spring MVC integrated Freemarker into the project as a view parser (ViewReporter). In work, sometimes it is necessary to use Freemarker native Api to generate static content. Let's learn how to generate text files with native Api.

2.4.1) demand analysis

Use freemaker native Api to generate html files from pages. This section tests the method of generating html files:

2.4.2) static test

Generate html file according to template file

① : modify application YML file, add the configuration information of the following template storage location, and the complete configuration is as follows:

<span style="background-color:#f8f8f8"><span style="color:#333333">server:
  port: 8881 #Service port
spring:
  application:
    name: freemarker-demo #Specify the service name
  freemarker:
    cache: false  #Close the template cache to facilitate testing
    settings:
      template_update_delay: 0 #Check the template update delay time. Setting it to 0 means checking immediately. If the time is greater than 0, there will be a cache, which is inconvenient for template testing
    suffix: .ftl               #Specifies the suffix of the Freemarker template file
    template-loader-path: classpath:/templates   #Formwork storage location</span></span>

② : create a test class under test

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.freemarker.test;


import com.heima.freemarker.FreemarkerDemoApplication;
import com.heima.freemarker.entity.Student;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

@SpringBootTest(classes = FreemarkerDemoApplication.class)
@RunWith(SpringRunner.class)
public class FreemarkerTest {

    @Autowired
    private Configuration configuration;

    @Test
    public void test() throws IOException, TemplateException {
        //Freemaker's template object to get the template
        Template template = configuration.getTemplate("02-list.ftl");
        Map params = getData();
        //synthesis
        //First parameter data model
        //Second parameter output stream
        template.process(params, new FileWriter("d:/list.html"));
    }

    private Map getData() {
        Map<String, Object> map = new HashMap<>();

        //Xiaoqiang object model data
        Student stu1 = new Student();
        stu1.setName("cockroach");
        stu1.setAge(18);
        stu1.setMoney(1000.86f);
        stu1.setBirthday(new Date());

        //Xiaohong object model data
        Student stu2 = new Student();
        stu2.setName("Xiao Hong");
        stu2.setMoney(200.1f);
        stu2.setAge(19);

        //Store the two object model data in the List collection
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);

        //Store List collection data into map
        map.put("stus", stus);


        //Create Map data
        HashMap<String, Student> stuMap = new HashMap<>();
        stuMap.put("stu1", stu1);
        stuMap.put("stu2", stu2);
        //Store map data in map
        map.put("stuMap", stuMap);

        //Return to Map
        return map;
    }
}</span></span>

3) Object storage service MinIO

3.1 introduction to Minio

MinIO is based on Apache license v2 0 open source protocol object storage service can be used as a cloud storage solution to save a large number of pictures, videos and documents. Due to the implementation of Golang, the server can work on Windows,Linux, OS X and FreeBSD. Simple configuration, basically copying executable programs, and single line commands can be run.

MinIO is compatible with Amazon S3 cloud storage service interface and is very suitable for storing large-capacity unstructured data, such as pictures, videos, log files, backup data and container / virtual machine images. An object file can be of any size, ranging from a few kb to a maximum of 5T.

S3 (Simple Storage Service)

Basic concepts

  • bucket – a directory similar to a file system

  • Object – a file that is analogous to a file system

  • Keys – analogy file name

Official website documents: MinIO Quickstart Guide| Minio Chinese document

3.2 MinIO features

  • data protection

    Minio uses the Minio error code to prevent hardware failures. Even if more than half of the driver s are damaged, they can still be recovered.

  • High performance

    As a high-performance object storage, it can achieve a read rate of 55GB/s and a write rate of 35GB/s under standard hardware conditions

  • Expandable capacity

    Different MinIO clusters can form a federation, form a global namespace, and span multiple data centers

  • SDK support

    Based on the lightweight characteristics of Minio, it is supported by sdk in languages such as Java, Python or Go

  • There is an operation page

    The user-friendly and simple operation interface is very convenient to manage the Bucket and its file resources

  • Simple function

    This design principle makes MinIO less error prone and faster to start

  • Rich API

    Support the basic functions of file resource sharing connection and sharing link expiration strategy, bucket operation, file list access and file upload and download.

  • Proactive notification of document changes

    If a Bucket changes, such as uploading and deleting objects, it can be monitored using the Bucket event notification mechanism and published in the following ways: AMQP, MQTT, Elasticsearch, Redis, NATS, MySQL, Kafka, Webhooks, etc.

3.3 unpacking

3.3.1 installation and startup

The minio environment already exists in the image we provide

We can use docker to deploy and start the environment

<span style="background-color:#f8f8f8"><span style="color:#333333">docker run -p 9000:9000 --name minio -d --restart=always -e "MINIO_ACCESS_KEY=minio" -e "MINIO_SECRET_KEY=minio123" -v /home/data:/data -v /home/config:/root/.minio minio/minio server /data</span></span>

3.3.2 management console

Suppose our server address is http://192.168.200.130:9000 , we enter in the address field: http://http://192.168.200.130:9000/ You can enter the login interface.

The Access Key is mini secret_ The key is minio123. After entering the system, you can see the main interface

Click the "+" sign in the lower right corner and click the icon below to create a bucket

3.4 getting started

3.4.1 create project and import pom dependency

Create a mini demo, and the corresponding pom is as follows

<span style="background-color:#f8f8f8"><span style="color:#333333"><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>heima-leadnews-test</artifactId>
        <groupId>com.heima</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>minio-demo</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>

        <dependency>
            <groupId>io.minio</groupId>
            <artifactId>minio</artifactId>
            <version>7.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

</project></span></span>

Boot class:

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.minio;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class MinIOApplication {

    public static void main(String[] args) {
        SpringApplication.run(MinIOApplication.class,args);
    }
}</span></span>

Create test class and upload html file

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.minio.test;

import io.minio.MinioClient;
import io.minio.PutObjectArgs;

import java.io.FileInputStream;

public class MinIOTest {


    public static void main(String[] args) {

        FileInputStream fileInputStream = null;
        try {

            fileInputStream =  new FileInputStream("D:\\list.html");;

            //1. Create a minio link client
            MinioClient minioClient = MinioClient.builder().credentials("minio", "minio123").endpoint("http://192.168.200.130:9000").build();
            //2. Upload
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object("list.html")//file name
                    .contentType("text/html")//file type
                    .bucket("leadnews")//The bucket noun is consistent with the noun created by minio
                    .stream(fileInputStream, fileInputStream.available(), -1) //File stream
                    .build();
            minioClient.putObject(putObjectArgs);

            System.out.println("http://192.168.200.130:9000/leadnews/ak47.jpg");

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

}</span></span>

3.5 package MinIO as starter

3.5.1 create module Heima file starter

Import dependency

<span style="background-color:#f8f8f8"><span style="color:#333333"><dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>7.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies></span></span>

3.5.2 configuration

MinIOConfigProperties

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.file.config;


import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.io.Serializable;

@Data
@ConfigurationProperties(prefix = "minio")  // File upload configuration prefix file oss
public class MinIOConfigProperties implements Serializable {

    private String accessKey;
    private String secretKey;
    private String bucket;
    private String endpoint;
    private String readPath;
}</span></span>

MinIOConfig

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.file.config;

import com.heima.file.service.FileStorageService;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Data
@Configuration
@EnableConfigurationProperties({MinIOConfigProperties.class})
//When introducing the FileStorageService interface
@ConditionalOnClass(FileStorageService.class)
public class MinIOConfig {

   @Autowired
   private MinIOConfigProperties minIOConfigProperties;

    @Bean
    public MinioClient buildMinioClient(){
        return MinioClient
                .builder()
                .credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey())
                .endpoint(minIOConfigProperties.getEndpoint())
                .build();
    }
}</span></span>

3.5.3 package operation minIO class

FileStorageService

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.file.service;

import java.io.InputStream;

/**
 * @author itheima
 */
public interface FileStorageService {


    /**
     *  Upload picture file
     * @param prefix  File prefix 
     * @param filename  file name
     * @param inputStream File stream
     * @return  File full path
     */
    public String uploadImgFile(String prefix, String filename,InputStream inputStream);

    /**
     *  Upload html file
     * @param prefix  File prefix 
     * @param filename   file name
     * @param inputStream  File stream
     * @return  File full path
     */
    public String uploadHtmlFile(String prefix, String filename,InputStream inputStream);

    /**
     * Delete file
     * @param pathUrl  File full path
     */
    public void delete(String pathUrl);

    /**
     * Download File
     * @param pathUrl  File full path
     * @return
     *
     */
    public byte[]  downLoadFile(String pathUrl);

}</span></span>

MinIOFileStorageService

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.file.service.impl;


import com.heima.file.config.MinIOConfig;
import com.heima.file.config.MinIOConfigProperties;
import com.heima.file.service.FileStorageService;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;
import org.springframework.util.StringUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

@Slf4j
@EnableConfigurationProperties(MinIOConfigProperties.class)
@Import(MinIOConfig.class)
public class MinIOFileStorageService implements FileStorageService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;

    private final static String separator = "/";

    /**
     * @param dirPath
     * @param filename  yyyy/mm/dd/file.jpg
     * @return
     */
    public String builderFilePath(String dirPath,String filename) {
        StringBuilder stringBuilder = new StringBuilder(50);
        if(!StringUtils.isEmpty(dirPath)){
            stringBuilder.append(dirPath).append(separator);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
        String todayStr = sdf.format(new Date());
        stringBuilder.append(todayStr).append(separator);
        stringBuilder.append(filename);
        return stringBuilder.toString();
    }

    /**
     *  Upload picture file
     * @param prefix  File prefix 
     * @param filename  file name
     * @param inputStream File stream
     * @return  File full path
     */
    @Override
    public String uploadImgFile(String prefix, String filename,InputStream inputStream) {
        String filePath = builderFilePath(prefix, filename);
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object(filePath)
                    .contentType("image/jpg")
                    .bucket(minIOConfigProperties.getBucket()).stream(inputStream,inputStream.available(),-1)
                    .build();
            minioClient.putObject(putObjectArgs);
            StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
            urlPath.append(separator+minIOConfigProperties.getBucket());
            urlPath.append(separator);
            urlPath.append(filePath);
            return urlPath.toString();
        }catch (Exception ex){
            log.error("minio put file error.",ex);
            throw new RuntimeException("Failed to upload file");
        }
    }

    /**
     *  Upload html file
     * @param prefix  File prefix 
     * @param filename   file name
     * @param inputStream  File stream
     * @return  File full path
     */
    @Override
    public String uploadHtmlFile(String prefix, String filename,InputStream inputStream) {
        String filePath = builderFilePath(prefix, filename);
        try {
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .object(filePath)
                    .contentType("text/html")
                    .bucket(minIOConfigProperties.getBucket()).stream(inputStream,inputStream.available(),-1)
                    .build();
            minioClient.putObject(putObjectArgs);
            StringBuilder urlPath = new StringBuilder(minIOConfigProperties.getReadPath());
            urlPath.append(separator+minIOConfigProperties.getBucket());
            urlPath.append(separator);
            urlPath.append(filePath);
            return urlPath.toString();
        }catch (Exception ex){
            log.error("minio put file error.",ex);
            ex.printStackTrace();
            throw new RuntimeException("Failed to upload file");
        }
    }

    /**
     * Delete file
     * @param pathUrl  File full path
     */
    @Override
    public void delete(String pathUrl) {
        String key = pathUrl.replace(minIOConfigProperties.getEndpoint()+"/","");
        int index = key.indexOf(separator);
        String bucket = key.substring(0,index);
        String filePath = key.substring(index+1);
        // Delete Objects
        RemoveObjectArgs removeObjectArgs = RemoveObjectArgs.builder().bucket(bucket).object(filePath).build();
        try {
            minioClient.removeObject(removeObjectArgs);
        } catch (Exception e) {
            log.error("minio remove file error.  pathUrl:{}",pathUrl);
            e.printStackTrace();
        }
    }


    /**
     * Download File
     * @param pathUrl  File full path
     * @return  File stream
     *
     */
    @Override
    public byte[] downLoadFile(String pathUrl)  {
        String key = pathUrl.replace(minIOConfigProperties.getEndpoint()+"/","");
        int index = key.indexOf(separator);
        String bucket = key.substring(0,index);
        String filePath = key.substring(index+1);
        InputStream inputStream = null;
        try {
            inputStream = minioClient.getObject(GetObjectArgs.builder().bucket(minIOConfigProperties.getBucket()).object(filePath).build());
        } catch (Exception e) {
            log.error("minio down file error.  pathUrl:{}",pathUrl);
            e.printStackTrace();
        }

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buff = new byte[100];
        int rc = 0;
        while (true) {
            try {
                if (!((rc = inputStream.read(buff, 0, 100)) > 0)) break;
            } catch (IOException e) {
                e.printStackTrace();
            }
            byteArrayOutputStream.write(buff, 0, rc);
        }
        return byteArrayOutputStream.toByteArray();
    }
}</span></span>

3.5.4 adding external automatic configuration

Create meta-inf / spring.net in resources factories

<span style="background-color:#f8f8f8"><span style="color:#333333">org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.heima.file.service.impl.MinIOFileStorageService</span></span>

3.5.5 use of other micro services

First, import the dependency of Heima file starter

Second, add the configuration required for minio in the microservice

<span style="background-color:#f8f8f8"><span style="color:#333333">minio:
  accessKey: minio
  secretKey: minio123
  bucket: leadnews
  endpoint: http://192.168.200.130:9000
  readPath: http://192.168.200.130:9000</span></span>

Third, inject FileStorageService into the corresponding business class. The example is as follows:

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.minio.test;


import com.heima.file.service.FileStorageService;
import com.heima.minio.MinioApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

@SpringBootTest(classes = MinioApplication.class)
@RunWith(SpringRunner.class)
public class MinioTest {

    @Autowired
    private FileStorageService fileStorageService;

    @Test
    public void testUpdateImgFile() {
        try {
            FileInputStream fileInputStream = new FileInputStream("E:\\tmp\\ak47.jpg");
            String filePath = fileStorageService.uploadImgFile("", "ak47.jpg", fileInputStream);
            System.out.println(filePath);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}</span></span>

4) Article details

4.1) demand analysis

4.2) implementation scheme

Scheme I

The user queries the article content table according to the article id and returns to the rendering page

Scheme II

4.3) implementation steps

1. Add support for MinIO and freemaker in the article microservice. Refer to the test items

2. Find the template file (article.ftl) in the data and copy it to the article microservice

3. Find index in the data JS and index CSS two files are manually uploaded to MinIO

4. Import dependency in article micro service

<span style="background-color:#f8f8f8"><span style="color:#333333"><dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    <dependency>
        <groupId>com.heima</groupId>
        <artifactId>heima-file-starter</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies></span></span>

5. Create ApArticleContentMapper

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.article.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.article.pojos.ApArticleContent;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ApArticleContentMapper extends BaseMapper<ApArticleContent> {
}</span></span>

6. Add a test class in the article microservice (create a detailed static page when adding articles later, which is currently generated manually)

<span style="background-color:#f8f8f8"><span style="color:#333333">package com.heima.article.test;


import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.article.ArticleApplication;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleContent;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

@SpringBootTest(classes = ArticleApplication.class)
@RunWith(SpringRunner.class)
public class ArticleFreemarkerTest {

    @Autowired
    private Configuration configuration;

    @Autowired
    private FileStorageService fileStorageService;


    @Autowired
    private ApArticleMapper apArticleMapper;

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;

    @Test
    public void createStaticUrlTest() throws Exception {
        //1. Get the article content
        ApArticleContent apArticleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, 1390536764510310401L));
        if(apArticleContent != null && StringUtils.isNotBlank(apArticleContent.getContent())){
            //2. The article content generates html files through freemaker
            StringWriter out = new StringWriter();
            Template template = configuration.getTemplate("article.ftl");

            Map<String, Object> params = new HashMap<>();
            params.put("content", JSONArray.parseArray(apArticleContent.getContent()));

            template.process(params, out);
            InputStream is = new ByteArrayInputStream(out.toString().getBytes());

            //3. Upload the html file to minio
            String path = fileStorageService.uploadHtmlFile("", apArticleContent.getArticleId() + ".html", is);

            //4. Modify ap_article table, save static_url field
            ApArticle article = new ApArticle();
            article.setId(apArticleContent.getArticleId());
            article.setStaticUrl(path);
            apArticleMapper.updateById(article);

        }
    }
}</span></span>

Topics: Javascript Vue.js elementUI