mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-26 09:11:52 +08:00
增加文件服务的展示
This commit is contained in:
parent
daa38661d2
commit
cee1aa3e60
@ -50,6 +50,7 @@
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
|
| 🚀 | 配置管理 | 对系统动态配置常用参数,支持 SpringBoot 加载 |
|
||||||
| | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
|
| | 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志 |
|
||||||
|
| 🚀 | 文件服务 | 支持本地文件存储,同时支持兼容 Amazon S3 协议的云服务、开源组件 |
|
||||||
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
|
| 🚀 | API 日志 | 包括 RESTful API 访问日志、异常日志两部分,方便排查 API 相关的问题 |
|
||||||
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
|
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
|
||||||
| | Redis 监控 |监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
|
| | Redis 监控 |监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
|
||||||
@ -64,7 +65,6 @@
|
|||||||
计划新增:
|
计划新增:
|
||||||
* 工作流
|
* 工作流
|
||||||
* 错误码
|
* 错误码
|
||||||
* 文件服务
|
|
||||||
|
|
||||||
### 研发工具
|
### 研发工具
|
||||||
|
|
||||||
|
26
pom.xml
26
pom.xml
@ -40,8 +40,8 @@
|
|||||||
<skywalking.version>8.3.0</skywalking.version>
|
<skywalking.version>8.3.0</skywalking.version>
|
||||||
<spring-boot-admin.version>2.3.1</spring-boot-admin.version>
|
<spring-boot-admin.version>2.3.1</spring-boot-admin.version>
|
||||||
<!-- 工具类相关 -->
|
<!-- 工具类相关 -->
|
||||||
<mapstruct.version>1.4.2.Final</mapstruct.version>
|
<lombok.version>1.16.14</lombok.version>
|
||||||
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
|
<mapstruct.version>1.4.1.Final</mapstruct.version>
|
||||||
<hutool.version>5.5.6</hutool.version>
|
<hutool.version>5.5.6</hutool.version>
|
||||||
<easyexcel.verion>2.2.7</easyexcel.verion>
|
<easyexcel.verion>2.2.7</easyexcel.verion>
|
||||||
<velocity.version>2.2</velocity.version>
|
<velocity.version>2.2</velocity.version>
|
||||||
@ -227,14 +227,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<optional>true</optional>
|
<version>${lombok.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mapstruct</groupId>
|
<groupId>org.mapstruct</groupId>
|
||||||
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
|
<artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
|
||||||
<version>${mapstruct.version}</version>
|
<version>${mapstruct.version}</version>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mapstruct</groupId>
|
<groupId>org.mapstruct</groupId>
|
||||||
@ -246,13 +245,6 @@
|
|||||||
<groupId>org.mapstruct</groupId>
|
<groupId>org.mapstruct</groupId>
|
||||||
<artifactId>mapstruct-jdk8</artifactId>
|
<artifactId>mapstruct-jdk8</artifactId>
|
||||||
<version>${mapstruct.version}</version>
|
<version>${mapstruct.version}</version>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.projectlombok</groupId>
|
|
||||||
<artifactId>lombok-mapstruct-binding</artifactId>
|
|
||||||
<version>${lombok-mapstruct-binding.version}</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -331,6 +323,18 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<source>${java.version}</source> <!-- or higher, depending on your project -->
|
<source>${java.version}</source> <!-- or higher, depending on your project -->
|
||||||
<target>${java.version}</target> <!-- or higher, depending on your project -->
|
<target>${java.version}</target> <!-- or higher, depending on your project -->
|
||||||
|
<annotationProcessorPaths>
|
||||||
|
<path>
|
||||||
|
<groupId>org.mapstruct</groupId>
|
||||||
|
<artifactId>mapstruct-processor</artifactId>
|
||||||
|
<version>${mapstruct.version}</version>
|
||||||
|
</path>
|
||||||
|
<path>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
</path>
|
||||||
|
</annotationProcessorPaths>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
18
ruoyi-ui/src/api/infra/file.js
Normal file
18
ruoyi-ui/src/api/infra/file.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 删除文件
|
||||||
|
export function deleteFile(id) {
|
||||||
|
return request({
|
||||||
|
url: '/infra/file/delete?id=' + id,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得文件分页
|
||||||
|
export function getFilePage(query) {
|
||||||
|
return request({
|
||||||
|
url: '/infra/file/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
202
ruoyi-ui/src/views/infra/file/index.vue
Normal file
202
ruoyi-ui/src/views/infra/file/index.vue
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
|
||||||
|
<!-- 搜索工作栏 -->
|
||||||
|
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
|
||||||
|
<el-form-item label="文件路径" prop="id">
|
||||||
|
<el-input v-model="queryParams.id" placeholder="请输入文件路径" clearable size="small" @keyup.enter.native="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="文件类型" prop="type">
|
||||||
|
<el-select v-model="queryParams.type" placeholder="请选择文件类型" clearable size="small">
|
||||||
|
<el-option label="请选择字典生成" value="" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="创建时间">
|
||||||
|
<el-date-picker v-model="dateRangeCreateTime" size="small" style="width: 240px" value-format="yyyy-MM-dd"
|
||||||
|
type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<!-- 操作工具栏 -->
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">上传文件</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<el-table v-loading="loading" :data="list">
|
||||||
|
<el-table-column label="文件路径" align="center" prop="id" width="300" />
|
||||||
|
<el-table-column label="文件类型" align="center" prop="type" width="80" />
|
||||||
|
<el-table-column label="文件内容" align="center" prop="content">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<img v-if="scope.row.type === 'jpg' || scope.row.type === 'png' || scope.row.type === 'gif'"
|
||||||
|
width="200px" :src="getFileUrl + scope.row.id">
|
||||||
|
<i v-else>非图片,无法预览</i>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
|
||||||
|
v-hasPermi="['infra:file:delete']">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
|
||||||
|
@pagination="getList"/>
|
||||||
|
|
||||||
|
<!-- 对话框(添加 / 修改) -->
|
||||||
|
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
|
||||||
|
<el-upload ref="upload" :limit="1" accept=".jpg, .png, .gif" :auto-upload="false" drag
|
||||||
|
:headers="upload.headers" :action="upload.url" :data="upload.data" :disabled="upload.isUploading"
|
||||||
|
:on-change="handleFileChange"
|
||||||
|
:on-progress="handleFileUploadProgress"
|
||||||
|
:on-success="handleFileSuccess">
|
||||||
|
<i class="el-icon-upload"></i>
|
||||||
|
<div class="el-upload__text">
|
||||||
|
将文件拖到此处,或 <em>点击上传</em>
|
||||||
|
</div>
|
||||||
|
<div class="el-upload__tip" style="color:red" slot="tip">提示:仅允许导入 jpg、png、gif 格式文件!</div>
|
||||||
|
</el-upload>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitFileForm">确 定</el-button>
|
||||||
|
<el-button @click="upload.open = false">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { deleteFile, getFilePage } from "@/api/infra/file";
|
||||||
|
import {getToken} from "@/utils/auth";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "File",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
getFileUrl: process.env.VUE_APP_BASE_API + '/api/infra/file/get/',
|
||||||
|
// 遮罩层
|
||||||
|
loading: true,
|
||||||
|
// 显示搜索条件
|
||||||
|
showSearch: true,
|
||||||
|
// 总条数
|
||||||
|
total: 0,
|
||||||
|
// 文件列表
|
||||||
|
list: [],
|
||||||
|
// 弹出层标题
|
||||||
|
title: "",
|
||||||
|
dateRangeCreateTime: [],
|
||||||
|
// 查询参数
|
||||||
|
queryParams: {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
id: null,
|
||||||
|
type: null,
|
||||||
|
},
|
||||||
|
// 用户导入参数
|
||||||
|
upload: {
|
||||||
|
open: false, // 是否显示弹出层
|
||||||
|
title: "", // 弹出层标题
|
||||||
|
isUploading: false, // 是否禁用上传
|
||||||
|
url: process.env.VUE_APP_BASE_API + '/api/' + "/infra/file/upload", // 请求地址
|
||||||
|
headers: { Authorization: "Bearer " + getToken() }, // 设置上传的请求头部
|
||||||
|
data: {} // 上传的额外数据,用于文件名
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/** 查询列表 */
|
||||||
|
getList() {
|
||||||
|
this.loading = true;
|
||||||
|
// 处理查询参数
|
||||||
|
let params = {...this.queryParams};
|
||||||
|
this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
|
||||||
|
// 执行查询
|
||||||
|
getFilePage(params).then(response => {
|
||||||
|
this.list = response.data.list;
|
||||||
|
this.total = response.data.total;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/** 取消按钮 */
|
||||||
|
cancel() {
|
||||||
|
this.open = false;
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
/** 表单重置 */
|
||||||
|
reset() {
|
||||||
|
this.form = {
|
||||||
|
content: undefined,
|
||||||
|
};
|
||||||
|
this.resetForm("form");
|
||||||
|
},
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
handleQuery() {
|
||||||
|
this.queryParams.pageNo = 1;
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
resetQuery() {
|
||||||
|
this.dateRangeCreateTime = [];
|
||||||
|
this.resetForm("queryForm");
|
||||||
|
this.handleQuery();
|
||||||
|
},
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
handleAdd() {
|
||||||
|
this.upload.open = true;
|
||||||
|
this.upload.title = "上传文件";
|
||||||
|
},
|
||||||
|
/** 处理上传的文件发生变化 */
|
||||||
|
handleFileChange(file, fileList) {
|
||||||
|
this.upload.data.path = file.name;
|
||||||
|
},
|
||||||
|
/** 处理文件上传中 */
|
||||||
|
handleFileUploadProgress(event, file, fileList) {
|
||||||
|
this.upload.isUploading = true; // 禁止修改
|
||||||
|
},
|
||||||
|
/** 发起文件上窜 */
|
||||||
|
submitFileForm() {
|
||||||
|
this.$refs.upload.submit();
|
||||||
|
},
|
||||||
|
/** 文件上传成功处理 */
|
||||||
|
handleFileSuccess(response, file, fileList) {
|
||||||
|
// 清理
|
||||||
|
this.upload.open = false;
|
||||||
|
this.upload.isUploading = false;
|
||||||
|
this.$refs.upload.clearFiles();
|
||||||
|
// 提示成功,并刷新
|
||||||
|
this.msgSuccess("上传成功");
|
||||||
|
this.getList();
|
||||||
|
},
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
handleDelete(row) {
|
||||||
|
const id = row.id;
|
||||||
|
this.$confirm('是否确认删除文件编号为"' + id + '"的数据项?', "警告", {
|
||||||
|
confirmButtonText: "确定",
|
||||||
|
cancelButtonText: "取消",
|
||||||
|
type: "warning"
|
||||||
|
}).then(function() {
|
||||||
|
return deleteFile(id);
|
||||||
|
}).then(() => {
|
||||||
|
this.getList();
|
||||||
|
this.msgSuccess("删除成功");
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
|||||||
package cn.iocoder.dashboard.framework.file.config;
|
package cn.iocoder.dashboard.framework.file.config;
|
||||||
|
|
||||||
import cn.iocoder.dashboard.modules.system.controller.common.SysFileController;
|
import cn.iocoder.dashboard.modules.infra.controller.file.InfFileController;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
@ -13,7 +13,7 @@ import javax.validation.constraints.NotNull;
|
|||||||
public class FileProperties {
|
public class FileProperties {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对应 {@link SysFileController#}
|
* 对应 {@link InfFileController#}
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "基础文件路径不能为空")
|
@NotNull(message = "基础文件路径不能为空")
|
||||||
private String basePath;
|
private String basePath;
|
||||||
|
@ -134,7 +134,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||||||
// 静态资源,可匿名访问
|
// 静态资源,可匿名访问
|
||||||
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
|
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js").permitAll()
|
||||||
// 文件的获取接口,可匿名访问
|
// 文件的获取接口,可匿名访问
|
||||||
.antMatchers(webProperties.getApiPrefix() + "/system/file/get/**").anonymous()
|
.antMatchers(webProperties.getApiPrefix() + "/infra/file/get/**").anonymous()
|
||||||
// Swagger 接口文档
|
// Swagger 接口文档
|
||||||
.antMatchers("/swagger-ui.html").anonymous()
|
.antMatchers("/swagger-ui.html").anonymous()
|
||||||
.antMatchers("/swagger-resources/**").anonymous()
|
.antMatchers("/swagger-resources/**").anonymous()
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.controller.common;
|
package cn.iocoder.dashboard.modules.infra.controller.file;
|
||||||
|
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.iocoder.dashboard.common.pojo.CommonResult;
|
import cn.iocoder.dashboard.common.pojo.CommonResult;
|
||||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.common.SysFileDO;
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
import cn.iocoder.dashboard.modules.system.service.common.SysFileService;
|
import cn.iocoder.dashboard.modules.infra.controller.file.vo.InfFilePageReqVO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.controller.file.vo.InfFileRespVO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.convert.file.InfFileConvert;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.dal.dataobject.file.InfFileDO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.service.file.InfFileService;
|
||||||
import cn.iocoder.dashboard.util.servlet.ServletUtils;
|
import cn.iocoder.dashboard.util.servlet.ServletUtils;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
@ -11,40 +15,53 @@ import io.swagger.annotations.ApiImplicitParams;
|
|||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.Valid;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
|
||||||
|
|
||||||
@Api(tags = "文件存储")
|
@Api(tags = "文件存储")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/system/file")
|
@RequestMapping("/infra/file")
|
||||||
|
@Validated
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SysFileController {
|
public class InfFileController {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SysFileService fileService;
|
private InfFileService fileService;
|
||||||
|
|
||||||
|
@PostMapping("/upload")
|
||||||
@ApiOperation("上传文件")
|
@ApiOperation("上传文件")
|
||||||
@ApiImplicitParams({
|
@ApiImplicitParams({
|
||||||
@ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class),
|
@ApiImplicitParam(name = "file", value = "文件附件", required = true, dataTypeClass = MultipartFile.class),
|
||||||
@ApiImplicitParam(name = "path", value = "文件路径", required = true, example = "yudaoyuanma.png", dataTypeClass = Long.class)
|
@ApiImplicitParam(name = "path", value = "文件路径", required = false, example = "yudaoyuanma.png", dataTypeClass = String.class)
|
||||||
})
|
})
|
||||||
@PostMapping("/upload")
|
|
||||||
public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
|
public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
|
||||||
@RequestParam("path") String path) throws IOException {
|
@RequestParam("path") String path) throws IOException {
|
||||||
return success(fileService.createFile(path, IoUtil.readBytes(file.getInputStream())));
|
return success(fileService.createFile(path, IoUtil.readBytes(file.getInputStream())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/delete")
|
||||||
|
@ApiOperation("删除文件")
|
||||||
|
@ApiImplicitParam(name = "id", value = "编号", required = true)
|
||||||
|
@PreAuthorize("@ss.hasPermission('infra:file:delete')")
|
||||||
|
public CommonResult<Boolean> deleteFile(@RequestParam("id") String id) {
|
||||||
|
fileService.deleteFile(id);
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get/{path}")
|
||||||
@ApiOperation("下载文件")
|
@ApiOperation("下载文件")
|
||||||
@ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class)
|
@ApiImplicitParam(name = "path", value = "文件附件", required = true, dataTypeClass = MultipartFile.class)
|
||||||
@GetMapping("/get/{path}")
|
|
||||||
public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException {
|
public void getFile(HttpServletResponse response, @PathVariable("path") String path) throws IOException {
|
||||||
SysFileDO file = fileService.getFile(path);
|
InfFileDO file = fileService.getFile(path);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
log.warn("[getFile][path({}) 文件不存在]", path);
|
log.warn("[getFile][path({}) 文件不存在]", path);
|
||||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||||
@ -53,4 +70,12 @@ public class SysFileController {
|
|||||||
ServletUtils.writeAttachment(response, path, file.getContent());
|
ServletUtils.writeAttachment(response, path, file.getContent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/page")
|
||||||
|
@ApiOperation("获得文件分页")
|
||||||
|
@PreAuthorize("@ss.hasPermission('infra:file:query')")
|
||||||
|
public CommonResult<PageResult<InfFileRespVO>> getFilePage(@Valid InfFilePageReqVO pageVO) {
|
||||||
|
PageResult<InfFileDO> pageResult = fileService.getFilePage(pageVO);
|
||||||
|
return success(InfFileConvert.INSTANCE.convertPage(pageResult));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.infra.controller.file.vo;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageParam;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||||
|
|
||||||
|
@ApiModel("文件分页 Request VO")
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class InfFilePageReqVO extends PageParam {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "文件路径", example = "yudao", notes = "模糊匹配")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "文件类型", example = "jpg", notes = "模糊匹配")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
@ApiModelProperty(value = "开始创建时间")
|
||||||
|
private Date beginCreateTime;
|
||||||
|
|
||||||
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
|
@ApiModelProperty(value = "结束创建时间")
|
||||||
|
private Date endCreateTime;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.infra.controller.file.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@ApiModel(value = "文件 Response VO", description = "不返回 content 字段,太大")
|
||||||
|
@Data
|
||||||
|
public class InfFileRespVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "文件路径", required = true, example = "yudao.jpg")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "文件类型", required = true, example = "jpg")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "创建时间", required = true)
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.infra.convert.file;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.controller.file.vo.InfFileRespVO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.dal.dataobject.file.InfFileDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface InfFileConvert {
|
||||||
|
|
||||||
|
InfFileConvert INSTANCE = Mappers.getMapper(InfFileConvert.class);
|
||||||
|
|
||||||
|
InfFileRespVO convert(InfFileDO bean);
|
||||||
|
|
||||||
|
PageResult<InfFileRespVO> convertPage(PageResult<InfFileDO> page);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.infra.dal.dataobject.file;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件表
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("inf_file")
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class InfFileDO extends BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件路径
|
||||||
|
*/
|
||||||
|
@TableId(type = IdType.INPUT)
|
||||||
|
private String id;
|
||||||
|
/**
|
||||||
|
* 文件类型
|
||||||
|
*
|
||||||
|
* 通过 {@link cn.hutool.core.io.FileTypeUtil#getType(InputStream)} 获取
|
||||||
|
*/
|
||||||
|
@TableField(value = "`type`")
|
||||||
|
private String type;
|
||||||
|
/**
|
||||||
|
* 文件内容
|
||||||
|
*/
|
||||||
|
private byte[] content;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.infra.dal.mysql.file;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
|
||||||
|
import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.controller.file.vo.InfFilePageReqVO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.dal.dataobject.file.InfFileDO;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface InfFileMapper extends BaseMapperX<InfFileDO> {
|
||||||
|
|
||||||
|
default Integer selectCountById(String id) {
|
||||||
|
return selectCount("id", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
default PageResult<InfFileDO> selectPage(InfFilePageReqVO reqVO) {
|
||||||
|
return selectPage(reqVO, new QueryWrapperX<InfFileDO>()
|
||||||
|
.likeIfPresent("id", reqVO.getId())
|
||||||
|
.likeIfPresent("type", reqVO.getType())
|
||||||
|
.betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
|
||||||
|
.orderByDesc("create_time"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,4 +27,7 @@ public interface InfErrorCodeConstants {
|
|||||||
ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1001002000, "API 错误日志不存在");
|
ErrorCode API_ERROR_LOG_NOT_FOUND = new ErrorCode(1001002000, "API 错误日志不存在");
|
||||||
ErrorCode API_ERROR_LOG_PROCESSED = new ErrorCode(1001002001, "API 错误日志已处理");
|
ErrorCode API_ERROR_LOG_PROCESSED = new ErrorCode(1001002001, "API 错误日志已处理");
|
||||||
|
|
||||||
|
// ========== 文件 1001003000 ==========
|
||||||
|
ErrorCode FILE_NOT_EXISTS = new ErrorCode(1001003000, "文件不存在");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.infra.service.file;
|
||||||
|
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.controller.file.vo.InfFilePageReqVO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.dal.dataobject.file.InfFileDO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件 Service 接口
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
public interface InfFileService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存文件,并返回文件的访问路径
|
||||||
|
*
|
||||||
|
* @param path 文件路径
|
||||||
|
* @param content 文件内容
|
||||||
|
* @return 文件路径
|
||||||
|
*/
|
||||||
|
String createFile(String path, byte[] content);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文件
|
||||||
|
*
|
||||||
|
* @param id 编号
|
||||||
|
*/
|
||||||
|
void deleteFile(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得文件
|
||||||
|
*
|
||||||
|
* @param path 文件路径
|
||||||
|
* @return 文件
|
||||||
|
*/
|
||||||
|
InfFileDO getFile(String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得文件分页
|
||||||
|
*
|
||||||
|
* @param pageReqVO 分页查询
|
||||||
|
* @return 文件分页
|
||||||
|
*/
|
||||||
|
PageResult<InfFileDO> getFilePage(InfFilePageReqVO pageReqVO);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.infra.service.file.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.FileTypeUtil;
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.dashboard.framework.file.config.FileProperties;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.controller.file.vo.InfFilePageReqVO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.dal.dataobject.file.InfFileDO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.dal.mysql.file.InfFileMapper;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.service.file.InfFileService;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
|
||||||
|
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.FILE_NOT_EXISTS;
|
||||||
|
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件 Service 实现类
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class InfFileServiceImpl implements InfFileService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InfFileMapper fileMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FileProperties fileProperties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String createFile(String path, byte[] content) {
|
||||||
|
if (fileMapper.selectCountById(path) > 0) {
|
||||||
|
throw exception(FILE_PATH_EXISTS);
|
||||||
|
}
|
||||||
|
// 保存到数据库
|
||||||
|
InfFileDO file = new InfFileDO();
|
||||||
|
file.setId(path);
|
||||||
|
file.setType(FileTypeUtil.getType(new ByteArrayInputStream(content)));
|
||||||
|
file.setContent(content);
|
||||||
|
fileMapper.insert(file);
|
||||||
|
// 拼接路径返回
|
||||||
|
return fileProperties.getBasePath() + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteFile(String id) {
|
||||||
|
// 校验存在
|
||||||
|
this.validateFileExists(id);
|
||||||
|
// 更新
|
||||||
|
fileMapper.deleteById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateFileExists(String id) {
|
||||||
|
if (fileMapper.selectById(id) == null) {
|
||||||
|
throw exception(FILE_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InfFileDO getFile(String path) {
|
||||||
|
return fileMapper.selectById(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<InfFileDO> getFilePage(InfFilePageReqVO pageReqVO) {
|
||||||
|
return fileMapper.selectPage(pageReqVO);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,30 +0,0 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.dal.dataobject.common;
|
|
||||||
|
|
||||||
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
|
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件表
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@TableName("sys_file")
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class SysFileDO extends BaseDO {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件路径
|
|
||||||
*/
|
|
||||||
@TableId(type = IdType.INPUT)
|
|
||||||
private String id;
|
|
||||||
/**
|
|
||||||
* 文件内容
|
|
||||||
*/
|
|
||||||
private byte[] content;
|
|
||||||
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.dal.mysql.common;
|
|
||||||
|
|
||||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.common.SysFileDO;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
|
||||||
|
|
||||||
@Mapper
|
|
||||||
public interface SysFileMapper extends BaseMapper<SysFileDO> {
|
|
||||||
|
|
||||||
default Integer selectCountById(String id) {
|
|
||||||
return selectCount(new QueryWrapper<SysFileDO>().eq("id", id));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.service.common;
|
|
||||||
|
|
||||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.common.SysFileDO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件 Service 接口
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
public interface SysFileService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存文件,并返回文件的访问路径
|
|
||||||
*
|
|
||||||
* @param path 文件路径
|
|
||||||
* @param content 文件内容
|
|
||||||
* @return 文件路径
|
|
||||||
*/
|
|
||||||
String createFile(String path, byte[] content);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得文件
|
|
||||||
*
|
|
||||||
* @param path 文件路径
|
|
||||||
* @return 文件
|
|
||||||
*/
|
|
||||||
SysFileDO getFile(String path);
|
|
||||||
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package cn.iocoder.dashboard.modules.system.service.common.impl;
|
|
||||||
|
|
||||||
import cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil;
|
|
||||||
import cn.iocoder.dashboard.framework.file.config.FileProperties;
|
|
||||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.common.SysFileDO;
|
|
||||||
import cn.iocoder.dashboard.modules.system.dal.mysql.common.SysFileMapper;
|
|
||||||
import cn.iocoder.dashboard.modules.system.service.common.SysFileService;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
|
|
||||||
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件 Service 实现类
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class SysFileServiceImpl implements SysFileService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SysFileMapper fileMapper;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private FileProperties fileProperties;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createFile(String path, byte[] content) {
|
|
||||||
if (fileMapper.selectCountById(path) > 0) {
|
|
||||||
throw ServiceExceptionUtil.exception(FILE_PATH_EXISTS);
|
|
||||||
}
|
|
||||||
// 保存到数据库
|
|
||||||
SysFileDO file = new SysFileDO();
|
|
||||||
file.setId(path);
|
|
||||||
file.setContent(content);
|
|
||||||
fileMapper.insert(file);
|
|
||||||
// 拼接路径返回
|
|
||||||
return fileProperties.getBasePath() + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SysFileDO getFile(String path) {
|
|
||||||
return fileMapper.selectById(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -99,6 +99,7 @@ public class ToolCodegenBuilder {
|
|||||||
.put(String.class.getSimpleName(), Sets.newHashSet("tinytext", "text", "mediumtext", "longtext", // 长文本
|
.put(String.class.getSimpleName(), Sets.newHashSet("tinytext", "text", "mediumtext", "longtext", // 长文本
|
||||||
"char", "varchar", "nvarchar", "varchar2")) // 短文本
|
"char", "varchar", "nvarchar", "varchar2")) // 短文本
|
||||||
.put(Date.class.getSimpleName(), Sets.newHashSet("datetime", "time", "date", "timestamp"))
|
.put(Date.class.getSimpleName(), Sets.newHashSet("datetime", "time", "date", "timestamp"))
|
||||||
|
.put("byte[]", Sets.newHashSet("blob"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -152,7 +152,7 @@ yudao:
|
|||||||
width: 160
|
width: 160
|
||||||
height: 60
|
height: 60
|
||||||
file:
|
file:
|
||||||
base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/file/get/
|
base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/infra/file/get/
|
||||||
codegen:
|
codegen:
|
||||||
base-package: ${yudao.info.base-package}
|
base-package: ${yudao.info.base-package}
|
||||||
db-schemas: ${spring.datasource.name}
|
db-schemas: ${spring.datasource.name}
|
||||||
|
@ -152,7 +152,7 @@ yudao:
|
|||||||
width: 160
|
width: 160
|
||||||
height: 60
|
height: 60
|
||||||
file:
|
file:
|
||||||
base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/file/get/
|
base-path: http://127.0.0.1:${server.port}/${yudao.web.api-prefix}/infra/file/get/
|
||||||
codegen:
|
codegen:
|
||||||
base-package: ${yudao.info.base-package}
|
base-package: ${yudao.info.base-package}
|
||||||
db-schemas: ${spring.datasource.name}
|
db-schemas: ${spring.datasource.name}
|
||||||
|
@ -16,6 +16,7 @@ import ${basePackage}.modules.${table.moduleName}.service.${table.businessName}.
|
|||||||
|
|
||||||
import ${ServiceExceptionUtilClassName};
|
import ${ServiceExceptionUtilClassName};
|
||||||
|
|
||||||
|
import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static ${basePackage}.modules.${table.moduleName}.enums.${simpleModuleName_upperFirst}ErrorCodeConstants.*;
|
import static ${basePackage}.modules.${table.moduleName}.enums.${simpleModuleName_upperFirst}ErrorCodeConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,7 +59,7 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
|
|||||||
|
|
||||||
private void validate${simpleClassName}Exists(${primaryColumn.javaType} id) {
|
private void validate${simpleClassName}Exists(${primaryColumn.javaType} id) {
|
||||||
if (${classNameVar}Mapper.selectById(id) == null) {
|
if (${classNameVar}Mapper.selectById(id) == null) {
|
||||||
throw ServiceExceptionUtil.exception(${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
|
throw exception(${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package ${basePackage}.modules.${table.moduleName}.service.${table.businessName};
|
package ${basePackage}.modules.${table.moduleName}.service.${table.businessName};
|
||||||
|
|
||||||
import ${basePackage}.BaseSpringBootUnitTest;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import cn.iocoder.dashboard.BaseSpringBootUnitTest;
|
import ${basePackage}.BaseDbUnitTest;
|
||||||
import ${basePackage}.modules.${table.moduleName}.service.${table.businessName}.impl.${table.className}ServiceImpl;
|
import ${basePackage}.modules.${table.moduleName}.service.${table.businessName}.impl.${table.className}ServiceImpl;
|
||||||
import ${basePackage}.modules.${table.moduleName}.controller.${table.businessName}.vo.*;
|
import ${basePackage}.modules.${table.moduleName}.controller.${table.businessName}.vo.*;
|
||||||
import ${basePackage}.modules.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
|
import ${basePackage}.modules.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
|
||||||
@ -16,6 +14,7 @@ import ${basePackage}.util.object.ObjectUtils;
|
|||||||
import ${PageResultClassName};
|
import ${PageResultClassName};
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static cn.hutool.core.util.RandomUtil.*;
|
import static cn.hutool.core.util.RandomUtil.*;
|
||||||
@ -64,7 +63,8 @@ import static org.mockito.Mockito.*;
|
|||||||
*
|
*
|
||||||
* @author ${table.author}
|
* @author ${table.author}
|
||||||
*/
|
*/
|
||||||
public class ${table.className}ServiceTest extends BaseSpringBootUnitTest {
|
@Import(${table.className}ServiceImpl.class)
|
||||||
|
public class ${table.className}ServiceTest extends BaseDbUnitTest {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private ${table.className}ServiceImpl ${classNameVar}Service;
|
private ${table.className}ServiceImpl ${classNameVar}Service;
|
||||||
@ -78,7 +78,7 @@ public class ${table.className}ServiceTest extends BaseSpringBootUnitTest {
|
|||||||
${table.className}CreateReqVO reqVO = randomPojo(${table.className}CreateReqVO.class);
|
${table.className}CreateReqVO reqVO = randomPojo(${table.className}CreateReqVO.class);
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
Long ${classNameVar}Id = ${classNameVar}Service.create${simpleClassName}(reqVO);
|
${primaryColumn.javaType} ${classNameVar}Id = ${classNameVar}Service.create${simpleClassName}(reqVO);
|
||||||
// 断言
|
// 断言
|
||||||
assertNotNull(${classNameVar}Id);
|
assertNotNull(${classNameVar}Id);
|
||||||
// 校验记录的属性是否正确
|
// 校验记录的属性是否正确
|
||||||
@ -118,7 +118,7 @@ public class ${table.className}ServiceTest extends BaseSpringBootUnitTest {
|
|||||||
${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class);
|
${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class);
|
||||||
${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据
|
${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据
|
||||||
// 准备参数
|
// 准备参数
|
||||||
Long id = db${simpleClassName}.getId();
|
${primaryColumn.javaType} id = db${simpleClassName}.getId();
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
${classNameVar}Service.delete${simpleClassName}(id);
|
${classNameVar}Service.delete${simpleClassName}(id);
|
||||||
@ -129,7 +129,7 @@ public class ${table.className}ServiceTest extends BaseSpringBootUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testDelete${simpleClassName}_notExists() {
|
public void testDelete${simpleClassName}_notExists() {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
Long id = randomLongId();
|
${primaryColumn.javaType} id = random${primaryColumn.javaType}Id();
|
||||||
|
|
||||||
// 调用, 并断言异常
|
// 调用, 并断言异常
|
||||||
assertServiceException(() -> ${classNameVar}Service.delete${simpleClassName}(id), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
|
assertServiceException(() -> ${classNameVar}Service.delete${simpleClassName}(id), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
|
||||||
|
@ -4,7 +4,7 @@ INSERT INTO `sys_menu`(
|
|||||||
`path`, `icon`, `component`, `status`
|
`path`, `icon`, `component`, `status`
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
'${table.classComment}管理', '${permissionPrefix}:query', 2, 0, ${table.parentMenuId},
|
'${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
|
||||||
'${simpleClassName_strikeCase}', '', '${table.moduleName}/${classNameVar}/index', 0
|
'${simpleClassName_strikeCase}', '', '${table.moduleName}/${classNameVar}/index', 0
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -12,8 +12,8 @@ VALUES (
|
|||||||
SELECT @parentId := LAST_INSERT_ID();
|
SELECT @parentId := LAST_INSERT_ID();
|
||||||
|
|
||||||
-- 按钮 SQL
|
-- 按钮 SQL
|
||||||
#set ($functionNames = ['创建', '更新', '删除', '导出'])
|
#set ($functionNames = ['查询', '创建', '更新', '删除', '导出'])
|
||||||
#set ($functionOps = ['create', 'update', 'delete', 'export'])
|
#set ($functionOps = ['query', 'create', 'update', 'delete', 'export'])
|
||||||
#foreach ($functionName in $functionNames)
|
#foreach ($functionName in $functionNames)
|
||||||
#set ($index = $foreach.count - 1)
|
#set ($index = $foreach.count - 1)
|
||||||
INSERT INTO `sys_menu`(
|
INSERT INTO `sys_menu`(
|
||||||
@ -21,7 +21,7 @@ INSERT INTO `sys_menu`(
|
|||||||
`path`, `icon`, `component`, `status`
|
`path`, `icon`, `component`, `status`
|
||||||
)
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
'${table.tableComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
|
'${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
|
||||||
'', '', '', 0
|
'', '', '', 0
|
||||||
);
|
);
|
||||||
#end
|
#end
|
||||||
|
@ -68,7 +68,7 @@
|
|||||||
#if ($column.javaType == "Date")## 时间类型
|
#if ($column.javaType == "Date")## 时间类型
|
||||||
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
|
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
|
<span>{{ parseTime(scope.row.${javaField}) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
#elseif("" != $column.dictType)## 数据字典
|
#elseif("" != $column.dictType)## 数据字典
|
||||||
|
@ -0,0 +1,126 @@
|
|||||||
|
package cn.iocoder.dashboard.modules.infra.service.file;
|
||||||
|
|
||||||
|
import cn.hutool.core.io.resource.ResourceUtil;
|
||||||
|
import cn.iocoder.dashboard.BaseDbUnitTest;
|
||||||
|
import cn.iocoder.dashboard.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.dashboard.framework.file.config.FileProperties;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.controller.file.vo.InfFilePageReqVO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.dal.dataobject.file.InfFileDO;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.dal.mysql.file.InfFileMapper;
|
||||||
|
import cn.iocoder.dashboard.modules.infra.service.file.impl.InfFileServiceImpl;
|
||||||
|
import cn.iocoder.dashboard.util.object.ObjectUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import static cn.iocoder.dashboard.modules.infra.enums.InfErrorCodeConstants.FILE_NOT_EXISTS;
|
||||||
|
import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS;
|
||||||
|
import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
|
||||||
|
import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
|
||||||
|
import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
|
||||||
|
import static cn.iocoder.dashboard.util.RandomUtils.randomString;
|
||||||
|
import static cn.iocoder.dashboard.util.date.DateUtils.buildTime;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@Import({InfFileServiceImpl.class, FileProperties.class})
|
||||||
|
public class InfFileServiceTest extends BaseDbUnitTest {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InfFileServiceImpl fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FileProperties fileProperties;
|
||||||
|
@Resource
|
||||||
|
private InfFileMapper fileMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateFile_success() {
|
||||||
|
// 准备参数
|
||||||
|
String path = randomString();
|
||||||
|
byte[] content = ResourceUtil.readBytes("file/erweima.jpg");
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
String url = fileService.createFile(path, content);
|
||||||
|
// 断言
|
||||||
|
assertEquals(fileProperties.getBasePath() + path, url);
|
||||||
|
// 校验数据
|
||||||
|
InfFileDO file = fileMapper.selectById(path);
|
||||||
|
assertEquals(path, file.getId());
|
||||||
|
assertEquals("jpg", file.getType());
|
||||||
|
assertArrayEquals(content, file.getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateFile_exists() {
|
||||||
|
// mock 数据
|
||||||
|
InfFileDO dbFile = randomPojo(InfFileDO.class);
|
||||||
|
fileMapper.insert(dbFile);
|
||||||
|
// 准备参数
|
||||||
|
String path = dbFile.getId(); // 模拟已存在
|
||||||
|
byte[] content = ResourceUtil.readBytes("file/erweima.jpg");
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> fileService.createFile(path, content), FILE_PATH_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteFile_success() {
|
||||||
|
// mock 数据
|
||||||
|
InfFileDO dbFile = randomPojo(InfFileDO.class);
|
||||||
|
fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据
|
||||||
|
// 准备参数
|
||||||
|
String id = dbFile.getId();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
fileService.deleteFile(id);
|
||||||
|
// 校验数据不存在了
|
||||||
|
assertNull(fileMapper.selectById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeleteFile_notExists() {
|
||||||
|
// 准备参数
|
||||||
|
String id = randomString();
|
||||||
|
|
||||||
|
// 调用, 并断言异常
|
||||||
|
assertServiceException(() -> fileService.deleteFile(id), FILE_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFilePage() {
|
||||||
|
// mock 数据
|
||||||
|
InfFileDO dbFile = randomPojo(InfFileDO.class, o -> { // 等会查询到
|
||||||
|
o.setId("yudao");
|
||||||
|
o.setType("jpg");
|
||||||
|
o.setCreateTime(buildTime(2021, 1, 15));
|
||||||
|
});
|
||||||
|
fileMapper.insert(dbFile);
|
||||||
|
// 测试 id 不匹配
|
||||||
|
fileMapper.insert(ObjectUtils.clone(dbFile, o -> o.setId("tudou")));
|
||||||
|
// 测试 type 不匹配
|
||||||
|
fileMapper.insert(ObjectUtils.clone(dbFile, o -> {
|
||||||
|
o.setId("yudao02");
|
||||||
|
o.setType("png");
|
||||||
|
}));
|
||||||
|
// 测试 createTime 不匹配
|
||||||
|
fileMapper.insert(ObjectUtils.clone(dbFile, o -> {
|
||||||
|
o.setId("yudao03");
|
||||||
|
o.setCreateTime(buildTime(2020, 1, 15));
|
||||||
|
}));
|
||||||
|
// 准备参数
|
||||||
|
InfFilePageReqVO reqVO = new InfFilePageReqVO();
|
||||||
|
reqVO.setId("yudao");
|
||||||
|
reqVO.setType("jp");
|
||||||
|
reqVO.setBeginCreateTime(buildTime(2021, 1, 10));
|
||||||
|
reqVO.setEndCreateTime(buildTime(2021, 1, 20));
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
PageResult<InfFileDO> pageResult = fileService.getFilePage(reqVO);
|
||||||
|
// 断言
|
||||||
|
assertEquals(1, pageResult.getTotal());
|
||||||
|
assertEquals(1, pageResult.getList().size());
|
||||||
|
assertPojoEquals(dbFile, pageResult.getList().get(0), "content");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,6 @@ package cn.iocoder.dashboard.modules.system.service.auth;
|
|||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.iocoder.dashboard.BaseDbAndRedisUnitTest;
|
import cn.iocoder.dashboard.BaseDbAndRedisUnitTest;
|
||||||
import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
|
|
||||||
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
|
import cn.iocoder.dashboard.framework.security.config.SecurityProperties;
|
||||||
import cn.iocoder.dashboard.modules.system.dal.dataobject.auth.SysUserSessionDO;
|
import cn.iocoder.dashboard.modules.system.dal.dataobject.auth.SysUserSessionDO;
|
||||||
import cn.iocoder.dashboard.modules.system.dal.mysql.auth.SysUserSessionMapper;
|
import cn.iocoder.dashboard.modules.system.dal.mysql.auth.SysUserSessionMapper;
|
||||||
@ -32,24 +31,24 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @since <pre>3月 8, 2021</pre>
|
* @since <pre>3月 8, 2021</pre>
|
||||||
*/
|
*/
|
||||||
@Import(
|
@Import(SysUserSessionServiceImpl.class)
|
||||||
SysUserSessionServiceImpl.class)
|
|
||||||
public class SysUserSessionServiceImplTest extends BaseDbAndRedisUnitTest {
|
public class SysUserSessionServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
SysUserSessionServiceImpl sysUserSessionService;
|
private SysUserSessionServiceImpl sysUserSessionService;
|
||||||
@Resource
|
@Resource
|
||||||
SysUserSessionMapper sysUserSessionMapper;
|
private SysUserSessionMapper sysUserSessionMapper;
|
||||||
|
|
||||||
@MockBean
|
@MockBean
|
||||||
SecurityProperties securityProperties;
|
private SecurityProperties securityProperties;
|
||||||
@MockBean
|
@MockBean
|
||||||
SysDeptServiceImpl sysDeptService;
|
private SysDeptServiceImpl sysDeptService;
|
||||||
@MockBean
|
@MockBean
|
||||||
SysUserServiceImpl sysUserService;
|
private SysUserServiceImpl sysUserService;
|
||||||
@MockBean
|
@MockBean
|
||||||
SysLoginLogServiceImpl sysLoginLogService;
|
private SysLoginLogServiceImpl sysLoginLogService;
|
||||||
@MockBean
|
@MockBean
|
||||||
SysLoginUserRedisDAO sysLoginUserRedisDAO;
|
private SysLoginUserRedisDAO sysLoginUserRedisDAO;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClearSessionTimeout_success() throws Exception {
|
public void testClearSessionTimeout_success() throws Exception {
|
||||||
|
BIN
src/test/resources/file/erweima.jpg
Normal file
BIN
src/test/resources/file/erweima.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@ -1,5 +1,6 @@
|
|||||||
-- inf 开头的 DB
|
-- inf 开头的 DB
|
||||||
DELETE FROM "inf_config";
|
DELETE FROM "inf_config";
|
||||||
|
DELETE FROM "inf_file";
|
||||||
|
|
||||||
-- sys 开头的 DB
|
-- sys 开头的 DB
|
||||||
DELETE FROM "sys_dept";
|
DELETE FROM "sys_dept";
|
||||||
|
@ -17,6 +17,18 @@ CREATE TABLE IF NOT EXISTS "inf_config" (
|
|||||||
PRIMARY KEY ("id")
|
PRIMARY KEY ("id")
|
||||||
) COMMENT '参数配置表';
|
) COMMENT '参数配置表';
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "inf_file" (
|
||||||
|
"id" varchar(188) NOT NULL,
|
||||||
|
"type" varchar(63) DEFAULT NULL,
|
||||||
|
"content" blob NOT NULL,
|
||||||
|
"creator" varchar(64) DEFAULT '',
|
||||||
|
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updater" varchar(64) DEFAULT '',
|
||||||
|
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||||
|
PRIMARY KEY ("id")
|
||||||
|
) COMMENT '文件表';
|
||||||
|
|
||||||
-- sys 开头的 DB
|
-- sys 开头的 DB
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "sys_dept" (
|
CREATE TABLE IF NOT EXISTS "sys_dept" (
|
||||||
|
Loading…
Reference in New Issue
Block a user