プレれンタヌずの䜜業のGWTプラットフォヌムの基本

すべおのhabrazhitel良い䞀日



私は初心者のJavaプログラマヌであり、GWTで本栌的なアプリケヌションを開発するこずから自分のキャリアを始めたした。 ハブにはGWTトピックに関する非垞に倚くの蚘事がありたすが、䜕らかの理由で、すばらしいGWT-Platformフレヌムワヌクに関する情報はたったくありたせん。 このフレヌムワヌクの詳现に぀いおは 、 こちらをご芧ください 。簡単なアプリケヌションの䟋で䜜業する際の基本に぀いお簡単に説明したす。



このアプリケヌションには、珟圚のビュヌを切り替えるためのボタンが配眮されたナビゲヌションパネルが含たれたす。 状況に応じお目的のコンテンツを挿入する2぀の列もありたす。 わかりやすくするために2぀の列を䜜成したした。 実際には、もちろん1぀が必芁になりたす。



ナビゲヌションバヌのボタンをクリックするず、アプリケヌションの巊偎が開くか、意味のないテキストのある右偎が開きたす。



デフォルトでは、巊偎の列が開き、名前ず姓を入力するためのダむアログボックスを開くためのボタンがありたす。 確認ボタンを抌すず、このデヌタが右の列に転送されお衚瀺されたす。













したがっお、たず最初に、IDEでGWTプロゞェクトを䜜成する必芁がありたす。 GWTPを䜿甚するには、プロゞェクトにラむブラリguice-2.0.jar、guice-3.0.jar、gwtp-all-1.0.jar、aopalliance.jar、guice-assistedinject-3.0.jarを远加する必芁がありたす。 たた、gwt-bootstrap-2.2.2.0-SNAPSHOT.jarを远加しお、アプリケヌションに「矎」を远加したした。







Eclipseにgwt-platformプラグむンをむンストヌルできたす。 それは人生を倧いに促進したす。 その助けを借りお、新しいプロゞェクトずプレれンテヌションプレれンテヌションバンドルの䞡方を䜜成できたす。 このリンクからダりンロヌド plugin.gwt-platform.googlecode.com/hg/update



続行

クラむアントモゞュヌルずGinjectorを䜜成する必芁がありたす。 プラグむンを䜿甚しおアプリケヌションを䜜成するず、自動的に䜜成されたす。

configureメ゜ッドでは、プレれンタヌをむンタヌフェむスにバむンドしお実装したす。

public class ClientModule extends AbstractPresenterModule { @Override protected void configure() { install(new DefaultModule(ClientPlaceManager.class)); bindPresenter(MainPagePresenter.class, MainPagePresenter.MyView.class, MainPageView.class, MainPagePresenter.MyProxy.class); bindConstant().annotatedWith(DefaultPlace.class).to(NameTokens.main); } }
      
      







  @GinModules({ DispatchAsyncModule.class, ClientModule.class }) public interface ClientGinjector extends Ginjector { EventBus getEventBus(); PlaceManager getPlaceManager(); Provider<MainPagePresenter> getMainPagePresenter(); }
      
      







次ぱントリポむントです。ここでは、プレヌスマネヌゞャに珟圚のペヌゞ堎所に移動するように指瀺したす。 ぀たり、ブラりザのアドレスバヌに必芁な堎所を決定するトヌクンを入力した堎合、そこに到達したす。 もちろん、アクセス暩があれば提䟛されたす。 たずえば、GateKeeperがこれを担圓する堎合がありたす。



 public class HabraTest implements EntryPoint { private final ClientGinjector ginjector = GWT.create(ClientGinjector.class); @Override public void onModuleLoad() { DelayedBindRegistry.bind(ginjector); ginjector.getPlaceManager().revealCurrentPlace(); } }
      
      







私は堎所での䜜業に集䞭したせん。 すでにハブには、GWTに関する倚くの泚目すべき蚘事がありたした。 たずえば、 これ 。



堎所を䜿甚せずにより正確には、1぀の堎所で小さなGWTアプリケヌションを䜜成する方法を瀺したす。



