Projekt: Installer z svn, mvn i spring-boot

Każda aplikacja warta lub nie warta uwagi ale posiadająca aspiracje ma dziś własny instalator. W dzisiejszym odcinku zajmiemy się stworzenie narzędzia do instalacji naszego projektu. Będzie to plik wykonywalny typu EXE. Jego zadaniem będzie zebraniem informacji od użytkownika o przeczytaniu licencji (zaznaczeniu odpowiedniego kwadracika), zadecydowanie o utworzeniu ikony na pulpicie, wybranie miejsca na dysku gdzie ma zostać zainstalowana aplikacja (plik jar), oraz na samym końcu uruchomienie naszej aplikacji.
Do tej prezentacji wybrałem bardzo prostą opcję czyli zagnieździłem plik .jar w pliku .exe, wiem że dziś mamy dobrodziejstwo internetu i możemy sobie spokojnie pobrać zasoby. Sypię głowę popiołem ale naszym celem jest uruchomienie aplikacji a nie sprzeczanie się nad tym co można 😉
Instalator jest bardzo prosty i to jest jego celem. Jeśli ktoś ma chęć rozszerzyć projekt o nowe możliwości to proszę bardzo, będzie mi miło że dałem komuś natchnienie.

Zapraszam do lektury i komentarzy!

Zacznijmy od wyboru technologii

L.P. Co Więcej
1 repo* http://git.e-strix.com/sample_installer.git/
2 Java 1.8.0
3 Maven 3.3.9

*) W konfiguracji projektu (plik pom.xml) jest oznaczony svn, natomiast aktualnie repo znajduje się na prywatnym serwerze git. Powodem jest fakt że nie opłaca stawiać mi się stawiać svn’a dla jednego projektu. W załączonym filmie będę pracował na SVN i myślę że to wystarczy. Jeśli jesteś zainteresowany konfiguracją SVN zapraszam tutaj

1. Zaczynajmy: Struktura projektu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
│   LICENSE.md
│   pom.xml
│   README.md

└───src
  └───main
    ├───java
    │  └───pl
    │    └───estrix
    │      └───javafx
    │        AppContext.java
    │        FilterProp.java
    │        InstallerService.java
    │        JavaApplication.java
    │        MainController.java
    │        Step1Controller.java
    │        Step2Controller.java
    │        Step3Controller.java
    │
    └───resources
      │    main.fxml
      │    step_1.fxml
      │    step_2.fxml
      │    step_3.fxml
      │
      ├───content
      │    application.ico
      │    config.bat
      │    JavaFxGitSample_5.0.0.jar
      │    sudo.cmd
      │
      ├───img
      │    application.png
      │    logo.png
      │
      └───META-INF
           spring.factories

Nie będę omawiał każdego pliku, nie ma na to czasu, zwrócę uwagę tylko na te, które wnoszą coś ciekawego. Są to dość proste rzeczy, jeśli masz wątpliwości to proszę wróć do podstaw programowania w java i javaFx. Jest wiele dobrych materiałów na YouTube o tym temacie, również w języku polskim. Mój ulubiony to kanał „Zacznij Programować”, polecam do zapoznania się 🙂

Cały projekt można pobrać z odnośnika repozytorium.

