From e898a9ef2c884033c3eb595931b227434b1de020 Mon Sep 17 00:00:00 2001 From: wangshaoping Date: Fri, 23 Aug 2024 18:03:32 +0800 Subject: [PATCH 1/2] update --- build.gradle | 14 +- erm.frontend/package.json | 2 +- erm.frontend/public/configure.js | 14 +- gradle.properties | 2 +- io.sc.engine.mv.frontend/package.json | 2 +- io.sc.engine.mv.frontend/public/configure.js | 14 +- .../src/views/sample/Sample.vue | 10 +- io.sc.engine.rule.frontend/package.json | 2 +- .../public/configure.js | 14 +- io.sc.engine.st.frontend/package.json | 2 +- io.sc.engine.st.frontend/public/configure.js | 14 +- io.sc.platform.core.frontend/package.json | 2 +- .../public/configure.js | 14 +- .../src/platform/PConst.ts | 5 + .../src/platform/index.ts | 3 +- .../src/platform/plugin/axios copy.ts | 164 ------------------ .../src/platform/plugin/environment/index.ts | 16 ++ .../src/platform/plugin/index.ts | 3 +- .../plugin/manager/ApplicationInitializer.ts | 40 ++--- .../platform/plugin/manager/RouterManager.ts | 88 +++++----- .../src/platform/plugin/manager/index.ts | 3 +- .../src/platform/plugin/router.ts | 10 +- .../src/platform/utils/JavascriptLoader.ts | 16 +- .../src/platform/views/Login.vue | 11 +- .../template-project/package.json | 4 +- .../template-project/public/configure.js | 14 +- .../package.json | 2 +- .../public/configure.js | 14 +- .../templates/pgp/setup/build.gradle.txt | 16 +- .../templates/pgp/setup/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../templates/pgp/setup/gradlew.bat | 20 +-- io.sc.platform.lcdp.frontend/package.json | 2 +- .../public/configure.js | 14 +- .../controller/ConfigureController.java | 2 +- .../controller/ConfigureJsController.java | 12 -- io.sc.platform.mvc.frontend/package.json | 2 +- .../public/configure.js | 14 +- ...ontroller.java => FrontendController.java} | 19 +- .../mvc/controller/IndexWebController.java | 10 +- .../platform/mvc/service/FrontEndService.java | 3 + .../mvc/service/impl/FrontEndServiceImpl.java | 20 ++- .../impl/FrontendExportServiceImpl.java | 18 +- .../META-INF/platform/plugins/security.json | 2 + .../src/main/resources/templates/configure.js | 11 +- .../package.json | 2 +- .../public/configure.js | 14 +- ...tUsernamePasswordAuthenticationFilter.java | 4 +- .../installer/AdministratorInstallerItem.java | 72 +++++--- io.sc.platform.system.frontend/package.json | 2 +- .../public/configure.js | 14 +- .../user/service/impl/UserServiceImpl.java | 5 - .../user/service/support/UserSession.java | 15 -- io.sc.standard.frontend/package.json | 2 +- io.sc.standard.frontend/public/configure.js | 14 +- 55 files changed, 410 insertions(+), 402 deletions(-) delete mode 100644 io.sc.platform.core.frontend/src/platform/plugin/axios copy.ts delete mode 100644 io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/configure/controller/ConfigureJsController.java rename io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/{FrontendModuleController.java => FrontendController.java} (71%) rename {io.sc.platform.lcdp => io.sc.platform.mvc}/src/main/resources/templates/configure.js (83%) diff --git a/build.gradle b/build.gradle index 83f7eab5..3b0210c7 100644 --- a/build.gradle +++ b/build.gradle @@ -684,13 +684,13 @@ subprojects { if(isFrontendProject(file('.'))) { if(project.name!='io.sc.platform.mvc.frontend'){ exclude("**/${project.name}/*.*"); - exclude("**/${project.name}/javascript/codemirror.*"); - exclude("**/${project.name}/javascript/echarts.*"); - exclude("**/${project.name}/javascript/platform-core.*"); - exclude("**/${project.name}/javascript/quasar.*"); - exclude("**/${project.name}/javascript/vue.*"); - exclude("**/${project.name}/fonts/*.*"); - exclude("**/${project.name}/webjars/**/*.*"); +// exclude("**/${project.name}/javascript/codemirror.*"); +// exclude("**/${project.name}/javascript/echarts.*"); +// exclude("**/${project.name}/javascript/platform-core.*"); +// exclude("**/${project.name}/javascript/quasar.*"); +// exclude("**/${project.name}/javascript/vue.*"); +// exclude("**/${project.name}/fonts/*.*"); +// exclude("**/${project.name}/webjars/**/*.*"); } } } diff --git a/erm.frontend/package.json b/erm.frontend/package.json index 5adc8978..afe53eeb 100644 --- a/erm.frontend/package.json +++ b/erm.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/erm.frontend/public/configure.js b/erm.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/erm.frontend/public/configure.js +++ b/erm.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/gradle.properties b/gradle.properties index d2708327..9cd66bb5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,7 +38,7 @@ application_version=1.0.0 platform_group=io.sc platform_version=8.1.46 platform_plugin_version=8.1.46 -platform_core_frontend_version=8.1.295 +platform_core_frontend_version=8.1.301 ########################################################### # dependencies version diff --git a/io.sc.engine.mv.frontend/package.json b/io.sc.engine.mv.frontend/package.json index f2974676..952c322e 100644 --- a/io.sc.engine.mv.frontend/package.json +++ b/io.sc.engine.mv.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.engine.mv.frontend/public/configure.js b/io.sc.engine.mv.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.engine.mv.frontend/public/configure.js +++ b/io.sc.engine.mv.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.engine.mv.frontend/src/views/sample/Sample.vue b/io.sc.engine.mv.frontend/src/views/sample/Sample.vue index 57b54535..346fc6fa 100644 --- a/io.sc.engine.mv.frontend/src/views/sample/Sample.vue +++ b/io.sc.engine.mv.frontend/src/views/sample/Sample.vue @@ -25,9 +25,9 @@ icon: 'bi-arrow-right-circle', click: () => { DialogManager.confirm($t('io.sc.engine.mv.sample.action.importExampleSample.tip'), () => { - axios.post(Environment.apiContextPath('/api/mv/sample/importExampleSample')).then(() => { - scoreRecordGridRef.refresh(); - defaultRecordGridRef.refresh(); + axios.post(Environment.apiContextPath('/api/mv/sample/importExampleSample'), {}, { loading: true }).then(() => { + scoreRecordGridRef?.refresh(); + defaultRecordGridRef?.refresh(); }); }); }, @@ -39,8 +39,8 @@ click: () => { DialogManager.confirm($t('io.sc.engine.mv.sample.action.removeAllSample.tip'), () => { axios.post(Environment.apiContextPath('/api/mv/sample/removeAllSample')).then(() => { - scoreRecordGridRef.refresh(); - defaultRecordGridRef.refresh(); + scoreRecordGridRef?.refresh(); + defaultRecordGridRef?.refresh(); }); }); }, diff --git a/io.sc.engine.rule.frontend/package.json b/io.sc.engine.rule.frontend/package.json index 4eb9d7e2..84feaf4b 100644 --- a/io.sc.engine.rule.frontend/package.json +++ b/io.sc.engine.rule.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.engine.rule.frontend/public/configure.js b/io.sc.engine.rule.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.engine.rule.frontend/public/configure.js +++ b/io.sc.engine.rule.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.engine.st.frontend/package.json b/io.sc.engine.st.frontend/package.json index b21dc20b..7ff4ce8e 100644 --- a/io.sc.engine.st.frontend/package.json +++ b/io.sc.engine.st.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.engine.st.frontend/public/configure.js b/io.sc.engine.st.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.engine.st.frontend/public/configure.js +++ b/io.sc.engine.st.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.platform.core.frontend/package.json b/io.sc.platform.core.frontend/package.json index 0b994174..22cb288e 100644 --- a/io.sc.platform.core.frontend/package.json +++ b/io.sc.platform.core.frontend/package.json @@ -1,6 +1,6 @@ { "name": "platform-core", - "version": "8.1.295", + "version": "8.1.301", "description": "前端核心包,用于快速构建前端的脚手架", "//main": "库的主文件", "main": "dist/platform-core.js", diff --git a/io.sc.platform.core.frontend/public/configure.js b/io.sc.platform.core.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.platform.core.frontend/public/configure.js +++ b/io.sc.platform.core.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.platform.core.frontend/src/platform/PConst.ts b/io.sc.platform.core.frontend/src/platform/PConst.ts index 70469d54..75aea481 100644 --- a/io.sc.platform.core.frontend/src/platform/PConst.ts +++ b/io.sc.platform.core.frontend/src/platform/PConst.ts @@ -59,6 +59,11 @@ class PConst { */ static API_I18N_MESSAGES_URL: string = '/api/mvc/i18n/getI18nMessages'; + /** + * 加载前端远程入口 API URL + */ + static API_REMOTE_ENTRY_URL: string = '/api/mvc/frontend/getRemoteEntries'; + /** * 登录 API URL */ diff --git a/io.sc.platform.core.frontend/src/platform/index.ts b/io.sc.platform.core.frontend/src/platform/index.ts index 47e299b0..77111468 100644 --- a/io.sc.platform.core.frontend/src/platform/index.ts +++ b/io.sc.platform.core.frontend/src/platform/index.ts @@ -79,6 +79,7 @@ export { router } from './plugin'; */ export { Environment } from './plugin'; export { ApplicationInitializer } from './plugin'; +export { AuthenticationManager } from './plugin'; export { ComponentManager } from './plugin'; export { ConfigureManager } from './plugin'; export { DialogManager } from './plugin'; @@ -86,7 +87,7 @@ export { I18nMessageManager } from './plugin'; export { MenuManager } from './plugin'; export { MockManager } from './plugin'; export { NotifyManager } from './plugin'; -export { AuthenticationManager } from './plugin'; +export { RemoteEntryManager } from './plugin'; export { RouterManager } from './plugin'; export { SessionManager } from './plugin'; export { TagViewManager } from './plugin'; diff --git a/io.sc.platform.core.frontend/src/platform/plugin/axios copy.ts b/io.sc.platform.core.frontend/src/platform/plugin/axios copy.ts deleted file mode 100644 index 809f3c83..00000000 --- a/io.sc.platform.core.frontend/src/platform/plugin/axios copy.ts +++ /dev/null @@ -1,164 +0,0 @@ -import type { App } from 'vue'; -import Axios from 'axios'; -import { i18n } from './i18n'; -import { PConst } from '@/platform/PConst'; -import { Environment } from '@/platform/plugin/environment'; -import { NotifyManager, Oauth2Manager } from './manager'; -import { QuasarTools } from '@/platform/utils'; - -const ignoredUrls: string[] = [PConst.API_I18N_MESSAGES_URL, PConst.API_APP_CONFIGURE_URL]; -const gc = Environment.getConfigure(); - -// 请求拦截器 -const requestInterceptor = (config: any) => { - config.headers.locale = gc.setting.i18n.locale; - // 忽略无需认证的请求 URL - for (const url of ignoredUrls) { - if (config.url.includes(url)) { - return config; - } - } - const result = config; - result.headers.Authorization = 'Bearer ' + Oauth2Manager.getLocalAccessToken(); - /* - // 对于需要认证的请求 URL 添加 basic 认证 - const result = config; - if (gc.axios?.basicAuth?.enable) { - result.headers.Authorization = 'Basic ' + window.btoa(gc.axios.basicAuth.username + ':' + gc.axios.basicAuth.password); - } - */ - // 如果请求时传入 { loading: true } 属性, 则自动显示 "正在处理..., 请等待" 模态对话框 - if (config?.loading) { - QuasarTools.getQuasar()?.loading?.show({ - message: i18n.global.t('loading'), - boxClass: 'bg-grey-2 text-grey-9', - spinnerColor: 'primary', - }); - } - return result; -}; - -// 请求错误拦截器 -const requestErrorInterceptor = (error: any) => { - return Promise.reject(error); -}; - -// 响应拦截器 -const responseInterceptor = (response: any) => { - // 请求成功, 进入该方法说明 response 的状态码为 2xx - QuasarTools.getQuasar()?.loading?.hide(); - return response.data; -}; - -// 响应错误拦截器 -const responseErrorInterceptor = (error: any) => { - QuasarTools.getQuasar()?.loading?.hide(); - // 请求失败, 进入该方法说明 response 的状态码不为 2xx - if (error.code === 'ECONNABORTED' || error.message.indexOf('timeout') !== -1 || error.message === 'Network Error') { - // 发生网络错误 - const $t = i18n.global.t; - NotifyManager.error($t('NetworkError')); - return Promise.reject({ - code: 'NetworkError', - errorMessageI18nKey: 'NetworkError', - errorMessage: error.message, - exception: 'NetworkError', - stackTrace: error.stack, - data: null, - }); - } else { - // 服务器端错误 - const response = error?.response; - const status = response?.status; - const data = response?.data; - if (status === 401) { - if (Oauth2Manager.isAuthorizationCodeRedirectUri()) { - return Promise.resolve({}); - } else { - if (gc.oauth2) { - let url = '/oauth2/authorize?'; - url += 'client_id=' + gc.oauth2.clientId; - url += '&client_secret=' + gc.oauth2.clientSecret; - url += '&response_type=code'; - url += '&redirect_uri=' + encodeURIComponent(gc.oauth2.redirectUri); - window.location.href = Environment.apiContextPath(url); - } - } - return; - } - //下载错误 - if (error.request.responseType === 'blob') { - NotifyManager.error(i18n.global.t(error?.code)); - return Promise.reject(error); - } - //其他错误 - if (status === 500) { - NotifyManager.error(i18n.global.t(data?.errorMessageI18nKey)); - return Promise.reject(response.data); - } else { - NotifyManager.error(i18n.global.t(status)); - return Promise.reject({ - code: status, - errorMessageI18nKey: status, - errorMessage: error.message, - exception: error.code, - stackTrace: error.stack, - data: null, - }); - } - } -}; - -// 普通 axios -const axios = Axios.create({ - baseURL: gc.axios?.baseURL || '', - timeout: gc.axios?.timeout || 1000 * 60, -}); -axios.interceptors.request.use(requestInterceptor, requestErrorInterceptor); -axios.interceptors.response.use(responseInterceptor, responseErrorInterceptor); - -// 无默认服务器端错误处理的 axios -const noErrorAxios = Axios.create({ - baseURL: gc.axios?.baseURL || '', - timeout: gc.axios?.timeout || 1000 * 60, -}); -noErrorAxios.interceptors.request.use(requestInterceptor, requestErrorInterceptor); -noErrorAxios.interceptors.response.use(responseInterceptor, (error: any) => { - QuasarTools.getQuasar()?.loading?.hide(); - // 请求失败, 进入该方法说明 response 的状态码不为 2xx - if (error.code === 'ECONNABORTED' || error.message.indexOf('timeout') !== -1 || error.message === 'Network Error') { - // 发生网络错误 - const $t = i18n.global.t; - NotifyManager.error($t('NetworkError')); - return Promise.reject({ - code: 'NetworkError', - errorMessageI18nKey: 'NetworkError', - errorMessage: error.message, - exception: 'NetworkError', - stackTrace: error.stack, - data: null, - }); - } else { - return Promise.reject(error); - } -}); - -// 下载二进制 axios -const blobAxios = Axios.create({ - baseURL: gc.axios?.baseURL || '', - timeout: gc.axios?.timeout || 1000 * 60, -}); -blobAxios.interceptors.request.use(requestInterceptor, requestErrorInterceptor); -blobAxios.interceptors.response.use((response: any) => { - QuasarTools.getQuasar()?.loading?.hide(); - return response; -}, responseErrorInterceptor); - -export default { - install: (app: App) => { - app.config.globalProperties.$axios = axios; - app.config.globalProperties.$blobAxios = blobAxios; - }, -}; - -export { axios, blobAxios, noErrorAxios }; diff --git a/io.sc.platform.core.frontend/src/platform/plugin/environment/index.ts b/io.sc.platform.core.frontend/src/platform/plugin/environment/index.ts index 3d05f41a..2dad9add 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/environment/index.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/environment/index.ts @@ -69,6 +69,22 @@ class Environment { */ static #layoutProviderMap = new Map(); + /** + * 获取前端是否独立部署 + * @returns 前端是否独立部署 + */ + public static isAloneFrontend() { + return window[PConst.APP][PConst.CONFIGURE].isAloneFrontend; + } + + /** + * 获取微前端入口 + * @returns 微前端入口 + */ + public static getRemoteEntries() { + return window[PConst.APP][PConst.CONFIGURE].remoteEntries; + } + /** * 获取 router 历史模式 * @returns router 历史模式 diff --git a/io.sc.platform.core.frontend/src/platform/plugin/index.ts b/io.sc.platform.core.frontend/src/platform/plugin/index.ts index 11426f84..5241aa4b 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/index.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/index.ts @@ -23,6 +23,7 @@ export { router } from './router'; export { Environment } from './environment'; export { ApplicationInitializer } from './manager'; +export { AuthenticationManager } from './manager'; export { ComponentManager } from './manager'; export { ConfigureManager } from './manager'; export { DialogManager } from './manager'; @@ -30,7 +31,7 @@ export { I18nMessageManager } from './manager'; export { MenuManager } from './manager'; export { MockManager } from './manager'; export { NotifyManager } from './manager'; -export { AuthenticationManager } from './manager'; +export { RemoteEntryManager } from './manager'; export { RouterManager } from './manager'; export { SessionManager } from './manager'; export { TagViewManager } from './manager'; diff --git a/io.sc.platform.core.frontend/src/platform/plugin/manager/ApplicationInitializer.ts b/io.sc.platform.core.frontend/src/platform/plugin/manager/ApplicationInitializer.ts index 81d22063..f4271dcc 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/manager/ApplicationInitializer.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/manager/ApplicationInitializer.ts @@ -3,17 +3,19 @@ import { toRaw } from 'vue'; import { PConst } from '@/platform/PConst'; import { Environment } from '@/platform/plugin/environment'; import { + AuthenticationManager, ComponentManager, - MockManager, ConfigureManager, - SessionManager, I18nMessageManager, - NotifyManager, MenuManager, + MockManager, + NotifyManager, + RemoteEntryManager, RouterManager, + SessionManager, } from '@/platform/plugin/manager'; import { router } from '@/platform/plugin'; -import { Tools, JavascriptLoader } from '@/platform/utils'; +import { Tools } from '@/platform/utils'; const gc = Environment.getConfigure(); @@ -42,14 +44,7 @@ class ApplicationInitializer { I18nMessageManager.setLocalI18nMessages(parameter.localI18nMessages); await I18nMessageManager.changeLanguage(gc.setting.i18n.locale as I18nMessageLocaleType, false); - // Oauth2 鉴权 - // if (Oauth2Manager.isAuthorizationCodeRedirectUri()) { - // Oauth2Manager.loadTokens(() => { - // window.location.href = Environment.getWebContextPath(); - // }); - // return; - // } - + // 构建初始路由 RouterManager.buildRoutes(); // 获取用户会话 @@ -70,21 +65,14 @@ class ApplicationInitializer { RouterManager.setLocalRoutes(parameter.localRoutes); RouterManager.buildRoutes(toRaw(userSession.routes)); - // 动态加载远程组件入口 JS 文件 - SessionManager.setRemoteEntries(userSession.remoteEntries); - const urls: string[] = SessionManager.getRemoteEntryUrls(); - if (urls && urls.length > 0) { - console.debug('Loading remote entry ...', urls); - const loader = new JavascriptLoader((errorUrl) => { - parameter.callback(); - }); - loader.load(urls); - } else { - parameter.callback(); - } + // 加载远程入口 + RemoteEntryManager.loadRemoteEntries(parameter.callback); } else { - parameter.callback(); - router.push({ name: 'login' }); + // 加载远程入口 + RemoteEntryManager.loadRemoteEntries(() => { + parameter.callback(); + router.push({ name: 'login' }); + }); } } diff --git a/io.sc.platform.core.frontend/src/platform/plugin/manager/RouterManager.ts b/io.sc.platform.core.frontend/src/platform/plugin/manager/RouterManager.ts index b45ab4e2..d0613812 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/manager/RouterManager.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/manager/RouterManager.ts @@ -120,8 +120,10 @@ class RouterManager { * @param priority 优先级 */ private static setRoutesPriority(objects: object[] = [], priority: number) { - for (const route of objects) { - route['priority'] = priority; + if (objects && objects.length > 0) { + for (const route of objects) { + route['priority'] = priority; + } } } @@ -131,14 +133,16 @@ class RouterManager { * @param objects 待合并的路由数组 */ private static mergeRoutes(map: Map, objects: object[] = []) { - for (const route of objects) { - const cachedRoute = map.get(route['name']); - if (cachedRoute) { - if (route['priority'] < cachedRoute['priority']) { + if (objects && objects.length > 0) { + for (const route of objects) { + const cachedRoute = map.get(route['name']); + if (cachedRoute) { + if (route['priority'] < cachedRoute['priority']) { + map.set(route['name'], route); + } + } else { map.set(route['name'], route); } - } else { - map.set(route['name'], route); } } } @@ -149,40 +153,42 @@ class RouterManager { * @param objects 待合并的路由数组 */ private static createRoutes(array: object[], objects: object[] = [], cache: Map, type: string) { - for (const route of objects) { - const cachedRoute = cache.get(route['name']); - if (cachedRoute) { - if (type === 'frontend-default') { - array.push({ - parent: cachedRoute['parent'], - name: cachedRoute['name'], - path: cachedRoute['path'], - icon: cachedRoute['icon'], - component: cachedRoute['component'], - redirect: cachedRoute['redirect'], - children: cachedRoute['children'], - }); - } else if (type === 'frontend-local') { - array.push({ - parent: cachedRoute['parent'], - name: cachedRoute['name'], - path: cachedRoute['path'], - icon: cachedRoute['icon'], - component: ComponentManager.getLocalComponent(cachedRoute['component']), - redirect: cachedRoute['redirect'], - children: cachedRoute['children'], - }); - } else { - array.push({ - parent: cachedRoute['parent'], - name: cachedRoute['name'], - path: cachedRoute['path'], - component: ComponentManager.getRemoteComponent(cachedRoute['module'], cachedRoute['component']), - redirect: cachedRoute['redirect'], - children: cachedRoute['children'], - }); + if (objects && objects.length > 0) { + for (const route of objects) { + const cachedRoute = cache.get(route['name']); + if (cachedRoute) { + if (type === 'frontend-default') { + array.push({ + parent: cachedRoute['parent'], + name: cachedRoute['name'], + path: cachedRoute['path'], + icon: cachedRoute['icon'], + component: cachedRoute['component'], + redirect: cachedRoute['redirect'], + children: cachedRoute['children'], + }); + } else if (type === 'frontend-local') { + array.push({ + parent: cachedRoute['parent'], + name: cachedRoute['name'], + path: cachedRoute['path'], + icon: cachedRoute['icon'], + component: ComponentManager.getLocalComponent(cachedRoute['component']), + redirect: cachedRoute['redirect'], + children: cachedRoute['children'], + }); + } else { + array.push({ + parent: cachedRoute['parent'], + name: cachedRoute['name'], + path: cachedRoute['path'], + component: ComponentManager.getRemoteComponent(cachedRoute['module'], cachedRoute['component']), + redirect: cachedRoute['redirect'], + children: cachedRoute['children'], + }); + } + cache.delete(cachedRoute['name']); } - cache.delete(cachedRoute['name']); } } } diff --git a/io.sc.platform.core.frontend/src/platform/plugin/manager/index.ts b/io.sc.platform.core.frontend/src/platform/plugin/manager/index.ts index 8e58bb9d..760bee83 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/manager/index.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/manager/index.ts @@ -1,4 +1,5 @@ export { ApplicationInitializer } from './ApplicationInitializer'; +export { AuthenticationManager } from './AuthenticationManager'; export { ComponentManager } from './ComponentManager'; export { ConfigureManager } from './ConfigureManager'; export { DialogManager } from './DialogManager'; @@ -6,7 +7,7 @@ export { I18nMessageManager } from './I18nMessageManager'; export { MenuManager } from './MenuManager'; export { MockManager } from './MockManager'; export { NotifyManager } from './NotifyManager'; -export { AuthenticationManager } from './AuthenticationManager'; +export { RemoteEntryManager } from './RemoteEntryManager'; export { RouterManager } from './RouterManager'; export { SessionManager } from './SessionManager'; export { TagViewManager } from './TagViewManager'; diff --git a/io.sc.platform.core.frontend/src/platform/plugin/router.ts b/io.sc.platform.core.frontend/src/platform/plugin/router.ts index 95c51318..2897d2e7 100644 --- a/io.sc.platform.core.frontend/src/platform/plugin/router.ts +++ b/io.sc.platform.core.frontend/src/platform/plugin/router.ts @@ -6,7 +6,6 @@ import { AuthenticationManager, TagViewManager } from './manager'; import WBasicLayout from '@/platform/layout/WBasicLayout.vue'; import Login from '@/platform/views/Login.vue'; import Home from '@/platform/views/Home.vue'; -import Oauth2 from '@/platform/views/Oauth2.vue'; import P404 from '@/platform/views/404.vue'; const gc = Environment.getConfigure(); @@ -39,12 +38,6 @@ const PLATFORM_ROUTES = [ path: '/home', component: Home, }, - { - parent: '/', - name: 'oauth2', - path: '/oauth2', - component: Oauth2, - }, { parent: '/', name: '404', @@ -80,7 +73,8 @@ router.beforeEach(async (to: any, from: any, next: any) => { next(); } else { //导航到登录页面 - next({ name: 'login' }); + //next({ name: 'login' }); + Environment.executeAction('openLoginDialog'); } } }); diff --git a/io.sc.platform.core.frontend/src/platform/utils/JavascriptLoader.ts b/io.sc.platform.core.frontend/src/platform/utils/JavascriptLoader.ts index 67750fcd..1f80f0fb 100644 --- a/io.sc.platform.core.frontend/src/platform/utils/JavascriptLoader.ts +++ b/io.sc.platform.core.frontend/src/platform/utils/JavascriptLoader.ts @@ -9,13 +9,15 @@ class JavascriptLoader { } public load(urls: string[]) { - for (const url of urls) { - const element = document.createElement('script'); - element.src = url; - element.onerror = this.onerror.bind(this, url); - element.onload = this.onload.bind(this, url); - this.#urlMap.set(url, element); - document.head.appendChild(element); + if (urls && urls.length > 0) { + for (const url of urls) { + const element = document.createElement('script'); + element.src = url; + element.onerror = this.onerror.bind(this, url); + element.onload = this.onload.bind(this, url); + this.#urlMap.set(url, element); + document.head.appendChild(element); + } } } diff --git a/io.sc.platform.core.frontend/src/platform/views/Login.vue b/io.sc.platform.core.frontend/src/platform/views/Login.vue index 3c459b9a..dee6f18a 100644 --- a/io.sc.platform.core.frontend/src/platform/views/Login.vue +++ b/io.sc.platform.core.frontend/src/platform/views/Login.vue @@ -224,6 +224,8 @@ const loginFormSubmit = (event) => { // 设置本地访问令牌 AuthenticationManager.setLocalAccessToken(response.data?.data); + // window.location.href = Environment.getWebContextPath(); + // 登录成功后,重新获取用户会话 SessionManager.loadUserSession().then((userSession) => { if (userSession) { @@ -241,15 +243,6 @@ const loginFormSubmit = (event) => { SessionManager.setRoutes(userSession.routes); RouterManager.setLocalRoutes(parameter.localRoutes); RouterManager.buildRoutes(toRaw(userSession.routes)); - - // 动态加载远程组件入口 JS 文件 - SessionManager.setRemoteEntries(userSession.remoteEntries); - const urls: string[] = SessionManager.getRemoteEntryUrls(); - if (urls && urls.length > 0) { - console.debug('Loading remote entry ...', urls); - const loader = new JavascriptLoader(() => {}); - loader.load(urls); - } } router.push('/'); }); diff --git a/io.sc.platform.core.frontend/template-project/package.json b/io.sc.platform.core.frontend/template-project/package.json index 4ed05fa9..72ad8f15 100644 --- a/io.sc.platform.core.frontend/template-project/package.json +++ b/io.sc.platform.core.frontend/template-project/package.json @@ -1,6 +1,6 @@ { "name": "platform-core", - "version": "8.1.295", + "version": "8.1.301", "description": "前端核心包,用于快速构建前端的脚手架", "private": false, "keywords": [], @@ -104,7 +104,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.platform.core.frontend/template-project/public/configure.js b/io.sc.platform.core.frontend/template-project/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.platform.core.frontend/template-project/public/configure.js +++ b/io.sc.platform.core.frontend/template-project/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.platform.developer.frontend/package.json b/io.sc.platform.developer.frontend/package.json index 7432f9bf..7d12c40d 100644 --- a/io.sc.platform.developer.frontend/package.json +++ b/io.sc.platform.developer.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.platform.developer.frontend/public/configure.js b/io.sc.platform.developer.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.platform.developer.frontend/public/configure.js +++ b/io.sc.platform.developer.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.platform.gradle/templates/pgp/setup/build.gradle.txt b/io.sc.platform.gradle/templates/pgp/setup/build.gradle.txt index 8371ab35..3b0210c7 100644 --- a/io.sc.platform.gradle/templates/pgp/setup/build.gradle.txt +++ b/io.sc.platform.gradle/templates/pgp/setup/build.gradle.txt @@ -684,13 +684,13 @@ subprojects { if(isFrontendProject(file('.'))) { if(project.name!='io.sc.platform.mvc.frontend'){ exclude("**/${project.name}/*.*"); - exclude("**/${project.name}/javascript/codemirror.*"); - exclude("**/${project.name}/javascript/echarts.*"); - exclude("**/${project.name}/javascript/platform-core.*"); - exclude("**/${project.name}/javascript/quasar.*"); - exclude("**/${project.name}/javascript/vue.*"); - exclude("**/${project.name}/fonts/*.*"); - exclude("**/${project.name}/webjars/**/*.*"); +// exclude("**/${project.name}/javascript/codemirror.*"); +// exclude("**/${project.name}/javascript/echarts.*"); +// exclude("**/${project.name}/javascript/platform-core.*"); +// exclude("**/${project.name}/javascript/quasar.*"); +// exclude("**/${project.name}/javascript/vue.*"); +// exclude("**/${project.name}/fonts/*.*"); +// exclude("**/${project.name}/webjars/**/*.*"); } } } @@ -850,5 +850,5 @@ task github { } tasks.named('wrapper') { - distributionUrl = "http://nexus.sc.io:8000/repository/maven-releases/gradle/gradle/${gradleVersion}/gradle-${gradleVersion}.zip" + distributionUrl = "http://nexus.sc.io:8000/repository/maven-releases/gradle/gradle/${gradleVersion}/gradle-${gradleVersion}-bin.zip" } diff --git a/io.sc.platform.gradle/templates/pgp/setup/gradle.properties b/io.sc.platform.gradle/templates/pgp/setup/gradle.properties index d2708327..9cd66bb5 100644 --- a/io.sc.platform.gradle/templates/pgp/setup/gradle.properties +++ b/io.sc.platform.gradle/templates/pgp/setup/gradle.properties @@ -38,7 +38,7 @@ application_version=1.0.0 platform_group=io.sc platform_version=8.1.46 platform_plugin_version=8.1.46 -platform_core_frontend_version=8.1.295 +platform_core_frontend_version=8.1.301 ########################################################### # dependencies version diff --git a/io.sc.platform.gradle/templates/pgp/setup/gradle/wrapper/gradle-wrapper.properties b/io.sc.platform.gradle/templates/pgp/setup/gradle/wrapper/gradle-wrapper.properties index 8a4670d0..12017782 100644 --- a/io.sc.platform.gradle/templates/pgp/setup/gradle/wrapper/gradle-wrapper.properties +++ b/io.sc.platform.gradle/templates/pgp/setup/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=http\://nexus.sc.io\:8000/repository/maven-releases/gradle/gradle/8.4/gradle-8.5.zip +distributionUrl=http\://nexus.sc.io\:8000/repository/maven-releases/gradle/gradle/8.7/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/io.sc.platform.gradle/templates/pgp/setup/gradlew.bat b/io.sc.platform.gradle/templates/pgp/setup/gradlew.bat index 6689b85b..7101f8e4 100644 --- a/io.sc.platform.gradle/templates/pgp/setup/gradlew.bat +++ b/io.sc.platform.gradle/templates/pgp/setup/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/io.sc.platform.lcdp.frontend/package.json b/io.sc.platform.lcdp.frontend/package.json index 8c6b1673..8c310d5b 100644 --- a/io.sc.platform.lcdp.frontend/package.json +++ b/io.sc.platform.lcdp.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.platform.lcdp.frontend/public/configure.js b/io.sc.platform.lcdp.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.platform.lcdp.frontend/public/configure.js +++ b/io.sc.platform.lcdp.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/configure/controller/ConfigureController.java b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/configure/controller/ConfigureController.java index 7c158939..d61ae47d 100644 --- a/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/configure/controller/ConfigureController.java +++ b/io.sc.platform.lcdp/src/main/java/io/sc/platform/lcdp/configure/controller/ConfigureController.java @@ -17,7 +17,7 @@ public class ConfigureController extends RestCrudController getRemoteEntries(HttpServletRequest request) throws Exception{ + return frontEndService.getRemoteEntries(request); + } + @GetMapping("/api/mvc/frontend/getApplicationName") + @ResponseBody public String getApplicationName() throws Exception{ return Environment.getInstance().getApplicationName(); } @PostMapping("/api/mvc/frontend/regist") + @ResponseBody public void regist(@RequestBody FrontEndModule frontEndModule){ frontEndService.regist(frontEndModule); } @PostMapping("/api/mvc/frontend/export") + @ResponseBody public ExportFileInfo export(@RequestBody FrontendExportParam param) throws Exception{ return frontEndExportService.export(param); } diff --git a/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/IndexWebController.java b/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/IndexWebController.java index 67800e35..4481cfc8 100644 --- a/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/IndexWebController.java +++ b/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/IndexWebController.java @@ -4,17 +4,20 @@ import io.sc.platform.mvc.service.FrontEndService; import io.sc.platform.mvc.service.SystemParameterService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; +import java.util.Map; /** * 系统首页控制器 */ @Controller -@RequestMapping public class IndexWebController { + @Autowired private FrontEndService frontEndService; @Autowired private SystemParameterService systemParameterService; @RequestMapping(value={"","/","index.html"}) @@ -22,4 +25,9 @@ public class IndexWebController { ModelAndView mv =new ModelAndView("io.sc.platform.mvc.frontend.html"); return mv; } + + @GetMapping("/configure.js") + public String configureJs(){ + return "configure.js"; + } } diff --git a/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/FrontEndService.java b/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/FrontEndService.java index ca4e5569..b1183fee 100644 --- a/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/FrontEndService.java +++ b/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/FrontEndService.java @@ -14,5 +14,8 @@ public interface FrontEndService { * @return 所有远程前端模块的入口 */ public Map getRemoteEntries(HttpServletRequest request); + + public Map getRemoteEntries(); + public void regist(FrontEndModule frontEndModule); } diff --git a/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/impl/FrontEndServiceImpl.java b/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/impl/FrontEndServiceImpl.java index 5c6d9b20..60fbe8d2 100644 --- a/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/impl/FrontEndServiceImpl.java +++ b/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/impl/FrontEndServiceImpl.java @@ -15,6 +15,7 @@ import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -56,7 +57,6 @@ public class FrontEndServiceImpl implements FrontEndService { Map result =new HashMap<>(); for (Map.Entry entry : localFrontEndModuleMap.entrySet()) { if(entry.getValue().getComponents().size()>0) { - result.put(entry.getKey(), getRemoteEntry(entry.getValue(), request)); } } @@ -68,6 +68,24 @@ public class FrontEndServiceImpl implements FrontEndService { return result; } + @Override + public Map getRemoteEntries() { + Map result =new HashMap<>(); + for (Map.Entry entry : localFrontEndModuleMap.entrySet()) { + FrontEndModule value =entry.getValue(); + if(value.getComponents().size()>0) { + result.put(entry.getKey(), value.getName() + "/javascript/remoteEntry.js"); + } + } + for (Map.Entry entry : remoteFrontEndModuleCache.asMap().entrySet()) { + FrontEndModule value =entry.getValue(); + if(value.getComponents().size()>0) { + result.put(entry.getKey(), value.getName() + "/javascript/remoteEntry.js"); + } + } + return result; + } + @Override public void regist(FrontEndModule frontEndModule) { remoteFrontEndModuleCache.put(frontEndModule.getName(),frontEndModule); diff --git a/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/impl/FrontendExportServiceImpl.java b/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/impl/FrontendExportServiceImpl.java index e693dd48..307e6dfa 100644 --- a/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/impl/FrontendExportServiceImpl.java +++ b/io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/service/impl/FrontendExportServiceImpl.java @@ -3,14 +3,17 @@ package io.sc.platform.mvc.service.impl; import io.sc.platform.core.DirectoryManager; import io.sc.platform.core.Environment; import io.sc.platform.core.util.FileUtil; +import io.sc.platform.core.util.ObjectMapper4Json; import io.sc.platform.core.util.UrlUtil; import io.sc.platform.core.util.ZipUtil; import io.sc.platform.mvc.plugins.PluginManager; import io.sc.platform.mvc.plugins.item.FrontEndModule; +import io.sc.platform.mvc.service.FrontEndService; import io.sc.platform.mvc.service.FrontendExportService; import io.sc.platform.mvc.support.ExportFileInfo; import io.sc.platform.mvc.support.FrontendExportParam; import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; @@ -26,6 +29,7 @@ import java.util.UUID; @Service public class FrontendExportServiceImpl implements FrontendExportService { + @Autowired private FrontEndService frontEndService; @Override public ExportFileInfo export(FrontendExportParam param) throws Exception { @@ -114,14 +118,22 @@ public class FrontendExportServiceImpl implements FrontendExportService { sb.append("window.APP = {};").append("\n"); sb.append("// 全局配置").append("\n"); sb.append("window.APP.configure ={").append("\n"); - sb.append(" // router 历史模式").append("\n"); - sb.append(" routerHistoryMode: 'web',").append("\n"); sb.append(" // 应用上下文路径").append("\n"); sb.append(" webContextPath: '").append(frontendWebContextPath).append("',").append("\n"); + sb.append("\n"); sb.append(" // 默认后端 API 请求的服务地址前缀").append("\n"); sb.append(" apiContextPaths: {").append("\n"); sb.append(" DEFAULT: '").append(backendApiWebContextPath).append("'").append("\n"); - sb.append(" }").append("\n"); + sb.append(" },").append("\n"); + sb.append("\n"); + sb.append(" // 是否是独立部署的前端").append("\n"); + sb.append(" isAloneFrontend: true,").append("\n"); + sb.append("\n"); + sb.append(" // 微前端入口").append("\n"); + sb.append(" remoteEntries: ").append(ObjectMapper4Json.getMapper().writeValueAsString(frontEndService.getRemoteEntries())).append(",").append("\n"); + sb.append("\n"); + sb.append(" // router 历史模式").append("\n"); + sb.append(" routerHistoryMode: 'hash',").append("\n"); sb.append("};").append("\n"); FileUtil.writeString(zipDirPath + "/configure.js",sb.toString()); diff --git a/io.sc.platform.mvc/src/main/resources/META-INF/platform/plugins/security.json b/io.sc.platform.mvc/src/main/resources/META-INF/platform/plugins/security.json index 64bf3d2e..3acdd6b0 100644 --- a/io.sc.platform.mvc/src/main/resources/META-INF/platform/plugins/security.json +++ b/io.sc.platform.mvc/src/main/resources/META-INF/platform/plugins/security.json @@ -1,6 +1,8 @@ { "permitPatterns":[ + "/api/mvc/frontend/getRemoteEntries", "/api/mvc/frontend/regist", + "/api/mvc/i18n/getI18nMessages", "/api/mvc/i18n/getI18nMessages/**/*", "/api/mvc/i18n/getI18nMessagesByKeys" diff --git a/io.sc.platform.lcdp/src/main/resources/templates/configure.js b/io.sc.platform.mvc/src/main/resources/templates/configure.js similarity index 83% rename from io.sc.platform.lcdp/src/main/resources/templates/configure.js rename to io.sc.platform.mvc/src/main/resources/templates/configure.js index e0eee353..d65c0cb6 100644 --- a/io.sc.platform.lcdp/src/main/resources/templates/configure.js +++ b/io.sc.platform.mvc/src/main/resources/templates/configure.js @@ -2,14 +2,17 @@ window.APP = {}; // 全局配置 window.APP.configure = { - // router 历史模式 - routerHistoryMode: 'hash', - // 应用上下文路径 webContextPath: '[(@{/})]', // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]' - } + }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', }; \ No newline at end of file diff --git a/io.sc.platform.scheduler.manager.frontend/package.json b/io.sc.platform.scheduler.manager.frontend/package.json index 283a181a..5b43348c 100644 --- a/io.sc.platform.scheduler.manager.frontend/package.json +++ b/io.sc.platform.scheduler.manager.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.platform.scheduler.manager.frontend/public/configure.js b/io.sc.platform.scheduler.manager.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.platform.scheduler.manager.frontend/public/configure.js +++ b/io.sc.platform.scheduler.manager.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.platform.security.loginform/src/main/java/io/sc/platform/security/loginform/filter/JwtUsernamePasswordAuthenticationFilter.java b/io.sc.platform.security.loginform/src/main/java/io/sc/platform/security/loginform/filter/JwtUsernamePasswordAuthenticationFilter.java index 5f1c97f5..1ef7a399 100644 --- a/io.sc.platform.security.loginform/src/main/java/io/sc/platform/security/loginform/filter/JwtUsernamePasswordAuthenticationFilter.java +++ b/io.sc.platform.security.loginform/src/main/java/io/sc/platform/security/loginform/filter/JwtUsernamePasswordAuthenticationFilter.java @@ -30,6 +30,7 @@ public class JwtUsernamePasswordAuthenticationFilter extends OncePerRequestFilte @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + final String token = bearerTokenResolver.resolve(request); if(StringUtils.hasText(token)) { WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext()); @@ -41,12 +42,13 @@ public class JwtUsernamePasswordAuthenticationFilter extends OncePerRequestFilte SecurityContextHolder.getContext().setAuthentication(authenticationToken); }catch (JwtException e){ SecurityContextHolder.clearContext(); + this.logger.error(e.getMessage()); this.logger.trace("Failed to process authentication request", e); this.logger.trace("Cleared SecurityContextHolder"); this.logger.trace("Handling authentication failure"); rememberMeServices.loginFail(request, response); failureHandler.onAuthenticationFailure(request, response, new AuthenticationServiceException(e.getMessage())); - throw e; + return; } } filterChain.doFilter(request,response); diff --git a/io.sc.platform.security/src/main/java/io/sc/platform/security/installer/AdministratorInstallerItem.java b/io.sc.platform.security/src/main/java/io/sc/platform/security/installer/AdministratorInstallerItem.java index 7437e2a7..75f6f249 100644 --- a/io.sc.platform.security/src/main/java/io/sc/platform/security/installer/AdministratorInstallerItem.java +++ b/io.sc.platform.security/src/main/java/io/sc/platform/security/installer/AdministratorInstallerItem.java @@ -47,39 +47,55 @@ public class AdministratorInstallerItem implements InstallerItem { // 创建用户 String userId =UUID.randomUUID().toString(); - SqlBuilder.getInsertIntoSqlBuilder().table("SYS_USER") - .field("ID_", userId) - .field("LOGINNAME_",administratorLoginName) - .field("USERNAME_","系统管理员") - .field("PASSWORD_",administratorPassword) - .field("ENABLE_",1) - .field("DATA_COME_FROM_","INPUT") - .field("CREATOR_","system") - .field("CREATE_DATE_",new Date()) - .field("LAST_MODIFIER_","system") - .field("LAST_MODIFYDATE_",new Date()) - .field("CORP_CODE_","_PRIMARY_") - .insert(jdbcTemplate); + List> list =jdbcTemplate.queryForList("select * from SYS_USER where LOGINNAME_=?",administratorLoginName); + if(list.isEmpty()){ + SqlBuilder.getInsertIntoSqlBuilder().table("SYS_USER") + .field("ID_", userId) + .field("LOGINNAME_", administratorLoginName) + .field("USERNAME_", "系统管理员") + .field("PASSWORD_", administratorPassword) + .field("ENABLE_", 1) + .field("DATA_COME_FROM_", "INPUT") + .field("CREATOR_", "system") + .field("CREATE_DATE_", new Date()) + .field("LAST_MODIFIER_", "system") + .field("LAST_MODIFYDATE_", new Date()) + .field("CORP_CODE_", "_PRIMARY_") + .insert(jdbcTemplate); + }else { + jdbcTemplate.update("update SYS_USER set PASSWORD_=? where LOGINNAME_=?",administratorPassword,administratorLoginName); + Map record =list.get(0); + userId =record.get("ID_").toString(); + } // 创建管理员角色 String roleId =UUID.randomUUID().toString(); - SqlBuilder.getInsertIntoSqlBuilder() - .table("SYS_ROLE") - .field("ID_", roleId) - .field("CODE_","admin") - .field("NAME_","系统管理员") - .field("DESCRIPTION_","系统管理员") - .field("ENABLE_",1) - .field("DATA_COME_FROM_","INPUT") - .field("CREATOR_","system") - .field("CREATE_DATE_", new java.sql.Date(new Date().getTime())) - .field("LAST_MODIFIER_","system") - .field("LAST_MODIFYDATE_",new java.sql.Date(new Date().getTime())) - .field("CORP_CODE_","_PRIMARY_") - .insert(jdbcTemplate); + list =jdbcTemplate.queryForList("select * from SYS_ROLE where CODE_='admin'"); + if(list.isEmpty()){ + SqlBuilder.getInsertIntoSqlBuilder() + .table("SYS_ROLE") + .field("ID_", roleId) + .field("CODE_","admin") + .field("NAME_","系统管理员") + .field("DESCRIPTION_","系统管理员") + .field("ENABLE_",1) + .field("DATA_COME_FROM_","INPUT") + .field("CREATOR_","system") + .field("CREATE_DATE_", new java.sql.Date(new Date().getTime())) + .field("LAST_MODIFIER_","system") + .field("LAST_MODIFYDATE_",new java.sql.Date(new Date().getTime())) + .field("CORP_CODE_","_PRIMARY_") + .insert(jdbcTemplate); + }else{ + Map record =list.get(0); + roleId =record.get("ID_").toString(); + } // 角色和用户的关系 - jdbcTemplate.update("insert into SYS_USER_ROLE(USER_ID_,ROLE_ID_) values (?,?)", userId,roleId); + list =jdbcTemplate.queryForList("select * from SYS_USER_ROLE where USER_ID_=? and ROLE_ID_=?",userId,roleId); + if(list.isEmpty()){ + jdbcTemplate.update("insert into SYS_USER_ROLE(USER_ID_,ROLE_ID_) values (?,?)", userId,roleId); + } DatasourceUtil.close(dataSource); } diff --git a/io.sc.platform.system.frontend/package.json b/io.sc.platform.system.frontend/package.json index ad5222cc..d699b125 100644 --- a/io.sc.platform.system.frontend/package.json +++ b/io.sc.platform.system.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.platform.system.frontend/public/configure.js b/io.sc.platform.system.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.platform.system.frontend/public/configure.js +++ b/io.sc.platform.system.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', diff --git a/io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/impl/UserServiceImpl.java b/io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/impl/UserServiceImpl.java index 7fdde95d..f2996f42 100644 --- a/io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/impl/UserServiceImpl.java +++ b/io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/impl/UserServiceImpl.java @@ -3,7 +3,6 @@ package io.sc.platform.system.user.service.impl; import io.sc.platform.jdbc.util.SqlBatcher; import io.sc.platform.mvc.plugins.PluginManager; import io.sc.platform.mvc.plugins.item.FrontEndRoute; -import io.sc.platform.mvc.service.FrontEndService; import io.sc.platform.mvc.service.SystemParameterService; import io.sc.platform.orm.api.exception.UserRawPasswordNotMatchException; import io.sc.platform.orm.service.impl.DaoServiceImpl; @@ -17,8 +16,6 @@ import io.sc.platform.system.api.menu.MenuRouteVo; import io.sc.platform.system.api.menu.MenuVo; import io.sc.platform.system.department.jpa.entity.DepartmentEntity; import io.sc.platform.system.i18n.service.I18nService; -import io.sc.platform.system.menu.jpa.entity.MenuEntity; -import io.sc.platform.system.menu.jpa.entity.MenuGroupEntity; import io.sc.platform.system.menu.service.MenuService; import io.sc.platform.system.org.jpa.entity.OrgEntity; import io.sc.platform.system.org.service.OrgService; @@ -53,7 +50,6 @@ public class UserServiceImpl extends DaoServiceImpl routes =new ArrayList<>(); - /** - * 微前端远程入口文件 Map - * key: 微前端模块名称,通常为项目名称 - * value: 微前端入口文件 url - */ - private Map remoteEntries =new HashMap<>(); - public Map getUser() { return user; } @@ -54,12 +47,4 @@ public class UserSession { public void setRoutes(List routes) { this.routes = routes; } - - public Map getRemoteEntries() { - return remoteEntries; - } - - public void setRemoteEntries(Map remoteEntries) { - this.remoteEntries = remoteEntries; - } } diff --git a/io.sc.standard.frontend/package.json b/io.sc.standard.frontend/package.json index a3278003..a70e4b75 100644 --- a/io.sc.standard.frontend/package.json +++ b/io.sc.standard.frontend/package.json @@ -92,7 +92,7 @@ "luckyexcel": "1.0.1", "mockjs": "1.1.0", "pinia": "2.1.7", - "platform-core": "8.1.295", + "platform-core": "8.1.301", "quasar": "2.15.4", "tailwindcss": "3.4.4", "vue": "3.4.31", diff --git a/io.sc.standard.frontend/public/configure.js b/io.sc.standard.frontend/public/configure.js index 3f4e2e53..5adaac35 100644 --- a/io.sc.standard.frontend/public/configure.js +++ b/io.sc.standard.frontend/public/configure.js @@ -2,22 +2,32 @@ window.APP = {}; // 全局配置 window.APP.configure ={ - // router 历史模式 - routerHistoryMode: 'web', // 应用上下文路径 webContextPath: '[(@{/})]'.startsWith('[')? '/' : '[(@{/})]', + // 默认后端 API 请求的服务地址前缀 apiContextPaths: { DEFAULT: '[(@{/})]'.startsWith('[')? 'http://localhost:8080/' : '[(@{/})]', }, + + // 是否是独立部署的前端 + isAloneFrontend: false, + + // router 历史模式 + routerHistoryMode: 'hash', + // 是否启用本地 mock enableLocalMock : false, + // mock 请求响应时间(单位:毫秒) localMockTimeout : 10, + // 是否启用使用远程服务端配置 enableRemoteConfigure : true, + // 是否首先使用本地路由 useLocaleRouterFirst : true, + // axios 配置 axios : { baseURL: '', From 61fcc8ba2366daaf6afa533c141f1faf5428d2fc Mon Sep 17 00:00:00 2001 From: wangshaoping Date: Fri, 23 Aug 2024 18:03:39 +0800 Subject: [PATCH 2/2] update --- .../plugin/manager/RemoteEntryManager.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 io.sc.platform.core.frontend/src/platform/plugin/manager/RemoteEntryManager.ts diff --git a/io.sc.platform.core.frontend/src/platform/plugin/manager/RemoteEntryManager.ts b/io.sc.platform.core.frontend/src/platform/plugin/manager/RemoteEntryManager.ts new file mode 100644 index 00000000..3f5c3344 --- /dev/null +++ b/io.sc.platform.core.frontend/src/platform/plugin/manager/RemoteEntryManager.ts @@ -0,0 +1,45 @@ +import { PConst } from '@/platform/PConst'; +import { Environment } from '@/platform/plugin/environment'; +import Axios from 'axios'; +import { JavascriptLoader } from '@/platform/utils'; + +class RemoteEntryManager { + /** + * 动态加载远程组件入口 JS 文件 + * @param callback 加载完成后的回调(当加载成功或失败后都会回调) + */ + public static loadRemoteEntries(callback) { + if (Environment.isAloneFrontend()) { + const remoteEntries = Environment.getRemoteEntries(); + if (remoteEntries) { + const urls = []; + for (const key in remoteEntries) { + urls.push(Environment.getWebContextPath() + remoteEntries[key]); + } + console.debug('Loading remote entries ...', urls); + const loader = new JavascriptLoader((errorUrl) => { + callback(); + }); + loader.load(urls); + } + } else { + const axios = Axios.create({}); + axios.get(Environment.apiContextPath(PConst.API_REMOTE_ENTRY_URL)).then((response) => { + const remoteEntries = response.data.data; + if (remoteEntries) { + const urls = []; + for (const key in remoteEntries) { + urls.push(remoteEntries[key]); + } + console.debug('Loading remote entries ...', urls); + const loader = new JavascriptLoader((errorUrl) => { + callback(); + }); + loader.load(urls); + } + }); + } + } +} + +export { RemoteEntryManager };