FastDFS (五) --------- FastDFS 在 web 项目中的应用
目录
- 前言
- 一、数据库环境搭建
- 二、开发环境搭建
- 三、功能设计
- 1. 展示所有债权信息
- 2. 为某一个债权合同上传文件
- 3. 下载某一个债权合同
- 4. 删除某一个债权合同,使用 ajax 实现异步删除
前言
本篇文章我们主要介绍 FastDFS 在 web 项目中的应用,通过完成 一个 P2P 项目合同管理的例子,在 WEB 项目中实现对文件的上传、下载和删除操作。
我们做这个项目的主要目标是 :
- 实现对 pdf 文件上传、下载、删除
- 熟练使用 Springboot + thymeleaf
一、数据库环境搭建
A、创建数据库 fastdfs
B、在该库下创建 creditor_info 表
CREATE TABLE `creditor_info` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`realName` varchar(35) DEFAULT NULL COMMENT '债权借款人姓名',`idCard` varchar(18) DEFAULT NULL COMMENT '债权借款人身份证',`address` varchar(150) DEFAULT NULL COMMENT '债权借款人地址',`gender` int(1) DEFAULT NULL COMMENT '1男2女',`phone` varchar(11) DEFAULT NULL COMMENT '债权借款人电话',`money` decimal(10,2) DEFAULT NULL COMMENT '债权借款人借款金额',`groupName` varchar(10) DEFAULT NULL COMMENT '债权合同所在组',`remoteFilePath` varchar(150) DEFAULT NULL COMMENT '债权合同所在路径',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
二、开发环境搭建
A、创建 SpringBoot 项目 fastdfs-web,添加 Web 和 Thymeleaf 依赖
B、在 pom.xml 文件中添加 Mybatis 依赖及 MySQL 依赖
!-- 加载mybatis整合springboot -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><!--在springboot的父工程中没有指定版本,我们需要手动指定--><version>1.3.2</version>
</dependency>
<!-- MySQL的jdbc驱动包 -->
<dependency><groupId>mysql</groupId><!--在springboot的父工程中指定了版本,我们就不需要手动指定了--><artifactId>mysql-connector-java</artifactId>
</dependency>
C、在pom.xml文件中添加resources,指定编译的位置
<resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource><!--如果存在jsp,需要指定jsp文件编译的位置-->
</resources>
D、在 SpringBoot 主配置文件 application.properties 中添加数据库配置信息
#数据库的连接配置信息
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.160.133:3306/fastdfs?useUnicode=true&characterEncoding=utf8&useSSL=false
E、创建相关的包和类
创建 controller,model,mapper,service 包,及其子包 impl。
创建 CreditorInfoController 类、CreditorInfoService 接口、创建 CreditorInfoServiceImpl 实现类。
F、实体类
package com.fancy.fastdfsweb.mapper;public class CreditorInfo {private Integer id;private String realName;private String idCart;private String address;private Integer gender;private String phone;private Double money;private String groupName;private String remoteFilePath;public CreditorInfo() {}public CreditorInfo(Integer id, String realName, String idCart, String address, Integer gender, String phone, Double money, String groupName, String remoteFilePath) {this.id = id;this.realName = realName;this.idCart = idCart;this.address = address;this.gender = gender;this.phone = phone;this.money = money;this.groupName = groupName;this.remoteFilePath = remoteFilePath;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getRealName() {return realName;}public void setRealName(String realName) {this.realName = realName;}public String getIdCart() {return idCart;}public void setIdCart(String idCart) {this.idCart = idCart;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Integer getGender() {return gender;}public void setGender(Integer gender) {this.gender = gender;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}public String getGroupName() {return groupName;}public void setGroupName(String groupName) {this.groupName = groupName;}public String getRemoteFilePath() {return remoteFilePath;}public void setRemoteFilePath(String remoteFilePath) {this.remoteFilePath = remoteFilePath;}
}
三、功能设计
1. 展示所有债权信息
A、在 CreditorInfoController 类中创建 index 方法,将 CreditorInfoService 注入到 controller 中
@Autowired
private CreditorInfoService creditorInfoService;@GetMapping("/fastdfs/index")
public String index(Model model) {List<CreditorInfo> creditorInfoList = creditorInfoService.getAllCreditorInfo();model.addAttribute("creditorInfoList", creditorInfoList);//模板页面, 不是 jspreturn "index";
}
B、在 CreditorInfoService 中提供 getAllCreditorInfo 方法
package com.fancy.fastdfsweb.service;import com.fancy.fastdfsweb.model.CreditorInfo;import java.util.List;public interface CreditorInfoService {List<CreditorInfo> getAllCreditorInfo();
}
C、在 CreditorInfoServiceImpl 中对 getAllCreditorInfo 方法进行实现
package com.fancy.fastdfsweb.service.impl;import com.fancy.fastdfsweb.model.CreditorInfo;
import com.fancy.fastdfsweb.service.CreditorInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class CreditorInfoServiceImpl implements CreditorInfoService {@Autowiredprivate CreditorMapper creditorInfoMapper;@Overridepublic List<CreditorInfo> getAllCreditorInfo() {return creditorInfoMapper.selectAllCreditorInfo();}
}
D、在 CreditorMapper 接口中定义 selectAllCreditorInfo 方法
package com.fancy.fastdfsweb.mapper;import com.fancy.fastdfsweb.model.CreditorInfo;
import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper
public interface CreditorMapper {List<CreditorInfo> selectAllCreditorInfo();
}
E、在 IDEA 中安装 free Mybatis 插件
插件可以通过点击 Mapper 接口中的方法,进入到 .xml
文件
F、定义 mapper 映射文件相关 SQL 语句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fancy.fastdfsweb.mapper.CreditorMapper"><select id="selectAllCreditorInfo" resultType="com.fancy.fastdfsweb.model.CreditorInfo">select * from creditor_info;</select>
</mapper>
G、展示页面的设计
在项目的 templates 目录下创建 index.html,初步展示出数据库中数据
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="utf-8"><title>债权合同管理</title><link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"><script th:src="@{/js/jquery-3.6.0.min.js}"></script><script th:src="@{/js/bootstrap.min.js}"></script>
</head>
<body style="margin: 50px"><table class="table table-striped"><caption>债权合同信息列表</caption><thead><tr><th>序号</th><th>债权借款人姓名</th><th>债权借款人身份证</th><th>债权借款人住址</th><th>债权借款人手机号</th><th>债权借款人性别</th><th>债权借款人借款金额</th></tr></thead><tbody><tr th:each="creditorInfo:${creditorInfoList}"><td th:text="${creditorInfoStat.count}"></td><td th:text="${creditorInfo.realName}"></td><td th:text="${creditorInfo.idCard}"></td><td th:text="${creditorInfo.address}"></td><td th:text="${creditorInfo.phone}"></td><td th:text="${creditorInfo.gender == 1 ?'男':'女'}"></td><td th:text="${creditorInfo.money}"></td></tr></tbody></table>
</body>
</html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
在 html 标签上加上 Thymeleaf 的命名空间
H、向数据库中加几条数据
I、启动项目,访问 http://localhost:8080/fastdfs/index 查看效果
2. 为某一个债权合同上传文件
A、在 index.html 中添加操作列
<th>合同管理</th>
<td><a th:href="@{'/fastdfs/toUpload?id=' + ${creditorInfo.id}}">上传</a></td>
B、在 CreditorController 中添加跳转到上传页面的方法 toUpload
@GetMapping("/fastdfs/toUpload")
public String toUpload(Model model, @RequestParam("id") Integer id) {model.addAttribute("id", id);return "upload";
}
C、在 templates 下创建 upload.html 页面
!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="utf-8"><title>债权合同上传</title><link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"><script th:src="@{/js/jquery-3.6.0.min.js}"></script><script th:src="@{/js/bootstrap.min.js}"></script>
</head>
<body><form th:action="@{/fastdfs/upload}" class="form-inline" role="form" method="post" enctype="multipart/form-data"><div class="form-group"><label class="sr-only" for="fileName">文件输入</label><input type="file" id="fileName" name="fileName"></div><input type="hidden" name="id" th:value="${id}"><button type="submit" class="btn btn-default">提交</button></form>
</body>
</html>
☹ 文件上传必须是 post 请求
☹ enctype 必须为 multipart/form-data, 该属性规定在发送到服务器之前应该如何对表单数据进行编码。
☹ 合同的 id 通过隐藏域传递
D、在 pom.xml 文件中加入 FastDFS 客户端的 jar 包依赖
<dependency><groupId>net.oschina.zcx7878</groupId><artifactId>fastdfs-client-java</artifactId><version>1.27.0.0</version>
</dependency>
E、将 FastDFS 客户端的配置文件 fast_client.conf 拷贝到 resources 目录下
F、将原来我们封装的 FastDFS 类拷贝到 fastdfs 包下,修改其中的 file_upload 方法,定义一些参数
public static String[] fileUpload(byte[] fileBytes, String fileExt){String[] uploadArray = null;try {//1. 获取StorageClient对象StorageClient storageClient = getStorageClient();//2.上传文件 第一个参数:本地文件路径 第二个参数:上传文件的后缀 第三个参数:文件信息uploadArray = storageClient.upload_file(fileBytes,fileExt,null);} catch (IOException e) {e.printStackTrace();} catch (MyException e) {e.printStackTrace();} finally {closeFastDFS();}return uploadArray;
}
G、在 CreditorController 中添加处理上传文件的方法
@PostMapping("/fastdfs/upload")
@ResponseBody
public String upload(@RequestParam("id") Integer id, @RequestParam("fileName")MultipartFile file) {// 原来文件上传是将文件写到本地或者远程服务器的某个目录下// 现在的文件上传是将文件上传到 fastdfs 文件服务器上// 1表示上传失败 0表示成功int result = 1;//abc.txt -->txtString fileExt = file.getOriginalFilename().substring(file.getOriginalFilename().indexOf(".") + 1);try {String[] uploadArray = FastDFSUtil.fileUpload(file.getBytes(), fileExt);if (uploadArray != null && uploadArray.length == 2) {// 文件上传到fastDFS成功 ,将合同文件路径更新到债权记录中CreditorInfo creditorInfo = new CreditorInfo();creditorInfo.setId(id);creditorInfo.setGroupName(uploadArray[0]);creditorInfo.setRemoteFilePath(uploadArray[1]);int updateRow = creditorInfoService.updateCreditorInfo(creditorInfo);if (updateRow > 0) {result = 0;}}} catch (IOException e) {e.printStackTrace();}return "<script>window.parent.uploadOK('" + result + ")</script>";
}
H、在 CreditorInfoService 中添加 updateCreditorInfo 方法
int updateCreditorInfo(CreditorInfo creditorInfo);
I、在 CreditorInfoServiceImpl 中添加 updateCreditorInfo 方法实现
@Override
public int updateCreditorInfo(CreditorInfo creditorInfo) {return creditorInfoMapper.updateCreditorInfo(creditorInfo);
}
J、在 CreditorMapper 中定义方法 updateCreditorInfoById
int updateCreditorInfo(CreditorInfo creditorInfo);
K、定义 mapper 中插入语句
<update id="updateCreditorInfo" parameterType="com.fancy.fastdfsweb.model.CreditorInfo">update creditor_info set groupName = #{groupName} , remoteFilePath = #{remoteFilePath} where id = #{id};
</update>
L、在 upload.html 做一个类似 ajax 的页面不刷新效果
在 upload.html 页面中加一个 iframe。
将 upload.html 页面中的 form 中的 target 设置为 iframe 的 name。
在 iframe 的父页面中,写一个函数,处理上传结果。
<iframe name="uploadFrame" style="display: none;"></iframe><script type="text/javascript" th:inline="javascript">function uploadOK(result){if(result == 0){//文件上传成功alert("文件上传成功");var contextPath = [[${#request.getContextPath()}]];window.location.href = contextPath + "/fastdfs/index";}else{alert("文件上传失败");}}</script>
M、如果上传文件超出了 1M,需要在 application.properties 中配置 SpringBoot 上传文件的最大限制
3. 下载某一个债权合同
A、修改 index.html 页面,下载加连接,并做判断
<span th:if="${creditorInfo.getGroupName() ne null && creditorInfo.getRemoteFilePath() ne null }"><a th:href="@{'/fastdfs/download?id=' + ${creditorInfo.id}}">下载</a>
</span>
B、在 CreditorController 中,完成下载的请求
☹ ResponseEntity 通常用于返回文件流。
☹ @ResponseBody 可以直接返回Json结果。
☹ ResponseEntity 不仅可以返回 json 结果,还可以定义返回的 HttpHeaders 和 HttpStatus。
☹ ResponseEntity 的优先级高于 @ResponseBody,在不是 @ResponseEntity 的情况下才去检查有没有 @ResponseBody 注解。如果响应类型是ResponseEntity 可以不写 @ResponseBody 注解,写了也没有关系。
@GetMapping("/fastdfs/download")
public ResponseEntity<byte[]> download(@RequestParam("id") Integer id) {CreditorInfo creditorInfo = creditorInfoService.getAllCreditorInfo(id);String extName = creditorInfo.getRemoteFilePath().substring(creditorInfo.getRemoteFilePath().indexOf("."));byte[] fileBytes = FastDFSUtil.fileDownload(creditorInfo.getGroupName(), creditorInfo.getRemoteFilePath());HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);//流类型httpHeaders.setContentDispositionFormData("attachment", System.currentTimeMillis() + extName);ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(fileBytes, httpHeaders, HttpStatus.OK);return responseEntity;
}
C、在 CreditorService 接口中添加 getCreditorInfoById 的方法
CreditorInfo getCreditorInfoById(Integer id);
D、在 CreditorServiceImpl 中添加 getCreditorInfoById 方法的实现
@Override
public CreditorInfo getCreditorInfoById(Integer id) {return creditorInfoMapper.selectCreditorInfoById();
}
E、定义 mapper 类及其配置文件 selectCreditorInfoById 方法
F、修改 FastDFS 类中 fileDown 方法的实现,传递参数
public static byte[] fileDownload(String groupName, String remoteFilePath){byte[] fileBytes = null;try {//1. 获取StorageClient对象StorageClient storageClient = getStorageClient();//2.下载文件 返回0表示成功,其它均表示失败fileBytes = storageClient.download_file(groupName, remoteFilePath);} catch (IOException e) {e.printStackTrace();} catch (MyException e) {e.printStackTrace();} finally {closeFastDFS();}return fileBytes;
}
4. 删除某一个债权合同,使用 ajax 实现异步删除
A、在 index.html 页面为删除加超链接
<a th:href="@{'javascript:deleteFile(' + ${creditorInfo.id} + ')'}">删除</a>
此超链接与删除放在同一个span中
B、index.html 页面提供 js 方法,并发送 ajax 请求,对响应结果进行处理
<script type="text/javascript" th:inline="javascript">function deleteFile(id) {var contextPath = [[${#request.getContextPath()}]];$.ajax({url:contextPath + "/fastdfs/fileDelete",type:"post",data:{"id" : id},success:function(responseMsg) {if (responseMsg == 0) {alert("删除成功");window.location.reload();} else {alert("删除失败");}}});}</script>
C、在 CreditorController 中处理删除请求
注意:删除 FastDFS 和清除数据库,所以我们将这些业务都放在 service 中进行事务的处理
@RequestMapping("/fastdfs/fileDelete")
@ResponseBody
public String fileDelete(@RequestParam("id") Integer id) {int result = 1;try {result = creditorInfoService.deleteContract(id);} catch (Exception e) {e.printStackTrace();}return String.valueOf(result);
}
D、在 CreditorService 接口中加删除合同的方法 deleteContract
因为目前提供的方法,如果 group 和 remoteFilePath 为空就不更新,所以我们需要自己提供。
E、在 CreditorServiceImpl 类中对 deleteContract 方法进行实现
@Override
@Transactional //加上该注解控制事务
public int deleteContract(Integer id) {int result = 1;//根据债权id获取债权信息CreditorInfo creditorInfo = creditorInfoMapper.selectCreditorInfoById(id);//注意:事务控制的数据库,所以我们先对数据库进行更新, 在操作FastDFS, 如果操作FastDFS失败了,那么对数据库的操作回滚int updateRow = creditorInfoMapper.updateContractById(id);if (updateRow > 0) {// 如果数据库更新, 那么删除 FastDFS 的文件if (updateRow > 0) {int num = FastDFSUtil.fileDelete(creditorInfo.getGroupName(), creditorInfo.getRemoteFilePath());if (num == 0) {result = 0;} else {throw new RuntimeException("FastDFS 文件删除失败");}}}return result;
}
F、在 CreditorMapper 类中添加更新的方法
int updateContractById(Integer id);
G、在 CreditorMapper.xml 中添加更新的方法
<update id="updateContractById" parameterType="java.lang.Integer">update creditor_info set groupName = NULL, remoteFilePath = NULL where id = #{id, jdbcType=INTEGER}
</update>
H、修改 FastDFS 类中的 fileDelete 方法,提供参数
public static int fileDelete(String groupName, String remoteFilePath){int num = 1;try {//1. 获取StorageClient对象StorageClient storageClient = getStorageClient();//2.删除文件 返回0表示成功,其它均表示失败num = storageClient.delete_file(groupName, remoteFilePath);} catch (IOException e) {e.printStackTrace();} catch (MyException e) {e.printStackTrace();} finally {closeFastDFS();}return num;
}
I、在 Application 类上开启事务支持
然后在浏览器中进行测试即可
如果想要美化弹窗,推荐使用 弹层组件 layer,官网 :https://www.layui.com/
FastDFS (五) --------- FastDFS 在 web 项目中的应用相关推荐
- JAVA Web项目中所出现错误及解决方式合集(不断更新中)
JAVA Web项目中所出现错误及解决方式合集 前言 一.几个或许会用到的软件下载官网 二.Eclipse的[preferences]下没有[sever]选项 三.Tomcat的安装路径找不到 四.T ...
- 编写高质量代码改善java程序的151个建议——[110-117]异常及Web项目中异常处理
编写高质量代码改善java程序的151个建议--[110-117]异常及Web项目中异常处理 原创地址:http://www.cnblogs.com/Alandre/(泥沙砖瓦浆木匠),需要转载的,保 ...
- maven mybatis mysql_Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问...
标签: 本篇内容还是建立在上一篇Java Web学习系列--Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Ja ...
- 在java web项目中编写自己的代码生成器
在java web项目中编写自己的代码生成器 转载于:https://www.cnblogs.com/punisher/p/5909943.html
- 在web项目中发布jaxws
概述 在web项目中发布基于jaxws的webservice. 参考文章:用JAX-WS在Tomcat中发布WebService 参考文章说,如果不是servlet3.0及以上,需要配置servlet ...
- Web项目中引进EasyUI的路径问题
场景 Web项目中引入EasyUI,新建test.html,页面中引入EasyUI相关资源文件. 运行后页面并没有改变,打开检查提示404找不到资源. 实现 项目路径为: 路径引用错误: test.h ...
- 由web项目中上传图片所引出的路径问题
我在做javaweb项目的时候,有个项目中需要进行图片的上传,有次我重新部署项目后,发现之前上传的图片不见了,最后找出原因:图片上传在服务器目录上,而不是绝对路径,所以特别想弄清楚javaweb项目中 ...
- maven web项目中的web.xml的版本如何更改
maven web项目中的web.xml的版本如何更改 问题 因web.xml的版本太低不支持el表达式的问题(maven3.6版本通过底层的maven web插件生成的最终的web.xml文件版本只 ...
- 在java web项目中实现随项目启动的额外操作
前言 在web项目中经常会遇到在项目启动初始,会要求做一些逻辑的实现,比如实现一个消息推送服务,实现不同类型数据同步的回调操作初始化,或则通知其他客户服务器本项目即将启动,等等.对于这种要求,目前个人 ...
最新文章
- 浅析C# new和override的区别
- vue.config.js配置
- Redis随笔Jedis、jedisCluster的使用
- Apache 和 Tomcat 服务器的区别
- oracle使用with as提高查询效率
- python算法程序_浅谈python常用程序算法
- Kafka开源转商业实践,助力车主无忧系统稳健 | 凌云时刻
- 高等数学 第七版 上册 下册 答案
- 电视盒子_刷机固件_免费合集分享
- 贪吃蛇-单机游戏-微信小程序项目开发流程详解
- 这些好用的抠图软件,助你实现一键抠图
- 实用工具篇--华为eNSP下载及安装
- ATSC和DVB数字电视系统的比较
- 计算机运行异常怎么办,电脑开机出现windows错误恢复怎么办
- (转)wuauclt.exe病毒解决方案
- 调起APP功能的实现
- 读书笔记,《刻意练习》,第四章,黄金标准
- 学习期间的感悟和个人写的一段歌词
- android手机刷ios6,2017安卓手机刷机方法
- 阿里云云栖社区合作指南
热门文章
- 【初学音频】Android的Audio系统之AudioTrack
- AudioTrack介绍
- matlab中一组数取百分位数,matlab求百分位数
- C语言内存使用的常见问题及解决之道
- 使用广播信道的数据链路层
- java 碳架山地车寿命_碳架自行车的好处和坏处
- 耶鲁大学计算机科学录取,美国TOP3耶鲁大学计算机科学硕士录取
- 4x4矩阵键盘扫描c语言程序,单片机4*4矩阵键盘扫描程序(c语言+汇编语言2个版本)...
- Python爬虫之scrapy高级(全站爬取,分布式,增量爬虫)
- 单片机C语言学习之移位相减16位除法