├── .gitignore ├── screen.png ├── README.md ├── src ├── main │ ├── resources │ │ ├── application.properties │ │ └── fxml │ │ │ └── main.fxml │ └── java │ │ └── ru │ │ └── habrahabr │ │ ├── service │ │ ├── ContactService.java │ │ └── ContactServiceImpl.java │ │ ├── repository │ │ └── ContactRepository.java │ │ ├── AbstractJavaFxApplicationSupport.java │ │ ├── Application.java │ │ ├── entity │ │ ├── Contact.java │ │ └── ContactWithProperties.java │ │ ├── ControllersConfiguration.java │ │ └── ui │ │ └── MainController.java └── test │ └── java │ └── ru │ └── habrahabr │ └── ApplicationTests.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml -------------------------------------------------------------------------------- /screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruslanys/sample-spring-boot-javafx/HEAD/screen.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Как подружить Spring Boot и JavaFX 2 | http://habrahabr.ru/post/265511/ 3 | 4 | ### Сборка 5 | ``` 6 | mvn clean package 7 | ``` 8 | 9 | ### Запуск 10 | ``` 11 | java -jar target/springboot-javafx-*.jar 12 | ``` 13 | 14 | ![Скриншот](screen.png "Скриншот") 15 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Параметры UI 2 | ui.title = Spring Boot - JavaFX 3 | 4 | # JMX нам не нужен, а его отключение позволит ускорить запуск 5 | spring.jmx.enabled=false 6 | 7 | # Настройка БД 8 | spring.datasource.test-on-borrow=true 9 | spring.datasource.validation-query=SELECT 1 10 | spring.jpa.show-sql=true 11 | spring.jpa.hibernate.ddl-auto=create -------------------------------------------------------------------------------- /src/main/java/ru/habrahabr/service/ContactService.java: -------------------------------------------------------------------------------- 1 | package ru.habrahabr.service; 2 | 3 | import ru.habrahabr.entity.Contact; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Date: 27.08.15 9 | * Time: 17:22 10 | * 11 | * @author Ruslan Molchanov (ruslanys@gmail.com) 12 | * @author http://mruslan.com 13 | */ 14 | public interface ContactService { 15 | 16 | Contact save(Contact contact); 17 | 18 | List findAll(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/ru/habrahabr/repository/ContactRepository.java: -------------------------------------------------------------------------------- 1 | package ru.habrahabr.repository; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | import org.springframework.transaction.annotation.Propagation; 5 | import org.springframework.transaction.annotation.Transactional; 6 | import ru.habrahabr.entity.Contact; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Date: 27.08.15 12 | * Time: 17:21 13 | * 14 | * @author Ruslan Molchanov (ruslanys@gmail.com) 15 | * @author http://mruslan.com 16 | */ 17 | @Transactional(propagation = Propagation.MANDATORY) 18 | public interface ContactRepository extends CrudRepository { 19 | 20 | List findAll(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/test/java/ru/habrahabr/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package ru.habrahabr; 2 | 3 | import javafx.embed.swing.JFXPanel; 4 | import org.junit.BeforeClass; 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.boot.test.SpringApplicationConfiguration; 8 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 9 | 10 | @RunWith(SpringJUnit4ClassRunner.class) 11 | @SpringApplicationConfiguration(classes = Application.class) 12 | public class ApplicationTests { 13 | 14 | @BeforeClass 15 | public static void bootstrapJavaFx(){ 16 | // implicitly initializes JavaFX Subsystem 17 | // see http://stackoverflow.com/questions/14025718/javafx-toolkit-not-initialized-when-trying-to-play-an-mp3-file-through-mediap 18 | new JFXPanel(); 19 | } 20 | 21 | @Test 22 | public void contextLoads() { 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ru/habrahabr/AbstractJavaFxApplicationSupport.java: -------------------------------------------------------------------------------- 1 | package ru.habrahabr; 2 | 3 | import javafx.application.Application; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.context.ConfigurableApplicationContext; 6 | 7 | public abstract class AbstractJavaFxApplicationSupport extends Application { 8 | 9 | private static String[] savedArgs; 10 | 11 | protected ConfigurableApplicationContext context; 12 | 13 | @Override 14 | public void init() throws Exception { 15 | context = SpringApplication.run(getClass(), savedArgs); 16 | context.getAutowireCapableBeanFactory().autowireBean(this); 17 | } 18 | 19 | @Override 20 | public void stop() throws Exception { 21 | super.stop(); 22 | context.close(); 23 | } 24 | 25 | protected static void launchApp(Class appClass, String[] args) { 26 | AbstractJavaFxApplicationSupport.savedArgs = args; 27 | Application.launch(appClass, args); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/ru/habrahabr/Application.java: -------------------------------------------------------------------------------- 1 | package ru.habrahabr; 2 | 3 | import javafx.scene.Scene; 4 | import javafx.stage.Stage; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Qualifier; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | 10 | @SpringBootApplication 11 | public class Application extends AbstractJavaFxApplicationSupport { 12 | 13 | @Value("${ui.title:JavaFX приложение}")// 14 | private String windowTitle; 15 | 16 | @Qualifier("mainView") 17 | @Autowired 18 | private ControllersConfiguration.ViewHolder view; 19 | 20 | @Override 21 | public void start(Stage stage) throws Exception { 22 | stage.setTitle(windowTitle); 23 | stage.setScene(new Scene(view.getView())); 24 | stage.setResizable(true); 25 | stage.centerOnScreen(); 26 | stage.show(); 27 | } 28 | 29 | public static void main(String[] args) { 30 | launchApp(Application.class, args); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ru/habrahabr/service/ContactServiceImpl.java: -------------------------------------------------------------------------------- 1 | package ru.habrahabr.service; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | import ru.habrahabr.entity.Contact; 6 | import ru.habrahabr.repository.ContactRepository; 7 | 8 | import javax.annotation.PostConstruct; 9 | import javax.transaction.Transactional; 10 | import java.util.List; 11 | 12 | /** 13 | * Date: 27.08.15 14 | * Time: 17:23 15 | * 16 | * @author Ruslan Molchanov (ruslanys@gmail.com) 17 | * @author http://mruslan.com 18 | */ 19 | @Service 20 | @Transactional 21 | public class ContactServiceImpl implements ContactService { 22 | 23 | private final ContactRepository repository; 24 | 25 | @Autowired 26 | public ContactServiceImpl(ContactRepository repository) { 27 | this.repository = repository; 28 | } 29 | 30 | /** 31 | * Метод добавляет парочку записей в БД после запуска приложения, 32 | * чтобы не было совсем пусто. 33 | * 34 | * Из-за того, что подключена H2 (in-memory) БД. 35 | */ 36 | @PostConstruct 37 | public void generateTestData() { 38 | save(new Contact("Иван Иванов", "+123456789", "ivan@ivan.ov")); 39 | save(new Contact("Петр Петров", "+987654321", "petr@pe.tr")); 40 | } 41 | 42 | @Override 43 | public Contact save(Contact contact) { 44 | return repository.save(contact); 45 | } 46 | 47 | @Override 48 | public List findAll() { 49 | return repository.findAll(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/ru/habrahabr/entity/Contact.java: -------------------------------------------------------------------------------- 1 | package ru.habrahabr.entity; 2 | 3 | import javax.persistence.*; 4 | import java.io.Serializable; 5 | 6 | /** 7 | * Date: 27.08.15 8 | * Time: 12:58 9 | * 10 | * @author Ruslan Molchanov (ruslanys@gmail.com) 11 | * @author http://mruslan.com 12 | */ 13 | @Entity 14 | @Table 15 | public class Contact implements Serializable { 16 | 17 | @Id 18 | @GeneratedValue 19 | private Long id; 20 | 21 | @Column(nullable = false) 22 | private String name; 23 | 24 | @Column(nullable = false, unique = true) 25 | private String phone; 26 | 27 | @Column(nullable = false, unique = true) 28 | private String email; 29 | 30 | public Contact() { 31 | } 32 | 33 | public Contact(String name, String phone, String email) { 34 | this.name = name; 35 | this.phone = phone; 36 | this.email = email; 37 | } 38 | 39 | public Long getId() { 40 | return id; 41 | } 42 | 43 | public void setId(Long id) { 44 | this.id = id; 45 | } 46 | 47 | public String getName() { 48 | return name; 49 | } 50 | 51 | public void setName(String name) { 52 | this.name = name; 53 | } 54 | 55 | public String getPhone() { 56 | return phone; 57 | } 58 | 59 | public void setPhone(String phone) { 60 | this.phone = phone; 61 | } 62 | 63 | public String getEmail() { 64 | return email; 65 | } 66 | 67 | public void setEmail(String email) { 68 | this.email = email; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/resources/fxml/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 |