一文迅速掌握minio、xxl-job、jave、mybatis-plus-join的使用

minio的使用

引入依赖

<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency> 版本号在项目父pom.xml中,后续依赖同理

配置地址和参数

minio:
url: http://localhost:9000
access.name: minioadmin 默认值
access.secret: minioadmin 默认值

注册核心Bean

@Configuration
public class MinioConfig {
@Value("${minio.url}")
private String endpoint;

@Value("${minio.access.name}")
private String accessKey;

@Value("${minio.access.secret}")
private String secretKey;

@Bean
public MinioClient minioClient() {
try {
读取配置文件中的参数值,构造者模式注册Bean
MinioClient minioClient = MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
return minioClient;
} catch (Exception e){
e.printStackTrace();
}
return null;
}

}

使用minio

创建桶

public Boolean createBucket(String name){
try {
查询桶是否存在,不存在则创建
boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
if (!isExist) {
构造者模式创建桶
minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
} else {
}
} catch (Exception e) {
}
return true;
}

删除桶

public Boolean deleteBucket(String name){
try {
minioClient.removeBucket(RemoveBucketArgs.builder().bucket(name).build());
} catch (Exception e) {
e.printStackTrace();
}
return true;
}

上传文件

public Boolean uploadVideoFile(String fileName, InputStream stream, String contentType) {
try {
String bucketName="video";
构造者模式将文件名、桶名、文件类型、文件流构造成一个对象,然后上传该对象到minio
minioClient.putObject(
PutObjectArgs.builder().bucket(bucketName).object(fileName)
.stream(stream, -1, 10485760)
.contentType(contentType)
.build());

stream.close();
return true;
} catch (Exception e) {
throw new RuntimeException("上传失败", e);
}
}

删除文件