Plik: pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?xml version="1.0" encoding="ISO-8859-2"?>
<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/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>pl.estrix</groupId>
  <artifactId>estrix-jar-launcher</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
  <name>launcher</name>
  <url>http://maven.apache.org</url>

  <profiles>
    <profile>
      <id>windows-deploy</id>
      <activation>
        <os>
          <family>Windows</family>
        </os>
      </activation>
      <build>
        <plugins>
          <plugin>
            <groupId>com.akathist.maven.plugins.launch4j</groupId>
            <artifactId>launch4j-maven-plugin</artifactId>
            <version>1.7.22</version>
            <executions>
              <execution>
                <id>l4j-clui</id>
                <phase>package</phase>
                <goals>
                  <goal>launch4j</goal>
                </goals>
                <configuration>
                  <headerType>gui</headerType>
                  <outfile>target/JavaFxGitSample-win-install.exe</outfile>
                  <jar>target/estrix-jar-launcher-1.0-SNAPSHOT.jar</jar>
                  <classPath>
                    <mainClass>org.springframework.boot.loader.JarLauncher</mainClass>
                    <preCp>anything</preCp>
                  </classPath>

                  <icon>src/main/resources/content/application.ico</icon>
                  <jre>
                    <minVersion>1.8.0</minVersion>
                    <jdkPreference>preferJre</jdkPreference>
                  </jre>

                  <versionInfo>
                    <fileVersion>1.0.0.0</fileVersion>
                    <txtFileVersion>${project.version}</txtFileVersion>
                    <fileDescription>${project.name}</fileDescription>
                    <copyright>2018 e-Strix.com</copyright>
                    <productVersion>1.0.0.0</productVersion>
                    <txtProductVersion>1.0.0.0</txtProductVersion>
                    <productName>${project.name}</productName>
                    <companyName>e-Strix Kamil Mucik</companyName>
                    <internalName>e-Strix Kamil Mucik</internalName>
                    <originalFilename>JavaFxGitSample-win-install.exe</originalFilename>
                  </versionInfo>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </profile>
  </profiles>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
  </parent>

  <scm>
    <connection>scm:svn:http://37.187.242.134/svn/estrix-javafx/013-project-for-YT-movie/svn_mvn/trunk</connection>
    <developerConnection>scm:svn:http://37.187.242.134/svn/estrix-javafx/013-project-for-YT-movie/svn_mvn/trunk</developerConnection>
    <url>http://37.187.242.134/svn/estrix-javafx/013-project-for-YT-movie/svn_mvn/trunk</url>
  </scm>

  <distributionManagement>
    <repository>
      <uniqueVersion>false</uniqueVersion>
      <id>corp1</id>
      <name>Corporate Repository</name>
      <url>file://C:\temp</url>
      <!--<url>scp://repo/maven2</url>-->
      <layout>default</layout>
    </repository>
  </distributionManagement>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring.boot.mainClass>pl.estrix.javafx.JavaApplication</spring.boot.mainClass>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-io</artifactId>
      <version>1.3.2</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <executable>true</executable>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-antrun-plugin</artifactId>
        <executions>
          <execution>
            <phase>generate-resources</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <tasks>
                <mkdir dir="${project.build.directory}" />
                <tstamp>
                  <format property="last.updated" pattern="yyyy.MM.dd HH:mm" />
                </tstamp>
                <echo file="${basedir}/target/classes/filter.properties" append="false" message="estrix.application.biuld-time=${last.updated}" />
                <echo file="${basedir}/target/classes/filter.properties" append="true" message="${line.separator}" />
                <echo file="${basedir}/target/classes/filter.properties" append="true" message="estrix.application.name=${project.name}" />
                <echo file="${basedir}/target/classes/filter.properties" append="true" message="${line.separator}" />
                <echo file="${basedir}/target/classes/filter.properties" append="true" message="estrix.application.version=${project.version}" />
              </tasks>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

Plik: src\main\java\pl\estrix\javafx\AppContext.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package pl.estrix.javafx;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.stage.Stage;
import org.springframework.context.ConfigurableApplicationContext;

class AppContext {

    /**
     * Path where app will be installed.
     */

    static String targetPath = "C:\\Users\\TEST\\AppData\\Local\";

    /**
     * No comment.
     */
    static Boolean createShortcut = false;

    static ConfigurableApplicationContext springContext;

    static Boolean finish = Boolean.FALSE;

    static Stage primaryStage;

    static BooleanProperty licenseAgreement = new SimpleBooleanProperty(Boolean.FALSE);
    static BooleanProperty buttonNextProperty = new SimpleBooleanProperty(Boolean.FALSE);
    static BooleanProperty buttonPrevProperty = new SimpleBooleanProperty(Boolean.FALSE);


}

Plik: src\main\java\pl\estrix\javafx\FilterProp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package pl.estrix.javafx;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("filter.properties")
class FilterProp {

    @Value("${estrix.application.name}")
    private String name ;
    @Value("${estrix.application.version}")
    private String version ;
    @Value("${estrix.application.biuld-time}")
    private String biuldTime ;

    String getName() {
        return name;
    }

    String getVersion() {
        return version;
    }

    String getBiuldTime() {
        return biuldTime;
    }

}

Plik: src\main\java\pl\estrix\javafx\InstallerService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package pl.estrix.javafx;

import org.apache.commons.io.FileUtils;

import java.io.*;
import java.net.URL;

class InstallerService {

