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 page | Load more | Load latest | |
---|---|---|---|
Interface path | /api/v1/article/load | /api/v1/article/loadmore | /api/v1/article/loadnew |
Request mode | POST | POST | POST |
parameter | ArticleHomeDto | ArticleHomeDto | ArticleHomeDto |
Response results | ResponseResult | ResponseResult | ResponseResult |
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>