目录

  • 前言
  • 一、数据库环境搭建
  • 二、开发环境搭建
  • 三、功能设计
    • 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 项目中的应用相关推荐

  1. JAVA Web项目中所出现错误及解决方式合集(不断更新中)

    JAVA Web项目中所出现错误及解决方式合集 前言 一.几个或许会用到的软件下载官网 二.Eclipse的[preferences]下没有[sever]选项 三.Tomcat的安装路径找不到 四.T ...

  2. 编写高质量代码改善java程序的151个建议——[110-117]异常及Web项目中异常处理

    编写高质量代码改善java程序的151个建议--[110-117]异常及Web项目中异常处理 原创地址:http://www.cnblogs.com/Alandre/(泥沙砖瓦浆木匠),需要转载的,保 ...

  3. maven mybatis mysql_Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问...

    标签: 本篇内容还是建立在上一篇Java Web学习系列--Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Ja ...

  4. 在java web项目中编写自己的代码生成器

    在java web项目中编写自己的代码生成器 转载于:https://www.cnblogs.com/punisher/p/5909943.html

  5. 在web项目中发布jaxws

    概述 在web项目中发布基于jaxws的webservice. 参考文章:用JAX-WS在Tomcat中发布WebService 参考文章说,如果不是servlet3.0及以上,需要配置servlet ...

  6. Web项目中引进EasyUI的路径问题

    场景 Web项目中引入EasyUI,新建test.html,页面中引入EasyUI相关资源文件. 运行后页面并没有改变,打开检查提示404找不到资源. 实现 项目路径为: 路径引用错误: test.h ...

  7. 由web项目中上传图片所引出的路径问题

    我在做javaweb项目的时候,有个项目中需要进行图片的上传,有次我重新部署项目后,发现之前上传的图片不见了,最后找出原因:图片上传在服务器目录上,而不是绝对路径,所以特别想弄清楚javaweb项目中 ...

  8. maven web项目中的web.xml的版本如何更改

    maven web项目中的web.xml的版本如何更改 问题 因web.xml的版本太低不支持el表达式的问题(maven3.6版本通过底层的maven web插件生成的最终的web.xml文件版本只 ...

  9. 在java web项目中实现随项目启动的额外操作

    前言 在web项目中经常会遇到在项目启动初始,会要求做一些逻辑的实现,比如实现一个消息推送服务,实现不同类型数据同步的回调操作初始化,或则通知其他客户服务器本项目即将启动,等等.对于这种要求,目前个人 ...

最新文章

  1. 浅析C# new和override的区别
  2. vue.config.js配置
  3. Redis随笔Jedis、jedisCluster的使用
  4. Apache 和 Tomcat 服务器的区别
  5. oracle使用with as提高查询效率
  6. python算法程序_浅谈python常用程序算法
  7. Kafka开源转商业实践,助力车主无忧系统稳健 | 凌云时刻
  8. 高等数学 第七版 上册 下册 答案
  9. 电视盒子_刷机固件_免费合集分享
  10. 贪吃蛇-单机游戏-微信小程序项目开发流程详解
  11. 这些好用的抠图软件,助你实现一键抠图
  12. 实用工具篇--华为eNSP下载及安装
  13. ATSC和DVB数字电视系统的比较
  14. 计算机运行异常怎么办,电脑开机出现windows错误恢复怎么办
  15. (转)wuauclt.exe病毒解决方案
  16. 调起APP功能的实现
  17. 读书笔记,《刻意练习》,第四章,黄金标准
  18. 学习期间的感悟和个人写的一段歌词
  19. android手机刷ios6,2017安卓手机刷机方法
  20. 阿里云云栖社区合作指南

热门文章

  1. 【初学音频】Android的Audio系统之AudioTrack
  2. AudioTrack介绍
  3. matlab中一组数取百分位数,matlab求百分位数
  4. C语言内存使用的常见问题及解决之道
  5. 使用广播信道的数据链路层
  6. java 碳架山地车寿命_碳架自行车的好处和坏处
  7. 耶鲁大学计算机科学录取,美国TOP3耶鲁大学计算机科学硕士录取
  8. 4x4矩阵键盘扫描c语言程序,单片机4*4矩阵键盘扫描程序(c语言+汇编语言2个版本)...
  9. Python爬虫之scrapy高级(全站爬取,分布式,增量爬虫)
  10. 单片机C语言学习之移位相减16位除法