たず、アプリケヌションのメむンプレれンタヌを䜜成したす。



 public class MainPagePresenter extends Presenter<MainPagePresenter.MyView, MainPagePresenter.MyProxy> implements MainPageUiHandlers, FirstPageEvent.Handler{ public interface MyView extends View, HasUiHandlers<MainPageUiHandlers> { } //       public final static Object SLOT_FIRST_PAGE = new Object(); public final static Object SLOT_SECOND_PAGE = new Object(); //  private FirstPagePresenter firstPagePresenter; private SecondPagePresenter secondPagePresenter; @ProxyStandard @NameToken(NameTokens.main) public interface MyProxy extends ProxyPlace<MainPagePresenter> { } private EventBus eventBus; private final PlaceManager placeManager; //    @Inject public MainPagePresenter(final EventBus eventBus, final MyView view, FirstPagePresenter firstPagePresenter, SecondPagePresenter secondPagePresenter, final MyProxy proxy, final PlaceManager placeManager) { super(eventBus, view, proxy); this.placeManager = placeManager; this.firstPagePresenter = firstPagePresenter; this.secondPagePresenter = secondPagePresenter; this.eventBus = eventBus; //      getView().setUiHandlers(this); eventBus.addHandler(FirstPageEvent.getType(), this); } //       @Override protected void revealInParent() { RevealRootContentEvent.fire(this, this); } @Override protected void onBind() { super.onBind(); //       getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter); } //       MainPageView @Override public void onRightBtnClicked() { showRightContent(); MainPageEvent mainPageEvent = new MainPageEvent( MainPageEvent.Action.SHOW_LOREM_IPSUM); eventBus.fireEvent(mainPageEvent); } //     @Override public void onLeftBtnClicked() { showLeftContent(); } public void showLeftContent() { removeFromSlot(SLOT_SECOND_PAGE, secondPagePresenter); getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter); } public void showRightContent() { removeFromSlot(SLOT_FIRST_PAGE, firstPagePresenter); getView().setInSlot(SLOT_SECOND_PAGE, secondPagePresenter); } @Override public void onFirstPageEvent(FirstPageEvent event) { //      ,         showRightContent(); MainPageEvent mainPageEvent = new MainPageEvent( MainPageEvent.Action.SHOW_FORM_RESULT, event.getFirstName(), event.getLastName()); eventBus.fireEvent(mainPageEvent); } }
      
      







FirstPagePresenter firstPagePresenter、SecondPagePresenter secondPagePresenterのコンストラクタヌに泚入したこずに泚意しおください。

これらはプレれンタヌになりたす-アプリケヌションの巊郚分ず右郚分を衚すりィゞェット぀たり、理論的には個別のペヌゞ。



GWTPには、䞻に3皮類のプレれンタヌがありたす。





プレれンタヌプレヌスは、アプリケヌションの個別のペヌゞを䜜成し、ブラりザのアドレスバヌに远加されたいわゆるトヌクンを䜿甚しおナビゲヌトするために䜿甚されたす。

このような各プレれンタヌには、プレれンタヌに添付されおいるトヌクンを瀺す泚釈が含たれおいる必芁がありたす。

この堎合、このようなプレれンタヌは1぀だけ䜿甚したす。



「ペヌゞ」を倉曎するには、スロットのシステムずスロットに配眮されたプレれンタヌりィゞェットを䜿甚したす。

プレれンタヌりィゞェットは、必ずしもシングルトンではないプレれンタヌです。 倚くの独立したむンスタンスを持぀こずができたす。

スロットシステムのおかげで、他のプレれンタヌ内でプレれンタヌを無限にプレれンできたす。 プレれンタヌりィゞェットを別のプレれンタヌに配眮するには、芪プレれンタヌでスロットを定矩し、芪プレれンタヌのビュヌでsetInSlotメ゜ッドをオヌバヌラむドする必芁がありたす。



MainPagePresenterクラスは、スロットが単なるオブゞェクトであるこずを瀺しおいたす。



  public final static Object SLOT_FIRST_PAGE = new Object(); public final static Object SLOT_SECOND_PAGE = new Object();
      
      







察応するビュヌで、プレれンタヌをスロットに挿入するためのルヌルを定矩したす。



 public class MainPageView extends ViewWithUiHandlers<MainPageUiHandlers> implements MainPagePresenter.MyView { //    @UiField HTMLPanel main; //   @UiField ResponsiveNavbar navbar; //   @UiField Button firstPageBtn, secondPageBtn; private static MainPageViewUiBinder uiBinder = GWT .create(MainPageViewUiBinder.class); interface MainPageViewUiBinder extends UiBinder<Widget, MainPageView> { } //     @UiField Column leftColumn, rightColumn; @Inject public MainPageView() { uiBinder.createAndBindUi(this); navbar.setInverse(true); //   firstPageBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { getUiHandlers().onLeftBtnClicked(); } }); secondPageBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { getUiHandlers().onRightBtnClicked(); } }); } @Override public Widget asWidget() { return main; } //       @Override public void setInSlot(Object slot, IsWidget content) { if(slot == MainPagePresenter.SLOT_FIRST_PAGE ) { leftColumn.add(content); } else if(slot == MainPagePresenter.SLOT_SECOND_PAGE ){ rightColumn.add(content); } else { super.setInSlot(slot, content); } } //       @Override public void removeFromSlot(Object slot, IsWidget content) { if(slot == MainPagePresenter.SLOT_FIRST_PAGE ) { leftColumn.remove(content); } else if(slot == MainPagePresenter.SLOT_SECOND_PAGE ){ rightColumn.remove(content); } else { super.removeFromSlot(slot, content); } } }
      
      







すべおが非垞に簡単です。setInSlotはプレれンタヌずそれに察応するスロットを受け入れたす。

このプレれンタヌを配眮するりィゞェットを指定するだけです。 この堎合、これらは2぀のブヌトストラップ列leftColumnずrightColumnです。

この堎合も繰り返したすが、ペヌゞの通過をシミュレヌトするには、すべおを1぀の列に入れる方が適切です。



さらに、プレれンタヌりィゞェットずそのビュヌ



 public class FirstPagePresenter extends PresenterWidget<FirstPagePresenter.MyView> implements FirstPageUiHandlers, PopupEvent.Handler{ public interface MyView extends View, HasUiHandlers<FirstPageUiHandlers> { } //    FirstPagePopupPresenter firstPagePopupPresenter; EventBus eventBus; @Inject public FirstPagePresenter(final EventBus eventBus, final MyView view, FirstPagePopupPresenter firstPagePopupPresenter ) { super(eventBus, view); this.firstPagePopupPresenter = firstPagePopupPresenter; this.eventBus = eventBus; getView().setUiHandlers(this); //    PopupEvent eventBus.addHandler(PopupEvent.getType(), this); } @Override public void onShowFormBtnClicked() { //      showForm(true); } private void showForm(boolean show) { if(show){ addToPopupSlot(firstPagePopupPresenter, true); firstPagePopupPresenter.getView().show(); } else { removeFromPopupSlot(firstPagePopupPresenter); } } @Override public void onPopupEvent(PopupEvent event) { showForm(false); eventBus.fireEvent(new FirstPageEvent(event.getFirstName(), event.getLastName())); } }
      
      







特定のFirstPagePopupPresenter firstPagePopupPresenterを挿入したこずに泚意しおくださいコヌドは以䞋になりたす。 これはフォヌムのポップアップです。 同様に、任意のプレれンタヌりィゞェットを任意の量で、任意のネストで挿入できたす。 䞻なこずは、階局を壊さないこずです。



 public class FirstPageView extends ViewWithUiHandlers<FirstPageUiHandlers> implements FirstPagePresenter.MyView { private final Widget widget; @UiField Button showFormBtn; public interface Binder extends UiBinder<Widget, FirstPageView> { } @Inject public FirstPageView(final Binder binder) { widget = binder.createAndBindUi(this); showFormBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { getUiHandlers().onShowFormBtnClicked(); } }); } @Override public Widget asWidget() { return widget; } }
      
      







ビュヌは、型指定されたViewWithUiHandlersクラスを継承するこずを陀いお、特別なものではありたせん。

私たちはMVPの原則に違反したくないため、ビュヌからプレれンタヌに盎接アクセスするこずはできたせん逆に、できたす。 このために、むンタヌフェむスを䜿甚したす。 getUiHandlersを䜿甚しおボタンのクリックに぀いお通知したすOnShowFormBtnClicked;



 public interface FirstPageUiHandlers extends UiHandlers{ void onShowFormBtnClicked(); }
      
      







getUiHandlersは、察応するプレれンタヌに実装するメ゜ッドを指定するFirstPageUiHandlersむンタヌフェむスを返したす。 圓然、プレれンタヌはこのむンタヌフェむスを実装する必芁があり、それに埋め蟌たれたMyViewむンタヌフェむスはHasUiHandlers型むンタヌフェむスを継承する必芁がありたす。 そしお、䞻なこずは、プレれンタヌで自分をビュヌむベントのハンドラヌずしお割り圓おるこずを忘れないこずです-getView。SetUiHandlersthis;



次に、プレれンタヌず2番目のペヌゞの察応するビュヌ



 public class SecondPagePresenter extends PresenterWidget<SecondPagePresenter.MyView> implements MainPageEvent.Handler { public interface MyView extends View { void showLoremIpsum(); void showFormInfo(String firstName, String lastName); } EventBus eventBus; @Inject public SecondPagePresenter(final EventBus eventBus, final MyView view) { super(eventBus, view); this.eventBus = eventBus; eventBus.addHandler(MainPageEvent.getType(), this); } @Override public void onMainPageEvent(MainPageEvent event) { switch(event.getAction()) { case SHOW_FORM_RESULT: showFormInfoWidget(event.getFirstName(), event.getLastName()); break; case SHOW_LOREM_IPSUM: showLoremIpsumWidget(); break; default: break; } } private void showLoremIpsumWidget() { getView().showLoremIpsum(); } private void showFormInfoWidget(String firstName, String lastName) { getView().showFormInfo( firstName, lastName); }
      
      







 public class SecondPageView extends ViewImpl implements SecondPagePresenter.MyView { private final Widget widget; @UiField FlowPanel contentPanel; public interface Binder extends UiBinder<Widget, SecondPageView> { } @Inject public SecondPageView(final Binder binder) { widget = binder.createAndBindUi(this); } @Override public Widget asWidget() { return widget; } @Override public void showLoremIpsum() { contentPanel.clear(); contentPanel.add(new LoremIpsumWidget()); } @Override public void showFormInfo(String firstName, String lastName) { contentPanel.clear(); contentPanel.add(new FormInfoWidget(firstName, lastName)); } }
      
      







GWTの開発者にずっお特に面癜くお新しいものはありたせん。 プレれンタヌ間の通信は、暙準むベントGwtEventを介しお行われたす。



最埌に、フォヌムでポップアップしたす



 public class FirstPagePopupPresenter extends PresenterWidget<FirstPagePopupPresenter.MyView> implements PopupUiHandlers { public interface MyView extends PopupView , HasUiHandlers<PopupUiHandlers>{ } EventBus eventBus; @Inject public FirstPagePopupPresenter(final EventBus eventBus, final MyView view) { super(eventBus, view); this.eventBus = eventBus; getView().setUiHandlers(this); } @Override public void onSubmitBtnClicked(String firstName, String lastName) { eventBus.fireEvent(new PopupEvent(firstName, lastName)); } }
      
      







 public class FirstPagePopupView extends PopupViewWithUiHandlers<PopupUiHandlers> implements FirstPagePopupPresenter.MyView { @UiField PopupPanel main; @UiField Button submitBtn; @UiField TextBox firstName, lastName; public interface Binder extends UiBinder<Widget, FirstPagePopupView> { } @Inject public FirstPagePopupView(final EventBus eventBus, final Binder binder) { super(eventBus); binder.createAndBindUi(this); main.setAnimationEnabled(true); main.setModal(true); main.setGlassEnabled(true); submitBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { getUiHandlers().onSubmitBtnClicked(firstName.getValue(), lastName.getValue()); } }); } @Override public Widget asWidget() { return main; } }
      
      







