forked from github/dataease
refactor: 背景图片直接存储在服务器
refactor: 背景图片直接存储在服务器
This commit is contained in:
parent
dbb8a7a76d
commit
f55749417d
@ -48,6 +48,7 @@ public class ShiroServiceImpl implements ShiroService {
|
||||
filterChainDefinitionMap.put("/plugin/theme/themes", ANON);
|
||||
filterChainDefinitionMap.put("/plugin/theme/items/**", ANON);
|
||||
filterChainDefinitionMap.put("/plugin/view/types", ANON);
|
||||
filterChainDefinitionMap.put("/static-resource/**", ANON);
|
||||
|
||||
// 验证链接
|
||||
filterChainDefinitionMap.put("/api/link/validate**", ANON);
|
||||
|
@ -0,0 +1,26 @@
|
||||
package io.dataease.commons.utils;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/4/24
|
||||
* Description:
|
||||
*/
|
||||
public class FileUtils {
|
||||
|
||||
public static void createIfAbsent(@NonNull Path path) throws IOException {
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
|
||||
if (Files.notExists(path)) {
|
||||
// Create directories
|
||||
Files.createDirectories(path);
|
||||
LogUtil.debug("Created directory: [{}]", path);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package io.dataease.commons.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/4/24
|
||||
* Description:
|
||||
*/
|
||||
public class StaticResourceUtils {
|
||||
public static final String URL_SEPARATOR = "/";
|
||||
|
||||
private static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
|
||||
|
||||
public static String ensureBoth(@NonNull String string, @NonNull String bothfix) {
|
||||
return ensureBoth(string, bothfix, bothfix);
|
||||
}
|
||||
|
||||
public static String ensureBoth(@NonNull String string, @NonNull String prefix,
|
||||
@NonNull String suffix) {
|
||||
return ensureSuffix(ensurePrefix(string, prefix), suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the string contain prefix.
|
||||
*
|
||||
* @param string string must not be blank
|
||||
* @param prefix prefix must not be blank
|
||||
* @return string contain prefix specified
|
||||
*/
|
||||
public static String ensurePrefix(@NonNull String string, @NonNull String prefix) {
|
||||
Assert.hasText(string, "String must not be blank");
|
||||
Assert.hasText(prefix, "Prefix must not be blank");
|
||||
|
||||
return prefix + StringUtils.removeStart(string, prefix);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensures the string contain suffix.
|
||||
*
|
||||
* @param string string must not be blank
|
||||
* @param suffix suffix must not be blank
|
||||
* @return string contain suffix specified
|
||||
*/
|
||||
public static String ensureSuffix(@NonNull String string, @NonNull String suffix) {
|
||||
Assert.hasText(string, "String must not be blank");
|
||||
Assert.hasText(suffix, "Suffix must not be blank");
|
||||
|
||||
return StringUtils.removeEnd(string, suffix) + suffix;
|
||||
}
|
||||
}
|
52
backend/src/main/java/io/dataease/config/DeMvcConfig.java
Normal file
52
backend/src/main/java/io/dataease/config/DeMvcConfig.java
Normal file
@ -0,0 +1,52 @@
|
||||
package io.dataease.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static io.dataease.commons.utils.StaticResourceUtils.ensureBoth;
|
||||
import static io.dataease.commons.utils.StaticResourceUtils.ensureSuffix;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/4/24
|
||||
* Description:
|
||||
*/
|
||||
@Configuration
|
||||
public class DeMvcConfig implements WebMvcConfigurer {
|
||||
private static final String FILE_PROTOCOL = "file://";
|
||||
public static final String FILE_SEPARATOR = File.separator;
|
||||
public static final String USER_HOME = "/opt/dataease/data";
|
||||
|
||||
private static String WORK_DIR = ensureSuffix(USER_HOME, FILE_SEPARATOR) + "static-resource" + FILE_SEPARATOR;
|
||||
|
||||
|
||||
/**
|
||||
* Upload prefix.
|
||||
*/
|
||||
private final static String UPLOAD_URL_PREFIX = "static-resource";
|
||||
|
||||
|
||||
/**
|
||||
* url separator.
|
||||
*/
|
||||
public static final String URL_SEPARATOR = "/";
|
||||
|
||||
/**
|
||||
* Configuring static resource path
|
||||
*
|
||||
* @param registry registry
|
||||
*/
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
String workDir = FILE_PROTOCOL + ensureSuffix(WORK_DIR, FILE_SEPARATOR);
|
||||
String uploadUrlPattern = ensureBoth(UPLOAD_URL_PREFIX, URL_SEPARATOR) + "**";
|
||||
registry.addResourceHandler(uploadUrlPattern)
|
||||
.addResourceLocations(workDir);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package io.dataease.config.properties;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/4/24
|
||||
* Description:
|
||||
*/
|
||||
@Data
|
||||
public class StaticResourceProperties {
|
||||
|
||||
/**
|
||||
* Upload prefix.
|
||||
*/
|
||||
private String uploadUrlPrefix = "static-resource";
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package io.dataease.controller.staticResource;
|
||||
|
||||
import io.dataease.service.staticResource.StaticResourceService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.pentaho.ui.xul.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/4/24
|
||||
* Description:
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/static/resource")
|
||||
public class StaticResourceController {
|
||||
|
||||
@Resource
|
||||
StaticResourceService staticResourceService;
|
||||
|
||||
@PostMapping("upload/{fileId}")
|
||||
@ApiOperation("Uploads static file")
|
||||
public void upload(@PathVariable("fileId") String fileId, @RequestPart("file") MultipartFile file) {
|
||||
staticResourceService.upload(fileId,file);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package io.dataease.service.staticResource;
|
||||
|
||||
import io.dataease.commons.utils.FileUtils;
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import io.dataease.exception.DataEaseException;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Author: wangjiahao
|
||||
* Date: 2022/4/24
|
||||
* Description:
|
||||
*/
|
||||
@Service
|
||||
public class StaticResourceService {
|
||||
|
||||
private final Path staticDir = Paths.get("/opt/dataease/data/static-resource/");
|
||||
|
||||
public void upload(String fileId,MultipartFile file) {
|
||||
// check if the path is valid (not outside staticDir)
|
||||
Assert.notNull(file, "Multipart file must not be null");
|
||||
try {
|
||||
String originName = file.getOriginalFilename();
|
||||
String newFileName = fileId+originName.substring(originName.lastIndexOf("."),originName.length());
|
||||
Path uploadPath = Paths.get(staticDir.toString(), newFileName);
|
||||
// create dir is absent
|
||||
FileUtils.createIfAbsent(Paths.get(staticDir.toString()));
|
||||
Files.createFile(uploadPath);
|
||||
file.transferTo(uploadPath);
|
||||
} catch (IOException e) {
|
||||
LogUtil.error("文件上传失败",e);
|
||||
DataEaseException.throwException("文件上传失败");
|
||||
} catch (Exception e){
|
||||
DataEaseException.throwException(e);
|
||||
}
|
||||
}
|
||||
}
|
26
frontend/src/api/staticResource/staticResource.js
Normal file
26
frontend/src/api/staticResource/staticResource.js
Normal file
@ -0,0 +1,26 @@
|
||||
import request from '@/utils/request'
|
||||
import { uuid } from 'vue-uuid'
|
||||
import store from '@/store'
|
||||
|
||||
export function uploadFile(fileId, file) {
|
||||
const param = new FormData()
|
||||
param.append('file', file.file)
|
||||
return request({
|
||||
url: '/static/resource/upload/' + fileId,
|
||||
method: 'post',
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
data: param,
|
||||
loading: false
|
||||
})
|
||||
}
|
||||
|
||||
export function uploadFileResult(file, callback) {
|
||||
const fileId = uuid.v1()
|
||||
const fileName = file.file.name
|
||||
const newFileName = fileId + fileName.substr(fileName.lastIndexOf('.'), fileName.length)
|
||||
const fileUrl = store.state.staticResourcePath + newFileName
|
||||
uploadFile(fileId, file).then(() => {
|
||||
callback(fileUrl)
|
||||
})
|
||||
}
|
||||
|
@ -109,7 +109,9 @@ const data = {
|
||||
// 仪表板视图明细
|
||||
panelViewDetailsInfo: {},
|
||||
// 当前tab页内组件
|
||||
curActiveTabInner: null
|
||||
curActiveTabInner: null,
|
||||
// static resource local path
|
||||
staticResourcePath: '/static-resource/'
|
||||
},
|
||||
mutations: {
|
||||
...animation.mutations,
|
||||
|
@ -64,7 +64,6 @@
|
||||
:on-remove="handleRemove"
|
||||
:http-request="upload"
|
||||
:file-list="fileList"
|
||||
:on-change="onChange"
|
||||
>
|
||||
<i class="el-icon-plus" />
|
||||
</el-upload>
|
||||
@ -108,9 +107,9 @@
|
||||
import { queryBackground } from '@/api/background/background'
|
||||
import BackgroundItem from '@/views/background/BackgroundItem'
|
||||
import { mapState } from 'vuex'
|
||||
import eventBus from '@/components/canvas/utils/eventBus'
|
||||
import { deepCopy } from '@/components/canvas/utils/utils'
|
||||
import { COLOR_PANEL } from '@/views/chart/chart/chart'
|
||||
import { uploadFileResult } from '@/api/staticResource/staticResource'
|
||||
|
||||
export default {
|
||||
name: 'Background',
|
||||
@ -179,7 +178,7 @@ export default {
|
||||
},
|
||||
handleRemove(file, fileList) {
|
||||
this.uploadDisabled = false
|
||||
this.panel.imageUrl = null
|
||||
this.curComponent.commonBackground.outerImage = null
|
||||
this.fileList = []
|
||||
this.commitStyle()
|
||||
},
|
||||
@ -187,16 +186,11 @@ export default {
|
||||
this.dialogImageUrl = file.url
|
||||
this.dialogVisible = true
|
||||
},
|
||||
onChange(file, fileList) {
|
||||
var _this = this
|
||||
_this.uploadDisabled = true
|
||||
const reader = new FileReader()
|
||||
reader.onload = function() {
|
||||
_this.curComponent.commonBackground.outerImage = reader.result
|
||||
}
|
||||
reader.readAsDataURL(file.raw)
|
||||
},
|
||||
upload(file) {
|
||||
const _this = this
|
||||
uploadFileResult(file, (fileUrl) => {
|
||||
_this.curComponent.commonBackground.outerImage = fileUrl
|
||||
})
|
||||
// console.log('this is upload')
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,11 @@
|
||||
accept=".jpeg,.jpg,.png,.gif"
|
||||
class="avatar-uploader"
|
||||
list-type="picture-card"
|
||||
:http-request="upload"
|
||||
:class="{disabled:uploadDisabled}"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-remove="handleRemove"
|
||||
:http-request="upload"
|
||||
:file-list="fileList"
|
||||
:on-change="onChange"
|
||||
>
|
||||
<i class="el-icon-plus" />
|
||||
</el-upload>
|
||||
@ -51,6 +50,7 @@
|
||||
import { mapState } from 'vuex'
|
||||
import { deepCopy } from '@/components/canvas/utils/utils'
|
||||
import { COLOR_PANEL } from '@/views/chart/chart/chart'
|
||||
import { uploadFileResult } from '@/api/staticResource/staticResource'
|
||||
|
||||
export default {
|
||||
name: 'BackgroundSelector',
|
||||
@ -98,19 +98,13 @@ export default {
|
||||
this.dialogImageUrl = file.url
|
||||
this.dialogVisible = true
|
||||
},
|
||||
onChange(file, fileList) {
|
||||
var _this = this
|
||||
_this.uploadDisabled = true
|
||||
const reader = new FileReader()
|
||||
reader.onload = function() {
|
||||
_this.panel.imageUrl = reader.result
|
||||
this.commitStyle()
|
||||
}
|
||||
this.$store.state.styleChangeTimes++
|
||||
reader.readAsDataURL(file.raw)
|
||||
},
|
||||
upload(file) {
|
||||
// console.log('this is upload')
|
||||
const _this = this
|
||||
uploadFileResult(file, (fileUrl) => {
|
||||
_this.$store.state.styleChangeTimes++
|
||||
_this.panel.imageUrl = fileUrl
|
||||
_this.commitStyle()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user