有后天管理的网站怎么建设,建设网站空间合同,python网站开发 pdf,手机优化软件app端文章 Day02: app端文章查看#xff0c;静态化freemarker,分布式文件系统minIOa. app端文章列表查询1) 需求分析2) 实现思路 b. app端文章详细1) 需求分析2) Freemarker概述a) 基础语法种类b) 集合指令#xff08;List和Map#xff09;c) if指令d) 运算符e) 空值处理f) … app端文章 Day02: app端文章查看静态化freemarker,分布式文件系统minIOa. app端文章列表查询1) 需求分析2) 实现思路 b. app端文章详细1) 需求分析2) Freemarker概述a) 基础语法种类b) 集合指令List和Mapc) if指令d) 运算符e) 空值处理f) 内建函数g) 静态化测试 c) 对象存储服务MinIO概述1) Linux安装2) 封装MinIO为startera) 创建模块heima-file-starterb) 配置类c) 封装操作minIO类d) 对外加入自动配置e) 其他微服务使用 d) 实现步骤 Day02: app端文章查看静态化freemarker,分布式文件系统minIO
a. app端文章列表查询
1) 需求分析 表结构分析
表名称说明ap_article文章信息表存储已发布的文章ap_article_configAPP已发布文章配置表ap_article_contentAPP已发布文章内容表ap_authorAPP文章作者信息表ap_collectionAPP收藏信息表
ap_article 文章基本信息表 ap_article_config 文章配置表 ap_article_content 文章内容表 三张表关系分析 表的拆分-垂直分表
垂直分表将一个表的字段分散到多个表中每个表存储其中一部分字段。
优势
1.少IO争抢减少锁表的几率查看文章概述与文章详情互不影响2.充分发挥高频数据的操作效率对文章概述数据操作的高效率不会被操作文章详情数据的低效率所拖累。
拆分规则 1.把不常用的字段单独放在一张表 2.把textblob等大字段拆分出来单独放在一张表 3.经常组合查询的字段单独放在一张表中
2) 实现思路
1.在默认频道展示10条文章信息2.可以切换频道查看不同种类文章3.当用户下拉可以加载最新的文章分页本页文章列表中发布时间为最大的时间为依据4.当用户上拉可以加载更多的文章信息按照发布时间本页文章列表中发布时间最小的时间为依据5.如果是当前频道的首页前端传递默认参数 maxBehotTime0毫秒minBehotTime20000000000000毫秒 2063年
# 按照发布时间倒序查询10条文章
# 频道筛选 where aa.channel_id 1
# 加载首页 and aa.publish_time 2063-04-19 00:00:00
# 加载更多 and aa.publish_time 2020-09-07 22:30:09‘
# 加载最新 and aa.publish_time 2020-09-07 22:30:09
# 该文章未下架未删除
select * from ap_article aa LEFT JOIN ap_article_config aac ON aa.id aac.article_id
where aac.is_down ! 1 and aac.is_delete ! 1
and aa.channel_id 1
and aa.publish_time 2063-04-19 00:00:00
order by aa.publish_time DESC
limit 10接口定义
加载首页加载更多加载最新接口路径/api/v1/article/load/api/v1/article/loadmore/api/v1/article/loadnew请求方式POSTPOSTPOST参数ArticleHomeDtoArticleHomeDtoArticleHomeDto响应结果ResponseResultResponseResultResponseResult
ArticleHomeDto
package com.heima.model.article.dtos;import lombok.Data;import java.util.Date;Data
public class ArticleHomeDto {// 最大时间Date maxBehotTime;// 最小时间Date minBehotTime;// 分页sizeInteger size;// 频道IDString tag;
}导入相关项目及在service的pom文件下添加相关module属性
需要在nacos中添加对应的配置
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/leadnews_article?useUnicodetruecharacterEncodingUTF-8serverTimezoneUTCusername: rootpassword: root
# 设置Mapper接口所对应的XML文件位置如果你在Mapper接口中有自定义方法需要进行该配置
mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.article.pojos定义控制器接口接口路径、请求方式、入参、出参
RestController
RequestMapping(/api/v1/article)
public class ArticleHomeController {Autowiredprivate ApArticleService apArticleService;/*** 加载首页* param dto* return*/PostMapping(/load)public ResponseResult load(RequestBody ArticleHomeDto dto){return apArticleService.load(dto, ArticleConstants.LOADTYPE_LOAD_MORE);}/*** 加载更多* param dto* return*/PostMapping(/loadmore)public ResponseResult loadmore(RequestBody ArticleHomeDto dto){return apArticleService.load(dto, ArticleConstants.LOADTYPE_LOAD_MORE);}/*** 加载最新* param dto* return*/PostMapping(/loadnew)public ResponseResult loadnew(RequestBody ArticleHomeDto dto){return apArticleService.load(dto, ArticleConstants.LOADTYPE_LOAD_NEW);}
}编写mapper文件文章表与文章配置表的多表查询
Mapper
public interface ApArticleMapper extends BaseMapperApArticle {/*** 加载文章列表* param dto* param type 1加载更多 2加载最新* return*/ListApArticle loadArticleList(ArticleHomeDto dto, Short type);
}对应的映射文件
?xml version1.0 encodingUTF-8?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.heima.article.mapper.ApArticleMapperresultMap idresultMap typecom.heima.model.article.pojos.ApArticleid columnid propertyid/result columntitle propertytitle/result columnauthor_id propertyauthorId/result columnauthor_name propertyauthorName/result columnchannel_id propertychannelId/result columnchannel_name propertychannelName/result columnlayout propertylayout/result columnflag propertyflag/result columnimages propertyimages/result columnlabels propertylabels/result columnlikes propertylikes/result columncollection propertycollection/result columncomment propertycomment/result columnviews propertyviews/result columnprovince_id propertyprovinceId/result columncity_id propertycityId/result columncounty_id propertycountyId/result columncreated_time propertycreatedTime/result columnpublish_time propertypublishTime/result columnsync_status propertysyncStatus/result columnstatic_url propertystaticUrl//resultMapselect idloadArticleList resultMapresultMapSELECTaa.*FROMap_article aaLEFT JOIN ap_article_config aac ON aa.id aac.article_idwhereand aac.is_delete ! 1and aac.is_down ! 1!-- loadmore --if testtype ! null and type 1and aa.publish_time ![CDATA[]] #{dto.minBehotTime}/ifif testtype ! null and type 2and aa.publish_time ![CDATA[]] #{dto.maxBehotTime}/ifif testdto.tag ! __all__and aa.channel_id #{dto.tag}/if/whereorder by aa.publish_time desclimit #{dto.size}/select
/mapper定义常量类
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__;
}编写业务层代码
Service
Transactional
Slf4j
public class ApArticleServiceImpl extends ServiceImplApArticleMapper, ApArticle implements ApArticleService {Autowiredprivate ApArticleMapper apArticleMapper;private final static short MAX_PAGE_SIZE 50;/*** 加载文章列表* param dto* param type 1加载更多 2加载最新* return*/Overridepublic ResponseResult load(ArticleHomeDto dto, Short type) {// 1.校验参数// 分页条数的校验Integer size dto.getSize();if (size null || size 0) {size 10; // 若没有值赋予默认值10}// 分页值不能超过50size Math.min(size, MAX_PAGE_SIZE);dto.setSize(size);// 校验type参数if (!type.equals(ArticleConstants.LOADTYPE_LOAD_MORE) !type.equals(ArticleConstants.LOADTYPE_LOAD_NEW)) {type ArticleConstants.LOADTYPE_LOAD_MORE; // 若没有值赋予默认值1}// 频道参数校验if (StringUtils.isBlank(dto.getTag())) {dto.setTag(ArticleConstants.DEFAULT_TAG);}// 时间校验if (dto.getMaxBehotTime() null) dto.setMaxBehotTime(new Date());if (dto.getMinBehotTime() null) dto.setMinBehotTime(new Date());// 2.查询ListApArticle apArticleList apArticleMapper.loadArticleList(dto, type);// 3.结果返回return ResponseResult.okResult(apArticleList);}
}b. app端文章详细
1) 需求分析 2) Freemarker概述
FreeMarker 是一款 模板引擎 即一种基于模板和要改变的数据 并用来生成输出文本(HTML网页电子邮件配置文件源代码等)的通用工具。 它不是面向最终用户的而是一个Java类库是一款程序员可以嵌入他们所开发产品的组件。 技术说明JspJsp 为 Servlet 专用不能单独进行使用VelocityVelocity从2010年更新完 2.0 版本后7年没有更新。Spring Boot 官方在 1.4 版本后对此也不在支持thmeleaf新技术功能较为强大但是执行的效率比较低freemarker性能好强大的模板语言、轻量
a) 基础语法种类
1、注释即#-- --介于其之间的内容会被freemarker忽略
#--我是一个freemarker注释--2、插值Interpolation即 ${..} 部分,freemarker会用真实的值代替**${..}**
Hello ${name}3、FTL指令和HTML标记类似名字前加#予以区分Freemarker会解析标签中的表达式或逻辑。
# FTL指令/# 4、文本仅文本信息这些不是freemarker的注释、插值、FTL指令的内容会被freemarker忽略解析直接输出内容。
#--freemarker中的普通文本--
我是一个普通的文本b) 集合指令List和Map
实例代码
!DOCTYPE html
html
headmeta charsetutf-8titleHello World!/title
/head
body#-- list 数据的展示 --
b展示list中的stu数据:/b
br
br
tabletrtd序号/tdtd姓名/tdtd年龄/tdtd钱包/td/tr#list stus as stutrtd${stu_index1}/tdtd${stu.name}/tdtd${stu.age}/tdtd${stu.money}/td/tr/#list/table
hr#-- Map 数据的展示 --
bmap数据的展示/b
br/br/
a href###方式一通过map[keyname].property/abr/
输出stu1的学生信息br/
姓名${stuMap[stu1].name}br/
年龄${stuMap[stu1].age}br/
br/
a href###方式二通过map.keyname.property/abr/
输出stu2的学生信息br/
姓名${stuMap.stu2.name}br/
年龄${stuMap.stu2.age}br/br/
a href###遍历map中两个学生信息/abr/
tabletrtd序号/tdtd姓名/tdtd年龄/tdtd钱包/td/tr#list stuMap?keys as key trtd${key_index}/tdtd${stuMap[key].name}/tdtd${stuMap[key].age}/tdtd${stuMap[key].money}/td/tr/#list
/table
hr/body
/html上面代码解释
${key_index} index得到循环的下标使用方法是在stu后边加_index它的值是从0开始
c) if指令
if 指令即判断指令是常用的FTL指令freemarker在解析时遇到if会进行判断条件为真则输出if中间的内容否则跳过内容不再输出。
指令格式
#if /if实例代码
tabletrtd姓名/tdtd年龄/tdtd钱包/td/tr#list stus as stu #if stu.name小红tr stylecolor: redtd${stu_index}/tdtd${stu.name}/tdtd${stu.age}/tdtd${stu.money}/td/tr#else trtd${stu_index}/tdtd${stu.name}/tdtd${stu.age}/tdtd${stu.money}/td/tr/#if/#list
/tabled) 运算符
1、算数运算符
FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:
加法 减法 -乘法 *除法 /求模 (求余) %
模板代码
b算数运算符/b
br/br/1005 运算 ${100 5 }br/100 - 5 * 5运算${100 - 5 * 5}br/5 / 2运算${5 / 2}br/12 % 10运算${12 % 10}br/
hr除了 运算以外其他的运算只能和 number 数字类型的计算。
2、比较运算符
或者:判断两个值是否相等.!:判断两个值是否不等.或者gt:判断左边值是否大于右边值或者gte:判断左边值是否大于等于右边值或者lt:判断左边值是否小于右边值或者lte:判断左边值是否小于等于右边值
比较运算符注意
**和!**可以用于字符串、数值和日期来比较是否相等**和!**两边必须是相同类型的值,否则会产生错误字符串 x 、x 、**X**比较是不等的.因为FreeMarker是精确比较其它的运行符可以作用于数字和日期,但不能作用于字符串使用**gt等字母运算符代替会有更好的效果,因为 FreeMarker会把**解释成FTL标签的结束字符可以使用括号来避免这种情况,如:#if (xy)
3、逻辑运算符
逻辑与:逻辑或:||逻辑非:!
逻辑运算符只能作用于布尔值,否则将产生错误 。
e) 空值处理
1、判断某变量是否存在使用 “??”
用法为:variable??,如果该变量存在,返回true,否则返回false
例为防止stus为空报错可以加上判断如下 #if stus??#list stus as stu....../#list/#if2、缺失变量默认值使用 “!” 使用!要以指定一个默认值当变量为空时显示默认值 例 ${name!‘’}表示如果name为空显示空字符串。 如果是嵌套对象则建议使用括起来 例 ${(stu.bestFriend.name)!‘’}表示如果stu或bestFriend或name为空默认显示空字符串。
f) 内建函数
内建函数语法格式 变量?函数名称
1、和到某个集合的大小
${集合名?size}
2、日期格式化
显示年月日: ${today?date} 显示时分秒${today?time} 显示日期时间${today?datetime} 自定义格式化 ${today?string(yyyy年MM月)}
3、内建函数c
model.addAttribute(“point”, 10292012278902L);
point是数字型使用${point}会显示这个数字的值每三位使用逗号分隔。
如果不想显示为每三位分隔的数字可以使用c函数将数字型转成字符串输出
${point?c}
4、将json字符串转成对象
一个例子
其中用到了 assign标签assign的作用是定义一个变量。
#assign text{bank:工商银行,account:10101920201920212} /
#assign datatext?eval /
开户行${data.bank} 账号${data.account}g) 静态化测试
使用Freemarker原生Api来生成静态内容
SpringBootTest(classes FreemarkerDemoApplication.class)
RunWith(SpringRunner.class)
public class FreemarkerTest {Autowiredprivate Configuration configuration;Testpublic void test() throws IOException, TemplateException {Template template configuration.getTemplate(02-list.ftl);/*** 合成方法** 第一个参数模型数据* 第二个参数输出流*/template.process(getData(), new FileWriter(F:/list.html));}private Map getData(){MapString, Object map new HashMap();Student stu1 new Student();stu1.setName(小强);stu1.setAge(18);stu1.setMoney(1000.86f);stu1.setBirthday(new Date());//小红对象模型数据Student stu2 new Student();stu2.setName(小红);stu2.setMoney(200.1f);stu2.setAge(19);//将两个对象模型数据存放到List集合中ListStudent stus new ArrayList();stus.add(stu1);stus.add(stu2);//向model中存放List集合数据map.put(stus,stus);MapString, Student stuMap new HashMap();stuMap.put(stu1,stu1);stuMap.put(stu2,stu2);//向model中存放Set集合数据map.put(stuMap,stuMap);return map;}
}c) 对象存储服务MinIO概述
对象存储的方式对比
存储方式优点缺点服务器磁盘开发便捷成本低扩展困难分布式文件系统容易实现扩容复杂度高第三方存储开发简单功能强大免维护收费
分布式文件系统
存储方式优点缺点FastDFS1.主备服务高可用。2.支持主从文件支持自定义扩展名。3.支持动态扩容1没有完备官方文档近几年没有更新2环境搭建较为麻烦MinIO1.性能高准硬件条件下它能达到55GB/s的读、35GB/s的写速率。2.部署自带管理界面。3.MinIO.Inc运营的开源项目社区活跃度高。4.提供了所有主流开发语言的SDK1不支持动态增加节点
1) Linux安装
1.拉取镜像
docker pull minio/minio2.创建容器
docker run -p 9000:9000 --name minio -d --restartalways -e MINIO_ACCESS_KEYminio -e MINIO_SECRET_KEYminio123 -v /home/data:/data -v /home/config:/root/.minio minio/minio server /data3.访问minio系统
http://192.168.200.130:9000
基本概念
bucket – 类比于文件系统的文件夹Object – 类比文件系统的文件Keys – 类比文件名
2) 封装MinIO为starter
a) 创建模块heima-file-starter
导入依赖
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-autoconfigure/artifactId/dependencydependencygroupIdio.minio/groupIdartifactIdminio/artifactIdversion7.1.0/version/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency
/dependenciesb) 配置类
MinIOConfigProperties
package com.heima.file.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;import java.io.Serializable;Data
ConfigurationProperties(prefix minio) // 文件上传 配置前缀file.oss
public class MinIOConfigProperties implements Serializable {private String accessKey;private String secretKey;private String bucket;private String endpoint;private String readPath;
}MinIOConfig
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})
//当引入FileStorageService接口时
ConditionalOnClass(FileStorageService.class)
public class MinIOConfig {Autowiredprivate MinIOConfigProperties minIOConfigProperties;Beanpublic MinioClient buildMinioClient(){return MinioClient.builder().credentials(minIOConfigProperties.getAccessKey(), minIOConfigProperties.getSecretKey()).endpoint(minIOConfigProperties.getEndpoint()).build();}
}c) 封装操作minIO类
FileStorageService
package com.heima.file.service;import java.io.InputStream;/*** author itheima*/
public interface FileStorageService {/*** 上传图片文件* param prefix 文件前缀* param filename 文件名* param inputStream 文件流* return 文件全路径*/public String uploadImgFile(String prefix, String filename,InputStream inputStream);/*** 上传html文件* param prefix 文件前缀* param filename 文件名* param inputStream 文件流* return 文件全路径*/public String uploadHtmlFile(String prefix, String filename,InputStream inputStream);/*** 删除文件* param pathUrl 文件全路径*/public void delete(String pathUrl);/*** 下载文件* param pathUrl 文件全路径* return**/public byte[] downLoadFile(String pathUrl);}MinIOFileStorageService
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 {Autowiredprivate MinioClient minioClient;Autowiredprivate 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();}/*** 上传图片文件* param prefix 文件前缀* param filename 文件名* param inputStream 文件流* return 文件全路径*/Overridepublic 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(separatorminIOConfigProperties.getBucket());urlPath.append(separator);urlPath.append(filePath);return urlPath.toString();}catch (Exception ex){log.error(minio put file error.,ex);throw new RuntimeException(上传文件失败);}}/*** 上传html文件* param prefix 文件前缀* param filename 文件名* param inputStream 文件流* return 文件全路径*/Overridepublic 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(separatorminIOConfigProperties.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(上传文件失败);}}/*** 删除文件* param pathUrl 文件全路径*/Overridepublic 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(index1);// 删除ObjectsRemoveObjectArgs 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();}}/*** 下载文件* param pathUrl 文件全路径* return 文件流**/Overridepublic 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(index1);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();}
}d) 对外加入自动配置
在resources中新建META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration\com.heima.file.service.impl.MinIOFileStorageServicee) 其他微服务使用
第一导入heima-file-starter的依赖
第二在微服务中添加minio所需要的配置
minio:accessKey: miniosecretKey: minio123bucket: leadnewsendpoint: http://192.168.200.130:9000readPath: http://192.168.200.130:9000第三在对应使用的业务类中注入FileStorageService样例如下
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 {Autowiredprivate FileStorageService fileStorageService;Testpublic 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();}}
}d) 实现步骤 1.在article微服务中添加MinIO和freemarker的依赖
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-freemarker/artifactId/dependencydependencygroupIdcom.heima/groupIdartifactIdheima-file-starter/artifactIdversion1.0-SNAPSHOT/version/dependency
/dependencies2.资料中找到模板文件article.ftl拷贝到article微服务下
3.资料中找到index.js和index.css两个文件手动上传到MinIO中
4.在artile微服务中新增测试类后期新增文章的时候创建详情静态页目前暂时手动生成
新建ApArticleContentMapper
Mapper
public interface ApArticleContentMapper extends BaseMapperApArticleContent {
}在artile微服务中新增测试类后期新增文章的时候创建详情静态页目前暂时手动生成
SpringBootTest(classes ArticleApplication.class)
RunWith(SpringRunner.class)
public class ArticleFreemarkerTest {Autowiredprivate Configuration configuration;Autowiredprivate FileStorageService fileStorageService;Autowiredprivate ApArticleMapper apArticleMapper;Autowiredprivate ApArticleContentMapper apArticleContentMapper;Testpublic void createStaticUrlTest() throws Exception {//1.获取文章内容ApArticleContent apArticleContent apArticleContentMapper.selectOne(Wrappers.ApArticleContentlambdaQuery().eq(ApArticleContent::getArticleId, 1390536764510310401L));if(apArticleContent ! null StringUtils.isNotBlank(apArticleContent.getContent())){//2.文章内容通过freemarker生成html文件Template template configuration.getTemplate(article.ftl);// 数据模型MapString, Object params new HashMap();params.put(content, JSONArray.parseArray(apArticleContent.getContent()));// 输出流StringWriter out new StringWriter();template.process(params, out);//3.把html文件上传到minio中InputStream is new ByteArrayInputStream(out.toString().getBytes());String path fileStorageService.uploadHtmlFile(, apArticleContent.getArticleId() .html, is);//4.修改ap_article表保存static_url字段ApArticle article new ApArticle();article.setId(apArticleContent.getArticleId());article.setStaticUrl(path);apArticleMapper.updateById(article);}}
}