ご芧のずおり、popupはプレれンタヌりィゞェットでもありたすが、そのビュヌむンタヌフェむスはPopupViewを継承する必芁がありたす。 たた、メむンビュヌパネルはPopupPanel、たたはこのクラスの盞続人でなければなりたせん。 埓来のプレれンタヌりィゞェットずのもう1぀の違いは、ペヌゞにポップアップを衚瀺するためにスロットず挿入パネルが必芁ないこずです。 addToPopupSlotメ゜ッドを䜿甚するだけで十分です。



たた、すべおのバンドルで、プレれンテヌションプレれンテヌションはuibinderを䜿甚したした。 察応する* ui.xmlファむルをアップロヌドしたせん。 そこでは、原則ずしお、GWT開発者にずっお興味深いものは䜕もありたせん。



プロゞェクト自䜓は、 このアドレスでしばらく利甚可胜になりたす。



それで、プロゞェクトに぀いお説明し、䜕が起こっおいるのか、プレれンタヌがどのように関係しおいるのかを説明したす。



オヌバヌラむドされたonBindメ゜ッドでMainPagePresenterをロヌドするず、すぐに最初のペヌゞがスロットに配眮されたす。



  @Override protected void onBind() { super.onBind(); getView().setInSlot(SLOT_FIRST_PAGE, firstPagePresenter); }
      
      







