저는 멋진 Java SDK를 사용해 Couchbase와 웹 애플리케이션을 꽤 오랫동안 다뤄왔지만, Couchbase를 사용해 데이터를 저장하는 데스크톱 애플리케이션도 만들 수 있다는 사실을 알고 계셨나요? JavaFX와 같은 Java 데스크톱 프레임워크는 Couchbase Java SDK를 사용할 수 있지만, 클라이언트 대면 애플리케이션에서 서버용 SDK를 사용하는 것은 좋은 생각이 아닐 수도 있습니다. 대신 Couchbase의 모바일 솔루션을 사용하여 클라이언트를 대상으로 하는 데스크톱 애플리케이션을 구축할 수 있습니다. 이 솔루션은 Android와 동일한 API를 사용하지만 데스크톱을 염두에 두고 설계되었습니다.
이 데이터를 컴퓨터 간에 동기화하기 위해 JavaFX, Couchbase Lite, 심지어 Couchbase Sync Gateway를 사용하여 간단한 데스크톱 애플리케이션을 구축하는 방법을 살펴 보겠습니다.
요구 사항
이 프로젝트를 성공적으로 수행하려면 몇 가지 요구 사항을 충족해야 합니다.
- JDK 1.7+
- Maven
- 카우치베이스 동기화 게이트웨이
이 프로젝트에서는 Maven을 사용하여 종속성을 수집하고 JAR 파일을 빌드합니다. 동기화 게이트웨이가 반드시 필요한 것은 아니지만 애플리케이션에 동기화 지원을 추가하려는 경우에는 필요합니다.
Maven으로 새로운 JavaFX 프로젝트 만들기
기본적인 Maven 프로젝트를 만들어야 합니다. 이 작업은 원하는 IDE에서 수행하거나 수동으로 수행할 수 있습니다. 기본적으로 필요한 것은 다음과 같은 파일 및 디렉토리 구조입니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
src 메인 자바 com 카우치베이스 카우치베이스싱글턴.자바 메인.자바 Todo.자바 TodoFXController.자바 리소스 TodoFX.fxml pom.xml |
개발을 시작하면 각 파일에 포함된 내용에 대해 자세히 알아보겠습니다. 지금은 Maven을 설정해야 합니다. pom.xml 파일에 필요한 종속성을 가져올 수 있도록 합니다.
프로젝트의 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 |
com.카우치베이스 카우치베이스-javafx-예제 4.0.0 카우치베이스 JavaFX 예 jar 1.0 com.카우치베이스.lite 카우치베이스-lite-자바 1.3.0 com.카우치베이스.lite 카우치베이스-lite-자바-sqlcipher 1.3.0 junit junit 4.12 테스트 com.zenjava javafx-maven-플러그인 8.5.0 com.카우치베이스.메인 org.아파치.maven.플러그인 maven-컴파일러-플러그인 3.3 1.7 1.7 maven-어셈블리-플러그인 2.2.1 jar-와 함께-종속성 true lib/ com.카우치베이스.메인 make-어셈블리 패키지 단일 |
위의 Maven 파일에서 불필요한 세부 사항을 너무 많이 다루지 않고, 특히 몇 가지 사항에 주목하고자 합니다.
|
1 2 3 4 5 6 7 |
com.카우치베이스.lite 카우치베이스-lite-자바 1.3.0 |
위의 종속성에서 Couchbase Lite를 프로젝트에 포함하고 있음을 알 수 있습니다. Couchbase Lite는 서버 어딘가에 있지 않은 로컬 데이터베이스라는 점을 기억하세요. 데이터는 로컬에 저장되며 컴포넌트는 애플리케이션 내에 번들로 제공됩니다.
다음 플러그인도 주목할 필요가 있습니다:
|
1 2 3 4 5 6 7 8 9 10 |
com.zenjava javafx-maven-플러그인 8.5.0 com.카우치베이스.메인 |
위의 플러그인은 JavaFX 프로젝트를 생성하기 위한 것입니다. 물론 이 프로젝트 생성은 IntelliJ와 같은 IDE를 사용하면 필수는 아니지만 훨씬 더 쉽습니다.
카우치베이스 싱글톤 클래스 생성하기
JavaFX 프로젝트의 UI와 컨트롤러를 만드는 데 투자하기 전에 데이터를 어떻게 처리할지 고민해 보겠습니다.
간소화를 위해 프로젝트 전체에서 데이터를 관리하기 위한 싱글톤 클래스를 만드는 것이 좋습니다. 또한 애플리케이션의 모든 곳에서 쿼리를 작성할 필요가 없도록 데이터 리스너를 설정할 때 매우 효과적입니다. 이제 프로젝트의 src/main/java/com/couchbase/CouchbaseSingleton.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 |
패키지 com.카우치베이스; 가져오기 com.카우치베이스.lite.*; 가져오기 com.카우치베이스.lite.리플리케이터.복제; 가져오기 자바.net.URL; 가져오기 자바.활용.ArrayList; 가져오기 자바.활용.해시맵; 가져오기 자바.활용.이터레이터; 가져오기 자바.활용.지도; public 클래스 카우치베이스싱글턴 { 비공개 관리자 관리자; 비공개 데이터베이스 데이터베이스; 비공개 복제 pushReplication; 비공개 복제 pullReplication; 비공개 정적 카우치베이스싱글턴 인스턴스 = null; 비공개 카우치베이스싱글턴() { 시도 { 이.관리자 = new 관리자(new 자바 컨텍스트("데이터"), 관리자.기본_옵션); 이.데이터베이스 = 이.관리자.getDatabase("fx-project"); 보기 todoView = 데이터베이스.getView("todos"); todoView.setMap(new 매퍼() { @오버라이드 public void 지도(지도<문자열, 개체> 문서, 이미터 emitter) { emitter.emit(문서.get("_id"), 문서); } }, "1"); } catch (예외 e) { e.프린트스택트레이스(); } } public 정적 카우치베이스싱글턴 getInstance() { 만약(인스턴스 == null) { 인스턴스 = new 카우치베이스싱글턴(); } 반환 인스턴스; } public 데이터베이스 getDatabase() { 반환 이.데이터베이스; } public void 시작 복제(URL 게이트웨이, 부울 연속) { 이.pushReplication = 이.데이터베이스.createPushReplication(게이트웨이); 이.pullReplication = 이.데이터베이스.createPullReplication(게이트웨이); 이.pushReplication.setContinuous(연속); 이.pullReplication.setContinuous(연속); 이.pushReplication.시작(); 이.pullReplication.시작(); } public void 중지복제() { 이.pushReplication.중지(); 이.pullReplication.중지(); } public Todo 저장(Todo 할 일) { 지도<문자열, 개체> 속성 = new 해시맵<문자열, 개체>(); 문서 문서 = 이.데이터베이스.createDocument(); 속성.put("type", "할 일"); 속성.put("title", 할 일.getTitle()); 속성.put("설명", 할 일.getDescription()); 시도 { 할 일.setDocumentId(문서.putProperties(속성).getDocument().getId()); } catch (예외 e) { e.프린트스택트레이스(); } 반환 할 일; } public ArrayList 쿼리() { ArrayList 결과 = new ArrayList(); 시도 { 보기 todoView = 이.데이터베이스.getView("todos"); 쿼리 쿼리 = todoView.createQuery(); 쿼리 열거자 결과 = 쿼리.실행(); 문서 문서 = null; 에 대한 (이터레이터 it = 결과; it.hasNext(); ) { QueryRow 행 = it.다음(); 문서 = 행.getDocument(); 결과.추가(new Todo(문서.getId(), (문자열) 문서.getProperty("title"), (문자열) 문서.getProperty("설명"))); } } catch (예외 e) { e.프린트스택트레이스(); } 반환 결과; } } |
위의 내용은 이해하기 어려운 내용이지만 혼란을 피하기 위해 꼭 필요한 내용입니다.
내부 카우치베이스싱글턴 클래스에는 4개의 개인 변수가 있습니다. 데이터베이스 관리자를 사용하면 데이터베이스를 열 수 있을 뿐만 아니라 생성할 수도 있습니다. 복제 객체는 어느 방향으로든 동기화를 담당합니다.
에서 생성자 메서드를 사용하여 다음과 같은 데이터베이스를 생성하고 엽니다. fx-project 를 클릭하고 데이터 쿼리 시 사용할 뷰를 구성합니다. 이 뷰는 토도스 는 로컬 데이터베이스에 저장된 모든 문서에 대해 문서 ID와 문서의 키-값 쌍을 생성합니다. 로컬 데이터베이스에 저장된 모든 문서의 생성자 메서드는 정적 메서드를 통해 인스턴스화하기 때문에 비공개입니다. getInstance.
이 가이드의 후반부까지 동기화에 대해 살펴보지는 않겠지만, 기초를 다지는 것은 좋은 생각입니다. 기본적으로 특정 동기화 게이트웨이 URL에 대한 지속적인 복제를 정의하고 싶을 뿐입니다. 또한 애플리케이션이 종료될 때 복제를 중지할 수 있기를 원합니다. 이제 데이터를 저장하고 로드하는 방법을 살펴봅시다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public Todo 저장(Todo 할 일) { 지도<문자열, 개체> 속성 = new 해시맵<문자열, 개체>(); 문서 문서 = 이.데이터베이스.createDocument(); 속성.put("type", "할 일"); 속성.put("title", 할 일.getTitle()); 속성.put("설명", 할 일.getDescription()); 시도 { 할 일.setDocumentId(문서.putProperties(속성).getDocument().getId()); } catch (예외 e) { e.프린트스택트레이스(); } 반환 할 일; } |
우리의 저장 메서드는 Todo 객체를 생성하고 데이터베이스에 저장합니다. 그 결과는 Todo 호출 메서드에 반환되는 문서 ID가 포함된 객체입니다. 이 Todo 클래스는 간단합니다. 아이디, 제목, 설명과 같은 기본 정보를 받아들이고 그에 맞는 적절한 겟터와 세터 메서드가 있습니다. 참고로 다음과 같은 모양이며 프로젝트의 src/main/java/com/couchbase/Todo.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 |
패키지 com.카우치베이스; 가져오기 자바.활용.*; public 클래스 Todo { 비공개 문자열 documentId; 비공개 문자열 title; 비공개 문자열 설명; Todo(문자열 documentId, 문자열 title, 문자열 설명) { 이.documentId = documentId; 이.title = title; 이.설명 = 설명; } Todo(문자열 title, 문자열 설명) { 이.documentId = UUID.randomUUID().toString(); 이.title = title; 이.설명 = 설명; } public void setDocumentId(문자열 documentId) { 이.documentId = documentId; } public 문자열 getDocumentId() { 반환 이.documentId; } public 문자열 getTitle() { 반환 이.title; } public 문자열 getDescription() { 반환 이.설명; } } |
이제 마지막 데이터 관련 함수인 쿼리 함수입니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public ArrayList 쿼리() { ArrayList 결과 = new ArrayList(); 시도 { 보기 todoView = 이.데이터베이스.getView("todos"); 쿼리 쿼리 = todoView.createQuery(); 쿼리 열거자 결과 = 쿼리.실행(); 문서 문서 = null; 에 대한 (이터레이터 it = 결과; it.hasNext(); ) { QueryRow 행 = it.다음(); 문서 = 행.getDocument(); 결과.추가(new Todo(문서.getId(), (문자열) 문서.getProperty("title"), (문자열) 문서.getProperty("설명"))); } } catch (예외 e) { e.프린트스택트레이스(); } 반환 결과; } |
우리가 만든 뷰를 기억하시나요? 이번에는 이를 쿼리해 보겠습니다. 결과 집합은 다음과 같은 배열로 로드됩니다. Todo 객체입니다. 이렇게 하면 데이터 계층 를 마무리하고 실제 애플리케이션 개발에 집중할 수 있게 되었습니다.
데스크톱 애플리케이션 디자인
필수는 아니지만 JavaFX 애플리케이션, 씬 빌더를 사용하면 그래픽 UI와 해당 컨트롤러 클래스를 매우 간단하게 만들 수 있습니다. 이 기능을 사용하지 않으려면 프로젝트의 src/main/resources/TodoFX.fxml 를 열고 다음 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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 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 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
<!--?xml 버전="1.0" 인코딩="UTF-8"?--> <!--?가져오기 javafx.장면.제어.*?--> <!--?가져오기 자바.lang.*?--> <!--?가져오기 javafx.장면.레이아웃.*?--> <텍스트 영역> <버튼 fx:id="fxSave" layoutX="530.0" 레이아웃Y="365.0" 니모닉 파싱="false" prefHeight="25.0" prefWidth="60.0" 텍스트="저장" /> </어린이> </창> </코드> </pre> <p>그리고 위 마크업 will give 우리 a UI 그 외모 같은 의 다음:</p> <p><img src="/wp-content/original-assets/2016/september/using-couchbase-in-a-javafx-desktop-application/todo-javafx-example.png" /></p> <p>아무것도 too fancy in 의 위, 올바른?</p> <p>우리 가지고 a simple UI 와 함께 a 목록, 두 입력 필드, 그리고 a 저장 버튼, as 설명 in 의 XML 마크업. In 의 마크업 우리 또한 참조 <코드>com.카우치베이스.TodoFXController</코드>. 이 는 의 논리 그 will be 바운드 에 의 특히 FX 보기. 열기 의 프로젝트의 src/main/java/com/couchbase/TodoFXController.java를 열고 다음을 포함하세요: ; 패키지 com.couchbase; com.couchbase.lite.*를 가져옵니다; com.couchbase.lite.Database.ChangeListener를 가져옵니다; javafx.application.Platform을 가져옵니다; javafx.collections.ObservableList를 가져옵니다; javafx.event.ActionEvent를 가져옵니다; javafx.event.EventHandler를 가져옵니다; javafx.fxml.FXML을 가져옵니다; javafx.fxml.Initializable을 가져옵니다; javafx.scene.control.*를 가져옵니다; javafx.util.Callback을 가져옵니다; java.net.URL을 가져옵니다; java.util.*를 가져옵니다; public 클래스 TodoFXController 구현 초기화 가능 { 개인 카우치베이스싱글턴 카우치베이스; @FXML private TextField fxTitle; @FXML private TextArea fxDescription; @FXML private ListView fxListView; @FXML 비공개 버튼 fxSave; 오버라이드 public void initialize(URL fxmlFileLocation, ResourceBundle resources) { 시도 { this.couchbase = CouchbaseSingleton.getInstance(); fxListView.getItems().addAll(this.couchbase.query()); this.couchbase.getDatabase().addChangeListener(new ChangeListener() { 오버라이드 public void changed(Database.ChangeEvent event) { for(int i = 0; i < event.getChanges().size(); i++) { final Document retrievedDocument = couchbase.getDatabase().getDocument(event.getChanges().get(i).getDocumentId()); Platform.runLater(new Runnable() { 오버라이드 public void run() { int documentIndex = indexOfByDocumentId(retrievedDocument.getId(), fxListView.getItems()); for(int j = 0; j -1) { fxListView.getItems().remove(documentIndex); } } else { if (documentIndex == -1) { fxListView.getItems().add(new Todo(retrievedDocument.getId(), (String) retrievedDocument.getProperty("title"), (String) retrievedDocument.getProperty("description"))); } else { fxListView.getItems().remove(documentIndex); fxListView.getItems().add(new Todo(retrievedDocument.getId(), (String) retrievedDocument.getProperty("title"), (String) retrievedDocument.getProperty("description"))); } } } }); } } }); } catch (Exception e) { e.printStackTrace(); } fxListView.setCellFactory(new Callback<ListView, ListCell>(){ 오버라이드 public ListCell call(ListView p) { ListCell cell = new ListCell(){ 오버라이드 protected void updateItem(Todo t, boolean bln) { super.updateItem(t, bln); if (t != null) { setText(t.getTitle()); } } }; 셀을 반환합니다; } }); fxSave.setOnAction(new EventHandler() { @Override public void handle(ActionEvent e) { if(!fxTitle.getText().equals("") && !fxDescription.getText().equals("")) { fxListView.getItems().add(couchbase.save(new Todo(fxTitle.getText(), fxDescription.getText()))); fxTitle.setText(""); fxDescription.setText(""); } else { 알림 알림 = 새 알림(알림.알림 유형.정보); alert.setTitle("누락된 정보"); alert.setHeaderText(null); alert.setContentText("이 예제에는 제목과 설명이 모두 필요합니다."); alert.showAndWait(); } } }); } private int indexOfByDocumentId(String needle, ObservableList haystack) { int result = -1; for(int i = 0; i < haystack.size(); i++) { if(haystack.get(i).getDocumentId().equals(needle)) { 결과 = i; break; } } 결과를 반환합니다; } } 위 코드에 관해서는 고려해야 할 사항이 많으므로 ' re 가는 에 break it down.</p><pre> <코드> @FXML 비공개 텍스트 필드 fxTitle; @FXML 비공개 텍스트 영역 fxDescription; @FXML 비공개 ListView fxListView; @FXML 비공개 버튼 fxSave; </코드> </pre> <p>기억하세요 의 FXML 파일? 각 의 의 위 변수 는 매핑 에 의 구성 요소 의 그 파일. 그러나, 무엇 우리 정말 케어 약 는 의 사용 의 의 <코드>초기화 가능</코드> 인터페이스 그 우리를 구현하고 있습니다. 이를 위해서는 initialize 함수가 필요합니다.ll 설정 우리의 컴포넌트 그리고 데이터베이스 청취자.</p><pre> <코드> fxListView.setCellFactory(new 콜백<ListView<Todo>, ListCell<Todo>>(){ @오버라이드 public ListCell<Todo> 통화(ListView<Todo> p) { ListCell<Todo> 셀 = new ListCell<Todo>(){ @오버라이드 보호됨 void 업데이트 항목(Todo t, 부울 bln) { super.업데이트 항목(t, bln); 만약 (t != null) { setText(t.getTitle()); } } }; 반환 셀; } }); </코드> </pre> <p>왜냐하면 우리목록에 사용자 정의 Todo 클래스를 사용하려면 목록 행에 데이터를 표시하는 방법을 구성해야 합니다. 기본적으로 문자열이지만 실제로는 데이터 요소의 제목을 추출하여 대신 표시하고 싶습니다.; this.couchbase = CouchbaseSingleton.getInstance(); fxListView.getItems().addAll(this.couchbase.query()); 위에서는 열린 데이터베이스 인스턴스를 가져와서 쿼리를 수행하고 화면에 표시되는 FX 목록에 모든 데이터를 추가하고 있습니다. 이는 애플리케이션이 로드될 때 한 번만 수행되는 작업입니다. 이후의 모든 데이터 로드는 데이터 리스너를 통해 이루어집니다. 데이터베이스 변경 리스너는 애플리케이션이 열려 있는 동안 데이터의 모든 변경 사항을 수신합니다. 변경 사항은 대량으로 발생할 수 있으므로 변경 사항을 반복하여 문서를 검색합니다. 문서가 새 문서인 경우 목록에 추가합니다. 문서에 삭제 표시가 있는 경우 목록에서 제거합니다. 문서가 기존 문서의 변경 사항인 경우, 이전 문서를 제거하고 새 문서를 목록에 추가합니다. 이 모든 작업은 Couchbase 변경 리스너가 백그라운드 스레드에서 발생하기 때문에 마지막으로 자체 클릭 이벤트가 있는 저장 버튼이 있습니다. 버튼을 클릭하고 입력 요소가 채워지면 데이터를 데이터베이스에 저장합니다. 현재 Couchbase Lite에 데이터를 저장하는 오프라인 데스크톱 애플리케이션이 있습니다. 이제 데이터 동기화/복제에 대해 걱정할 필요가 없습니다. 데스크톱과 서버 간에 데이터 동기화하기다음 단계는 Couchbase Mobile 덕분에 쉽습니다. 데스크톱 애플리케이션 코드를 수정하기 전에 Couchbase 동기화 게이트웨이를 설치 및 실행해야 합니다. 동기화 게이트웨이를 설치한 상태에서 다음 기본 구성 파일을 만듭니다. ; { "log":["CRUD+", "REST+", "Changes+", "Attach+"], "데이터베이스": { "fx-example": { "서버":"월러스:", "sync":` 함수 (문서) { 채널(doc.channels); } `, "users": { "GUEST": { "disabled": false, "admin_channels": ["*"] } } } } } 위 구성 파일은 가장 기본적인 구성 파일입니다. 인메모리 데이터베이스를 사용하여 읽기/쓰기 규칙이 없는 <p>바운싱 뒤로 에 의 JavaFX 애플리케이션. 열기 의 프로젝트의 src/main/java/com/couchbase/Main.java 파일에 다음을 포함합니다: ; this.couchbase = CouchbaseSingleton.getInstance(); this.couchbase.startReplication(new URL("http://localhost:4984/fx-example/"), true); 위 내용은 결론방금 Couchbase Lite에 데이터를 저장하고 데이터를 동기화하는 간단한 JavaFX 애플리케이션을 만드는 방법을 살펴보았습니다. Maven과 명령줄을 사용하여 이 애플리케이션을 실행하려면 다음을 실행하세요. ; MVN JFX:실행 카우치베이스는 매우 유연하기 때문에 애플리케이션 코드를 거의 변경하지 않고도 동일한 애플리케이션을 모바일로 확장할 수 있습니다. 만약 ' d 같은 에 다운로드 의 전체 프로젝트 in 이 가이드, it can be 발견 on GitHub <a href="https://github.com/couchbaselabs/couchbase-lite-javafx-example">여기</a>.</p></텍스트 영역> |