分布式文件系统 SpringBoot+FastDFS+Vue.js【二】
- 六、实现上传功能并展示数据
-
- 6.1.创建数据库
- 6.2.创建spring boot项目fastDFS-java
- 6.3.引入依赖
- 6.3.fastdfs-client配置文件
- 6.4.跨域配置GlobalCrosConfig.java
- 6.5.创建模型--实体类
-
- 6.5.1.FastDfsFile.java
- 6.5.2.FastDfsFileType.java
- 6.5.3.PageBean.java
- 6.5.4.R.java
- 6.5.5.Result.java
- 6.6.创建application.yml
- 6.7.创建Service
-
- 6.7.1.FastDfsFileService
- 6.7.2.FastDfsFileServiceImpl
- 6.7.3.FastDfsFileTypeService
- 6.7.4.FastDfsFileTypeServiceImpl
- 6.8.创建Mapper
-
- 6.8.1.FastDfsFileMapper
- 6.8.2.FastDfsFileMapper.xml
- 6.8.3.FastDfsFileTypeMapper
- 6.8.4.FastDfsFileTypeMapper.xml
- 6.9.创建fastDFS客户端
- 6.10.创建全局异常处理器
- 6.11.创建Controller
- 6.13.创建vue2项目
- 6.14.安装相关模块
- 6.15.main.js
- 6.16.src/router/index.js
- 6.17.src/utils/request.js
- 6.18.src/api/fastdfs/fast.js
- 6.19.上传图片页面fastdfsuploadimg.vue
- 6.20.图片管理页面fastdfsimg.vue
- 6.21.效果演示
- endl
六、实现上传功能并展示数据
6.1.创建数据库
CREATE DATABASE IF NOT EXISTS fastdfs CHARACTER SET utf8mb4;
show databases;
USE fastdfs;
CREATE TABLE `fast_dfs_file` (
`id` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
`file_id` varchar(200) NOT NULL COMMENT '文件的fileId',
`file_path` varchar(200) NOT NULL COMMENT '文件路径',
`file_size` bigint(25) NOT NULL COMMENT '文件大小',
`file_name` varchar(25) NOT NULL COMMENT '文件名',
`ext` varchar(30) NOT NULL COMMENT '文件的扩展名,不包含(.)',
`file_type` varchar(50) NOT NULL COMMENT '文件类型',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '最后修改时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='文件表';
CREATE TABLE `fast_dfs_file_type` (
`id` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
`file_type` varchar(50) NOT NULL COMMENT '文件类型',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '最后修改时间'
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='文件类型表';
insert into fast_dfs_file_type(file_type)values('image/jpeg'),('image/png'),('image/jpg');
6.2.创建spring boot项目fastDFS-java
6.3.引入依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/>
</parent>
<groupId>com.orange</groupId>
<artifactId>fastDFS-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--fastdfs-client-java依赖需要自己手动打包上传到本地仓库-->
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.31-SNAPSHOT</version>
</dependency>
<!--mybatis起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--springboot单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--pagehelper分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<!--json处理器-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<!--fastJson是一个JSON的处理工具包,由阿里巴巴公司研发推出。我们使用它将List或者Map转换成JSON对象-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.2.0</version>
</dependency>
<!--shiro安全依赖包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
<build>
<!--项目打包时会将Java目录中的*.xml文件也进行打包-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**
6.3.fastdfs-client配置文件
## fastdfs-client.properties
#fastDFS连接超时时间,针对socket套接字函数connect
connect_timeout_in_seconds = 5
#fastDFS网络超时时间
network_timeout_in_seconds = 30
#编码格式
charset = UTF-8
#是否启用token验证(针对fdfs配置文件/etc/fdfs/http.conf,防盗链)
http_anti_steal_token = false
#连接密钥(http.conf要配置一样的密钥)
http_secret_key = FastDFS1234567890
#tracker服务器访问端口
http_tracker_http_port = 80
#tracker服务器地址,多个以逗号隔开
fastdfs.tracker_servers = 192.168.229.141:22122
6.4.跨域配置GlobalCrosConfig.java
@Configuration
public class GlobalCrosConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.allowedMethods("POST", "GET", "HEAD", "PUT", "OPTIONS", "DELETE")
.allowedOriginPatterns("*")
.maxAge(3600);
}
}
6.5.创建模型–实体类
6.5.1.FastDfsFile.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@Repository
public class FastDfsFile {
private Long id;
private String fileId;
private String filePath;
private Long fileSize;
private String fileName;
private String ext;
private String fileType;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
6.5.2.FastDfsFileType.java
@Data
@NoArgsConstructor
@AllArgsConstructor
@Repository
public class FastDfsFileType {
private Long id;
private String fileType;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}
6.5.3.PageBean.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean<T> {
private int currPageNo;
private int pageSize;
private int totalCount;
private int totalPage;
private List<T> lists;
}
6.5.4.R.java
@Data
@Accessors(chain = true)
public class R {
private Integer code;
private String message;
private Map<String,Object> data=new HashMap<>();
public static R ok(){
R r = new R();
r.setCode(0);
r.setMessage("成功");
return r;
}
public static R error(){
R r = new R();
r.setCode(-1);
r.setMessage("失败");
return r;
}
public R data(String key,Object value){
this.data.put(key, value);
return this;
}
}
6.5.5.Result.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
private Integer code;
private String msg;
private Object data;
public static Result success(){
return new Result(1,"success",null);
}
public static Result success(Object data){
return new Result(1,"success",data);
}
public static Result error(String msg){
return new Result(0,msg,null);
}
}
6.6.创建application.yml
server:
port: 9090
#Mybatis配置
mybatis:
configuration: #sql日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#驼峰命名
map-underscore-to-camel-case: true
mapper-locations: classpath:com/orange/fastdfs/mapper
6.7.创建Service
6.7.1.FastDfsFileService
public interface FastDfsFileService {
void save(FastDfsFile fastDfsFile);
void updateById(FastDfsFile fastDfsFile);
FastDfsFile selectById(Long id);
Long selectByFileId(String fileId);
int deleteFastDfsFileById(Long id);
List<FastDfsFile> selectAll();
PageBean<FastDfsFile> findFastDfsFileByPage(int currPageNo, int pageSize);
}
6.7.2.FastDfsFileServiceImpl
@Service
public class FastDfsFileServiceImpl implements FastDfsFileService {
@Resource
private FastDfsFileMapper fastDfsFileMapper;
@Override
public void save(FastDfsFile fastDfsFile) {
fastDfsFileMapper.insert(fastDfsFile);
}
@Override
public void updateById(FastDfsFile fastDfsFile) {
fastDfsFileMapper.updateById(fastDfsFile);
}
@Override
public FastDfsFile selectById(Long id) {
return fastDfsFileMapper.selectById(id);
}
@Override
public Long selectByFileId(String fileId) {
return fastDfsFileMapper.selectByFileId(fileId);
}
@Override
public int deleteFastDfsFileById(Long id) {
return fastDfsFileMapper.deleteById(id);
}
@Override
public List<FastDfsFile> selectAll() {
return fastDfsFileMapper.selectAll();
}
@Override
public PageBean<FastDfsFile> findFastDfsFileByPage(int currPageNo, int pageSize) {
PageBean<FastDfsFile> pageBean = new PageBean<>();
pageBean.setCurrPageNo(currPageNo);
pageBean.setPageSize(pageSize);
int totalCount = fastDfsFileMapper.selectCount();
pageBean.setTotalCount(totalCount);
Double num = Math.ceil(totalCount / pageSize);
int totalPage = num.intValue();
pageBean.setTotalPage(totalPage);
int offset = (currPageNo - 1) * pageSize;
int limit = pageBean.getPageSize();
List<FastDfsFile> list = fastDfsFileMapper.findeByPage(offset, limit);
pageBean.setLists(list);
return pageBean;
}
}
6.7.3.FastDfsFileTypeService
public interface FastDfsFileTypeService {
int selectByFileType(String fileType);
}
6.7.4.FastDfsFileTypeServiceImpl
@Service
public class FastDfsFileTypeServiceImpl implements FastDfsFileTypeService {
@Resource
private FastDfsFileTypeMapper fastDfsFileTypeMapper;
@Override
public int selectByFileType(String fileType) {
return fastDfsFileTypeMapper.select(fileType);
}
}
6.8.创建Mapper
6.8.1.FastDfsFileMapper
@Mapper
public interface FastDfsFileMapper {
void insert(FastDfsFile fastDfsFile);
Long selectByFileId(String fileId);
int deleteById(Long id);
List<FastDfsFile> selectAll();
int selectCount();
List<FastDfsFile> findeByPage(int offset, int limit);
void updateById(FastDfsFile fastDfsFile);
FastDfsFile selectById(Long id);
}
6.8.2.FastDfsFileMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orange.fastdfsjava.mapper.FastDfsFileMapper">
<insert id="insert" parameterType="com.orange.fastdfsjava.pojo.FastDfsFile">
insert into fast_dfs_file
(file_id, file_path, file_size, ext, file_name, file_type, create_time, update_time)
values (#{fileId}, #{filePath}, #{fileSize}, #{ext}, #{fileName}, #{fileType}, #{createTime}, #{updateTime})
</insert>
<update id="updateById">
update fast_dfs_file
set file_id = #{fileId},
file_path = #{filePath},
file_size = #{fileSize},
ext = #{ext},
file_name = #{fileName},
file_type = #{fileType},
create_time = #{createTime},
update_time = #{updateTime}
where id = #{id}
</update>
<delete id="deleteById">
delete
from fast_dfs_file
where id = #{id}
</delete>
<select id="selectByFileId" resultType="java.lang.Long">
select id
from fast_dfs_file
where file_id = #{fileId}
</select>
<select id="selectAll" resultType="com.orange.fastdfsjava.pojo.FastDfsFile">
select *
from fast_dfs_file
</select>
<select id="selectCount" resultType="java.lang.Integer">
select count(*)
from fast_dfs_file
</select>
<select id="findeByPage" resultType="com.orange.fastdfsjava.pojo.FastDfsFile">
select *
from fast_dfs_file limit #{offset},#{limit}
</select>
<select id="selectById" resultType="com.orange.fastdfsjava.pojo.FastDfsFile">
select *
from fast_dfs_file
where id = #{id}
</select>
</mapper>
6.8.3.FastDfsFileTypeMapper
@Mapper
public interface FastDfsFileTypeMapper {
int select(String fileType);
}
6.8.4.FastDfsFileTypeMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.orange.fastdfsjava.mapper.FastDfsFileTypeMapper">
<select id="select" resultType="java.lang.Integer">
select count(*)
from fast_dfs_file_type
where file_type = #{fileType}
</select>
</mapper>
6.9.创建fastDFS客户端
@Slf4j
public class FastDFSClient {
static {
try {
ClientGlobal.initByProperties("config/fastdfs-client.properties");
log.info("network_timeout = {} ms", ClientGlobal.g_network_timeout);
log.info("charset= {}", ClientGlobal.g_charset);
} catch (IOException e) {
e.printStackTrace();
} catch (MyException e) {
e.printStackTrace();
}
}
public static FastDfsFile upload(MultipartFile file, FastDfsFile fastDFSFile) throws IOException {
byte[] file_buff = null;
InputStream inputStream = file.getInputStream();
if (inputStream != null) {
int len = inputStream.available();
file_buff = new byte[len];
inputStream.read(file_buff);
}
inputStream.close();
try {
TrackerClient trackerClient = new TrackerClient(ClientGlobal.getG_tracker_group());
TrackerServer trackerServer = trackerClient.getTrackerServer();
StorageServer storageServer = null;
StorageClient1 storageClient = new StorageClient1(trackerServer, storageServer);
NameValuePair[] metaList = new NameValuePair[1];
metaList[0] = new NameValuePair("fileName", fastDFSFile.getFileName());
String fileId = storageClient.upload_file1(file_buff, fastDFSFile.getExt(), metaList);
log.info("upload success. file id is: {}", fileId);
fastDFSFile.setFileId(fileId);
fastDFSFile.setFilePath(fileId);
fastDFSFile.setFileSize(file.getSize());
fastDFSFile.setCreateTime(LocalDateTime.now());
fastDFSFile.setUpdateTime(LocalDateTime.now());
storageClient.close();
return fastDFSFile;
} catch (Exception e) {
log.error("上传文件失败:", e);
e.printStackTrace();
return null;
}
}
}
6.10.创建全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result ex(Exception ex){
ex.printStackTrace();
return Result.error("对不起,操作失败,请联系管理员");
}
}
6.11.创建Controller
@Slf4j
@RestController
@RequestMapping("/fastDFSFile")
public class FileServerController {
@Resource
private FastDfsFileService fastDfsFileService;
@Resource
private FastDfsFileTypeService fastDfsFileTypeService;
@PostMapping("/upload")
@ResponseBody
public R upload(@RequestParam("file") MultipartFile file) throws IOException {
FastDfsFile fastDFSFile = new FastDfsFile();
String contentType = file.getContentType();
log.info("上传的文件类型为:{}", contentType);
int count = fastDfsFileTypeService.selectByFileType(contentType);
if (count < 1) {
log.info("不支持此文件类型上传 : {}", contentType);
return R.error().setCode(208).setMessage("不支持此文件类型上传 : " + contentType);
}
log.info("此文件类型为 : {}", contentType);
fastDFSFile.setFileType(contentType);
String originalFilename = file.getOriginalFilename();
log.info("原始文件名称 : {}", originalFilename);
fastDFSFile.setFileName(originalFilename);
String filenameExtension = StringUtils.getFilenameExtension(originalFilename);
log.info("文件类型 = {}", filenameExtension);
if (filenameExtension == null) {
return R.error().setCode(208).setMessage("此文件没有文件扩展名");
}
fastDFSFile.setExt(filenameExtension);
String fileName = UUID.randomUUID().toString().replace("-", "") + "." + filenameExtension;
log.info("新文件名称 = {}", fileName);
FastDfsFile fastDfsFile1 = FastDFSClient.upload(file, fastDFSFile);
if (fastDfsFile1 != null) {
fastDfsFileService.save(fastDfsFile1);
Long id = fastDfsFileService.selectByFileId(fastDfsFile1.getFileId());
fastDfsFile1.setId(id);
return R.ok().setCode(200).setMessage("上传成功").data("fastDfsFile",fastDfsFile1);
}
return R.error().setCode(208).setMessage("上传失败");
}
@GetMapping("/getPageFastImg/{page}/{limit}")
public R getPageFastImg(@PathVariable int page, @PathVariable int limit) {
PageBean<FastDfsFile> pageBean = fastDfsFileService.findFastDfsFileByPage(page, limit);
return R.ok().setCode(200).setMessage("查询成功").data("pageBean",pageBean);
}
}
6.13.创建vue2项目
6.14.安装相关模块
npm install axios@1.5.0
npm install vue-axios
npm install vue-router@3.0.1
npm i element-ui -S
6.15.main.js
import App from './App.vue'
import Vue from 'vue'
import axios from 'axios'
import VueAxios from 'vue-axios'
import VueRouter from 'vue-router'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import router from './router/index'
Vue.prototype.$baseImagePath = 'http://192.168.229.141'
Vue.prototype.$axios = axios;
Vue.use(VueRouter)
Vue.use(router)
Vue.use(VueAxios, axios)
Vue.use(ElementUI)
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
data: {
Bus: new Vue()
}
}).$mount('#app');
6.16.src/router/index.js
import VueRouter from "vue-router";
import fastdfsuploadimg from '../view/fastdfs/fastdfsuploadimg'
import fastdfsimg from "../view/fastdfs/fastdfsimg"
const routes = [
{
path: '/',
name: 'fastdfsuploadimg',
component: fastdfsuploadimg
},
{
path: '/fastdfsimg',
name: 'fastdfsimg',
component: fastdfsimg
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
6.17.src/utils/request.js
import axios from 'axios'
const service = axios.create({
baseURL: 'http://localhost:9090',
timeout: 1000000
})
service.interceptors.request.use(
config => {
return config;
},
error => {
console.log(error);
return Promise.reject(error);
}
);
service.interceptors.response.use(
response => {
const data = response.data;
return data;
},
error => {
console.log('err' + error);
return Promise.reject(error);
}
);
export default service;
6.18.src/api/fastdfs/fast.js
import request from "../../utils/request";
const api_name = '/fastDFSFile'
export default {
uploadImg() {
return request({
url: `${api_name}/upload`,
method: 'post',
})
},
getPageFastImg(page, limit) {
return request({
url: `${api_name}/getPageFastImg/${page}/${limit}`,
method: 'get',
})
},
}
6.19.上传图片页面fastdfsuploadimg.vue
<template>
<div>
<h2>上传图片</h2>
<el-form>
<el-form-item>
<el-upload
list-type="picture-card"
:multiple="false"
:action="uploadUrl"
:limit="1"
:on-success="onUploadSuccessIdCard"
>
<i class="el-icon-plus"></i>
</el-upload>
</el-form-item>
</el-form>
<span v-if="dialogImageUrl != ''">图片地址:
<a target="_blank" v-if="dialogImageUrl != ''" :href="dialogImageUrl">{{ dialogImageUrl }}</a>
</span>
<br/>
</div>
</template>
<script>
import service from "../../utils/request";
export default {
name: "UploadImg",
data() {
return {
dialogImageUrl: "",
file_id: "",
dialogVisible: false,
uploadUrl: "",
datas: {},
};
},
created() {
this.uploadUrl = service.defaults.baseURL + "/fastDFSFile/upload"
},
methods: {
onUploadSuccessIdCard(response) {
this.file_id = response.data.fastDfsFile.fileId;
this.datas = response.fastDfsFile.data;
this.dialogImageUrl = this.$baseImagePath+"/" + response.data.fastDfsFile.filePath;
},
},
},
};
</script>
<style scoped>
</style>
6.20.图片管理页面fastdfsimg.vue
<template>
<div>
<h2>图片管理</h2>
<!--图片列表-->
<el-table
size="small"
style="margin: 30px;"
empty-text="无数据"
:data="imgList"
highlight-current-row v-loading="loading" border element-loading-text="拼命加载中">
<el-table-column align="center" sortable prop="filePath" label="文件路径" width="450"></el-table-column>
<el-table-column align="center" sortable prop="fileSize" label="文件大小" width="100"></el-table-column>
<el-table-column align="center" sortable prop="fileName" label="文件名" width="130"></el-table-column>
<el-table-column align="center" sortable prop="ext" label="扩展名" width="100"></el-table-column>
<el-table-column align="center" sortable prop="fileType" label="文件类型" width="100"></el-table-column>
<el-table-column align="center" sortable prop="filePath" label="预览图片" width="100">
<template slot-scope="scope">
<img :src="getImageUrl(scope.row.filePath)" style="max-width: 100px;max-height: 100px" alt="图标"/>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination class="pagination" style="text-align: center;margin-top: 50px"
layout="prev, pager, next"
:current-page="page"
:total="total"
:page-size="limit">
</el-pagination>
</div>
</template>
<script>
import fastApi from "@/api/fastdfs/fast";
export default {
name: "FastdfsImg",
data() {
return {
total: 0,
page: 1,
limit: 5,
imgList: {},
}
},
created() {
this.init()
},
methods: {
init() {
fastApi.getPageFastImg(this.page, this.limit).then(response => {
this.imgList = response.data.pageBean.lists
this.total = response.data.pageBean.totalCount
})
},
getImageUrl(filePath) {
return this.$baseImagePath + '/' + filePath;
},
},
}
</script>
<style scoped>
</style>
6.21.效果演示
endl