Repository: wuruoyun/electron-vue-spring Branch: master Commit: 42eccb72578b Files: 38 Total size: 39.5 KB Directory structure: gitextract_hvz2qq8e/ ├── .gitignore ├── LICENSE ├── README.md ├── build/ │ ├── build-installer.js │ └── build-server.js ├── electron/ │ ├── index.js │ ├── logger.js │ ├── preload.js │ └── splash.html ├── package.json ├── spring/ │ ├── .gitignore │ ├── .mvn/ │ │ └── wrapper/ │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── demo/ │ │ │ ├── DemoApplication.java │ │ │ ├── controller/ │ │ │ │ └── ItemController.java │ │ │ ├── model/ │ │ │ │ └── Item.java │ │ │ └── service/ │ │ │ ├── ItemService.java │ │ │ └── impl/ │ │ │ └── ItemServiceImpl.java │ │ └── resources/ │ │ ├── application.properties │ │ └── logback-spring.xml │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── demo/ │ └── DemoApplicationTests.java └── vue/ ├── .gitignore ├── README.md ├── index.html ├── package.json ├── src/ │ ├── App.vue │ ├── env.d.ts │ ├── interop-fallback.ts │ ├── keys.ts │ ├── main.ts │ └── types/ │ ├── Interop.ts │ └── Item.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store node_modules/ dist/ npm-debug.log yarn-error.log # Editor directories and files .vscode .idea *.suo *.ntvs* *.njsproj *.sln ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2017 Ruoyun Wu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Electron-Vue-Spring > An opionated desktop application with web front-end and Java backend. In some cases, you may like to use Java backend for an Electron desktop app. The reasons could be you have some legacy Java codes that you want to reuse, or you want to have the same codes run on Cloud as well as on desktop. This project has two sub projects: 1. `vue`: a Vue 3 app in TypeScript as the front-end, based on the scaffold project created using Vite. You may also replace this project with a React or Angular project with similar design. 2. `spring`: a Spring Boot application as the backend, based on a Maven project created by [Spring Initializer](https://start.spring.io/) with Web dependency. Both Windows and Mac OS are supported. ## Prerequisites - JDK 11, such as [Amazon Corretto 11](https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html) - Node 14.x - Maven 3.x > NOTE: This project uses your system Java to run the spring web app. If you prefer to bundle JRE into the app, configure the `extraFiles` of Electron Builder to copy it when making the installer. ## Build Installer Build the final installer, which can be found in folder `dist`. It is an `exe` file for Windows and `dmg` file for Mac. ```bash # install dependencies npm install # install dependencies for vue project cd vue npm install cd .. # build installer for production npm run build ``` ## Development Setup During development, you may work on front-end and backend separately with independent tools, such as using Visual Studio Code for front-end and IntelliJ for backend. Note that the front-end `vue` project has its own `package.json` so it can be built independently. - To run backend, import the Maven project into your favorite Java IDE and launch from there. The embedded Tomcat server will be running on port `8080`. - To run front-end, run `npm run dev` in `vue` folder. Vite will run a server on port `9000` with hot reload. It is configured to proxy `actuator/health` and `api` URL to port `8080`. - To run the Electron part, run `npm run start` in root folder. The Electron app loads the home page at `http://localhost:9000`, therefore you should run both backend and front-end first. ## How it works The main idea is to use Electron as a browser, and the front-end and backend of the app work as a web app. It might not be a common design, but is helpful in some cases. The backend is a typical Spring Boot app, serving API to the front-end. The front-end is a typical Vue app, consuming API from the backend. ### Build process When building the final desktop app installer: 1. Front-end is built first. The final artifacts, including `index.html` and JavaScript files, are copied into `spring/src/main/resources/public` folder. 2. Backend is built second. It creates a web app with the front-end artifacts created above and an executable jar. 3. Electron installer is built last. It includes the web app created above in the bundle and creates an executable installer. However, both `vue` sub project and `spring` sub project are free of Electron and can be built independently without building the Electron part. They can be deployed online, instead of packaged into Electron app, allowing you to use the same code base for online and desktop deployment. ### Launch process When launching the Electron app: 1. Electron app detects an available port and starts the backend server with Node `child_process` at the specified port. The PID of the server process is kept to potentially kill the process before quiting the app. 2. Electron app then displays a splash window, at the same time pings the `actuator/health` URL of the backend server periodically. 3. Once the `actuator/health` ping returns OK (the web app is up), Electron app closes the splash window and open a new window to load the home page of the web app. > The Electron app starts the backend server only in production build. During development, you will need to manually start the front-end dev server as mentioned earlier. ### Shutdown process When shutting down the Electron app: 1. Electron app handles the `will-quit` event by trying to stop the backend server and cancel the quit. 2. The first attempt is to shutdown gracefully via the `actuator/shutdown` URL of the backend server. 3. If that fails, the Electron app will attempt to kill the process by its PID. 4. Either of the shutsown attempts above will clear up the `baseUrl` and call `app.quit()` again. 5. With `baseUrl` being cleared, `will-quit` handler will not prevent the quitting this time. ### Node access Although the Java backend is running locally, it is more secure to load the page with Node integration disabled (defualt behavior). This prevents third-party JavaScript libraries used by your web app from accessing Node directly, and mitigates the risk if your app navigates to external website. The access to Node can be selectively re-introduced back to the web app via [preload.js](electron/preload.js), which defines a set of API on a global `window.interop` object. This object is provided by the Vue app instance in [main.ts](vue/src/main.ts) for injection into Vue components via key `KEY_INTEROP`. This allows any UI component to call the API. ### Log Aggregation The log messages from Electron, Vue and Spring apps are aggregated into the [electron logger](https://www.npmjs.com/package/electron-log) in Electron app. By default it writes logs to the following locations: - on Linux: `~/.config/{app name}/logs/{process type}.log` - on macOS: `~/Library/Logs/{app name}/{process type}.log` - on Windows: `%USERPROFILE%\AppData\Roaming\{app name}\logs\{process type}.log` In the Vue app, the electron logger is wrapped by the `log` property of `window.interop` object. This `log` object is provided by Vue app instance in [main.ts](vue/src/main.ts) for injection into Vue components via key `KEY_LOG`. Calling `$log.info(...)` will send the log messages (after attaching a prefix to identify it is from UI) to electron logger. Other logging level works in the same way. In the Spring app, `logback-spring.xml` configuration sends the log to console, which is the standard output received by the Electron app. The logback message pattern put the log level (`INFO`, `DEBUG`, etc.) at the begining of the message so that Electron app checks and calls the corresponding function (`info`, `debug`, etc.) on the electron logger. ## License [MIT](LICENSE) ================================================ FILE: build/build-installer.js ================================================ const shell = require('shelljs') shell.echo('##########################') shell.echo('# Building electron #') shell.echo('##########################') if (!shell.test('-e', 'spring/target')) { shell.echo('Error: server is not built yet.') shell.exit(1) } shell.rm('-rf', 'dist') if (shell.exec('electron-builder build').code !== 0) { shell.echo('Error: electron build failed') shell.exit(1) } ================================================ FILE: build/build-server.js ================================================ const shell = require('shelljs') shell.echo('##########################') shell.echo('# Building vue #') shell.echo('##########################') shell.cd('vue') const PUBLIC = '../spring/src/main/resources/public/' shell.rm('-rf', PUBLIC); if (shell.exec('npm run build').code !== 0) { shell.echo('Error: vue build failed') shell.exit(1) } shell.cp('-R', 'dist/', PUBLIC) shell.cd('..') shell.echo('##########################') shell.echo('# Building spring #') shell.echo('##########################') shell.cd('spring') const mvnw = process.platform === 'win32' ? 'mvnw' : './mvnw' if (shell.exec(mvnw + ' clean package').code !== 0) { shell.echo('Error: spring build failed') shell.exit(1) } ================================================ FILE: electron/index.js ================================================ const { app, ipcMain, BrowserWindow, dialog } = require('electron') const path = require('path') const url = require('url') var findPort = require('find-free-port') const isDev = require('electron-is-dev') const logger = require('./logger') const axios = require('axios') const JAR = 'spring-1.0.0.jar' // how to avoid manual update of this? const MAX_CHECK_COUNT = 10 // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let mainWindow // The server url and process let serverProcess let baseUrl function startServer(port) { logger.info(`Starting server at port ${port}`) const server = `${path.join(app.getAppPath(), '..', '..', JAR)}` logger.info(`Launching server with jar ${server} at port ${port}...`) serverProcess = require('child_process').spawn('java', [ '-jar', server, `--server.port=${port}`, ]) serverProcess.stdout.on('data', logger.server) if (serverProcess.pid) { baseUrl = `http://localhost:${port}` logger.info('Server PID: ' + serverProcess.pid) } else { logger.error('Failed to launch server process.') } } function stopServer() { logger.info('Stopping server...') axios .post(`${baseUrl}/actuator/shutdown`, null, { headers: { 'Content-Type': 'application/json' }, }) .then(() => logger.info('Server stopped')) .catch((error) => { logger.error('Failed to stop the server gracefully.', error) if (serverProcess) { logger.info(`Killing server process ${serverProcess.pid}`) const kill = require('tree-kill') kill(serverProcess.pid, 'SIGTERM', function (err) { logger.info('Server process killed') serverProcess = null baseUrl = null app.quit() // quit again }) } }) .finally(() => { serverProcess = null baseUrl = null app.quit() // quit again }) } function createSplash() { const splash = new BrowserWindow({ width: 400, height: 300, frame: false }) splash.loadURL( url.format({ pathname: path.join(__dirname, 'splash.html'), protocol: 'file:', slashes: true, }) ) return splash } function createWindow(callback) { mainWindow = new BrowserWindow({ width: 800, height: 600, show: false, // hide until ready-to-show webPreferences: { preload: path.join(__dirname, 'preload.js'), }, }) loadHomePage() // Open the DevTools. // mainWindow.webContents.openDevTools() mainWindow.once('ready-to-show', () => { mainWindow.show() if (callback) callback() }) // Emitted when the window is closed. mainWindow.on('closed', function () { // Dereference the window object, usually you would store windows // in an array if your app supports multi windows, this is the time // when you should delete the corresponding element. mainWindow = null }) } function quitOnError(title, content) { logger.error(content) dialog.showErrorBox(title, content) app.quit() } function loadHomePage() { logger.info(`Loading home page at ${baseUrl}`) // check server health and switch to main page checkCount = 0 setTimeout(function cycle() { axios .get(`${baseUrl}/actuator/health`) .then(() => mainWindow.loadURL(`${baseUrl}?_=${Date.now()}`)) .catch((e) => { if (e.code === 'ECONNREFUSED') { if (checkCount < MAX_CHECK_COUNT) { checkCount++ setTimeout(cycle, 1000) } else { quitOnError( 'Server timeout', `UI does not receive server response for ${MAX_CHECK_COUNT} seconds.` ) app.quit() } } else { logger.error(e) quitOnError('Server error', 'UI receives an error from server.') } }) }, 200) } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.whenReady().then(() => { logger.info('###################################################') logger.info('# Application Starting #') logger.info('###################################################') // handle messages from ipcRenderer via preload.js ipcMain.on('app:badgeCount', (_, count) => app.setBadgeCount(count)) ipcMain.handle('dialog:openFile', () => dialog.showOpenDialogSync()) ipcMain.handle('dialog:saveFile', () => dialog.showSaveDialogSync()) if (isDev) { // Assume the webpack dev server is up at port 9000 baseUrl = `http://localhost:9000` createWindow() } else { // Create window first to show splash before starting server const splash = createSplash() // Start server at an available port (prefer 8080) findPort(8080, function (err, port) { if (!err) { startServer(port) createWindow(() => splash.close()) } else { quitOnError('Error', 'Unable to get a server port.') } }) } }) // Quit when all windows are closed. app.on('window-all-closed', function () { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', function () { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (mainWindow === null) { createWindow() } }) app.on('will-quit', (e) => { if (!isDev && baseUrl != null) { stopServer() e.preventDefault() // will quite later after stopped the server } }) // In this file you can include the rest of your app's specific main process // code. You can also put them in separate files and require them here. ================================================ FILE: electron/logger.js ================================================ const logger = require('electron-log') logger.server = function (data) { // data is from server std.out and may includes multiple lines const messages = data.toString().split('\n') messages.forEach((msg) => { if (msg.length > 0) { if (msg.startsWith('INFO')) logger.info(msg.substring(6)) else if (msg.startsWith('WARN')) logger.warn(msg.substring(6)) else if (msg.startsWith('ERROR')) logger.error(msg.substring(6)) else if (msg.startsWith('DEBUG')) logger.debug(msg.substring(6)) else logger.silly(msg) } }) } module.exports = logger ================================================ FILE: electron/preload.js ================================================ const { app, contextBridge, ipcRenderer } = require('electron') const logger = require('./logger') const LOG_PREFIX = '[ui]' contextBridge.exposeInMainWorld('interop', { log: { info(msg) { logger.info(`${LOG_PREFIX} ${msg}`) }, debug(msg) { logger.debug(`${LOG_PREFIX} ${msg}`) }, warn(msg) { logger.warn(`${LOG_PREFIX} ${msg}`) }, error(msg) { logger.error(`${LOG_PREFIX} ${msg}`) }, log(msg) { logger.silly(`${LOG_PREFIX} ${msg}`) }, }, setBadgeCount(count) { return ipcRenderer.send('app:badgeCount', count) }, showOpenDialog() { return ipcRenderer.invoke('dialog:openFile') }, showSaveDialog() { return ipcRenderer.invoke('dialog:saveFile') }, }) ================================================ FILE: electron/splash.html ================================================
Starting server, please wait...
================================================ FILE: package.json ================================================ { "name": "electron-vue-spring", "version": "1.0.0", "description": "A minimal starter project for using Electron, Vue and Spring.", "author": "Wu, Ruoyun", "repository": { "type": "git", "url": "https://github.com/wuruoyun/electron-vue-spring.git" }, "main": "electron/index.js", "scripts": { "start": "electron ./electron", "build-server": "node build/build-server.js", "build-installer": "node build/build-installer.js", "build": "npm-run-all clean build-server build-installer", "clean": "rimraf dist" }, "license": "MIT", "build": { "appId": "electron-vue-spring", "files": [ "electron/**/*", "node_modules/**/*", "!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}", "!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}", "!**/node_modules/*.d.ts", "!**/node_modules/.bin", "!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}", "!.editorconfig", "!**/._*", "!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}", "!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}", "!**/{appveyor.yml,.travis.yml,circle.yml}", "!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}" ], "extraFiles": [ { "from": "spring/target", "filter": [ "*.jar" ] } ] }, "devDependencies": { "electron": "^18.0.3", "electron-builder": "^22.14.13", "npm-run-all": "^4.1.5", "rimraf": "^3.0.2", "shelljs": "^0.8.5" }, "dependencies": { "axios": "^0.26.1", "electron-is-dev": "^2.0.0", "electron-log": "^4.4.6", "find-free-port": "^2.0.0", "tree-kill": "^1.2.2" } } ================================================ FILE: spring/.gitignore ================================================ target/ !.mvn/wrapper/maven-wrapper.jar ### public folder is from external SPA ### src/main/resources/public ### STS ### .apt_generated .classpath .factorypath .project .settings .springBeans ### IntelliJ IDEA ### .idea *.iws *.iml *.ipr ### NetBeans ### nbproject/private/ build/ nbbuild/ dist/ nbdist/ .nb-gradle/ ### Eclipse ### .settings .classpath .project ================================================ FILE: spring/.mvn/wrapper/maven-wrapper.properties ================================================ distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip ================================================ FILE: spring/mvnw ================================================ #!/bin/sh # ---------------------------------------------------------------------------- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- # Maven2 Start Up Batch script # # Required ENV vars: # ------------------ # JAVA_HOME - location of a JDK home dir # # Optional ENV vars # ----------------- # M2_HOME - location of maven2's installed home dir # MAVEN_OPTS - parameters passed to the Java VM when running Maven # e.g. to debug Maven itself, use # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 # MAVEN_SKIP_RC - flag to disable loading of mavenrc files # ---------------------------------------------------------------------------- if [ -z "$MAVEN_SKIP_RC" ] ; then if [ -f /etc/mavenrc ] ; then . /etc/mavenrc fi if [ -f "$HOME/.mavenrc" ] ; then . "$HOME/.mavenrc" fi fi # OS specific support. $var _must_ be set to either true or false. cygwin=false; darwin=false; mingw=false case "`uname`" in CYGWIN*) cygwin=true ;; MINGW*) mingw=true;; Darwin*) darwin=true # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home # See https://developer.apple.com/library/mac/qa/qa1170/_index.html if [ -z "$JAVA_HOME" ]; then if [ -x "/usr/libexec/java_home" ]; then export JAVA_HOME="`/usr/libexec/java_home`" else export JAVA_HOME="/Library/Java/Home" fi fi ;; esac if [ -z "$JAVA_HOME" ] ; then if [ -r /etc/gentoo-release ] ; then JAVA_HOME=`java-config --jre-home` fi fi if [ -z "$M2_HOME" ] ; then ## resolve links - $0 may be a link to maven's home PRG="$0" # need this for relative symlinks while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG="`dirname "$PRG"`/$link" fi done saveddir=`pwd` M2_HOME=`dirname "$PRG"`/.. # make it fully qualified M2_HOME=`cd "$M2_HOME" && pwd` cd "$saveddir" # echo Using m2 at $M2_HOME fi # For Cygwin, ensure paths are in UNIX format before anything is touched if $cygwin ; then [ -n "$M2_HOME" ] && M2_HOME=`cygpath --unix "$M2_HOME"` [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"` fi # For Migwn, ensure paths are in UNIX format before anything is touched if $mingw ; then [ -n "$M2_HOME" ] && M2_HOME="`(cd "$M2_HOME"; pwd)`" [ -n "$JAVA_HOME" ] && JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" # TODO classpath? fi if [ -z "$JAVA_HOME" ]; then javaExecutable="`which javac`" if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then # readlink(1) is not available as standard on Solaris 10. readLink=`which readlink` if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then if $darwin ; then javaHome="`dirname \"$javaExecutable\"`" javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" else javaExecutable="`readlink -f \"$javaExecutable\"`" fi javaHome="`dirname \"$javaExecutable\"`" javaHome=`expr "$javaHome" : '\(.*\)/bin'` JAVA_HOME="$javaHome" export JAVA_HOME fi fi fi if [ -z "$JAVACMD" ] ; then if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi else JAVACMD="`which java`" fi fi if [ ! -x "$JAVACMD" ] ; then echo "Error: JAVA_HOME is not defined correctly." >&2 echo " We cannot execute $JAVACMD" >&2 exit 1 fi if [ -z "$JAVA_HOME" ] ; then echo "Warning: JAVA_HOME environment variable is not set." fi CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher # traverses directory structure from process work directory to filesystem root # first directory with .mvn subdirectory is considered project base directory find_maven_basedir() { if [ -z "$1" ] then echo "Path not specified to find_maven_basedir" return 1 fi basedir="$1" wdir="$1" while [ "$wdir" != '/' ] ; do if [ -d "$wdir"/.mvn ] ; then basedir=$wdir break fi # workaround for JBEAP-8937 (on Solaris 10/Sparc) if [ -d "${wdir}" ]; then wdir=`cd "$wdir/.."; pwd` fi # end of workaround done echo "${basedir}" } # concatenates all lines of a file concat_lines() { if [ -f "$1" ]; then echo "$(tr -s '\n' ' ' < "$1")" fi } BASE_DIR=`find_maven_basedir "$(pwd)"` if [ -z "$BASE_DIR" ]; then exit 1; fi export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} echo $MAVEN_PROJECTBASEDIR MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" # For Cygwin, switch paths to Windows format before running java if $cygwin; then [ -n "$M2_HOME" ] && M2_HOME=`cygpath --path --windows "$M2_HOME"` [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"` [ -n "$MAVEN_PROJECTBASEDIR" ] && MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` fi WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ $MAVEN_OPTS \ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" ================================================ FILE: spring/mvnw.cmd ================================================ @REM ---------------------------------------------------------------------------- @REM Licensed to the Apache Software Foundation (ASF) under one @REM or more contributor license agreements. See the NOTICE file @REM distributed with this work for additional information @REM regarding copyright ownership. The ASF licenses this file @REM to you under the Apache License, Version 2.0 (the @REM "License"); you may not use this file except in compliance @REM with the License. You may obtain a copy of the License at @REM @REM http://www.apache.org/licenses/LICENSE-2.0 @REM @REM Unless required by applicable law or agreed to in writing, @REM software distributed under the License is distributed on an @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @REM KIND, either express or implied. See the License for the @REM specific language governing permissions and limitations @REM under the License. @REM ---------------------------------------------------------------------------- @REM ---------------------------------------------------------------------------- @REM Maven2 Start Up Batch script @REM @REM Required ENV vars: @REM JAVA_HOME - location of a JDK home dir @REM @REM Optional ENV vars @REM M2_HOME - location of maven2's installed home dir @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven @REM e.g. to debug Maven itself, use @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files @REM ---------------------------------------------------------------------------- @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' @echo off @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% @REM set %HOME% to equivalent of $HOME if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") @REM Execute a user defined script before this one if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre @REM check for pre script, once with legacy .bat ending and once with .cmd ending if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" :skipRcPre @setlocal set ERROR_CODE=0 @REM To isolate internal variables from possible post scripts, we use another setlocal @setlocal @REM ==== START VALIDATION ==== if not "%JAVA_HOME%" == "" goto OkJHome echo. echo Error: JAVA_HOME not found in your environment. >&2 echo Please set the JAVA_HOME variable in your environment to match the >&2 echo location of your Java installation. >&2 echo. goto error :OkJHome if exist "%JAVA_HOME%\bin\java.exe" goto init echo. echo Error: JAVA_HOME is set to an invalid directory. >&2 echo JAVA_HOME = "%JAVA_HOME%" >&2 echo Please set the JAVA_HOME variable in your environment to match the >&2 echo location of your Java installation. >&2 echo. goto error @REM ==== END VALIDATION ==== :init @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". @REM Fallback to current working directory if not found. set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir set EXEC_DIR=%CD% set WDIR=%EXEC_DIR% :findBaseDir IF EXIST "%WDIR%"\.mvn goto baseDirFound cd .. IF "%WDIR%"=="%CD%" goto baseDirNotFound set WDIR=%CD% goto findBaseDir :baseDirFound set MAVEN_PROJECTBASEDIR=%WDIR% cd "%EXEC_DIR%" goto endDetectBaseDir :baseDirNotFound set MAVEN_PROJECTBASEDIR=%EXEC_DIR% cd "%EXEC_DIR%" :endDetectBaseDir IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig @setlocal EnableExtensions EnableDelayedExpansion for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% :endReadAdditionalConfig SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* if ERRORLEVEL 1 goto error goto end :error set ERROR_CODE=1 :end @endlocal & set ERROR_CODE=%ERROR_CODE% if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost @REM check for post script, once with legacy .bat ending and once with .cmd ending if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" :skipRcPost @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' if "%MAVEN_BATCH_PAUSE%" == "on" pause if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% exit /B %ERROR_CODE% ================================================ FILE: spring/pom.xml ================================================Fetching items...
Failed to receive items. {{ error }}
Click buttons below to set app badge count (calling Electron via preload script)
Selected File(s) : {{ selectedFile }}