博客x主页:己不由心王道长!
文章说明:黑马头条开发
✅系列专栏:微服务项目
本篇内容:对黑马的黑马头条微服务进行开发讲解
☕️每日一语:这个世界本来就不完美,如果我们再不接受不完美的自己,那我们要怎么活。☕️
交流社区:己不由心王道长(优质编程社区)
文章内容为微服务内容,项目是跟着黑马头条进行的。本次内容为黑马头条的第二天,主要内容是文章列表加载、freemarker、minIO、文章详情,本期文章并未涉及到输入参数和选择频道的查询
一、文章信息表:
二、 文章配置表:
三、 文章内容表:
四、 表关系:
五、 为什么分表和分表的好处:
- 由于不同信息对应的数据大小不一样,操作时消耗的时间也不一样,所以分表。
- 在某一个数据进行操作时,可能因为其数据大小较大,不会在短时间内完成,当对这个数据进行操作时,又会进行锁表,导致其他资源无法访问,降低了效率。
- 分表是为了解决效率问题,好处应该就是提高了效率,不会进行长时间锁表。
六、 表的拆分原则:
- 将一个表的字段分散到多个表中,每个表存储其中一部分字段
- 1、把不常用的字段单独放在一张表
- 2、把text、blob等大字段拆分出来单独放在一张表
- 3、经常组合查询的字段单独放在一张表中
一、导入文章数据库:
二、导入对应实体类:
2,可以切换频道查看不同种类文章
3,当用户下拉可以加载最新的文章(分页)本页文章列表中发布时间为最大的时间为依据
4,当用户上拉可以加载更多的文章信息(按照发布时间)本页文章列表中发布时间最小的时间为依据
5,如果是当前频道的首页,前端传递默认参数:
maxBehotTime:0(毫秒)
minBehotTime:20000000000000(毫秒)—>2063年
加载首页 | 加载更多 | 加载最新 | |
---|---|---|---|
接口路径 | /api/v1/article/load | /api/v1/article/loadmore | /api/v1/article/loadnew |
请求方式 | POST | POST | POST |
参数 | ArticleHomeDto | ArticleHomeDto | ArticleHomeDto |
响应结果 | ResponseResult | ResponseResult | ResponseResult |
ArticleHomeDto:
package com.heima.model.article.dtos;
import lombok.Data;
import java.util.Date;
@Data
public class ArticleHomeDto {
// 最大时间
Date maxBehotTime;
// 最小时间
Date minBehotTime;
// 分页size
Integer size;
// 频道ID
String tag;
}
一、启动nacos:配置
二、编写接口:
三、编写mapper:
- 由于涉及到多表查询和复杂自定义查询,mybatisPlus无能为力,所以需要需要自己编写mapper(还是喜欢熟悉的感觉).
package com.heima.article.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.article.dtos.ArticleHomeDto;
import com.heima.model.article.pojos.ApArticle;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @Author Administrator
* @Date 2023/6/22 20:29
* @description
* @Version 1.0
*/
@Mapper
public interface ApArticleMapper extends BaseMapper<ApArticle> {
public List<ApArticle> loadArticleList (@Param("dto")ArticleHomeDto dto,@Param("type") short type);
}
# 文章微服务
- id: article
uri: lb://leadnews-article
predicates:
- Path=/article/**
filters:
- StripPrefix= 1
五、启动nginx,测试:
有一个大坑这里说一下:
我们在前面添加接口测试工具的时候,添加Kneife4j的时候,并没有导入正确的包,但是可以正常使用,在这里会导致一些问题,删除依赖即可。
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。
常用的java模板引擎还有哪些?
Jsp、Freemarker、Thymeleaf 、Velocity 等。
1.Jsp 为 Servlet 专用,不能单独进行使用。
2.Thymeleaf 为新技术,功能较为强大,但是执行的效率比较低。
3.Velocity从2010年更新完 2.0 版本后,便没有在更新。Spring Boot 官方在 1.4 版本后对此也不在支持,虽然 Velocity 在 2017 年版本得到迭代,但为时已晚。
一、freemarker作为springmvc一种视图格式,默认情况下SpringMVC支持freemarker视图格式。
二、需要创建Spring Boot+Freemarker工程用于测试模板。
一、在这个专门进行测试的微服务中创建一个freemarker-demo 的测试工程专门用于freemarker的功能测试与模板的测试。
测试entity对象:
package com.heima.freemarker.entity;
import lombok.Data;
import java.util.Date;
/**
* @Author Administrator
* @Date 2023/6/23 17:12
* @description
* @Version 1.0
*/
@Data
public class Student {
private String name;//姓名
private int age;//年龄
private Date birthday;//生日
private Float money;//钱包
}
controller:
package com.heima.freemarker.controller;
import com.heima.freemarker.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
/**
* @Author Administrator
* @Date 2023/6/23 17:15
* @description
* @Version 1.0
*/
@Controller
public class HelloController {
@GetMapping("/basic")
public String test(Model model) {
//1.纯文本形式的参数
model.addAttribute("name", "freemarker");
//2.实体类相关的参数
Student student = new Student();
student.setName("小明");
student.setAge(18);
model.addAttribute("stu", student);
return "01-basic";
}
}
配置文件:
server:
port: 8881 #服务端口
spring:
application:
name: freemarker-demo #指定服务名
freemarker:
cache: false #关闭模板缓存,方便测试
settings:
template_update_delay: 0 #检查模板更新延迟时间,设置为0表示立即检查,如果时间大于0会有缓存不方便进行模板测试
suffix: .ftl #指定Freemarker模板文件的后缀名
注意:这里由于springboot2.2.0版本以后,free marker模板引擎默认的模板文件后缀已经由ftl改变为ftlh,如果你的springboot版本在这以上,那么使用ftl将会无法正常映射,除非你在配置文件中指定路径
我们可以去看看源码:找到依赖—》找到springboot自动配置依赖下的spring.factories
找到free marker:快捷键:CTRL+f +名称
一、注释,即<#-- -->,介于其之间的内容会被freemarker忽略
<#--我是一个freemarker注释-->
二、插值(Interpolation):即 ${..}部分,freemarker会用真实的值代替
${…}
Hello ${name}
三、FTL指令:和HTML标记类似,名字前加#予以区分,Freemarker会解析标签中的表达式或逻辑
<# >FTL指令#>
四、文本,仅文本信息,这些不是freemarker的注释、插值、FTL指令的内容会被freemarker忽略解析,直接输出内容。
<#--freemarker中的普通文本-->
我是一个普通的文本
map:
<#-- Map 数据的展示 -->
<b>map数据的展示:b>
<br/><br/>
<a href="###">方式一:通过map['keyname'].propertya><br/>
输出stu1的学生信息:<br/>
姓名:${stuMap['stu1'].name}<br/>
年龄:${stuMap['stu1'].age}<br/>
<br/>
<a href="###">方式二:通过map.keyname.propertya><br/>
输出stu2的学生信息:<br/>
姓名:${stuMap.stu2.name}<br/>
年龄:${stuMap.stu2.age}<br/>
list:
<#list stus as stu> <#-- stus是model传过来时的名称,as是标准写法,stu是list集合中的每个元素,有点像foreach语法-->
<tr>
<td>${stu_index+1}td> <#--stu_index:取集合元素时默认带的下标,从0开始-->
<td>${stu.name}td> <#--元素的名字-->
<td>${stu.age}td>
<td>${stu.money}td>
tr>
#list>
map和list:
<br/>
<a href="###">遍历map中两个学生信息:a><br/>
<table>
<tr>
<td>序号td>
<td>姓名td>
<td>年龄td>
<td>钱包td>
tr>
<#list stuMap?keys as key > <#--取出stuMap中所有的keys并as key 取出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>
一、if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否则跳过内容不再输出
<#if >if>
1、数据模型:
使用list指令中测试数据模型,判断名称为小红的数据字体显示为红色。
2、模板:
姓名
年龄
钱包
<#list stus as stu >
<#if stu.name='小红'>
${stu_index}
${stu.name}
${stu.age}
${stu.money}
<#else >
${stu_index}
${stu.name}
${stu.age}
${stu.money}
#if>
#list>
3、输出:
姓名为“小强”则字体颜色显示为红色。
1、算数运算符
FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:
+
-
*
/
%
模板代码:
<b>算数运算符b>
<br/><br/>
100+5 运算: ${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
:判断左边值是否小于等于右边值= 和 == 模板代码
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello World!title>
head>
<body>
<b>比较运算符b>
<br/>
<br/>
<dl>
<dt> =/== 和 != 比较:dt>
<dd>
<#if "xiaoming" == "xiaoming">
字符串的比较 "xiaoming" == "xiaoming"
#if>
dd>
<dd>
<#if 10 != 100>
数值的比较 10 != 100
#if>
dd>
dl>
<dl>
<dt>其他比较dt>
<dd>
<#if 10 gt 5 >
形式一:使用特殊字符比较数值 10 gt 5
#if>
dd>
<dd>
<#-- 日期的比较需要通过?date将属性转为data类型才能进行比较 -->
<#if (date1?date >= date2?date)>
形式二:使用括号形式比较时间 date1?date >= date2?date
#if>
dd>
dl>
<br/>
<hr>
body>
html>
比较运算符注意
=
和!=
**可以用于字符串、数值和日期来比较是否相等=
和!=
**两边必须是相同类型的值,否则会产生错误"x"
、"x "
、**"X"
**比较是不等的.因为FreeMarker是精确比较gt
等字母运算符代替>
会有更好的效果,因为 FreeMarker会把>
**解释成FTL标签的结束字符<#if (x>y)>
3、逻辑运算符
逻辑运算符只能作用于布尔值,否则将产生错误 。
模板代码
<b>逻辑运算符b>
<br/>
<br/>
<#if (10 lt 12 )&&( 10 gt 5 ) >
(10 lt 12 )&&( 10 gt 5 ) 显示为 true
#if>
<br/>
<br/>
<#if !false>
false 取反为true
#if>
<hr>
1、判断某变量是否存在使用 “??”
用法为:variable??,如果该变量存在,返回true,否则返回false
例:为防止stus为空报错可以加上判断如下:
<#if stus??>
<#list stus as stu>
......
#list>
#if>
2、缺失变量默认值使用 “!”
使用!要以指定一个默认值,当变量为空时显示默认值
例: ${name!‘’}表示如果name为空显示空字符串。
如果是嵌套对象则建议使用()括起来
例: ${(stu.bestFriend.name)!‘’}表示,如果stu或bestFriend或name为空默认显示空字符串。
内建函数语法格式: 变量+?+函数名称
1、和到某个集合的大小
${集合名?size}
2、日期格式化
显示年月日: ${today?date}
显示时分秒:${today?time}
显示日期+时间:${today?datetime}
自定义格式化: ${today?string("yyyy年MM月")}
3、内建函数c
model.addAttribute(“point”, 102920122);
point是数字型,使用${point}会显示这个数字的值,每三位使用逗号分隔。
如果不想显示为每三位分隔的数字,可以使用c函数将数字型转成字符串输出
${point?c}
4、将json字符串转成对象
一个例子:
其中用到了 assign标签,assign的作用是定义一个变量。
<#assign text="{'bank':'工商银行','account':'10101920201920212'}" />
<#assign data=text?eval />
开户行:${data.bank} 账号:${data.account}
模板代码:
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>inner Functiontitle>
head>
<body>
<b>获得集合大小b><br>
集合大小:
<hr>
<b>获得日期b><br>
显示年月日: <br>
显示时分秒:<br>
显示日期+时间:<br>
自定义格式化: <br>
<hr>
<b>内建函数Cb><br>
没有C函数显示的数值: <br>
有C函数显示的数值:
<hr>
<b>声明变量assignb><br>
<hr>
body>
html>
内建函数模板页面:
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>inner Functiontitle>
head>
<body>
<b>获得集合大小b><br>
集合大小:${stus?size}
<hr>
<b>获得日期b><br>
显示年月日: ${today?date} <br>
显示时分秒:${today?time}<br>
显示日期+时间:${today?datetime}<br>
自定义格式化: ${today?string("yyyy年MM月")}<br>
<hr>
<b>内建函数Cb><br>
没有C函数显示的数值:${point} <br>
有C函数显示的数值:${point?c}
<hr>
<b>声明变量assignb><br>
<#assign text="{'bank':'工商银行','account':'10101920201920212'}" />
<#assign data=text?eval />
开户行:${data.bank} 账号:${data.account}
<hr>
body>
html>
MinIO基于Apache License v2.0开源协议的对象存储服务,可以做为云存储的解决方案用来保存海量的图片,视频,文档。由于采用Golang实现,服务端可以工作在Windows,Linux, OS X和FreeBSD上。配置简单,基本是复制可执行程序,单行命令可以运行起来。
MinIO兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小,从几kb到最大5T不等。
S3 ( Simple Storage Service简单存储服务)
基本概念:
官网文档:http://docs.minio.org.cn/docs/
数据保护
Minio使用Minio Erasure Code(纠删码)来防止硬件故障。即便损坏一半以上的driver,但是仍然可以从中恢复。
高性能
作为高性能对象存储,在标准硬件条件下它能达到55GB/s的读、35GB/s的写速率
可扩容
不同MinIO集群可以组成联邦,并形成一个全局的命名空间,并跨越多个数据中心
SDK支持
基于Minio轻量的特点,它得到类似Java、Python或Go等语言的sdk支持
有操作页面
面向用户友好的简单操作界面,非常方便的管理Bucket及里面的文件资源
功能简单
这一设计原则让MinIO不容易出错、更快启动
丰富的API
支持文件资源的分享连接及分享链接的过期策略、存储桶操作、文件列表访问及文件上传下载的基本功能等。
文件变化主动通知
存储桶(Bucket)如果发生改变,比如上传对象和删除对象,可以使用存储桶事件通知机制进行监控,并通过以下方式发布出去:AMQP、MQTT、Elasticsearch、Redis、NATS、MySQL、Kafka、Webhooks等。
我们提供的镜像中已经有minio的环境
我们可以使用docker进行环境部署和启动
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
假设我们的服务器地址为http://192.168.200.130:9000,我们在地址栏输入:http://192.168.200.130:9000/即可进入登录界面。
现在我们查看控制台:
创建minio-demo,对应pom如下
<?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>
主要是踩坑的,基础薄弱,scope是元素的作用,:
compile(默认)
含义:compile 是默认值,如果没有指定 scope 值,该元素的默认值为 compile。被依赖项目需要参与到当前项目的编译,测试,打包,运行等阶段。
provided
含义:被依赖项目理论上可以参与编译、测试、运行等阶段,相当于compile,但是再打包阶段做了exclude的动作。
适用场景:例如, 如果我们在开发一个web 应用,在编译时我们需要依赖 servlet-api.jar,但是在运行时我们不需要该 jar 包,因为这个 jar 包已由应用服务器提供,此时我们需要使用 provided 进行范围修饰。
runtime
含义:表示被依赖项目无需参与项目的编译,但是会参与到项目的测试和运行。与compile相比,被依赖项目无需参与项目的编译。
适用场景:例如,在编译的时候我们不需要 JDBC API 的 jar 包,而在运行的时候我们才需要 JDBC 驱动包。
test
含义: 表示被依赖项目仅仅参与测试相关的工作,包括测试代码的编译,执行。
适用场景:例如,Junit 测试。
在测试时加入了scope依赖,导致依赖注入一直失败,所以要把scope去掉。