From f55749417de23e110af2da118e0f7aba0855ebe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=98=89=E8=B1=AA?= <42510293+ziyujiahao@users.noreply.github.com> Date: Mon, 25 Apr 2022 12:13:05 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20=E8=83=8C=E6=99=AF=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E7=9B=B4=E6=8E=A5=E5=AD=98=E5=82=A8=E5=9C=A8=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: 背景图片直接存储在服务器 --- .../auth/service/impl/ShiroServiceImpl.java | 1 + .../io/dataease/commons/utils/FileUtils.java | 26 +++++++++ .../commons/utils/StaticResourceUtils.java | 54 +++++++++++++++++++ .../java/io/dataease/config/DeMvcConfig.java | 52 ++++++++++++++++++ .../properties/StaticResourceProperties.java | 18 +++++++ .../StaticResourceController.java | 28 ++++++++++ .../staticResource/StaticResourceService.java | 48 +++++++++++++++++ .../src/api/staticResource/staticResource.js | 26 +++++++++ frontend/src/store/index.js | 4 +- frontend/src/views/background/index.vue | 18 +++---- .../PanelStyle/BackgroundSelector.vue | 22 +++----- 11 files changed, 270 insertions(+), 27 deletions(-) create mode 100644 backend/src/main/java/io/dataease/commons/utils/FileUtils.java create mode 100644 backend/src/main/java/io/dataease/commons/utils/StaticResourceUtils.java create mode 100644 backend/src/main/java/io/dataease/config/DeMvcConfig.java create mode 100644 backend/src/main/java/io/dataease/config/properties/StaticResourceProperties.java create mode 100644 backend/src/main/java/io/dataease/controller/staticResource/StaticResourceController.java create mode 100644 backend/src/main/java/io/dataease/service/staticResource/StaticResourceService.java create mode 100644 frontend/src/api/staticResource/staticResource.js 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() + }) } } } From f4130f61a28a519ff65be147ab928c6056bae443 Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Mon, 25 Apr 2022 13:00:18 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20dataease=E9=80=82=E9=85=8D=E7=AC=A6?= =?UTF-8?q?=E5=8F=B7=E5=9C=B0=E5=9B=BE=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/io/dataease/service/chart/ChartViewService.java | 3 +++ .../main/java/io/dataease/service/sys/PluginService.java | 6 ++++-- .../src/components/canvas/custom-component/UserView.vue | 7 +++++++ .../components/canvas/custom-component/UserViewDialog.vue | 1 + .../canvas/custom-component/UserViewMobileDialog.vue | 1 + frontend/src/views/chart/view/ChartEdit.vue | 3 +++ frontend/src/views/system/plugin/PluginCom.vue | 3 +++ 7 files changed, 22 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java index f8dc176372..c3d1e31871 100644 --- a/backend/src/main/java/io/dataease/service/chart/ChartViewService.java +++ b/backend/src/main/java/io/dataease/service/chart/ChartViewService.java @@ -503,6 +503,9 @@ public class ChartViewService { // 如果是插件视图 走插件内部的逻辑 if (ObjectUtils.isNotEmpty(view.getIsPlugin()) && view.getIsPlugin()) { Map> fieldMap = new HashMap<>(); + List xAxisExt = new Gson().fromJson(view.getXAxisExt(), new TypeToken>() { + }.getType()); + fieldMap.put("xAxisExt",xAxisExt); fieldMap.put("xAxis", xAxis); fieldMap.put("yAxis", yAxis); fieldMap.put("extStack", extStack); diff --git a/backend/src/main/java/io/dataease/service/sys/PluginService.java b/backend/src/main/java/io/dataease/service/sys/PluginService.java index 0627830715..db6882f081 100644 --- a/backend/src/main/java/io/dataease/service/sys/PluginService.java +++ b/backend/src/main/java/io/dataease/service/sys/PluginService.java @@ -1,6 +1,7 @@ package io.dataease.service.sys; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ZipUtil; import com.google.gson.Gson; import io.dataease.dto.MyPluginDTO; import io.dataease.ext.ExtSysPluginMapper; @@ -72,8 +73,9 @@ public class PluginService { //2.解压目标文件dest 得到plugin.json和jar String folder = pluginDir + "folder/"; try { - ZipUtils.unzip(dest, folder); - } catch (IOException e) { + ZipUtil.unzip(dest.getAbsolutePath(), folder); + // ZipUtils.unzip(dest, folder); + } catch (Exception e) { DeFileUtils.deleteFile(pluginDir + "temp/"); DeFileUtils.deleteFile(folder); // 需要删除文件 diff --git a/frontend/src/components/canvas/custom-component/UserView.vue b/frontend/src/components/canvas/custom-component/UserView.vue index 0e8f35793e..3dfc26d96a 100644 --- a/frontend/src/components/canvas/custom-component/UserView.vue +++ b/frontend/src/components/canvas/custom-component/UserView.vue @@ -21,7 +21,14 @@ :ref="element.propValue.id" :component-name="chart.type + '-view'" :obj="{chart, trackMenu, searchCount, terminalType: scaleCoefficientType}" + :chart="chart" + :track-menu="trackMenu" + :search-count="searchCount" + :terminal-type="scaleCoefficientType" + :scale="scale" class="chart-class" + @onChartClick="chartClick" + @onJumpClick="jumpClick" /> diff --git a/frontend/src/components/canvas/custom-component/UserViewMobileDialog.vue b/frontend/src/components/canvas/custom-component/UserViewMobileDialog.vue index d57297fd04..6dd44ebe5e 100644 --- a/frontend/src/components/canvas/custom-component/UserViewMobileDialog.vue +++ b/frontend/src/components/canvas/custom-component/UserViewMobileDialog.vue @@ -5,6 +5,7 @@ v-if="chart.isPlugin" :component-name="chart.type + '-view'" :obj="{chart: mapChart || chart}" + :chart="mapChart || chart" class="chart-class" /> diff --git a/frontend/src/views/chart/view/ChartEdit.vue b/frontend/src/views/chart/view/ChartEdit.vue index 6ef0cf3eac..f4a1a28171 100644 --- a/frontend/src/views/chart/view/ChartEdit.vue +++ b/frontend/src/views/chart/view/ChartEdit.vue @@ -962,7 +962,10 @@ ref="dynamicChart" :component-name="chart.type + '-view'" :obj="{chart}" + :chart-id="chart.id" + :chart="chart" class="chart-class" + @onChartClick="chartClick" /> Date: Mon, 25 Apr 2022 13:13:37 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=E6=96=B0=E5=A2=9Etab=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/canvas/components/Editor/SettingMenu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/canvas/components/Editor/SettingMenu.vue b/frontend/src/components/canvas/components/Editor/SettingMenu.vue index 6c64133a79..c765fdcf1b 100644 --- a/frontend/src/components/canvas/components/Editor/SettingMenu.vue +++ b/frontend/src/components/canvas/components/Editor/SettingMenu.vue @@ -12,7 +12,7 @@ {{ $t('panel.upComponent') }} {{ $t('panel.downComponent') }} {{ $t('panel.linkage_setting') }} - {{ $t('panel.add_tab') }} + {{ $t('panel.add_tab') }} {{ $t('panel.setting_jump') }} {{ $t('panel.component_style') }}