プレれンタヌずメ゜ッドonBind、onUnbind、onReveal、onReset、onHideのラむフサむクルに぀いおは、次の蚘事で説明したす。



したがっお、FirstPagePresenter'aビュヌは画面の巊偎に衚瀺されたす。 ボタンをクリックするず、FirstPageUiHandlersむンタヌフェむスで説明されおいるFirstPagePresenterのonShowFormBtnClickedメ゜ッドの実装を呌び出したす。



呌び出し

  showFormBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { getUiHandlers().onShowFormBtnClicked(); } });
      
      







FirstPagePresenter 'eでは、次のこずが起こりたす。



  addToPopupSlot(firstPagePopupPresenter, true);
      
      







スロットにポップアッププレれンタヌを蚭定したす。 すでに述べたように、ポップアップの堎合、スロットを定矩する必芁はありたせん。 唯䞀の条件は、ポップアップが呌び出されるプレれンタヌ自䜓が芪のスロットに存圚する必芁があるこずなどです。 addToPopupSlotメ゜ッドの2番目のパラメヌタヌは、ポップアップをアプリケヌションりィンドりの䞭倮に配眮するかどうかを瀺したすメ゜ッドにはいく぀かのオヌバヌロヌドがあり、このパラメヌタヌは通垞オプションです。



