├── .classpath ├── .gitignore ├── .project ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── codetreatise │ ├── Main.java │ ├── bean │ └── User.java │ ├── config │ ├── AppJavaConfig.java │ ├── SpringFXMLLoader.java │ └── StageManager.java │ ├── controller │ ├── LoginController.java │ └── UserController.java │ ├── generic │ └── GenericService.java │ ├── logging │ └── ExceptionWriter.java │ ├── repository │ └── UserRepository.java │ ├── service │ ├── UserService.java │ └── impl │ │ └── UserServiceImpl.java │ └── view │ └── FxmlView.java └── resources ├── Bundle.properties ├── application.properties ├── fxml ├── Login.fxml └── User.fxml ├── images └── edit.png └── styles └── Styles.css /.classpath: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | 3 | .settings/ -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | JavaFXSpringBootApp 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.common.project.facet.core.builder 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.springframework.ide.eclipse.core.springbuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | 30 | org.springframework.ide.eclipse.core.springnature 31 | org.eclipse.jdt.core.javanature 32 | org.eclipse.m2e.core.maven2Nature 33 | org.eclipse.wst.common.project.facet.core.nature 34 | 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaFX Spring Boot App 2 | The application frontend created using JavaFX and backend services are implemented using Spring Boot. The app demonstrate simple CRUD operation and switching between two scenes with Login and User Dashboard view. 3 | 4 | # Getting Started: 5 | 6 | 1. Clone the project in your workspace using command - git clone https://github.com/RamAlapure/JavaFXSpringBootApp.git 7 | 2. Then import as maven project into eclipse. 8 | 3. Check Java 8 configuration if there is any error. 9 | 4. Update project as maven if dependencies are not resolved. 10 | 5. Create a schema javafx in your mysql database or open configuration file application.properties from resources directory and change schema name to your schema name and also change username and password. 11 | 6. If all goes well just run Main.java 12 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.codetreatise 7 | JavaFXSpringBootApp 8 | jar 9 | 1.0 10 | 11 | JavaFXSpringBootApp 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 1.5.2.RELEASE 17 | 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-aop 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-cache 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-security 43 | 44 | 45 | 46 | mysql 47 | mysql-connector-java 48 | runtime 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-test 53 | test 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-compiler-plugin 66 | 67 | true 68 | 69 | 70 | 71 | 72 | The Application front-end designed using JavaFX and Spring Boot is used as backend to bootstrap the app. The scenes are created in FXML using Scene Builder. The app demonstrate simple CRUD using Spring Boot and JavaFX. 73 | 74 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/Main.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise; 2 | 3 | import javafx.application.Application; 4 | import javafx.stage.Stage; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.boot.builder.SpringApplicationBuilder; 7 | import org.springframework.context.ConfigurableApplicationContext; 8 | 9 | import com.codetreatise.config.StageManager; 10 | import com.codetreatise.view.FxmlView; 11 | 12 | @SpringBootApplication 13 | public class Main extends Application { 14 | 15 | protected ConfigurableApplicationContext springContext; 16 | protected StageManager stageManager; 17 | 18 | public static void main(final String[] args) { 19 | Application.launch(args); 20 | } 21 | 22 | @Override 23 | public void init() throws Exception { 24 | springContext = springBootApplicationContext(); 25 | } 26 | 27 | @Override 28 | public void start(Stage stage) throws Exception { 29 | stageManager = springContext.getBean(StageManager.class, stage); 30 | displayInitialScene(); 31 | } 32 | 33 | @Override 34 | public void stop() throws Exception { 35 | springContext.close(); 36 | } 37 | 38 | /** 39 | * Useful to override this method by sub-classes wishing to change the first 40 | * Scene to be displayed on startup. Example: Functional tests on main 41 | * window. 42 | */ 43 | protected void displayInitialScene() { 44 | stageManager.switchScene(FxmlView.LOGIN); 45 | } 46 | 47 | 48 | private ConfigurableApplicationContext springBootApplicationContext() { 49 | SpringApplicationBuilder builder = new SpringApplicationBuilder(Main.class); 50 | String[] args = getParameters().getRaw().stream().toArray(String[]::new); 51 | return builder.run(args); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/bean/User.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.bean; 2 | 3 | import java.time.LocalDate; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | import javax.persistence.Table; 11 | 12 | /** 13 | * @author Ram Alapure 14 | * @since 05-04-2017 15 | */ 16 | 17 | @Entity 18 | @Table(name="User") 19 | public class User { 20 | 21 | @Id 22 | @GeneratedValue(strategy=GenerationType.IDENTITY) 23 | @Column(name = "id", updatable = false, nullable = false) 24 | private long id; 25 | 26 | private String firstName; 27 | 28 | private String lastName; 29 | 30 | private LocalDate dob; 31 | 32 | private String gender; 33 | 34 | private String role; 35 | 36 | private String email; 37 | 38 | private String password; 39 | 40 | 41 | public long getId() { 42 | return id; 43 | } 44 | 45 | public void setId(long id) { 46 | this.id = id; 47 | } 48 | 49 | public String getFirstName() { 50 | return firstName; 51 | } 52 | 53 | public void setFirstName(String firstName) { 54 | this.firstName = firstName; 55 | } 56 | 57 | public String getLastName() { 58 | return lastName; 59 | } 60 | 61 | public void setLastName(String lastName) { 62 | this.lastName = lastName; 63 | } 64 | 65 | public LocalDate getDob() { 66 | return dob; 67 | } 68 | 69 | public void setDob(LocalDate dob) { 70 | this.dob = dob; 71 | } 72 | 73 | public String getGender() { 74 | return gender; 75 | } 76 | 77 | public void setGender(String gender) { 78 | this.gender = gender; 79 | } 80 | 81 | public String getRole() { 82 | return role; 83 | } 84 | 85 | public void setRole(String role) { 86 | this.role = role; 87 | } 88 | 89 | public String getEmail() { 90 | return email; 91 | } 92 | 93 | public void setEmail(String email) { 94 | this.email = email; 95 | } 96 | 97 | public String getPassword() { 98 | return password; 99 | } 100 | 101 | public void setPassword(String password) { 102 | this.password = password; 103 | } 104 | 105 | @Override 106 | public String toString() { 107 | return "User [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", dob=" + dob + ", email=" 108 | + email + "]"; 109 | } 110 | 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/config/AppJavaConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.codetreatise.config; 7 | 8 | import java.io.IOException; 9 | import java.io.StringWriter; 10 | import java.util.ResourceBundle; 11 | import javafx.stage.Stage; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | import org.springframework.context.annotation.Lazy; 16 | import org.springframework.context.annotation.Scope; 17 | 18 | import com.codetreatise.logging.ExceptionWriter; 19 | 20 | @Configuration 21 | public class AppJavaConfig { 22 | 23 | @Autowired 24 | SpringFXMLLoader springFXMLLoader; 25 | 26 | /** 27 | * Useful when dumping stack trace to a string for logging. 28 | * @return ExceptionWriter contains logging utility methods 29 | */ 30 | @Bean 31 | @Scope("prototype") 32 | public ExceptionWriter exceptionWriter() { 33 | return new ExceptionWriter(new StringWriter()); 34 | } 35 | 36 | @Bean 37 | public ResourceBundle resourceBundle() { 38 | return ResourceBundle.getBundle("Bundle"); 39 | } 40 | 41 | @Bean 42 | @Lazy(value = true) //Stage only created after Spring context bootstap 43 | public StageManager stageManager(Stage stage) throws IOException { 44 | return new StageManager(springFXMLLoader, stage); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/config/SpringFXMLLoader.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.config; 2 | 3 | import java.io.IOException; 4 | import java.util.ResourceBundle; 5 | import javafx.fxml.FXMLLoader; 6 | import javafx.scene.Parent; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.ApplicationContext; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Will load the FXML hierarchy as specified in the load method and register 13 | * Spring as the FXML Controller Factory. Allows Spring and Java FX to coexist 14 | * once the Spring Application context has been bootstrapped. 15 | */ 16 | @Component 17 | public class SpringFXMLLoader { 18 | private final ResourceBundle resourceBundle; 19 | private final ApplicationContext context; 20 | 21 | @Autowired 22 | public SpringFXMLLoader(ApplicationContext context, ResourceBundle resourceBundle) { 23 | this.resourceBundle = resourceBundle; 24 | this.context = context; 25 | } 26 | 27 | public Parent load(String fxmlPath) throws IOException { 28 | FXMLLoader loader = new FXMLLoader(); 29 | loader.setControllerFactory(context::getBean); //Spring now FXML Controller Factory 30 | loader.setResources(resourceBundle); 31 | loader.setLocation(getClass().getResource(fxmlPath)); 32 | return loader.load(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/config/StageManager.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.config; 2 | 3 | import static org.slf4j.LoggerFactory.getLogger; 4 | 5 | import java.util.Objects; 6 | 7 | import org.slf4j.Logger; 8 | 9 | import com.codetreatise.view.FxmlView; 10 | 11 | import javafx.application.Platform; 12 | import javafx.scene.Parent; 13 | import javafx.scene.Scene; 14 | import javafx.stage.Stage; 15 | 16 | /** 17 | * Manages switching Scenes on the Primary Stage 18 | */ 19 | public class StageManager { 20 | 21 | private static final Logger LOG = getLogger(StageManager.class); 22 | private final Stage primaryStage; 23 | private final SpringFXMLLoader springFXMLLoader; 24 | 25 | public StageManager(SpringFXMLLoader springFXMLLoader, Stage stage) { 26 | this.springFXMLLoader = springFXMLLoader; 27 | this.primaryStage = stage; 28 | } 29 | 30 | public void switchScene(final FxmlView view) { 31 | Parent viewRootNodeHierarchy = loadViewNodeHierarchy(view.getFxmlFile()); 32 | show(viewRootNodeHierarchy, view.getTitle()); 33 | } 34 | 35 | private void show(final Parent rootnode, String title) { 36 | Scene scene = prepareScene(rootnode); 37 | //scene.getStylesheets().add("/styles/Styles.css"); 38 | 39 | //primaryStage.initStyle(StageStyle.TRANSPARENT); 40 | primaryStage.setTitle(title); 41 | primaryStage.setScene(scene); 42 | primaryStage.sizeToScene(); 43 | primaryStage.centerOnScreen(); 44 | 45 | try { 46 | primaryStage.show(); 47 | } catch (Exception exception) { 48 | logAndExit ("Unable to show scene for title" + title, exception); 49 | } 50 | } 51 | 52 | private Scene prepareScene(Parent rootnode){ 53 | Scene scene = primaryStage.getScene(); 54 | 55 | if (scene == null) { 56 | scene = new Scene(rootnode); 57 | } 58 | scene.setRoot(rootnode); 59 | return scene; 60 | } 61 | 62 | /** 63 | * Loads the object hierarchy from a FXML document and returns to root node 64 | * of that hierarchy. 65 | * 66 | * @return Parent root node of the FXML document hierarchy 67 | */ 68 | private Parent loadViewNodeHierarchy(String fxmlFilePath) { 69 | Parent rootNode = null; 70 | try { 71 | rootNode = springFXMLLoader.load(fxmlFilePath); 72 | Objects.requireNonNull(rootNode, "A Root FXML node must not be null"); 73 | } catch (Exception exception) { 74 | logAndExit("Unable to load FXML view" + fxmlFilePath, exception); 75 | } 76 | return rootNode; 77 | } 78 | 79 | 80 | private void logAndExit(String errorMsg, Exception exception) { 81 | LOG.error(errorMsg, exception, exception.getCause()); 82 | Platform.exit(); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/controller/LoginController.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.controller; 2 | 3 | 4 | import java.io.IOException; 5 | import java.net.URL; 6 | import java.util.ResourceBundle; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Lazy; 10 | import org.springframework.stereotype.Controller; 11 | 12 | import com.codetreatise.config.StageManager; 13 | import com.codetreatise.service.UserService; 14 | import com.codetreatise.view.FxmlView; 15 | 16 | import javafx.event.ActionEvent; 17 | import javafx.fxml.FXML; 18 | import javafx.fxml.Initializable; 19 | import javafx.scene.control.Button; 20 | import javafx.scene.control.Label; 21 | import javafx.scene.control.PasswordField; 22 | import javafx.scene.control.TextField; 23 | 24 | /** 25 | * @author Ram Alapure 26 | * @since 05-04-2017 27 | */ 28 | 29 | @Controller 30 | public class LoginController implements Initializable{ 31 | 32 | @FXML 33 | private Button btnLogin; 34 | 35 | @FXML 36 | private PasswordField password; 37 | 38 | @FXML 39 | private TextField username; 40 | 41 | @FXML 42 | private Label lblLogin; 43 | 44 | @Autowired 45 | private UserService userService; 46 | 47 | @Lazy 48 | @Autowired 49 | private StageManager stageManager; 50 | 51 | @FXML 52 | private void login(ActionEvent event) throws IOException{ 53 | if(userService.authenticate(getUsername(), getPassword())){ 54 | 55 | stageManager.switchScene(FxmlView.USER); 56 | 57 | }else{ 58 | lblLogin.setText("Login Failed."); 59 | } 60 | } 61 | 62 | public String getPassword() { 63 | return password.getText(); 64 | } 65 | 66 | public String getUsername() { 67 | return username.getText(); 68 | } 69 | 70 | @Override 71 | public void initialize(URL location, ResourceBundle resources) { 72 | 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.controller; 2 | 3 | import java.io.IOException; 4 | import java.net.URL; 5 | import java.time.LocalDate; 6 | import java.util.List; 7 | import java.util.Optional; 8 | import java.util.ResourceBundle; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.context.annotation.Lazy; 14 | import org.springframework.stereotype.Controller; 15 | 16 | import com.codetreatise.bean.User; 17 | import com.codetreatise.config.StageManager; 18 | import com.codetreatise.service.UserService; 19 | import com.codetreatise.view.FxmlView; 20 | 21 | import javafx.application.Platform; 22 | import javafx.collections.FXCollections; 23 | import javafx.collections.ObservableList; 24 | import javafx.event.ActionEvent; 25 | import javafx.fxml.FXML; 26 | import javafx.fxml.Initializable; 27 | import javafx.geometry.Pos; 28 | import javafx.scene.control.Alert; 29 | import javafx.scene.control.Alert.AlertType; 30 | import javafx.scene.control.Button; 31 | import javafx.scene.control.ButtonType; 32 | import javafx.scene.control.ComboBox; 33 | import javafx.scene.control.DatePicker; 34 | import javafx.scene.control.Label; 35 | import javafx.scene.control.MenuItem; 36 | import javafx.scene.control.PasswordField; 37 | import javafx.scene.control.RadioButton; 38 | import javafx.scene.control.SelectionMode; 39 | import javafx.scene.control.TableCell; 40 | import javafx.scene.control.TableColumn; 41 | import javafx.scene.control.TableView; 42 | import javafx.scene.control.TextField; 43 | import javafx.scene.control.ToggleGroup; 44 | import javafx.scene.control.cell.PropertyValueFactory; 45 | import javafx.scene.image.Image; 46 | import javafx.scene.image.ImageView; 47 | import javafx.util.Callback; 48 | /** 49 | * @author Ram Alapure 50 | * @since 05-04-2017 51 | */ 52 | 53 | @Controller 54 | public class UserController implements Initializable{ 55 | 56 | @FXML 57 | private Button btnLogout; 58 | 59 | @FXML 60 | private Label userId; 61 | 62 | @FXML 63 | private TextField firstName; 64 | 65 | @FXML 66 | private TextField lastName; 67 | 68 | @FXML 69 | private DatePicker dob; 70 | 71 | @FXML 72 | private RadioButton rbMale; 73 | 74 | @FXML 75 | private ToggleGroup gender; 76 | 77 | @FXML 78 | private RadioButton rbFemale; 79 | 80 | @FXML 81 | private ComboBox cbRole; 82 | 83 | @FXML 84 | private TextField email; 85 | 86 | @FXML 87 | private PasswordField password; 88 | 89 | @FXML 90 | private Button reset; 91 | 92 | @FXML 93 | private Button saveUser; 94 | 95 | @FXML 96 | private TableView userTable; 97 | 98 | @FXML 99 | private TableColumn colUserId; 100 | 101 | @FXML 102 | private TableColumn colFirstName; 103 | 104 | @FXML 105 | private TableColumn colLastName; 106 | 107 | @FXML 108 | private TableColumn colDOB; 109 | 110 | @FXML 111 | private TableColumn colGender; 112 | 113 | @FXML 114 | private TableColumn colRole; 115 | 116 | @FXML 117 | private TableColumn colEmail; 118 | 119 | @FXML 120 | private TableColumn colEdit; 121 | 122 | @FXML 123 | private MenuItem deleteUsers; 124 | 125 | @Lazy 126 | @Autowired 127 | private StageManager stageManager; 128 | 129 | @Autowired 130 | private UserService userService; 131 | 132 | private ObservableList userList = FXCollections.observableArrayList(); 133 | private ObservableList roles = FXCollections.observableArrayList("Admin", "User"); 134 | 135 | @FXML 136 | private void exit(ActionEvent event) { 137 | Platform.exit(); 138 | } 139 | 140 | /** 141 | * Logout and go to the login page 142 | */ 143 | @FXML 144 | private void logout(ActionEvent event) throws IOException { 145 | stageManager.switchScene(FxmlView.LOGIN); 146 | } 147 | 148 | @FXML 149 | void reset(ActionEvent event) { 150 | clearFields(); 151 | } 152 | 153 | @FXML 154 | private void saveUser(ActionEvent event){ 155 | 156 | if(validate("First Name", getFirstName(), "[a-zA-Z]+") && 157 | validate("Last Name", getLastName(), "[a-zA-Z]+") && 158 | emptyValidation("DOB", dob.getEditor().getText().isEmpty()) && 159 | emptyValidation("Role", getRole() == null) ){ 160 | 161 | if(userId.getText() == null || userId.getText() == ""){ 162 | if(validate("Email", getEmail(), "[a-zA-Z0-9][a-zA-Z0-9._]*@[a-zA-Z0-9]+([.][a-zA-Z]+)+") && 163 | emptyValidation("Password", getPassword().isEmpty())){ 164 | 165 | User user = new User(); 166 | user.setFirstName(getFirstName()); 167 | user.setLastName(getLastName()); 168 | user.setDob(getDob()); 169 | user.setGender(getGender()); 170 | user.setRole(getRole()); 171 | user.setEmail(getEmail()); 172 | user.setPassword(getPassword()); 173 | 174 | User newUser = userService.save(user); 175 | 176 | saveAlert(newUser); 177 | } 178 | 179 | }else{ 180 | User user = userService.find(Long.parseLong(userId.getText())); 181 | user.setFirstName(getFirstName()); 182 | user.setLastName(getLastName()); 183 | user.setDob(getDob()); 184 | user.setGender(getGender()); 185 | user.setRole(getRole()); 186 | User updatedUser = userService.update(user); 187 | updateAlert(updatedUser); 188 | } 189 | 190 | clearFields(); 191 | loadUserDetails(); 192 | } 193 | 194 | 195 | } 196 | 197 | @FXML 198 | private void deleteUsers(ActionEvent event){ 199 | List users = userTable.getSelectionModel().getSelectedItems(); 200 | 201 | Alert alert = new Alert(AlertType.CONFIRMATION); 202 | alert.setTitle("Confirmation Dialog"); 203 | alert.setHeaderText(null); 204 | alert.setContentText("Are you sure you want to delete selected?"); 205 | Optional action = alert.showAndWait(); 206 | 207 | if(action.get() == ButtonType.OK) userService.deleteInBatch(users); 208 | 209 | loadUserDetails(); 210 | } 211 | 212 | private void clearFields() { 213 | userId.setText(null); 214 | firstName.clear(); 215 | lastName.clear(); 216 | dob.getEditor().clear(); 217 | rbMale.setSelected(true); 218 | rbFemale.setSelected(false); 219 | cbRole.getSelectionModel().clearSelection(); 220 | email.clear(); 221 | password.clear(); 222 | } 223 | 224 | private void saveAlert(User user){ 225 | 226 | Alert alert = new Alert(AlertType.INFORMATION); 227 | alert.setTitle("User saved successfully."); 228 | alert.setHeaderText(null); 229 | alert.setContentText("The user "+user.getFirstName()+" "+user.getLastName() +" has been created and \n"+getGenderTitle(user.getGender())+" id is "+ user.getId() +"."); 230 | alert.showAndWait(); 231 | } 232 | 233 | private void updateAlert(User user){ 234 | 235 | Alert alert = new Alert(AlertType.INFORMATION); 236 | alert.setTitle("User updated successfully."); 237 | alert.setHeaderText(null); 238 | alert.setContentText("The user "+user.getFirstName()+" "+user.getLastName() +" has been updated."); 239 | alert.showAndWait(); 240 | } 241 | 242 | private String getGenderTitle(String gender){ 243 | return (gender.equals("Male")) ? "his" : "her"; 244 | } 245 | 246 | public String getFirstName() { 247 | return firstName.getText(); 248 | } 249 | 250 | public String getLastName() { 251 | return lastName.getText(); 252 | } 253 | 254 | public LocalDate getDob() { 255 | return dob.getValue(); 256 | } 257 | 258 | public String getGender(){ 259 | return rbMale.isSelected() ? "Male" : "Female"; 260 | } 261 | 262 | public String getRole() { 263 | return cbRole.getSelectionModel().getSelectedItem(); 264 | } 265 | 266 | public String getEmail() { 267 | return email.getText(); 268 | } 269 | 270 | public String getPassword() { 271 | return password.getText(); 272 | } 273 | 274 | 275 | @Override 276 | public void initialize(URL location, ResourceBundle resources) { 277 | 278 | cbRole.setItems(roles); 279 | 280 | userTable.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 281 | 282 | setColumnProperties(); 283 | 284 | // Add all users into table 285 | loadUserDetails(); 286 | } 287 | 288 | 289 | 290 | /* 291 | * Set All userTable column properties 292 | */ 293 | private void setColumnProperties(){ 294 | /* Override date format in table 295 | * colDOB.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter() { 296 | String pattern = "dd/MM/yyyy"; 297 | DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(pattern); 298 | @Override 299 | public String toString(LocalDate date) { 300 | if (date != null) { 301 | return dateFormatter.format(date); 302 | } else { 303 | return ""; 304 | } 305 | } 306 | 307 | @Override 308 | public LocalDate fromString(String string) { 309 | if (string != null && !string.isEmpty()) { 310 | return LocalDate.parse(string, dateFormatter); 311 | } else { 312 | return null; 313 | } 314 | } 315 | }));*/ 316 | 317 | colUserId.setCellValueFactory(new PropertyValueFactory<>("id")); 318 | colFirstName.setCellValueFactory(new PropertyValueFactory<>("firstName")); 319 | colLastName.setCellValueFactory(new PropertyValueFactory<>("lastName")); 320 | colDOB.setCellValueFactory(new PropertyValueFactory<>("dob")); 321 | colGender.setCellValueFactory(new PropertyValueFactory<>("gender")); 322 | colRole.setCellValueFactory(new PropertyValueFactory<>("role")); 323 | colEmail.setCellValueFactory(new PropertyValueFactory<>("email")); 324 | colEdit.setCellFactory(cellFactory); 325 | } 326 | 327 | Callback, TableCell> cellFactory = 328 | new Callback, TableCell>() 329 | { 330 | @Override 331 | public TableCell call( final TableColumn param) 332 | { 333 | final TableCell cell = new TableCell() 334 | { 335 | Image imgEdit = new Image(getClass().getResourceAsStream("/images/edit.png")); 336 | final Button btnEdit = new Button(); 337 | 338 | @Override 339 | public void updateItem(Boolean check, boolean empty) 340 | { 341 | super.updateItem(check, empty); 342 | if(empty) 343 | { 344 | setGraphic(null); 345 | setText(null); 346 | } 347 | else{ 348 | btnEdit.setOnAction(e ->{ 349 | User user = getTableView().getItems().get(getIndex()); 350 | updateUser(user); 351 | }); 352 | 353 | btnEdit.setStyle("-fx-background-color: transparent;"); 354 | ImageView iv = new ImageView(); 355 | iv.setImage(imgEdit); 356 | iv.setPreserveRatio(true); 357 | iv.setSmooth(true); 358 | iv.setCache(true); 359 | btnEdit.setGraphic(iv); 360 | 361 | setGraphic(btnEdit); 362 | setAlignment(Pos.CENTER); 363 | setText(null); 364 | } 365 | } 366 | 367 | private void updateUser(User user) { 368 | userId.setText(Long.toString(user.getId())); 369 | firstName.setText(user.getFirstName()); 370 | lastName.setText(user.getLastName()); 371 | dob.setValue(user.getDob()); 372 | if(user.getGender().equals("Male")) rbMale.setSelected(true); 373 | else rbFemale.setSelected(true); 374 | cbRole.getSelectionModel().select(user.getRole()); 375 | } 376 | }; 377 | return cell; 378 | } 379 | }; 380 | 381 | 382 | 383 | /* 384 | * Add All users to observable list and update table 385 | */ 386 | private void loadUserDetails(){ 387 | userList.clear(); 388 | userList.addAll(userService.findAll()); 389 | 390 | userTable.setItems(userList); 391 | } 392 | 393 | /* 394 | * Validations 395 | */ 396 | private boolean validate(String field, String value, String pattern){ 397 | if(!value.isEmpty()){ 398 | Pattern p = Pattern.compile(pattern); 399 | Matcher m = p.matcher(value); 400 | if(m.find() && m.group().equals(value)){ 401 | return true; 402 | }else{ 403 | validationAlert(field, false); 404 | return false; 405 | } 406 | }else{ 407 | validationAlert(field, true); 408 | return false; 409 | } 410 | } 411 | 412 | private boolean emptyValidation(String field, boolean empty){ 413 | if(!empty){ 414 | return true; 415 | }else{ 416 | validationAlert(field, true); 417 | return false; 418 | } 419 | } 420 | 421 | private void validationAlert(String field, boolean empty){ 422 | Alert alert = new Alert(AlertType.WARNING); 423 | alert.setTitle("Validation Error"); 424 | alert.setHeaderText(null); 425 | if(field.equals("Role")) alert.setContentText("Please Select "+ field); 426 | else{ 427 | if(empty) alert.setContentText("Please Enter "+ field); 428 | else alert.setContentText("Please Enter Valid "+ field); 429 | } 430 | alert.showAndWait(); 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/generic/GenericService.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.generic; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Ram Alapure 7 | * @since 05-04-2017 8 | */ 9 | 10 | public interface GenericService { 11 | 12 | T save(T entity); 13 | 14 | T update(T entity); 15 | 16 | void delete(T entity); 17 | 18 | void delete(Long id); 19 | 20 | void deleteInBatch(List entities); 21 | 22 | T find(Long id); 23 | 24 | List findAll(); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/logging/ExceptionWriter.java: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * To change this license header, choose License Headers in Project Properties. 4 | * To change this template file, choose Tools | Templates 5 | * and open the template in the editor. 6 | */ 7 | package com.codetreatise.logging; 8 | 9 | import java.io.PrintWriter; 10 | import java.io.Writer; 11 | 12 | /** 13 | * Handles writing exceptions to the Logger Tab and and utility methods needed 14 | * to facilitate logging of exceptions 15 | */ 16 | public class ExceptionWriter extends PrintWriter { 17 | public ExceptionWriter(Writer writer) { 18 | super(writer); 19 | } 20 | 21 | private String wrapAroundWithNewlines(String stringWithoutNewlines) { 22 | return ("\n" + stringWithoutNewlines + "\n"); 23 | } 24 | 25 | /* 26 | * Convert a stacktrace into a string 27 | */ 28 | public String getExceptionAsString(Throwable throwable) { 29 | throwable.printStackTrace(this); 30 | 31 | String exception = super.out.toString(); 32 | 33 | return (wrapAroundWithNewlines(exception)); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | import com.codetreatise.bean.User; 7 | 8 | @Repository 9 | public interface UserRepository extends JpaRepository { 10 | 11 | User findByEmail(String email); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.service; 2 | 3 | import com.codetreatise.bean.User; 4 | import com.codetreatise.generic.GenericService; 5 | 6 | public interface UserService extends GenericService { 7 | 8 | boolean authenticate(String email, String password); 9 | 10 | User findByEmail(String email); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/service/impl/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.service.impl; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import com.codetreatise.bean.User; 9 | import com.codetreatise.repository.UserRepository; 10 | import com.codetreatise.service.UserService; 11 | 12 | @Service 13 | public class UserServiceImpl implements UserService { 14 | 15 | @Autowired 16 | private UserRepository userRepository; 17 | 18 | @Override 19 | public User save(User entity) { 20 | return userRepository.save(entity); 21 | } 22 | 23 | @Override 24 | public User update(User entity) { 25 | return userRepository.save(entity); 26 | } 27 | 28 | @Override 29 | public void delete(User entity) { 30 | userRepository.delete(entity); 31 | } 32 | 33 | @Override 34 | public void delete(Long id) { 35 | userRepository.delete(id); 36 | } 37 | 38 | @Override 39 | public User find(Long id) { 40 | return userRepository.findOne(id); 41 | } 42 | 43 | @Override 44 | public List findAll() { 45 | return userRepository.findAll(); 46 | } 47 | 48 | @Override 49 | public boolean authenticate(String username, String password){ 50 | User user = this.findByEmail(username); 51 | if(user == null){ 52 | return false; 53 | }else{ 54 | if(password.equals(user.getPassword())) return true; 55 | else return false; 56 | } 57 | } 58 | 59 | @Override 60 | public User findByEmail(String email) { 61 | return userRepository.findByEmail(email); 62 | } 63 | 64 | @Override 65 | public void deleteInBatch(List users) { 66 | userRepository.deleteInBatch(users); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/codetreatise/view/FxmlView.java: -------------------------------------------------------------------------------- 1 | package com.codetreatise.view; 2 | 3 | import java.util.ResourceBundle; 4 | 5 | public enum FxmlView { 6 | 7 | USER { 8 | @Override 9 | public String getTitle() { 10 | return getStringFromResourceBundle("user.title"); 11 | } 12 | 13 | @Override 14 | public String getFxmlFile() { 15 | return "/fxml/User.fxml"; 16 | } 17 | }, 18 | LOGIN { 19 | @Override 20 | public String getTitle() { 21 | return getStringFromResourceBundle("login.title"); 22 | } 23 | 24 | @Override 25 | public String getFxmlFile() { 26 | return "/fxml/Login.fxml"; 27 | } 28 | }; 29 | 30 | public abstract String getTitle(); 31 | public abstract String getFxmlFile(); 32 | 33 | String getStringFromResourceBundle(String key){ 34 | return ResourceBundle.getBundle("Bundle").getString(key); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/resources/Bundle.properties: -------------------------------------------------------------------------------- 1 | login.title=Login 2 | user.title=User Dashboard 3 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | specs.dir=/specs/ 2 | 3 | ################### Spring Boot Data Source Configuration ############ 4 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 5 | spring.datasource.url=jdbc:mysql://localhost:3306/javafx?useSSL=false 6 | spring.datasource.username=root 7 | spring.datasource.password=root@123 8 | spring.datasource.initialize=true 9 | spring.jpa.hibernate.ddl-auto=update 10 | spring.jpa.show-sql=true -------------------------------------------------------------------------------- /src/main/resources/fxml/Login.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 21 | 22 | 23 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/fxml/User.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 | 57 | 58 | 59 | 64 | 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 | 125 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |
151 | 152 | 153 | 154 | 155 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 |
196 |
197 | -------------------------------------------------------------------------------- /src/main/resources/images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RamAlapure/JavaFXSpringBootApp/7f5594aa7e7edd5f38de3323249a9b8aabe2496e/src/main/resources/images/edit.png -------------------------------------------------------------------------------- /src/main/resources/styles/Styles.css: -------------------------------------------------------------------------------- 1 | /* CSS for app */ 2 | 3 | .btnGreen{ 4 | -fx-background-color: #3cbc53; 5 | } 6 | 7 | .background{ 8 | -fx-background-color: DODGERBLUE; 9 | } 10 | 11 | --------------------------------------------------------------------------------