How to Build a Web Application in Java, package as a .exe file to run as a Desktop Application

Published Jun 23, 2017
How to Build a Web Application in Java, package as a .exe file to run as a Desktop Application

In this post I am going to show you how to build a web application in Java, then package the application as a .exe file and install and run the application like desktop application.

In this tutorial you will need to create a java web application (Maven) using NetBeans or any other IDE of your choice.

Capture.PNG

Next add the following dependencies to your pom file.

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mycompany</groupId>
    <artifactId>DesktopApp</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>DesktopApp</name>

    <properties>
        <tomcat.version>8.0.24</tomcat.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-dbcp</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-logging-juli</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jasper</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jasper-el</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jsp-api</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.185</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>DesktopApp</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <inherited>true</inherited>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>appassembler-maven-plugin</artifactId>
                <version>1.1.1</version>
                <configuration>
                    <assembleDirectory>target</assembleDirectory>
                    <programs>
                        <program>
                            <mainClass>launch.Main</mainClass>
                            <name>webapp</name>
                        </program>
                    </programs>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>assemble</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

Now we are going to create a login page, this will be the first screen a user will see. In your webapp directory open index.html and add the following lines of code.

<!DOCTYPE html>
<html>
    <head>
        <title>Start Page</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <h1>Login to your desktop application</h1>
        
        <input type="text" value="User Name">
        <input type="password" value="Password">
        
        <input type="submit" value="Sign In">
        
        
    </body>
</html>

Great! Now create a package called "launch" and create two java classes called "Main.java" and "Frame.java". Here are the content of both files.

Frame.java

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package launch;



import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
 
 
public class Frame extends Application {
  
  /**
  *
  * @author Onuche Idoko
  * 
  */
  
    private Scene scene;
    @Override public void start(Stage stage) {
        // create the scene
        stage.setTitle("Desktop Application");
        scene = new Scene(new Browser(),750,500, Color.web("#666970"));
        stage.setScene(scene);
        //scene.getStylesheets().add("webviewsample/BrowserToolbar.css");        
        stage.show();
    }
 
    public static void main(String[] args){
        launch(args);
    }
}
class Browser extends Region {
 
    final WebView browser = new WebView();
    final WebEngine webEngine = browser.getEngine();
     
    public Browser() {
        //apply the styles
        getStyleClass().add("browser");
        // load the web page
        webEngine.load("http://localhost:9821/DesktopApp");
        //add the web view to the scene
        getChildren().add(browser);
 
    }
    private Node createSpacer() {
        Region spacer = new Region();
        HBox.setHgrow(spacer, Priority.ALWAYS);
        return spacer;
    }
 
    @Override protected void layoutChildren() {
        double w = getWidth();
        double h = getHeight();
        layoutInArea(browser,0,0,w,h,0, HPos.CENTER, VPos.CENTER);
    }
 
    @Override protected double computePrefWidth(double height) {
        return 750;
    }
 
    @Override protected double computePrefHeight(double width) {
        return 500;
    }
}

Main.java

package launch;

import java.io.File;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.swing.JOptionPane;

import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
import org.apache.commons.io.FilenameUtils;
import org.apache.tomcat.util.descriptor.web.ContextResource;

public class Main {

    /**
     *
     * @author Onuche Idoko
     * @param args
     * @throws java.lang.Exception
     *
     */
    public static void main(String[] args) throws Exception {

        File file_path = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
        String path = file_path.getAbsolutePath();
        System.out.println(path);

        String linux_path = FilenameUtils.separatorsToUnix(path);
        System.out.println(linux_path);

        String[] split_path = linux_path.split("/DesktopApp/target");

        String path_to_win = split_path[0];

        String windows_path = FilenameUtils.separatorsToWindows(path_to_win);
        System.out.println("APPLICATION IN : " + windows_path);
        
        int code = 0;
        
        try {

            URL siteURL = new URL("http://localhost:9821/DesktopApp");
            HttpURLConnection connection = (HttpURLConnection) siteURL
                    .openConnection();
            connection.setRequestMethod("GET");
            connection.connect();

            code = connection.getResponseCode();
        } catch (Exception e) {

        }

        if (code != 200) {

            String appDir = windows_path;

            String webappDirLocation = appDir + "/DesktopApp/src/main/webapp/";
            Tomcat tomcat = new Tomcat();

            //The port that we should run on can be set into an environment variable
            //Look for that variable and default to 9821 if it isn't there.
            String webPort = System.getenv("PORT");
            if (webPort == null || webPort.isEmpty()) {
                webPort = "9821";
            } else {
                JOptionPane.showMessageDialog(null, "System Error!!!", "System Error", JOptionPane.ERROR_MESSAGE);
                System.exit(0);
            }

            tomcat.setPort(Integer.valueOf(webPort));

            // Additions to make @WebServlet work
            String buildPath = appDir + "/DesktopApp/target/classes";
            String webAppMount = "/WEB-INF/classes";

            File contextConfigFile = new File(webappDirLocation + "/" + "META-INF/context.xml");

            StandardContext context = (StandardContext) tomcat.addWebapp("/DesktopApp", new File(webappDirLocation).getAbsolutePath());
            context.setConfigFile(contextConfigFile.toURI().toURL());
            File additionalWebInfClasses = new File(buildPath);

            tomcat.enableNaming();

            WebResourceRoot resources = new StandardRoot(context);
            resources.addPreResources(new DirResourceSet(resources, webAppMount, additionalWebInfClasses.getAbsolutePath(), "/"));
            context.setResources(resources);

            System.out.println("configuring app with basedir: " + new File("./" + webappDirLocation).getAbsolutePath());

            tomcat.start();
            Frame.main(args);

            System.exit(0);
            tomcat.getServer().await();

        } else if (code == 200) {
            JOptionPane.showMessageDialog(null, "Application already running!!!", "Desktop App", JOptionPane.WARNING_MESSAGE);
            System.exit(0);
        }
    }
}

The Frame.java loads the content of your web application in a frame, while the Main.java is responsible for launching your application. Now our app is running as expected.

Capture.PNG

Finally, you need to build and package your application into a .exe using NSISStudio

Discover and read more posts from Onuche Idoko
get started
Enjoy this post?

Leave a like and comment for Onuche

2
1