diff --git a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
index 1aae87f3de..3466cadd6e 100644
--- a/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
+++ b/backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
@@ -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);
diff --git a/backend/src/main/java/io/dataease/commons/utils/FileUtils.java b/backend/src/main/java/io/dataease/commons/utils/FileUtils.java
new file mode 100644
index 0000000000..64760511b0
--- /dev/null
+++ b/backend/src/main/java/io/dataease/commons/utils/FileUtils.java
@@ -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);
+ }
+ }
+}
diff --git a/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java b/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java
new file mode 100644
index 0000000000..cd644a98a0
--- /dev/null
+++ b/backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java
@@ -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;
+ }
+}
diff --git a/backend/src/main/java/io/dataease/config/DeMvcConfig.java b/backend/src/main/java/io/dataease/config/DeMvcConfig.java
new file mode 100644
index 0000000000..04f73c5217
--- /dev/null
+++ b/backend/src/main/java/io/dataease/config/DeMvcConfig.java
@@ -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);
+
+ }
+}
diff --git a/backend/src/main/java/io/dataease/config/properties/StaticResourceProperties.java b/backend/src/main/java/io/dataease/config/properties/StaticResourceProperties.java
new file mode 100644
index 0000000000..9e49adeb24
--- /dev/null
+++ b/backend/src/main/java/io/dataease/config/properties/StaticResourceProperties.java
@@ -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";
+
+}
diff --git a/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java b/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java
new file mode 100644
index 0000000000..8f4297289f
--- /dev/null
+++ b/backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java
@@ -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);
+ }
+}
diff --git a/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java b/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java
new file mode 100644
index 0000000000..61cc19bacd
--- /dev/null
+++ b/backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java
@@ -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);
+ }
+ }
+}
diff --git a/frontend/src/api/staticResource/staticResource.js b/frontend/src/api/staticResource/staticResource.js
new file mode 100644
index 0000000000..de424b0680
--- /dev/null
+++ b/frontend/src/api/staticResource/staticResource.js
@@ -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)
+ })
+}
+
diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js
index 9aaef94971..1946f180c5 100644
--- a/frontend/src/store/index.js
+++ b/frontend/src/store/index.js
@@ -109,7 +109,9 @@ const data = {
// 仪表板视图明细
panelViewDetailsInfo: {},
// 当前tab页内组件
- curActiveTabInner: null
+ curActiveTabInner: null,
+ // static resource local path
+ staticResourcePath: '/static-resource/'
},
mutations: {
...animation.mutations,
diff --git a/frontend/src/views/background/index.vue b/frontend/src/views/background/index.vue
index 3a5ca9c74e..cdec3808a9 100644
--- a/frontend/src/views/background/index.vue
+++ b/frontend/src/views/background/index.vue
@@ -64,7 +64,6 @@
:on-remove="handleRemove"
:http-request="upload"
:file-list="fileList"
- :on-change="onChange"
>
@@ -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')
}
diff --git a/frontend/src/views/panel/SubjectSetting/PanelStyle/BackgroundSelector.vue b/frontend/src/views/panel/SubjectSetting/PanelStyle/BackgroundSelector.vue
index 85cbcd70b3..a1ad601846 100644
--- a/frontend/src/views/panel/SubjectSetting/PanelStyle/BackgroundSelector.vue
+++ b/frontend/src/views/panel/SubjectSetting/PanelStyle/BackgroundSelector.vue
@@ -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"
>
@@ -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()
+ })
}
}
}