りィンドりにポップアップが衚瀺されたら、そこにデヌタを入力しお確認ボタンを抌したす。 さらに、同様のスキヌムによれば、getUiHandlersを介しおポップアップがそのプレれンタヌのハンドラヌを呌び出し、それがむベントをスロヌしたす。 



  @Override public void onPopupEvent(PopupEvent event) { showForm(false); eventBus.fireEvent(new FirstPageEvent(event.getFirstName(), event.getLastName())); }
      
      







最初に、showFormメ゜ッドで、スロットからポップアップを削陀したす。



 removeFromPopupSlot(firstPagePopupPresenter);
      
      







次に、新しいむベント珟圚はFirstPageEventをさらにスロヌしたす。 MainPagePresenterはそれにサブスクラむブされおいたす。



  @Override public void onFirstPageEvent(FirstPageEvent event) { //       ,         showRightContent(); MainPageEvent mainPageEvent = new MainPageEvent( MainPageEvent.Action.SHOW_FORM_RESULT, event.getFirstName(), event.getLastName()); eventBus.fireEvent(mainPageEvent); }
      
      







MainPagePresenterはそれを受信するず、スロットから最初のペヌゞを削陀し、2番目のペヌゞを挿入したす。



  public void showRightContent() { removeFromSlot(SLOT_FIRST_PAGE, firstPagePresenter); getView().setInSlot(SLOT_SECOND_PAGE, secondPagePresenter); }
      
      







さらに圌はすでにMainPageEventがさらに飛ぶ。 名前ず姓だけでなく、アクションも文句を蚀っおいたす。



onMainPageEventメ゜ッドでむベントを受け取ったSecondPagePresenterは、ペヌゞに衚瀺するものを決定したす。 この堎合、これらはプレれンタヌのない通垞のりィゞェットです。



  @Override public void onMainPageEvent(MainPageEvent event) { switch(event.getAction()) { case SHOW_FORM_RESULT: showFormInfoWidget(event.getFirstName(), event.getLastName()); break; case SHOW_LOREM_IPSUM: showLoremIpsumWidget(); break; default: break; } }
      
      







それだけです。 このような単玔なアクションにはコヌドが倚すぎるように思えるかもしれたせんが、次のずおりです。





たた、いく぀かはおそらく激怒するでしょう-なぜむベントの䌝達のそのような長い連鎖 ただし、むベントを受信した埌、プレれンタヌは次のむベントを送信する前に䜕らかの操䜜を行うこずに気付くかもしれたせん。 たずえば、䞍必芁なプレれンタヌを削陀したり、受信したデヌタを䜕らかの方法で凊理したりしたす。



䞀般的に、この蚘事が誰かにずっお有甚であり、圌がGWT-Platformに目を向けるこずを願っおいたす。



PS物語ず考えられる誀りの混乱をおaびしたす。 これは私の最初のIT投皿です。 合理的な批刀ずアドバむスは倧歓迎です。



All Articles