    static void createFolder(String path) {
        try {
            path += "_SampleApp/";
            boolean success = (new File(path)).mkdirs();

            if (success) {
                AppContext.targetPath = path;
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    static void createSettings(){
        try {
            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(AppContext.targetPath + "settings.bat", true)));
            out.println("set app_path="+AppContext.targetPath);
            out.println("set app_desktop_shortcut="+AppContext.createShortcut);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static void copyResource(String file){
        URL inputUrl = InstallerService.class.getResource("/content/" + file);
        File dest = new File(AppContext.targetPath + "/" + file);
        try {
            FileUtils.copyURLToFile(inputUrl, dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    static void executeBatch(){
        try {
            Runtime.getRuntime().exec("cmd /c config.bat", null, new File(AppContext.targetPath));
        } catch (IOException  e) {
            e.printStackTrace();
        }
    }

    static void launchApp(){
        try {
            Runtime.getRuntime().exec("javaw.exe -jar JavaFxGitSample_5.0.0.jar", null, new File(AppContext.targetPath));
        } catch (IOException  e) {
            e.printStackTrace();
        }
    }
}

Plik: src\main\java\pl\estrix\javafx\JavaApplication.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package pl.estrix.javafx;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.*;

@SpringBootApplication
@ComponentScan(basePackages = "pl.estrix.javafx")
@PropertySource("classpath:filter.properties")
@Configuration
public class JavaApplication extends Application {

    private ConfigurableApplicationContext context;
    private Parent rootNode;

    public static void main(final String[] args) {
        Application.launch(args);
    }

    @Override
    public void init() throws Exception {
        SpringApplicationBuilder builder = new SpringApplicationBuilder(JavaApplication.class);
        context = builder.run(getParameters().getRaw().toArray(new String[0]));

        AppContext.springContext = context;
        FXMLLoader loader = new FXMLLoader(getClass().getResource("/main.fxml"));
        loader.setControllerFactory(AppContext.springContext::getBean);
        rootNode = loader.load();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(new Scene(rootNode, 580, 420));
        primaryStage.centerOnScreen();
        primaryStage.show();

        Image icon = new Image(JavaApplication.class.getResourceAsStream("/img/application.png"));
        primaryStage.getIcons().add(icon);

        AppContext.primaryStage = primaryStage;
    }

    @Override
    public void stop() throws Exception {
        AppContext.springContext.close();
        Platform.exit();
    }

}

Plik: src\main\java\pl\estrix\javafx\MainController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package pl.estrix.javafx;

import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.io.IOException;

@Controller
public class MainController {

    @Autowired
    private FilterProp filterProp;
    @Autowired
    private JavaApplication javaApplication;

    @FXML
    private BorderPane borderPane;
    @FXML
    private Button nextButton;
    @FXML
    private Button prevButton;
    @FXML
    private Label infoBuild;
    @FXML
    private Label infoName;
    @FXML
    private Label infoVersion;

    @FXML
    public void initialize() {
        nextButton.disableProperty().bind(AppContext.buttonNextProperty.not());
        prevButton.disableProperty().bind(AppContext.buttonPrevProperty.not());

        infoBuild.setText(filterProp.getBiuldTime());
        infoName.setText(filterProp.getName());
        infoVersion.setText(filterProp.getVersion());

        step1();
    }

    private void setCenter(String fxmlPath)  {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource(fxmlPath));
            loader.setControllerFactory(AppContext.springContext::getBean);
            AnchorPane node = loader.load();

            borderPane.setCenter( node);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void step1() {setCenter("/step_1.fxml"); }

    private void step2() {setCenter("/step_2.fxml"); }

    void step3() {setCenter("/step_3.fxml"); }

    public void onPrevAction() {
        step1();
    }

    public void onNextAction() {
        step2();
    }

    void onCloseAction() {
        try {
            javaApplication.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Plik: src\main\java\pl\estrix\javafx\Step1Controller.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package pl.estrix.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.RadioButton;
import org.springframework.stereotype.Controller;

@Controller
public class Step1Controller {

    @FXML
    private RadioButton agreementCheckYes;

    @FXML
    public void initialize() {
        agreementCheckYes.selectedProperty().addListener( (object, oldValue, newValue) ->{
            AppContext.licenseAgreement.setValue(newValue);
            AppContext.buttonNextProperty.setValue(newValue);
        });

        AppContext.buttonPrevProperty.setValue(Boolean.FALSE);
        agreementCheckYes.selectedProperty().setValue(AppContext.licenseAgreement.getValue());
    }
}

Plik: src\main\java\pl\estrix\javafx\Step2Controller.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package pl.estrix.javafx;

import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.stage.DirectoryChooser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.io.File;

@Controller
public class Step2Controller {

    @Autowired
    private MainController mainController;

    @FXML
    private TextField textField2;
    @FXML
    private ProgressBar progressBar;
    @FXML
    private CheckBox createShortcut;
    @FXML
    private Button installButton;
    @FXML
    private Button changeDirButton;

    @FXML
    public void initialize() {
        AppContext.buttonPrevProperty.setValue(Boolean.TRUE);
        AppContext.buttonNextProperty.setValue(Boolean.FALSE);

        textField2.setText(AppContext.targetPath);

        createShortcut.selectedProperty().addListener( ((observable, oldValue, newValue) -> {
            AppContext.createShortcut = newValue;
        }));

        Platform.runLater( () -> {
            installButton.requestFocus();
        });
    }

    public void onPathChangeAction() {
        DirectoryChooser chooser = new DirectoryChooser();
        chooser.setTitle("Wybierz folder aplikacji");
        File defaultDirectory = new File(AppContext.targetPath);
        chooser.setInitialDirectory(defaultDirectory);
        File selectedDirectory = chooser.showDialog(AppContext.primaryStage);
        if (selectedDirectory != null) {
            AppContext.targetPath = selectedDirectory.getAbsolutePath();
        } else {
            AppContext.targetPath = textField2.getPromptText();
        }
        textField2.setText(AppContext.targetPath);
    }

    public void onInstallAction() {
        Task copyWorker = createWorker();
        progressBar.progressProperty().unbind();
        progressBar.progressProperty().bind(copyWorker.progressProperty());
        installButton.disableProperty().setValue(Boolean.TRUE);
        changeDirButton.disableProperty().setValue(Boolean.TRUE);
        createShortcut.disableProperty().setValue(Boolean.TRUE);

        copyWorker.messageProperty().addListener((observable, oldValue, newValue) ->
                System.out.println(newValue)
        );
        copyWorker.stateProperty().addListener((observable, oldValue, newValue) -> {
            if (Worker.State.SUCCEEDED.equals(newValue)){
                AppContext.finish = true;
                AppContext.buttonNextProperty.setValue(Boolean.TRUE);
                AppContext.buttonPrevProperty.setValue(Boolean.FALSE);
                mainController.step3();
            }
        });

        new Thread(copyWorker).start();
    }


    private Task createWorker() {
        return new Task() {
            @Override
            protected Object call() throws Exception {
                updateProgress(1,10);
                InstallerService.createFolder(AppContext.targetPath);
                updateProgress(2,10);
                InstallerService.createSettings();
                updateProgress(3,10);
                InstallerService.copyResource("sudo.cmd");
                updateProgress(4,10);
                InstallerService.copyResource("JavaFxGitSample_5.0.0.jar");
                updateProgress(5,10);
                InstallerService.copyResource("application.ico");
                updateProgress(6,10);
                InstallerService.copyResource("config.bat");
                updateProgress(7,10);
                InstallerService.executeBatch();

                updateProgress(10,10);
                return true;
            }
        };
    }

}

Plik: src\main\java\pl\estrix\javafx\Step3Controller.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package pl.estrix.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class Step3Controller {

    @Autowired
    private MainController mainController;

    @FXML
    private CheckBox launchApp;

    @FXML
    public void initialize() {
        AppContext.buttonPrevProperty.setValue(Boolean.FALSE);
        AppContext.buttonNextProperty.setValue(Boolean.FALSE);
    }

    public void onExitAppAction() {
        if (launchApp.isSelected()) {
            InstallerService.launchApp();
        }

        mainController.onCloseAction();
    }

}

Plik: src\main\resources\main.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="420.0" prefWidth="580.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.MainController">
   <children>
      <VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
            <HBox alignment="CENTER" style="-fx-background-color: #ffffff;">
               <children>
                  <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="380.0" prefWidth="160.0" HBox.hgrow="ALWAYS">
                     <children>
                        <ImageView fitHeight="380.0" fitWidth="160.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="0.0">
                           <image>
                              <Image url="@img/logo.png" />
                           </image>
                        </ImageView>
                        <Label fx:id="infoVersion" layoutX="35.0" layoutY="318.0" text="Label" AnchorPane.bottomAnchor="4.0" AnchorPane.leftAnchor="8.0" />
                        <Label fx:id="infoName" layoutY="327.0" text="Label" AnchorPane.bottomAnchor="24.0" AnchorPane.leftAnchor="8.0" />
                        <Label fx:id="infoBuild" layoutX="10.0" layoutY="337.0" text="Label" AnchorPane.bottomAnchor="44.0" AnchorPane.leftAnchor="8.0" />
                     </children>
                  </AnchorPane>
                  <VBox maxHeight="1.7976931348623157E308" prefWidth="217.0" style="-fx-background-color: #00cd6b;" HBox.hgrow="ALWAYS">
                     <children>
                        <Label alignment="CENTER" contentDisplay="CENTER" maxWidth="1.7976931348623157E308" text="e-Strix.com" textAlignment="CENTER" textFill="WHITE">
                           <VBox.margin>
                              <Insets bottom="10.0" top="10.0" />
                           </VBox.margin>
                        </Label>
                        <AnchorPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" style="-fx-background-color: #f0f0f0;" VBox.vgrow="ALWAYS">
                           <children>
                              <BorderPane fx:id="borderPane" layoutX="106.0" layoutY="61.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
                           </children>
                        </AnchorPane>
                     </children>
                  </VBox>
               </children>
               <cursor>
                  <Cursor fx:constant="DEFAULT" />
               </cursor>
            </HBox>
            <AnchorPane maxWidth="1.7976931348623157E308" prefHeight="200.0">
               <children>
                  <Button fx:id="prevButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#onPrevAction" prefWidth="100.0" text="Wstecz" AnchorPane.leftAnchor="178.0" AnchorPane.topAnchor="8.0" />
                  <Button fx:id="nextButton" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" onAction="#onNextAction" prefWidth="100.0" text="Dalej" textAlignment="CENTER" AnchorPane.rightAnchor="18.0" AnchorPane.topAnchor="8.0" />
               </children>
            </AnchorPane>
         </children>
      </VBox>
   </children>
</AnchorPane>

Plik: src\main\resources\step_1.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="340.0" prefWidth="420.0" style="-fx-background-color: #f0f0f0;" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.Step1Controller">
   <children>
      <TextArea layoutX="11.0" layoutY="14.0" promptText="Licencja" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="8.0" AnchorPane.topAnchor="8.0" />
      <RadioButton layoutX="14.0" layoutY="281.0" mnemonicParsing="false" selected="true" text="Nie zgadzam się" AnchorPane.bottomAnchor="30.0" AnchorPane.leftAnchor="8.0">
         <toggleGroup>
            <ToggleGroup fx:id="accept" />
         </toggleGroup>
      </RadioButton>
      <RadioButton fx:id="agreementCheckYes" layoutX="14.0" layoutY="309.0" mnemonicParsing="false" text="Zgadzam się" toggleGroup="$accept" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="8.0" />
   </children>
</AnchorPane>

Plik: src\main\resources\step_2.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="340.0" prefWidth="420.0" style="-fx-background-color: #f0f0f0;" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.Step2Controller">
   <children>
      <Label layoutX="43.0" layoutY="39.0" text="step 2" AnchorPane.leftAnchor="8.0" AnchorPane.topAnchor="24.0" />
      <TextField fx:id="textField2" disable="true" editable="false" layoutX="43.0" layoutY="70.0" prefHeight="25.0" prefWidth="284.0" promptText="C:\Program Files\JavaFxSample" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="64.0" AnchorPane.topAnchor="48.0" />
      <ProgressBar fx:id="progressBar" layoutX="8.0" layoutY="300.0" prefHeight="26.0" prefWidth="200.0" progress="0.0" AnchorPane.bottomAnchor="22.0" AnchorPane.leftAnchor="8.0" AnchorPane.rightAnchor="64.0" />
      <Separator layoutY="273.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
      <Button fx:id="installButton" layoutX="344.0" layoutY="292.0" mnemonicParsing="false" onAction="#onInstallAction" text="Instaluj" AnchorPane.rightAnchor="8.0" />
      <CheckBox fx:id="createShortcut" layoutX="40.0" layoutY="114.0" mnemonicParsing="false" text="Utwórz ikonę na pulpicie" AnchorPane.leftAnchor="8.0" AnchorPane.topAnchor="84.0" />
      <Button fx:id="changeDirButton" layoutX="345.0" layoutY="70.0" mnemonicParsing="false" onAction="#onPathChangeAction" text="Zmień" AnchorPane.rightAnchor="8.0" AnchorPane.topAnchor="48.0" />
   </children>
</AnchorPane>

Plik: src\main\resources\step_3.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="340.0" prefWidth="420.0" style="-fx-background-color: #f0f0f0;" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.Step3Controller">
    <children>
        <Label layoutX="61.0" layoutY="35.0" text="Podsumowanie" AnchorPane.leftAnchor="24.0" AnchorPane.topAnchor="24.0" />
      <Button layoutX="120.0" layoutY="155.0" mnemonicParsing="false" onAction="#onExitAppAction" prefHeight="30.0" prefWidth="180.0" text="Zakończ" />
      <CheckBox fx:id="launchApp" layoutX="44.0" layoutY="170.0" mnemonicParsing="false" text="Uruchom aplikacje" AnchorPane.leftAnchor="24.0" AnchorPane.topAnchor="64.0" />
    </children>
</AnchorPane>

Plik: src\main\resources\content\config.bat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@echo off

:configloader
call settings.bat
:configloaderends

set mypath=%cd%
set binPath=%mypath%\bin
if not exist "%binPath%" (
    mkdir  %binPath%
)

rem :::::::: CREATE Menu Start Icon
echo Set oWS = WScript.CreateObject("WScript.Shell") > %mypath%\CreateShortcut.vbs
echo sLinkFile = "%mypath%\bin\JavaFxGitSample.lnk" >> %mypath%\CreateShortcut.vbs
echo Set oLink = oWS.CreateShortcut(sLinkFile) >> %mypath%\CreateShortcut.vbs
echo oLink.TargetPath = "%mypath%\JavaFxGitSample_5.0.0.jar" >> %mypath%\CreateShortcut.vbs
echo oLink.WorkingDirectory = "%mypath%" >> %mypath%\CreateShortcut.vbs
echo oLink.Description = "JavaFxGitSample" >> %mypath%\CreateShortcut.vbs
echo oLink.IconLocation = "%mypath%\application.ico" >> %mypath%\CreateShortcut.vbs
echo oLink.Save >> CreateShortcut.vbs
cscript CreateShortcut.vbs
del CreateShortcut.vbs

if "%app_desktop_shortcut%" == "true" (
    copy %mypath%\bin\JavaFxGitSample.lnk %userprofile%\Desktop\JavaFxGitSample.lnk
)

sudo.cmd  xcopy  %mypath%\bin %ProgramData%\Microsoft\Windows""Start Menu""\Programs\e-Strix\

Plik: src\main\resources\content\sudo.cmd

1
2
3
4
@echo Set objShell = CreateObject("Shell.Application") > %temp%\sudo.tmp.vbs
@echo args = Right("%*", (Len("%*") - Len("%1"))) >> %temp%\sudo.tmp.vbs
@echo objShell.ShellExecute "%1", args, "", "runas" >> %temp%\sudo.tmp.vbs
@cscript %temp%\sudo.tmp.vbs

Plik: src\main\resources\META-INF\spring.factories

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
pl.estrix.javafx.JavaApplication

Projekt: git gradle spring-boot

http://git.e-strix.com/sample_fx_app.git/

W każdym (nawet freelancer’skim) projekcie przychodzi moment na to aby zacząć pisać kod i tu już dostajemy wiatr w żagiel i stopy wody pod kilem. W zasadzie ogranicza nas tylko lenistwo z jednej strony i kreatywność z drugiej.

Dla potrzeb prezentacji wybiorę sobie coś na czasie, a będzie to:

  • spring-boot
  • gradle
  • git
  • javafx

A zatem bez zbędnych patosów, teorii i literatury zacznijmy od stworzenia kilku plików.

Tworzenie projektu

Zacznijmy od utworzenia repozytorium. Jeśli nie widziałeś mojego wpisu na ten temat to zobacz pierw: php7-git-gitlist.

A teraz do rzeczy. Struktura projektu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
└───javafx-git-sample
    │     .gitignore
    │     build.gradle
    │     latest.properties
    │     settings.gradle
    │
    ├───gradle
    │        release.gradle
    │
    └───src
        └───main
            ├───java
            │    └───pl
            │        └───estrix
            │            └───javafx
            │                    FilterProp.java
            │                    JavaApplication.java
            │                    MainController.java
            │
            └───resources
                │     logo.png
                │     main.fxml
                │
                └───META-INF
                        spring.factories

Plik .gitignore

1
2
3
4
.gradle/
.idea/
build/
*.iml

Plik build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
buildscript {
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE")
    }
}

apply from: 'gradle/release.gradle'
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'


bootJar {
    mainClassName = 'pl.estrix.javafx.JavaApplication'
    manifest {
        attributes 'Start-Class': 'pl.estrix.javafx.JavaApplication'
    }
}

springBoot {
    mainClassName = 'pl.estrix.javafx.JavaApplication'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter")
    testCompile("junit:junit")
}


def buildTime() {
    new Date().format('yyyy.MM.dd HH:mm')
}

def generatedResources = "$buildDir/resources/main/"
sourceSets {
    main {
        output.dir(generatedResources, builtBy: 'generateMyResources')
    }
}

task generateMyResources {
    doLast {
        def generatedTmp = new File(generatedResources)
        if( !generatedTmp.exists() ) {
            generatedTmp.mkdirs()
        }
        def generated = new File(generatedResources, "filter.properties")

        generated.text = "estrix.application.biuld-time=${buildTime()}\n" +
                "estrix.application.name=${project.name}\n" +
                "estrix.application.version=${project.version}\n"
    }
}

Plik latest.properties

1
2
3
4
#Tue Apr 10 16:59:22 CEST 2018
bugfix=0
major=1
minor=0

Plik settings.gradle

1
rootProject.name = 'JavaFxGitSample'

Plik gradle/release.gradle

Notatka: Pomysł na zarządzanie wersjami pochodzi z https://www.youtube.com/watch?v=Y6SVoXFsw7I

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class Version {
    int major
    int minor
    int bugfix
    boolean snapshot = true

    static Version load(File versionFile){
        def props = new Properties()
        versionFile.withInputStream {
            stream -> props.load(stream)
        }
        def major = Integer.parseInt(props['major'])
        def minor = Integer.parseInt(props['minor'])
        def bugfix = Integer.parseInt(props['bugfix'])
        return new Version(major:major, minor:minor, bugfix:bugfix)
    }

    String toString(){
        "${major}.${minor}.${bugfix}${snapshot ? '-SNAPSHOT':''}"
    }

    void store(File versionFile){
        def props = new Properties()
        props['bugfix'] =  bugfix.toString()
        props['major']  =  major.toString()
        props['minor']  =  minor.toString()
        props.store(versionFile.newWriter(), null)
    }

    Version next(String releaseType = "bugfix"){
        if(releaseType == "major"){
            return new Version(major:major+1, minor:0, bugfix:0)
        }else if(releaseType == "minor"){
            return new Version(major:major, minor:minor+1, bugfix:0)
        }else{
            return new Version(major:major, minor:minor, bugfix:bugfix+1)
        }
    }
}

def latest = Version.load(rootProject.file("latest.properties"))
allprojects{
    version = latest.next()
}
gradle.taskGraph.whenReady { graph ->
    if(graph.hasTask(":release")){
        allprojects{
            version = latest.next(release.type)
            version.snapshot = false
        }
    }
}

task persistVersionInfo(type:Exec){
    commandLine "git" , "commit","-i", "latest.properties", "-m", "' update version to ${-> version }'"
    doFirst{
      version.store(file("latest.properties"))
   }
}

task tagWorkspace(type:Exec){  
   commandLine 'git', 'tag', "${-> version }"
   commandLine 'git', 'push', 'origin',  'HEAD:master'
}

task release(type:Release){
    type = System.getProperty("type")
    dependsOn  "build", "persistVersionInfo", "tagWorkspace"
}

import org.gradle.api.internal.tasks.options.Option

class Release extends DefaultTask{
    @Option(option="type", description="the type of a release.")
    String type = "bugfix"

    @TaskAction void release(){
        println "doing a $type release of ${project.version}"
    }
}

Plik src/main/java/pl/estrix/javafx/FilterProp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package pl.estrix.javafx;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("filter.properties")
public class FilterProp {

    @Value("${estrix.application.name}")
    private String name;
    @Value("${estrix.application.version}")
    private String version;
    @Value("${estrix.application.biuld-time}")
    private String biuldTime;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public String getBiuldTime() {
        return biuldTime;
    }

    public void setBiuldTime(String biuldTime) {
        this.biuldTime = biuldTime;
    }
}

Plik src/main/java/pl/estrix/javafx/JavaApplication.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package pl.estrix.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@SpringBootApplication
@ComponentScan("pl.estrix.javafx")
@PropertySource("classpath:filter.properties")
@Configuration
public class JavaApplication extends Application {

    private ConfigurableApplicationContext context;
    private Parent rootNode;

    public static void main(final String[] args) {
        Application.launch(args);
    }

    @Override
    public void init() throws Exception {
        SpringApplicationBuilder builder = new SpringApplicationBuilder(JavaApplication.class);
        context = builder.run(getParameters().getRaw().toArray(new String[0]));

        FXMLLoader loader = new FXMLLoader(getClass().getResource("/main.fxml"));
        loader.setControllerFactory(context::getBean);
        rootNode = loader.load();

    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setScene(new Scene(rootNode, 480, 320));
        primaryStage.centerOnScreen();
        primaryStage.show();
    }

    @Override
    public void stop() throws Exception {
        context.close();
    }

}

Plik src/main/java/pl/estrix/javafx/MainController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package pl.estrix.javafx;

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MainController {

    @Autowired
    private FilterProp filterProp;

    @FXML
    private Label propName;
    @FXML
    private Label propVersion;
    @FXML
    private Label propBuildTime;

    @FXML
    public void initialize() {
        propName.setText(filterProp.getName());
        propVersion.setText(filterProp.getVersion());
        propBuildTime.setText(filterProp.getBiuldTime());
    }
}

Plik src/main/resources/main.fxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="320.0" prefWidth="480.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="pl.estrix.javafx.MainController">
   <children>
      <HBox alignment="CENTER" style="-fx-background-color: #ffffff;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
         <children>
            <AnchorPane prefHeight="320.0" prefWidth="255.0" HBox.hgrow="ALWAYS">
               <children>
                  <ImageView fitHeight="320.0" fitWidth="255.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="0.0">
                     <image>
                        <Image url="@logo.png" />
                     </image>
                  </ImageView>
               </children>
            </AnchorPane>
            <VBox prefHeight="320.0" prefWidth="217.0" style="-fx-background-color: #ffffff;" HBox.hgrow="ALWAYS">
               <children>
                  <Label alignment="CENTER" contentDisplay="CENTER" maxWidth="1.7976931348623157E308" text="e-Strix.com" textAlignment="CENTER">
                     <VBox.margin>
                        <Insets bottom="10.0" top="10.0" />
                     </VBox.margin>
                  </Label>
                  <GridPane>
                    <columnConstraints>
                      <ColumnConstraints hgrow="SOMETIMES" maxWidth="106.0" minWidth="10.0" prefWidth="58.0" />
                      <ColumnConstraints hgrow="SOMETIMES" maxWidth="163.0" minWidth="10.0" prefWidth="163.0" />
                    </columnConstraints>
                    <rowConstraints>
                      <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                      <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                      <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                    </rowConstraints>
                     <children>
                        <Label text="Name" />
                        <Label text="Version" GridPane.rowIndex="1" />
                        <Label text="Buil Time" GridPane.rowIndex="2" />
                        <Label fx:id="propName" text="Label" GridPane.columnIndex="1" />
                        <Label fx:id="propVersion" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="1" />
                        <Label fx:id="propBuildTime" text="Label" GridPane.columnIndex="1" GridPane.rowIndex="2" />
                     </children>
                  </GridPane>
               </children>
            </VBox>
         </children>
         <cursor>
            <Cursor fx:constant="SW_RESIZE" />
         </cursor>
      </HBox>
   </children>
</AnchorPane>

Plik src/main/resources/META-INF/spring.factories

1
2
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
pl.estrix.javafx.JavaApplication

Plik src/main/resources/logo.png

1
wget http://e-strix.com/wp-content/uploads/2018/04/logo.png -P src/main/resources/

Budowa lokalna

Uruchamianie

1
gradle clean generateMyResources bootRun

Budowanie jar

1
gradle clean generateMyResources bootJar

Uruchamianie

1
java -jar build\libs\JavaFxGitSample-1.0.1-SNAPSHOT.jar

No dobra, teraz wiemy jak zbudować aplikację. Ale docelowo ma to robić Ci, zatem zabieramy się za konfigurację job’ów.

Konfiguracja Jenkins

Budowa zdalna

Jenkins new project

W polu: Repository URL

git@git.e-strix.com:repositories/javafx-git-sample.git

W polu: Repository browser

gitlist

W polu: Repository browser -> URL

git.e-strix.com

W polu: Budowanie -> Invoke Gradle -> Version

Gradle_4_6

W polu: Budowanie -> Tasks

clean generateMyResources bootJar

 

Podnoszenie wersji

Kroki takie jak w przypadku „Budowa zdalna” z tą różnicą że w:

W polu: Budowanie -> Tasks

clean release --type minor

Gdzie wartość –type przyjmuje wartości:

  • major
  • minor
  • bugfix – domyślny

Publikacja na Landing Page

W polu: Budowanie -> Execute Shell -> Command

mkdir -p release_lib

rm -f ./release_lib/*

cp ${WORKSPACE}/../javafx-git-sample-release/build/libs/*.jar ./release_lib/

rm -f /home/appuser/public_html/download/*.jar

cp ./release_lib/*.jar /home/appuser/public_html/download/

 

Zakończenie

Jak widzisz storzenie projektu jest dość proste. Mimo że musiałem kilka godzin spędzić na odnalezieniu odpowiedniej dla mojego projektu ścieżki rozwoju. Przetestowałem kilka rozwiązań, pluginów i stwierdziłem że jednak najlepsze rozwiązanie to będzie ręczne napisanie skryptu (mimo że zapożyczyłem rozwiązanie od mądrych ludzi z internetu).