欢迎大家关注我的以下主页,尤其是今日头条!!!谢谢🙏🙏🙏
csdn:雷园的csdn博客
个人博客:雷园的个人博客
简书:雷园的简书
今日头条:来自底层程序员的仰望
项目背景
-
在这里呢,我简单的说一下什么是图床。
-
经常写博客的同志们肯定会经常性的贴一些图片到博客当中,但是如果将图片跟随博文一起上传,那么会造成博客体积越来越大。
-
这个时候呢就该我们的图床上场了。
-
以前呢我经常用的是mac客户端的iPic,也确实是非常的好用尤其是可以与Typora结合,可以自动上传并转换图片地址为外网链接。
-
但是免费的图床时隔一段时间后,图片会自动失效,会导致你的博客成了这个样子:
属实是非常的难受,因为有好多东西我都不记得了。。。这个样子像是丢失了记忆一样。
-
当然啦,他也不是只有免费的,还有收费,那自然是非常的好用了,方便快捷速度也很快,不过要收费的。因为个人收入不高,所以没有花钱去支持他们,只好自己动手做一个简易的图床啦。
项目简介
- 虽然项目非常简单,但是我还是简单的介绍一下技术选型。
- 编程语言我选择了我最擅长的Java。
- 服务端框架我选择了构建速度最快的SpringBoot。
- 前端代码非常简单,我选择了HTML、JavaScript以及jquery。
- 文件服务我选择了FastDfs以及Nginx。
- 服务器版本我选择了Tomcat9。
- “云主机”选型。
- 这里为什么打上双引号呢,因为云主机呢,着实是挺贵的,所以呢我选择了在本地PC上搭建,然后通过一台低配置的VPS进行端口映射,实现外网访问。
- 但是呢本地的PC、运行这些个东西也挺是费劲的,所以我还选择了使用Docker实现部署。
- 可见呢项目虽小却也是“五脏俱全”。
- 简单说一下为什么要使用Docker。
- 首先呢,FastDfs无论是配置还是启动运行,都比较费劲,我记得初次搭建的时候耗费了很长的时间。
- 经过一次搭建我就受够了它,所以我选择了使用DockerFile构建一个开箱即用的FastDfs镜像,这样以来无论到什么样的系统环境当中,只要可以运行Docker我就可以非常快速的构建起来一个fdfs文件服务系统。
- 多次的应用也证明了我的想法是没有错的。
项目功能描述
-
此项目主要是实现简单的图片拖拽上传,并返回上传后的图片链接以及预览图展示,可实现拖拽多图片实现同时上传,点击图片自动复制图片链接。效果图如下
-
待实现功能:
- 分用户实现上传。
- 分用户实现上传记录。
- 分用户实现已上传文件管理。
项目结构
-
web项目结构如下:
咳咳!!!不要笑不要笑~~
-
Java服务端项目结构如下
同样也是非常的简单哈!
-
由上可见我们的项目结构是非常的简单的。
项目代码实现
-
虽然web项目只有一个页面,但是我们还是要说一下的哈。页面中的css我就不细说了,感兴趣的可以看一下我的js代码,不然的话直接Copy也可以的哦。
<html lang="en"> <style> body { height: 100%; padding: 0; margin: 0; } .outer { height: 100%; padding: 100px 0 0; box-sizing: border-box; } .A { height: 100px; margin: -100px 0 0; background: #BBE8F2; } .B { height: 100%; background: #D9C666; } </style> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body class="outer"> <div id="area" class="A">将图片拖拽到此区域</div> <div id="preview" class="B"></div> <script src="http://code.jquery.com/jquery-latest.js"></script> <script> $(document).on({ dragleave: function (e) { //拖离 e.preventDefault(); }, drop: function (e) { //拖后放 e.preventDefault(); }, dragenter: function (e) { //拖进 e.preventDefault(); }, dragover: function (e) { //拖来拖去 e.preventDefault(); } }); var box = document.getElementById('area'); //拖拽区域 box.addEventListener("drop", function (e) { e.preventDefault(); //取消默认浏览器拖拽效果 var fileList = e.dataTransfer.files; //获取文件对象 //检测是否是拖拽文件到页面的操作 if (fileList.length == 0) { return false; } //上传 xhr = new XMLHttpRequest(); // 这里的false参数代表使用同步方式提交表单 xhr.open("post", "http://ip:port/uploadFile", false); xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); // 创建一个表单 var fd = new FormData(); //检测文件是不是图片,同样服务端也可以对文件类型做限制,但实际上fdfs对于上传文件并无格式要求 for (var i = 0; i < fileList.length; i++) { if (fileList[i].type.indexOf('image') === -1) { alert("您拖的不是图片!"); return false; } // 因为实现多图片上传,所以循环将所有图片都添加到files元素当中 fd.append('files', fileList[i]); } // 提交表单 xhr.send(fd); // 等待请求结果 if (xhr.status === 200) { // 若服务端返回code为SUC则代表处理成功 if ($.parseJSON(xhr.responseText).code == "SUC") { var str = ""; // 对返回的图片链接列表urlList进行处理 for (var i = 0; i < $.parseJSON(xhr.responseText).urlList.length; i++) { // 动态拼接html元素,元素内容为上传后的预览图片以及图片链接 str = str + "<a href='javascript:void(0);' onclick='CopyUrl(" + i + ")'><img style='width: 150px' src='" + $.parseJSON(xhr.responseText).urlList[i] + "'/></a><e>点击图片复制链接:<input id='img" + i + "' style='width: 50%' value=' " + $.parseJSON(xhr.responseText).urlList[i] + "' readonly/></e><br/>"; } // 将拼接结果展示到页面中 $("#preview").html(str); } } }, false ); // 实现点击图片自动复制图片链接 function CopyUrl(id) { document.getElementById("img" + id).select(); document.execCommand("copy"); } </script> </body> </html>
-
接下来我们就说一下服务端的Java代码实现:
-
先来说一下Idea下的SpringBoot项目创建吧,说的仔细一点虽然啰嗦却也是对小白的一种福利,大佬们尽管跳过这段好了。
-
依照此步骤创建项目即可,接下来我们说一下代码。
-
先来说一下我们需要手动引入的依赖,先来看pom.xml
<!-- druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.10</version> </dependency> <!-- fdfs --> <dependency> <groupId>com.github.tobato</groupId> <artifactId>fastdfs-client</artifactId> <version>1.26.2</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
-
提前解惑:虽然我们当前的版本中暂时没有用涉及到数据库存储,但我们后期会加入相关的数据留存以及权限等等。而且我们在项目创建中选择了mysql数据库,根据springboot的启动要求我们必须在启动配置项当中配置数据库相关参数,否则无法正常启动项目。而为了日后方便拓展开发,我们选择使用阿里的Druid数据源进行配置。关于为什么引入lombok,完全是因为个人习惯,虽然我们的项目结构中只有一个vo类,但难免以后会增多,加入lombok省去了我们很多的麻烦,虽然可以IDEA可以自动生成,但是也比不过什么都不用操作来的好!!!而FDFS相关包是我们当前版本的核心,我们需要依赖于这个包进行文件的上传等操作。
-
接下来我们看一下项目配置,application.yml。当然大家也可以使用application.properties,个人比较习惯使用yml。
server: port: 8081 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://192.168.6.23:3306/qingongzhuxue?characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false username: root password: root thymeleaf: prefix: classpath:/templates/ suffix: .html mode: HTML5 fdfs: connect-timeout: 600 so-timeout: 1500 thumb-image: width: 150 height: 150 tracker-list: - fdfs:22122 # 这个配置项是我自定义的配置项,后面的代码中会用到 head: url: http://ip:6001/
-
来看一下我们唯一的vo类,FileUploadResponse.java
package com.leiyuan.tuchuang.vo; import lombok.Data; import java.util.List; /** * //////////////////////////////////////////////////////////////////// * // _ooOoo_ // * // o8888888o // * // 88" . "88 // * // (| ^_^ |) // * // O\ = /O // * // ____/`---'\____ // * // .' \\| |// `. // * // / \\||| : |||// \ // * // / _||||| -:- |||||- \ // * // | | \\\ - /// | | // * // | \_| ''\---/'' | | // * // \ .-\__ `-` ___/-. / // * // ___`. .' /--.--\ `. . ___ // * // ."" '< `.___\_<|>_/___.' >'"". // * // | | : `- \`.;`\ _ /`;.`/ - ` : | | // * // \ \ `-. \_ __\ /__ _/ .-` / / // * // ========`-.____`-.___\_____/___.-`____.-'======== // * // `=---=' // * // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // * // 佛祖保佑 永不宕机 永无BUG // * //////////////////////////////////////////////////////////////////// * * @author 来自底层程序员的仰望 * @ClassName FileUploadResponse * @date 2019-07-29 15:49 * <p></p> **/ @Data public class FileUploadResponse { // 错误代码 private String code; // 上传成功后的图片链接列表 private List<String> urlList; }
嗯!!!就是这个效果,拜倒在我的注释之下吧!!!
-
然后就是看看我们唯一的Controller:TestController.java:
package com.leiyuan.tuchuang.controller; import com.leiyuan.tuchuang.vo.FileUploadResponse; import com.github.tobato.fastdfs.domain.StorePath; import com.github.tobato.fastdfs.service.FastFileStorageClient; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * //////////////////////////////////////////////////////////////////// * // _ooOoo_ // * // o8888888o // * // 88" . "88 // * // (| ^_^ |) // * // O\ = /O // * // ____/`---'\____ // * // .' \\| |// `. // * // / \\||| : |||// \ // * // / _||||| -:- |||||- \ // * // | | \\\ - /// | | // * // | \_| ''\---/'' | | // * // \ .-\__ `-` ___/-. / // * // ___`. .' /--.--\ `. . ___ // * // ."" '< `.___\_<|>_/___.' >'"". // * // | | : `- \`.;`\ _ /`;.`/ - ` : | | // * // \ \ `-. \_ __\ /__ _/ .-` / / // * // ========`-.____`-.___\_____/___.-`____.-'======== // * // `=---=' // * // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // * // 佛祖保佑 永不宕机 永无BUG // * //////////////////////////////////////////////////////////////////// * * @author 雷园 * @ClassName TestController * @date 2019-07-29 14:59 * <p></p> **/ // 设置全局返回为json @RestController("/") // 设置允许跨域访问 @CrossOrigin(origins = "*", maxAge = 3600) public class TestController { // 自动注入fdfs @Autowired private FastFileStorageClient storageClient; // 获取配置文件中的值,也就是上面所说的我自定义的配置变量 @Value("${fdfs.head.url}") private String url; /** * * @param files 文件数组 * @return FileUploadResponse * @throws IOException 抛出IO异常 */ @PostMapping(value = "/uploadFile") public FileUploadResponse uploadFile(MultipartFile[] files) throws IOException { // 初始化一个列表 List<String> urlList = new ArrayList<>(); // 循环文件数组将文件上传 for (MultipartFile file : files) { // 文件上传 StorePath storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(),FilenameUtils.getExtension(file.getOriginalFilename()), null); // 拼接图片地址 urlList.add(url + storePath.getGroup() + "/" + storePath.getPath()); } // 组合返回数据 FileUploadResponse fileUploadResponse = new FileUploadResponse(); fileUploadResponse.setCode("SUC"); fileUploadResponse.setUrlList(urlList); return fileUploadResponse; } }
-
最后我们看一下启动类:TuchuangApplication.java
package com.leiyuan.tuchuang; import com.github.tobato.fastdfs.FdfsClientConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.EnableMBeanExport; import org.springframework.context.annotation.Import; import org.springframework.jmx.support.RegistrationPolicy; // 这里加入fdfs配置类 @Import(FdfsClientConfig.class) // 解决启动异常的问题 @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) @SpringBootApplication public class TuchuangApplication { public static void main(String[] args) { SpringApplication.run(TuchuangApplication.class, args); } }
-
-
到这里,我们的代码算是写完了,接下来就是使用Docker进行部署了。
结束语
- 此篇幅有些过长了,有关部署的部分,大家请查看我的下一篇文章,如何利用Docker快捷部署私人图床工具;
- 作为程序员的我当然对于算法分析以及Java、Python、Go同样有着浓厚的兴趣,相信我们可以在技术的道路上走的更远。
- 对于Docker还要多说两句,作者最近在学习和应用docker-compose编排以及docker swarm集群部署,手头也有很多闲置的服务器用来练手,希望同样感兴趣的同学们可以私我或者评论我们多多交流学习心得。
- 谢谢大家!!!