public Boolean deleteBucket(String bucketName,String fileName){
try { minioClient.removeBucket(RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
} catch (Exception e) {
e.printStackTrace();
}
return true;
}

获取文件

public InputStream getObject(String objectName) {
try {
GetObjectArgs getObjectArgs = GetObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build();
return minioClient.getObject(getObjectArgs);
} catch (Exception e) {
log.error("错误:" + e.getMessage());
}
return null;
}

关于minio的使用有几点需要注意:

1.minio中同一个桶内不能有重名文件,类似windows系统一个文件夹下不能有重名文件,但windows会给重名文件中第二个上传的文件默认加后缀(1),而minio会直接覆盖前一个文件,因此有需求是上传同名文件时可以加前缀后缀如uuid区分开来

2.minio版本更新极快,因此不同的minio中间件版本和maven依赖版本组合的结果是不能百分百预测的,可能会出现未知bug,因此保险起见,最好不修改教程中的minio中间件版本和maven依赖,可以保证不出bug正常运行


xxl-job的使用

下载xxl-job执行器的管理器和执行器的jar包(https://labilibili.com/package/xxl-job)

修改xxl-job执行器配置


只需修改xxl-job连接数据库的用户名和密码

在本地数据库中创建xxl-job表

CREATE database if NOT EXISTS `xxl_job` default character set utf8mb4 collate utf8mb4_unicode_ci;
use `xxl_job`;
SET NAMES utf8mb4;
注意这段代码,这是适配Linux上的建表语句因为在Linux上才需要先指定用哪个数据库,若使用本机部署则可以把这段代码删掉,只需要在远程连接数据库软件比如dbeaver、navicat中先建数据库,然后在该数据库中新建sql编辑器,再将sql复制上去执行,若一次性执行有问题则需要一个表一个表的创建

启动xxl-job

该项目在idea中打开后上方默认就可以启动执行器管理器,启动后在浏览器地址栏输入http://localhost:8080/xxl-job-admin,自动重定向到登录页面


输入用户名admin和密码123456登录

执行器注册进管理器并执行任务

上方下载的执行器已改好配置,无需修改任何地方,在需要执行任务的方法上使用注解即可

@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");

for (int i = 0; i < 5; i++) {
XxlJobHelper.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
// default success
}

启动程序后在管理器中查看是否有注册进去

注册进去后在任务管理的某个任务右侧的操作按钮中选择执行一次

接下来的参数设置出于快速入门的目的不需要输入任何参数直接保存


在执行日志中选择某项任务右侧的操作,可查看日志

jave的使用

引入依赖

<dependency>
<groupId>ws.schild</groupId>
<artifactId>jave-all-deps</artifactId>
</dependency>

转码和获取视频相关信息

给将被转码的视频文件流提供一个文件路径和名字
String filePath = Files.createTempDirectory(".tmp").toString();
String videoFileName="video";
File file = new File(filePath, videoFileName);
将视频文件流转移到该File对象中
Files.copy(videoInputStream,Paths.get(file.getAbsolutePath()), StandardCopyOption.REPLACE_EXISTING);
将该File对象封装进转码工具对象中
MultimediaObject multimediaObject = new MultimediaObject(file);
获取视频信息
VideoInfo videoInfo = multimediaObject.getInfo().getVideo();
获取视频时长
Integer totalLength = Math.toIntExact(multimediaObject.getInfo().getDuration()) / 1000;
String length;
根据时长值拼接最后的字符串形式时长
if (totalLength / 60 < 1) {
if (totalLength % 60 < 10) {
length = "00:0" + totalLength;
} else {
length = "00:" + totalLength;
}
} else {
if (totalLength / 60 < 10) {
if(totalLength%60<10){
length = "0" + totalLength / 60 + ":0" + totalLength % 60;
}else {
length = "0" + totalLength / 60 + ":" + totalLength % 60;
}
} else {
length = totalLength / 60 + ":" + totalLength % 60;
}
}
videoMapper.updateById(updateVideo.setLength(length));
String rightFormat = "h264";
如果视频编码不是h264则浏览器播放不出来,需要转码
if (!rightFormat.equals(videoInfo.getDecoder())) {
String contentType = "video/mp4";
String outPutForMatType = "mp4";
VideoAttributes videoAttributes = new VideoAttributes();
创建转码后的结果文件
String targetFileName = "target";
File target = new File(filePath, targetFileName);
填装转码参数
videoAttributes.setCodec(rightFormat);
AudioAttributes audio = new AudioAttributes();
EncodingAttributes attrs = new EncodingAttributes();
设置转码后的输出格式为mp4
attrs.setOutputFormat(outPutForMatType);
attrs.setAudioAttributes(audio);
attrs.setVideoAttributes(videoAttributes);
创建核心转码工具类
Encoder encoder = new Encoder();
执行转码
encoder.encode(multimediaObject, target, attrs);
获取转码后的结果文件的文件流
FileInputStream inputStream = new FileInputStream(target);
以video/mp4格式重新上传minio
CustomMultipartFile customMultipartFile = new CustomMultipartFile(inputStream, uploadVideo.getUrl().substring(uploadVideo.getUrl().lastIndexOf("/") + 1)

截屏

public Result<String> getVideoCover(MultipartFile multipartFile) throws IOException, EncoderException {
创建截屏后的文件对象
String filePath = Files.createTempDirectory(".tmp").toString();
String coverFileName="coverFileName.jpg";
String videoFileName="video";
File videoFile=new File(filePath,videoFileName);
File coverFile1 = new File(filePath, coverFileName);
将视频流封装进截屏需要用到工具类
Files.copy(multipartFile.getInputStream(), Paths.get(videoFile.getAbsolutePath()), StandardCopyOption.REPLACE_EXISTING);
ScreenExtractor screenExtractor = new ScreenExtractor();
MultimediaObject multimediaObject = new MultimediaObject(videoFile);
截屏参数,可以修改1000的值为其他值,该值代表截屏视频第几秒的参数,其他的已设置好建议不要动,改参数输出结果暂时还未测试
screenExtractor.renderOneImage(multimediaObject, -1, -1, 1000, coverFile1, 1);
InputStream inputStream1 = new FileInputStream(coverFile1);

String img=Base64.encode(IoUtil.readBytes(inputStream1));
videoFile.delete();
coverFile1.delete();
return Result.data(img);
}

mybatis-plus-join的使用

mybatis-plus-join是mybatis-plus的增强版,可在业务层实现联表查询,解决了mybatis-plus无法多表查询的问题(作者多次测试结论是该框架在复杂多表查询时还存在欠缺,简单的多表查询可以用,复杂的多表查询不建议),下方mybatis-plus用法有疑问的可以在我之前的教程中学习

引入依赖

<dependency>
<groupId>com.github.yulichang</groupId>
<artifactId>mybatis-plus-join-boot-starter</artifactId>
</dependency>

在mybatis-plus基础上修改mapper写法

@Mapper
改为MpjBaseMapper,原有mybatis-plus单表增删改查功能不受影响
public interface PlayMapper extends MPJBaseMapper<Play> {
}

业务中使用该mapper

创建mpj的wrapper,泛型需和mapper一致
MPJLambdaWrapper<Play> wrapper=new MPJLambdaWrapper<>();
设置查询条件,同mybatis-plus
wrapper.eq(Play::getUserId,userId);
wrapper.orderByDesc(Play::getCreateTime);
选择查询后封装到的响应类中需要获取的表字段,若表对应的mybatis-plus实体类的java属性与响应类的字段一致则不需要第二个参数
wrapper.select(Play::getCreateTime);
否则需要特地指出如何映射
wrapper.selectAs(Video::getName, HistoryVideoResponse::getVideoName);
wrapper.select(Video::getLength);
wrapper.selectAs(Video::getId,HistoryVideoResponse::getVideoId);
wrapper.selectAs(Video::getCover,HistoryVideoResponse::getVideoCover);
wrapper.selectAs(User::getId,HistoryVideoResponse::getAuthorId);
wrapper.selectAs(User::getCover,HistoryVideoResponse::getAuthorCover);
wrapper.selectAs(User::getNickname, HistoryVideoResponse::getAuthorName);
核心表联接代码,innerJoin对应sql中内连接,leftjoin、rightjoin对应sql中左、右连接,第一二三个参数分别对应联接sql的参数,下方等效 play t inner join video t1 on video.id=play.video_id inner join user t2 on t2.id=t1.user_id,该框架按表出现顺序默认从t开始给表起别名,该特性在单表自连接查询和连接同一个其他表多次时会用到用于区分表
wrapper.innerJoin(Video.class,Video::getId,Play::getVideoId);
wrapper.innerJoin(User.class, User::getId,Video::getUserId);
List<HistoryVideoResponse> responses= playMapper.selectJoinList(HistoryVideoResponse.class,wrapper);
return Result.data(responses);
}


最后,宣传一下自己的仿b站前后端分离微服务项目,依赖版本号也在该项目的父pom.xml

实现了以下功能:

视频的上传、查看与上传时获取封面

视频的点赞、评论、可同时新增和删除多个收藏记录的收藏、多功能的弹幕

用户的个人信息查看编辑、用户之间的关注

用户的个人主页权限修改、查看、由个人主页权限动态决定的用户个人主页内容的获取

手机号、邮箱、图形验证码的多种方式登录

支持临时会话的服务器为代理的一对一实时私聊

基于讯飞星火的文生文、文生图、(全网首发)智能PPT

关注up动态视频、评论、点赞、私聊消息的生成与推送

基于es实现的视频和用户的聚合搜索、推荐视频

网关的路由和统一鉴权与授权

基于双token的七天内无感刷新token

防csrf、xss、抓包、恶意上传脚本攻击

统一处理异常和泛型封装响应体、自定义修改响应序列化值

简易的仿redis缓存读取与数据过期剔除实现

xxl-job+ redis+ rocketmq+ es+ 布隆过滤器的自定义es与mysql数据同步

slueth+zipkin的多服务间请求链路追踪

集中多服务日志到一个文件目录下与按需添加特定内容入日志

多服务的详细接口文档

项目地址LABiliBili,github地址GitHub - aigcbilibili/aigcbilibili: 仿bilibili前后端实现,演示地址https://labilibili.com/video/演示.mp4,如果大家觉得有帮助的话可以去github点个小星星♪(・ω・)ノ


0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
骆驼菜菜
作者分享
宣传下自己的仿B站前后端分离微服务开源项目
6
好久没冒泡过了,宣传下开源项目 仿B站前后端分离微服务项目 实现了以下功能: 视频的上传、查看、点赞、评论、收藏、弹幕(有分片上传与断点续传实现) 用户的个人信息查看编辑、关注 用户个人主页权限查看修改、个人主页内容获取 图形码、手机号、邮箱登录注册 一对一实时私聊 大模型文生文、文生图、智能PPT 关注UP动态、评论点赞私聊消息的生成与推送 视频和用户的聚合搜索、关键字补全、关键字高亮 项目亮点: 技术栈相当丰富且贴近企业需求:使用了当下企业开发最常用的可以快速开发单体应用的SpringBoot,保证了下限的基础上引用了SpringCloud系列组件搭建微服务提高上限,并使用了流行中间件Redis、RocketMQ、ElasticSearch,完整覆盖所有公司对Java应届生的要求,技术栈达到要求则过筛选率大大提高,且按需引入技术如实时连接Websocket、转码Jave等,体现出相对于大部分Java人更强的解决需求能力,进一步提供过筛选率,同时更广的技术栈代表可供面试官提问的点更多,也是可以自己提前准备主动引导面试官的点更多 技术亮点多:一份好的简历需要有足够多能和面试官细聊的地方,本项目亮点相当多,像分片上传、断点续传、数据同步流程、一对一实时私聊、集成大模型功能及全网首发的给出主题生成ppt所有文案实现等都足够和面试官展示军火相当久且可以延伸出足够多八股,将一场面试节奏完全掌握在自己手中 有详细完整最快落地的教程:从部署环境到前后端运行到接口调通有相当完整详细的教程,完全无需会一点前端知识,不用配置特定环境或特定包目录运行前端和解决任何前端相关bug即可启动前端,且运行所需包都可直接从作者文件床中获取无需在官网中找省去麻烦从而最快本机跑通项目功能,并附带项目技术栈使用讲解更快理解项目 有配套简历话术:配合现成简历话术极快改进简历,省去大量的反复修改简历时间 有java基础的情况下按照教程操作最快不到一天就能把仿b站项目本机运行起来 项目地址:https://labilibili.com,github地址https://github.com/aigcbilibili/aigcbilibili,已有240star,欢迎访问项目,给GitHub点个小星星就更好啦
12
原创仿b站前后端分离微服务开源项目
7
仿b站项目最终版 实现了以下功能: 视频的上传、查看、点赞、评论、收藏、弹幕(有分片上传与断点续传实现) 用户的个人信息查看编辑、关注 用户个人主页权限查看修改、个人主页内容获取 图形码、手机号、邮箱登录注册 一对一实时私聊 文生文、文生图、智能PPT 关注UP动态、评论点赞私聊消息的生成与推送 视频和用户的聚合搜索、关键字补全、关键字高亮1 项目亮点 重复度极低,项目需求都是作者一比一复刻分析b站功能决定的,在企业招聘需求减少招聘要求提高的当下意味着在简历筛选会得到远高于常人的被感兴趣程度(绝大部分Java人都是做的黑马尚硅谷项目或其余较流行项目,项目上的千篇一律导致hr及面试官对简历感兴趣程度较低,相对不愿意细看简历,且由于这些项目网上资料过多过详细容易被面试官判定为难度较小的项目而不能确定Java人是否高水平,以及对使用这些项目的人简历要求提高甚至见到简历写这些项目就直接丢弃) 技术栈相当丰富且贴近企业需求:使用了当下企业开发最常用的可以快速开发单体应用的SpringBoot,保证了下限的基础上引用了SpringCloud系列组件搭建微服务提高上限,并使用了流行中间件Redis、RocketMQ、ElasticSearch,完整覆盖所有公司对Java应届生的要求,技术栈达到要求则过筛选率大大提高,且按需引入技术如实时连接Websocket、转码Jave等,体现出相对于大部分Java人更强的解决需求能力,进一步提供过筛选率,同时更广的技术栈代表可供面试官提问的点更多,也是可以自己提前准备主动引导面试官的点更多 技术亮点多:一份好的简历需要有足够多能和面试官细聊的地方,本项目亮点相当多,像分片上传、断点续传、数据同步流程、一对一实时私聊、集成大模型功能及全网首发的给出主题生成ppt所有文案实现等都足够和面试官展示军火相当久且可以延伸出足够多八股,将一场面试节奏完全掌握在自己手中 有详细完整最快落地的教程:从部署环境到前后端运行到接口调通有相当完整详细的教程,且运行所需包都可直接从作者文件床中获取无需在官网中找省去麻烦从而最快本机跑通项目功能,并附带项目技术栈使用讲解更快理解项目 有配套简历话术:配合现成简历话术极快改进简历,省去大量的反复修改简历时间 技术栈 springboot:快速开发Java应用程序 security:具备强大的鉴权授权 nacos:服务注册与发现 openfeign:远程调用服务 gateway:请求入口与路由网关 redis:跨服务缓存 elasticsearch:更快的查询与更高的查询匹配度 rocketmq:异步处理队列 minio:文件对象存储 mybatis-plus:便捷执行单表增删改查 mybatis-plus-join:业务层多表查询 druid:阿里数据库连接池 jwt:token实现形式 swagger:接口文档 gson:谷歌序列化转换 hutool:集成众多工具类省去手动实现工具类 websocket:实时长连接 讯飞星火api:集成大模型功能 jave:视频操作,转码、压缩、截图、去水印等 xxl-job:分布式可视化定时任务 zipkin:请求链路追踪信息可视化ui slueth:发送请求链路追踪信息 相关教程 本机运行环境部署https://articles.zsxq.com/id_hvd3tkx3pq6v.html 前后端运行https://articles.zsxq.com/id_o9k66ma79cu0.html 前后端接口调通https://articles.zsxq.com/id_zx28jqj1euco.html 需求分析与需求实现思路https://articles.zsxq.com/id_rft27b8wfv2i.html 简历写法https://articles.zsxq.com/id_0nnixwez6516.html redis、mybatis-plus、es、rocketmq使用https://articles.zsxq.com/id_8mx58r4c7dr2.html websocket、spring security、swagger knife4j、openfeign的使用https://articles.zsxq.com/id_8coisfuz2ts5.html minio、xxl-job、jave、mybatis-plus-join的使用https://articles.zsxq.com/id_1c7w2j0a5gld.html zipkin sleuth、completableFuture、手机号邮箱号登录https://articles.zsxq.com/id_0pvpjum0ms82.html 项目地址 线上地址:https://labilibili.com,演示地址:https://labilibili.com/video/演示.mp4,github地址https://github.com/aigcbilibili/aigcbilibili ,欢迎访问项目,给GitHub点个小星星就更好啦
8
仿b站前后端分离微服务项目简历写法
6
下载 APP