日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pcl_openmap_OpenMap教程5 – 3层GIS应用程序

發布時間:2023/12/3 编程问答 69 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pcl_openmap_OpenMap教程5 – 3层GIS应用程序 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

pcl_openmap

1.簡介

歡迎使用OpenMap系列教程的第5個教程。 OpenMap是一個免費的開源Java GIS庫。

這是以前的教程列表:

  • 在第一個教程中,我們創建了一個基本的OpenMap GIS應用程序,該應用程序在JFrame中顯示一個從文件系統加載的具有一個形狀圖層的地圖。 該教程基于com.bbn.openmap.app.example.SimpleMap 。
  • 在第二個教程中,我們擴展了基本應用程序以使用MapHandler 。
  • 在第三個教程中,我們看到了如何利用BeanContext技術在openmap.properties文件中聲明我們的類并以聲明方式構建整個應用程序。
  • 第四個教程介紹了地圖圖層。

在本教程中,我們將討論如何基于OpenMap構建3層GIS應用程序。 我們將在探索新的OpenMap功能方面稍作休息,并將主要回顧我們在先前教程中學到的內容。

2.需求和架構概述

您的老板或客戶提出了一些要求。 在第一個沖刺(例如Scrum)中,應用程序應該能夠:

  • 從數據庫讀取數據/向數據庫寫入數據
  • 在GIS地圖上顯示數據
  • 與數據交互并顯示其屬性
  • 將地理數據移動到其他位置并將其保存回數據庫
  • 創建/更新/刪除地圖數據

您可能會說得很簡單,然后繼續草繪應用程序的3層架構草案:

圖1: 三層架構

3層架構遵循“ 模型-視圖-控制器(MVC)”架構模式。 從數據庫(后端)創建模型 。 我們的View是我們在之前的教程中構建的OpenMap GIS應用程序,能夠將數據顯示為點,線,多邊形等。并且Controller將所有內容連接起來。
類似的架構是Model-View-ViewModel(MVVM) ,我們還將對其進行簡要討論。

3.技術

3.1后端

后端主要是數據庫,或更準確地說,是數據庫管理系統(DBMS) 。 在這里,您可以選擇:

*具有或不具有地理空間擴展的關系數據庫 (Oracle,MySQL,Postgresql,MS SQL Server,Sqlite,Hsqldb,JavaDB等)。 地理空間擴展存在于MySQL , Postgresql , Oracle , SQLite ; MS SQL Server 2008帶有內置的空間擴展。
* 基于對象的空間數據庫
*具有空間支持的No-SQL數據庫(例如CassandraDB, CouchDB , MongoDB , Neo4j等)

優化了空間數據庫或地理數據庫,以存儲和查詢表示在幾何空間中定義的對象的數據。 大多數空間數據庫都允許根據OpenGIS規范表示簡單的幾何對象,例如點,線和面以及空間索引。 但是,您無需具有GeoSpatial數據庫即可構建GIS應用程序,但是使用它會有好處。

3.2模型

您如何訪問數據庫以檢索要用于Java應用程序的數據? 以下是您可以使用的可能技術的列表:

  • SQL查詢數據庫,即Java Database Connectivity或JDBC 。 這是傳統方式(但是我們在2016年!)。 您需要“講” SQL來查詢數據庫并在ResultSets檢索數據,當您的應用程序遵循面向對象模型時(除非您的數據庫也是面向對象或對象關系的)也不太方便。
  • 對象關系映射,例如Java Persistence API(JPA) 。 這是將數據庫表映射到Java對象的現代方法。 NetBeans為您提供了一個不錯的JPA映射向導。
  • 功能映射。 如果您是Java 8專家,并且喜歡lambda,那么為什么不使用λ表達式和Stream API而不是SQL查詢或JPA? Speedment是一個Java庫,使這個夢想成為現實。 這是SQL和Stream API之間的比較,以便查詢數據。

3.3控制器

最后一個問題是如何將視圖連接到模型? 這里的關鍵問題是各個組件之間的松耦合。 松散耦合使您可以使用另一種技術替換應用程序的任何層,而又不影響其他層(或進行有限的更改)。 有許多解決方案,例如:

  • Java 6 ServiceLoader
  • NetBeans查找API
  • Dukescript(MVVM) 。 將DukeScript用于客戶端-服務器應用程序的好處之一是代碼重用。 您可以在客戶端和服務器上使用相同的模型類。 這是映射JPA和Dukescript的教程 。

4.構建我們的應用程序

我不會在這里探索所有這些技術。 請隨意查看本文結尾處的參考。

在本文中,我們將看到如何使用模型的JPA和控制器的NetBeans Lookup API來構建MVC GIS應用程序。 在以后的文章中,我們將看到替代技術,例如用Speedment替換JPA和用Dukescript用MVVM替換MVC。

4.1我們的觀點

在之前的文章中,我們已經創建了一個OpenMap應用程序。 讓我們回顧一下并重構它。

我們的OpenMap應用程序包含以下文件層次結構:

  • openmap
    • DMSCoordInfoFormatter
    • DemoLayer
    • MyDrawingTool
    • OpenMap
  • openmap.properties

讓我們這樣重構它:

  • openmap
    • OpenMap.java
    • openmap.controller
    • openmap.model
    • openmap.view
      • DMSCoordInfoFormatter.java
      • DemoLayer.java
      • MyDrawingTool.java
  • openmap.properties

也不要忘記更新openmap.properties的路徑。 上面的包結構描述了Model-View-Controller(MVC)設計模式。

在NetBeans中(而且在其他IDE),你可以很容易地應用重構(如移動一個文件或文件夾到另一個文件夾或重命名文件/文件夾)上的文件/文件夾,右鍵單擊并選擇子菜單重構下一個重構。

添加一個城市圖層(來自OpenMap的原始openmap.properties ):

清單1 – openmap.properties –城市層

# These layers are turned on when the map is first started. Order # does not matter here... openmap.startUpLayers=demo cities graticule shapePolitical# Layers listed here appear on the Map in the order of their names. openmap.layers=demo cities graticule shapePolitical ... ### # LocationLayer that holds cities. The palette for this layer lets # you turn on the names and declutter matrix, if you want. The # declutter matrix can get expensive at small scales. cities.class=com.bbn.openmap.layer.location.LocationLayer cities.prettyName=World Cities cities.locationHandlers=csvcities cities.useDeclutter=false cities.declutterMatrix=com.bbn.openmap.layer.DeclutterMatrixcsvcities.class=com.bbn.openmap.layer.location.csv.CSVLocationHandler csvcities.prettyName=World Cities csvcities.locationFile=resources/map/cities.csv csvcities.csvFileHasHeader=true csvcities.locationColor=FF0000 csvcities.nameColor=008C54 csvcities.showNames=false csvcities.showLocations=true csvcities.nameIndex=0 csvcities.latIndex=5 csvcities.lonIndex=4 csvcities.csvFileHasHeader=true

并且不要忘記將cities.csv復制到resources/map 。

再次運行該應用程序以查看新層。

4.2我們的數據庫架構

我們的數據庫架構顯示在下面的清單中。 它主要由一個Supplier表組成。 我們想在地圖上將我們的供應商顯示為GeoPoint 。

以下是在NetBeans中創建SQLite數據庫的步驟(您可以選擇任何喜歡的DBMS):

  • 右鍵單擊Libraries
  • 從彈出菜單中選擇添加JAR /文件夾...
  • 導航到您從中下載SQLite的文件夾,然后選擇sqlite-jdbc-xxx.jar
  • 選擇復制到庫文件夾 ,然后單擊打開 。 驅動程序應顯示在“ 庫”下。
  • 單擊窗口→服務菜單以顯示服務選項卡。
  • 展開數據庫節點
  • 右鍵單擊“ 驅動程序”節點,然后選擇“ 新驅動程序”
  • 點擊添加
  • 導航到從SQLite網站下載sqlite-jdbc-xxxx.jar文件的位置 ; 驅動程序類應為org.sqlite.JDBC和Name → SQLite
  • 單擊確定 。 SQLite應該列在Drivers
  • 右鍵單擊數據庫,然后選擇New Connection…
  • 選擇SQLite驅動程序,然后單擊下一步
  • 提供一個JDBC URL,例如jdbc:sqlite:C:\db\suppliers.sqlite-3并單擊Finish 。 您的連接應顯示在“ 數據庫”下。
  • 右鍵單擊它,然后選擇Connect…
  • 右鍵單擊表,然后選擇Execute Command…
  • 輸入以下SQL語句,然后單擊“ Run SQL按鈕:
  • 清單2 –供應商表

    CREATE TABLE supplier ( SID ?? ??? ??? ?INTEGER?????????? PRIMARY KEY, NAME????? ??? ??? ?VARCHAR2 (30)???? NOT NULL, CITY????? ??? ??? ?VARCHAR2 (30)???? NOT NULL, TYPE?? ??? ??? ?VARCHAR2 (10)???? NOT NULL CONSTRAINT TYPE CHECK (TYPE IN ('GROSS','RETAIL')), LATITUDE?? ??? ?NUMBER (12,10)??? NOT NULL CONSTRAINT LATITUDE CHECK (LATITUDE BETWEEN -90.0000000000 AND 90.0000000000), LONGITUDE? ??? ??? ?NUMBER (13,10)??? NOT NULL CONSTRAINT LONGITUDE CHECK (LONGITUDE BETWEEN -180.0000000000 AND 180.0000000000), CONSTRAINT UID UNIQUE (SID, NAME, LATITUDE, LONGITUDE) )

    驗證新表是否已創建并列在“ 表”下。 您可以將相同的樣本數據添加到表中:

    清單3 –樣本數據

    INSERT INTO supplier (NAME, CITY, TYPE, LATITUDE, LONGITUDE) VALUES ('HP', 'ATHENS', 'GROSS', 38.1216011, 23.65486336); INSERT INTO supplier (NAME, CITY, TYPE, LATITUDE, LONGITUDE) VALUES ('DELL', 'BRUSSELS', 'RETAIL', 50.83704758, 4.367612362); INSERT INTO supplier (NAME, CITY, TYPE, LATITUDE, LONGITUDE) VALUES ('APPLE', 'LONDON', 'RETAIL', 51.48791122, -0.177998126); INSERT INTO supplier (NAME, CITY, TYPE, LATITUDE, LONGITUDE) VALUES ('TOSHIBA', 'PARIS', 'GROSS', 48.88155365, 2.432832718);

    在繼續操作之前,請不要忘記斷開與數據庫的連接。 由于SQLite是獨立數據庫,因此它主要是文件系統中的文件。 一次只能有一個應用程序可以訪問它。 如果從“ 服務”選項卡連接到它,并嘗試同時從OpenMap應用程序訪問它,則會出現數據庫被鎖定的異常。 對于諸如Postgresql或MS SQL Server之類的“實際” DBMS,情況并非如此,它們可以并發訪問。

    4.3建立模型

    讓我們根據以上模式構建一個JPA模型。 NetBeans提供了很好的JPA支持:

  • 右鍵單擊openmap.model
  • New → Other → Persistence → Entity Classes from Database選擇New → Other → Persistence → Entity Classes from Database然后單擊下一步。
  • 選擇您的數據庫連接 ( suppliers.sqlite-3 )
  • 從“ 可用表”中選擇suppliers 表 ,然后單擊“ 添加”以將其移動到“ 選定表”中 。
  • 點擊下一步
  • 在第3步中,僅選中“ 為持久字段生成命名查詢注釋” ,然后單擊“ 下一步”
  • 在第4步中,取消選中所有復選框,然后單擊Finish
  • 向導在openmap.model下創建了一個新類Suppliers和一個不必要的SupplierPK 。 它還創建了文件META-INF/persistence.xml ,其中包含有關數據庫的連接信息:

    清單4 – persistence.xml

    <?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"><persistence-unit name="OpenMapPU" transaction-type="RESOURCE_LOCAL"><provider>org.eclipse.persistence.jpa.PersistenceProvider</provider><class>openmap.model.Supplier</class><properties><property name="javax.persistence.jdbc.url" value="jdbc:sqlite:C:\db\suppliers.sqlite3"/><property name="javax.persistence.jdbc.user" value=""/><property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC"/><property name="javax.persistence.jdbc.password" value=""/></properties></persistence-unit> </persistence>

    由于包含主鍵定義的架構(請參見清單2),向導將為主鍵生成SupplierPK類。 這不是必需的,因此刪除此類并從Supplier類中刪除此字段及其引用。 修改您的Supplier類,使其類似于以下清單:

    清單5 – Supplier.java

    package openmap.model;import java.io.Serializable; import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.NamedQueries; import javax.persistence.NamedQuery; import javax.persistence.Table; import javax.persistence.Transient;/**** @author ikost*/ @Entity @Table(name = "supplier") @NamedQueries({@NamedQuery(name = "Supplier.findAll", query = "SELECT s FROM Supplier s"),@NamedQuery(name = "Supplier.findBySid", query = "SELECT s FROM Supplier s WHERE s.sid = :sid"),@NamedQuery(name = "Supplier.findByName", query = "SELECT s FROM Supplier s WHERE s.name = :name"),@NamedQuery(name = "Supplier.findByCity", query = "SELECT s FROM Supplier s WHERE s.city = :city"),@NamedQuery(name = "Supplier.findByType", query = "SELECT s FROM Supplier s WHERE s.type = :type"),@NamedQuery(name = "Supplier.findByLatitude", query = "SELECT s FROM Supplier s WHERE s.latitude = :latitude"),@NamedQuery(name = "Supplier.findByLongitude", query = "SELECT s FROM Supplier s WHERE s.longitude = :longitude")}) public class Supplier implements Serializable {private static final long serialVersionUID = 1L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Basic(optional = false)@Column(name = "SID")private int sid;@Basic(optional = false)@Column(name = "NAME")private String name;@Basic(optional = false)@Column(name = "CITY")private String city;@Basic(optional = false)@Column(name = "TYPE")@Enumerated(EnumType.STRING)private String type;@Basic(optional = false)@Column(name = "LATITUDE")private double latitude;@Basic(optional = false)@Column(name = "LONGITUDE")private double longitude;public enum TYPE {GROSS, RETAIL};public Supplier() {}public Supplier(int id) {this.sid = id;}public Supplier(int id, String name, String city,TYPE type, double latitude, double longitude) {this.sid = id;this.name = name;this.city = city;this.type = type;this.latitude = latitude;this.longitude = longitude;}public int getSid() {return sid;}public void setSid(int sid) {this.sid = sid;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public TYPE getType() {return type;}public void setType(TYPE type) {this.type = type;}public double getLatitude() {return latitude;}public void setLatitude(double latitude) {this.latitude = latitude;}public double getLongitude() {return longitude;}public void setLongitude(double longitude) {this.longitude = longitude;}@Overridepublic int hashCode() {return sid;}@Overridepublic boolean equals(Object object) {if (!(object instanceof Supplier)) {return false;}Supplier other = (Supplier) object;if (this.sid != other.sid) {return false;}return true;}@Overridepublic String toString() {return "openmap.model.Supplier[ sid =" + sid + " ]";}}

    JPA 2.1為枚舉提供了映射支持(請參見上面清單中的type字段)。

    4.4建立您的控制器

    NetBeans還可輕松為模型生成控制器。

  • 右鍵單擊openmap.controller
  • New → Other → Persistence → JPA Controller Classes from Entity Classes選擇New → Other → Persistence → JPA Controller Classes from Entity Classes ,然后單擊下一步
  • 從“ 可用實體類 ”列表中選擇“ Supplier ”,然后單擊“ 添加”將其移動到“ 選定實體類 ”列表中。
  • 點擊下一步
  • 在第3步中,將包固定為openmap.controller 。
  • 點擊完成
  • 該向導創建了SupplierJpaController以及3個異常文件。 現在,視圖可以訪問此控制器以便對模型執行操作。

    清單6 – SupplierJpaController.java

    package openmap.controller;import java.io.Serializable; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Query; import javax.persistence.EntityNotFoundException; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import openmap.controller.exceptions.NonexistentEntityException; import openmap.model.Supplier;/**** @author ikost*/ public class SupplierJpaController implements Serializable {public SupplierJpaController(EntityManagerFactory emf) {this.emf = emf;}private EntityManagerFactory emf = null;public EntityManager getEntityManager() {return emf.createEntityManager();}public void create(Supplier supplier) {EntityManager em = null;try {em = getEntityManager();em.getTransaction().begin();em.persist(supplier);em.getTransaction().commit();} finally {if (em != null) {em.close();}}}public void edit(Supplier supplier) throws NonexistentEntityException, Exception {EntityManager em = null;try {em = getEntityManager();em.getTransaction().begin();supplier = em.merge(supplier);em.getTransaction().commit();} catch (Exception ex) {String msg = ex.getLocalizedMessage();if (msg == null || msg.length() == 0) {int id = supplier.getSid();if (findSupplier(id) == null) {throw new NonexistentEntityException("The supplier with id " + id + " no longer exists.");}}throw ex;} finally {if (em != null) {em.close();}}}public void destroy(int id) throws NonexistentEntityException {EntityManager em = null;try {em = getEntityManager();em.getTransaction().begin();Supplier supplier;try {supplier = em.getReference(Supplier.class, id);supplier.getSid();} catch (EntityNotFoundException enfe) {throw new NonexistentEntityException("The supplier with id " + id + " no longer exists.", enfe);}em.remove(supplier);em.getTransaction().commit();} finally {if (em != null) {em.close();}}}public List<Supplier> findSupplierEntities() {return findSupplierEntities(true, -1, -1);}public List<Supplier> findSupplierEntities(int maxResults, int firstResult) {return findSupplierEntities(false, maxResults, firstResult);}private List<Supplier> findSupplierEntities(boolean all, int maxResults, int firstResult) {EntityManager em = getEntityManager();try {CriteriaQuery cq = em.getCriteriaBuilder().createQuery();cq.select(cq.from(Supplier.class));Query q = em.createQuery(cq);if (!all) {q.setMaxResults(maxResults);q.setFirstResult(firstResult);}return q.getResultList();} finally {em.close();}}public Supplier findSupplier(int id) {EntityManager em = getEntityManager();try {return em.find(Supplier.class, id);} finally {em.close();}}public int getSupplierCount() {EntityManager em = getEntityManager();try {CriteriaQuery cq = em.getCriteriaBuilder().createQuery();Root<Supplier> rt = cq.from(Supplier.class);cq.select(em.getCriteriaBuilder().count(rt));Query q = em.createQuery(cq);return ((Long) q.getSingleResult()).intValue();} finally {em.close();}} }

    在此示例中,我們只有一個域對象Supplier但在實際應用中,您將有許多域對象。 一個常見的解決方案是創建一個Facade ,該Facade僅將視圖所需的方法公開,而將其余的隱藏。 在下面的內容中,我們展示如何使用NetBeans Lookup API創建松散耦合的Facade IDBManager (請參閱參考資料)。

    清單7 – IDBManager.java

    package openmap.controller;import java.util.List; import openmap.model.Supplier;/*** A facade of our controllers.** @author ikost*/ public interface IDBManager {List getSuppliers(); }

    單擊IDBManager左側的blob,然后選擇“ 實現接口” 。 如下表所示修改DBManager實現,以將其轉換為服務提供者:

    清單8 – DBManager.java

    package openmap.controller;import java.util.List; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import openmap.model.Supplier; import org.openide.util.lookup.ServiceProvider;@ServiceProvider(service = IDBManager.class) public class DBManager implements IDBManager {private final EntityManagerFactory emf;private final SupplierJpaController suppliers;public DBManager() {emf = Persistence.createEntityManagerFactory("OpenMapPU");suppliers = new SupplierJpaController(emf);}@Overridepublic List getSuppliers() {return suppliers.findSupplierEntities();} }

    @ServiceProvider(service = IDBManager.class)可以解決所有問題。 此行將DBManager添加到默認查找中。 在下一部分中,我們將從視圖中了解如何訪問DBManager 。 為了使其工作,如果NetBeans沒有自動添加依賴項,則需要向org-openide-util-lookup.jar添加一個依賴項。

  • 右鍵單擊Libraries
  • 從彈出菜單中選擇添加JAR /文件夾...
  • 導航到并選擇<NetBeans_Installation>/platform/lib/org-openide-util-lookup.jar
  • 選擇復制到庫文件夾 ,然后單擊打開
  • 清理并構建您的項目,以使更改生效。
  • 但是什么是查找? 查找是將類對象作為鍵并將這些類對象的實例集作為值的映射,即

    Lookup = Map<Class, Set<Class>> ,例如Map<String, Set<String>>或Map<Provider, Set<Provider>> 。 NetBeans提供了許多訪問默認查找的方法:

    Provider provider = Lookup.getDefault().lookup(Provider.class); provider.aMethod();

    或如果您具有Provider多個實現:

    Collection providers = Lookup.getDefault().lookupAll(Provider.class); for (Provider provider : providers) { ... }

    從上面的代碼示例中可以看到,客戶端不知道客戶端使用哪種實現。 它只知道接口。 松耦合!

    上面的代碼將服務添加到默認查找中。 客戶端在接口的默認查找中查找。 默認查找是一個評估META-INF/services文件夾中的服務聲明的查找。 可通過Lookup.getDefault()方法調用它。 如果您對更多細節感興趣,則Netbeans在build/classes/META-INF/services/文件夾內創建一個文本文件package.Provider ,其中包含實現類的完全限定名稱。 通過以這種方式請求服務接口,您會收到在META-INF/services文件夾中注冊的實現類的實例。

    當然,在NetBeans胖客戶端平臺中還有其他查找,而不是默認查找,但是這些不在本文討論范圍之內。

    4.5建立您的視圖

    最后,我們需要創建一個新圖層,該圖層將在地圖上顯示我們的供應商,并在openmap.properties中聲明它,以便將其添加到地圖中。 如果您遵循以前的教程,那么現在應該很容易做到。 讓我們逐步構建SupplierLayer.java :

    清單9 – SupplierLayer.java

    package openmap.controller; public class SupplierLayer extends OMGraphicHandlerLayer {private static final String LOOKUP_OBJECT = "Lookup Object";public SupplierLayer() {// This is how to set the ProjectionChangePolicy, which// dictates how the layer behaves when a new projection is// received.setProjectionChangePolicy(new StandardPCPolicy(this, true));setRenderPolicy(new BufferedImageRenderPolicy());// Making the setting so this layer receives events from the// SelectMouseMode, which has a modeID of "Gestures". Other// IDs can be added as needed.setMouseModeIDsForEvents(new String[]{"Gestures"});}/*** Called from the prepare() method if the layer discovers that its* OMGraphicList is {@code null}.** @return new {@code OMGraphicList} with {@code OMGraphics{ that you always* want to display and reproject as necessary.*/public OMGraphicList init() {final IDBManager dbManager = Lookup.getDefault().lookup(IDBManager.class);final List suppliers = dbManager.getSuppliers();// This layer keeps a pointer to an OMGraphicList that it uses// for painting. It's initially set to null, which is used as// a flag in prepare() to signal that the OMGraphcs need to be// created. The list returned from prepare() gets set in the// layer.// This layer uses the StandardPCPolicy for new// projections, which keeps the list intact and simply calls// generate() on it with the new projection, and repaint()// which calls paint().OMGraphicList omList = new OMGraphicList();// Add suppliers as OMPoints.for (Supplier supplier : suppliers) {OMPoint omSupplier = new OMPoint(supplier.getLatitude(),supplier.getLongitude(), 3); // radiusomSupplier.putAttribute(OMGraphicConstants.LABEL,new OMTextLabeler(supplier.getName(), OMText.JUSTIFY_LEFT));omSupplier.putAttribute(LOOKUP_OBJECT, supplier);omSupplier.setLinePaint(Color.BLUE);omSupplier.setSelectPaint(Color.ORANGE);omSupplier.setOval(true);omList.add(omSupplier);}return omList;}/*** This is an important Layer method to override. The prepare method gets* called when the layer is added to the map, or when the map projection* changes. We need to make sure the OMGraphicList returned from this method* is what we want painted on the map. The OMGraphics need to be generated* with the current projection. We test for a null OMGraphicList in the* layer to see if we need to create the OMGraphics. This layer doesn't* change it's OMGraphics for different projections, if your layer does, you* need to clear out the OMGraphicList and add the OMGraphics you want for* the current projection.** @return*/@Overridepublic synchronized OMGraphicList prepare() {OMGraphicList list = getList();// Here's a test to see if it's the first time that the layer has been// added to the map. This list object will be whatever was returned from// this method the last time prepare() was called. In this// example, we always return an OMGraphicList object, so if it's null,// prepare() must not have been called yet.if (list == null) {list = init();}/** This call to the list is critical! OMGraphics need to be told where* to paint themselves, and they figure that out when they are given the* current Projection in the generate(Projection) call. If an* OMGraphic's location is changed, it will need to be regenerated* before it is rendered, otherwise it won't draw itself. You generally* know you have a generate problem when OMGraphics show up with the* projection changes (zooms and pans), but not at any other time after* something about the OMGraphic changes.** If you want to be more efficient, you can replace this call to the* list as an else clause to the (list == null) check above, and call* generate(Projection) on all the OMGraphics in the init() method below* as you create them. This will prevent the* OMGraphicList.generate(Projection) call from making an additional* loop through all of the OMGraphics before they are returned.*/list.generate(getProjection());return list;}/*** Query that an OMGraphic can be highlighted when the mouse moves over it.* If the answer is true, then highlight with this OMGraphics will be* called.** @param omg* @return*/@Overridepublic boolean isHighlightable(OMGraphic omg) {return true;}/*** Query that an OMGraphic is selectable. Examples of handing selection are* in the EditingLayer. The default OMGraphicHandlerLayer behavior is to add* the OMGraphic to an OMGraphicList called selectedList. If you aren't* going to be doing anything in particular with the selection, then return* false here to reduce the workload of the layer.** @param omg* @return* @see com.bbn.openmap.layer.OMGraphicHandlerLayer#select* @see com.bbn.openmap.layer.OMGraphicHandlerLayer#deselect*/@Overridepublic boolean isSelectable(OMGraphic omg) {return true;}/*** Query for what tooltip to display for an OMGraphic* the mouse is over.** @param omg* @return*/@Overridepublic String getToolTipTextFor(OMGraphic omg) {String ttText = null;if (omg instanceof OMPoint) {OMPoint point = ((OMPoint) omg);Object attribute = point.getAttribute(OMGraphicConstants.LABEL);if (attribute != null && attribute instanceof OMTextLabeler) {OMTextLabeler labeler = (OMTextLabeler) attribute;ttText = labeler.getData();}}return ttText;}@Overridepublic Component getGUI() {JPanel panel = PaletteHelper.createPaletteJPanel("Suppliers Layer");JCheckBox chkShowLabels = new JCheckBox("Show/Hide Labels", true);chkShowLabels.addItemListener((ItemEvent e) -> {OMGraphicList omSuppliers = getList();for (OMGraphic omSupplier : omSuppliers) {if (chkShowLabels.isSelected()) {omSupplier.putAttribute(OMGraphicConstants.LABEL,new OMTextLabeler(((Supplier) omSupplier.getAttribute(LOOKUP_OBJECT)).getName(),OMText.JUSTIFY_LEFT));} else {omSupplier.removeAttribute(OMGraphicConstants.LABEL);}}repaint();});panel.add(chkShowLabels);return panel;} }

    在init()方法中,我們使用默認的 Lookup從DBManager檢索Supplier的列表。 我們遍歷所有Supplier并從其中的每一個中創建一個OMPoint 。 通過設置屬性OMGraphicConstants.LABEL創建點的標簽。 通過使用鍵"Lookup Object"將支持的Supplier添加到OMPoint的屬性映射中,我們可以實現一個技巧。 我們稍后將需要它。 (不要將其與NetBeans的Lookup混淆;我們只是以類似的方式命名它,以表明它類似于NetBeans的Lookup但與它無關;您可以將其命名為其他名稱)。 最后,將每個點添加到返回的OMGraphicList 。

    單擊“ 工具”按鈕時,“ 圖層”對話框將調用getGUI()方法(請參見下圖):

    圖2 –供應商層

    該方法創建一個帶有復選框的新面板,以顯示/隱藏該圖層的標簽。 Supplier的標簽是從OMPoint屬性圖檢索的Supplier名稱,以便為其設置OMGraphicConstants.LABEL屬性。 選中復選框后,標簽可見,否則屬性被刪除。 圖層被repaint()編輯。 不幸的是, repaint()不能100%起作用。 您需要縮放地圖或調整地圖大小,以便再次顯示標簽。

    接下來,當我們右鍵單擊Supplier以顯示其屬性時,我們想顯示一個彈出菜單。 從上一教程中,您知道我們需要重寫getItemsForOMGraphicMenu()方法。 如果要在右鍵單擊圖層上的任何位置時顯示彈出菜單,請重寫以下方法getItemsForMapMenu() :

    清單10 – SupplierLayer.java(續)

    @Override public List getItemsForOMGraphicMenu(OMGraphic omg) {final OMGraphic chosen = omg;List menuItems = new ArrayList<>();JMenuItem mnuProperties = new JMenuItem("Properties")mnuProperties.addActionListener((ActionEvent ae) -> {//...});menuItems.add(mnuProperties);return menuItems; }/*** This method is called mnuCreate a right mouse click is detected over the map* and not over an OMGraphic. You can provide a List of components to be* displayed in a popup menu. You have to do the wiring for making the list* components do something, though.** @param me* @return*/ @Override public List getItemsForMapMenu(MapMouseEvent me) {List l = new ArrayList<>();JMenuItem mnuCreate = new JMenuItem("Create New Supplier");mnuCreate.addActionListener((ActionEvent ae) -> {fireRequestMessage("Create New Supplier");});l.add(mnuCreate);return l; }

    我們缺少顯示數據的表格。 我們將在此處進行快速介紹,以向您展示另一個NetBeans向導,但是您可以使用Matisse或您所知道的自由構建自己的對話框。

  • 創建一個新的包openmap.view.properties
  • 右鍵單擊它,然后選擇新建→其他→Swing GUI表單→主/詳細樣本表單 ,然后單擊下一步。
  • 將其命名為SuppliersPropertiesDialogBox ,然后單擊“ 下一步”。
  • 選擇您的數據庫連接 , 供應商表,然后從要包括的列中排除SID字段。
  • 點擊完成
  • 該向導已創建一個主/明細表格,但是我們只需要明細部分。 如下圖所示對其進行自定義。

    圖3 –供應商屬性對話框

    選擇每個文本字段和“ 刪除”按鈕,單擊“ 綁定” (“ 屬性”區域),然后從已enabled屬性和text屬性中刪除對主表的任何引用。

    圖4 –刪除綁定

    將類型文本字段更改為組合框,因為type僅限制為enum值'GROSS'和'RETAIL' 。

  • 右鍵單擊組合框,然后選擇“ Customize Code…
  • 單擊第二個默認代碼組合框,然后將其更改為custom屬性 。
  • 將代碼更改為以下代碼,然后單擊“ 確定”
  • cmbType.setModel(new javax.swing.DefaultComboBoxModel<>(Supplier.TYPE.values()));
  • 再次單擊組合框,然后在“ 屬性”中單擊“ 代碼”
  • 將類型參數設置為<Supplier.TYPE>
  • 在底部添加標簽( lblStatus )。 使它不透明。 與數據庫的事務處理成功后,將顯示為綠色,否則顯示為紅色。 這對用戶是一個很好的反饋,以確保他/她的修改得以保留。

    該對話框與實體管理器耦合以檢索要顯示的數據,但這通常是一個不好的設計。 刪除對實體管理器和主表的所有引用,并將其轉換為JDialog 。 為了避免java.lang.IllegalArgumentException: GroupLayout can only be used with one Container at a time ,請將所有組件添加到JPanel

  • 在“ 設計”視圖中調整對話框的大小
  • 將一個面板從面板拖到頂部(旋轉容器)
  • 將面板的變量名稱更改為panel
  • 將其布局設置為Free Design
  • 從導航器中選擇所有小部件,然后將它們拖動到新面板中; 它們的布局應保持不變。
  • 在導航器中選擇JDialog并將其大小屬性設置為[400, 230] 。 取消選中“ 可調整大小”屬性。
  • 源代碼應如下所示:

    清單11 – SuppliersPropertiesDialogBox.java

    public class SuppliersPropertiesDialogBox extends JDialog {private final Supplier supplier;private final IDBManager dbManager;public SuppliersPropertiesDialogBox(Supplier s) {dbManager = Lookup.getDefault().lookup(IDBManager.class);initComponents();supplier = s;setData(supplier);}@SuppressWarnings("unchecked")private void btnCloseActionPerformed(java.awt.event.ActionEvent evt) {this.setVisible(false);}private void btnDeleteActionPerformed(java.awt.event.ActionEvent evt) {try {dbManager.delete(supplier);lblStatus.setBackground(Color.green);} catch (Exception ex) {Logger.getLogger(SuppliersPropertiesDialogBox.class.getName()).log(Level.SEVERE, null, ex);lblStatus.setBackground(Color.red);}}private void btnSaveActionPerformed(java.awt.event.ActionEvent evt) {try {dbManager.save(getData());lblStatus.setBackground(Color.green);} catch (Exception ex) {Logger.getLogger(SuppliersPropertiesDialogBox.class.getName()).log(Level.SEVERE, null, ex);lblStatus.setBackground(Color.red);}}public void setData(Supplier supplier) {txtName.setText(supplier.getName());txtCity.setText(supplier.getCity());txtLatitude.setText(String.valueOf(supplier.getLatitude()));txtLongitude.setText(String.valueOf(supplier.getLongitude()));cmbType.setSelectedItem(supplier.getType());}public Supplier getData() {supplier.setName(txtName.getText());supplier.setCity(txtCity.getText());supplier.setLatitude(Double.valueOf(txtLatitude.getText()));supplier.setLongitude(Double.valueOf(txtLongitude.getText()));supplier.setType(Supplier.TYPE.valueOf(cmbType.getSelectedItem().toString()));return supplier;}// initComponents() generated method omitted ... }

    如您所見,我們引用DBManager來處理數據。 我們需要向其中添加以下新方法:

    清單12 – IDBManager.java

    public interface IDBManager {List getSuppliers();void delete(Supplier supplier) throws Exception;void save(Supplier supplier) throws Exception; }

    及其實現:
    清單13 – DBManager.java

    @Overridepublic void delete(Supplier supplier) throws Exception {try {suppliers.destroy(supplier.getSid());} catch (NonexistentEntityException ex) {Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);throw ex;}}@Overridepublic void save(Supplier supplier) throws Exception {Supplier s = suppliers.findSupplier(supplier.getSid());if (s == null) {suppliers.create(supplier);} else {try {suppliers.edit(supplier);} catch (Exception ex) {Logger.getLogger(DBManager.class.getName()).log(Level.SEVERE, null, ex);throw ex;}}}

    現在可以將SupplierLayer修改為:

    清單14 – SupplierLayer.java

    @Overridepublic List getItemsForOMGraphicMenu(OMGraphic omg) {List menuItems = new ArrayList<>();JMenuItem mnuProperties = new JMenuItem("Properties");mnuProperties.addActionListener((ActionEvent ae) -> {SuppliersPropertiesDialogBox dlgProperties =new SuppliersPropertiesDialogBox((Supplier)omg.getAttribute(LOOKUP_OBJECT));dlgProperties.setVisible(true);});menuItems.add(mnuProperties);return menuItems;}

    最后,

  • 清理并構建您的應用程序,然后運行它
  • 單擊“ 圖層控件”按鈕,使“ 世界城市”圖層不可見; 這樣,您的鼠標點擊地圖就不會選擇城市,而是供應商
  • 右鍵單擊地圖上的供應商,然后從彈出菜單中選擇“ 屬性 ”; 下圖對話框將顯示。 當您單擊“ 保存”時,您獲得綠色反饋,表明您的更改已成功保存。
  • 圖5 –供應商屬性對話框

    做得好! 您已經構建了大多數功能,并且您的設計允許您進行修改而無需更改所有層。

    這是您可以嘗試的TODO列表:

    • 將上述對話框中的緯度/經度文本字段設置為易于閱讀的格式,即xxoyy'zzz"N|S , xxxoyy'zzz"E|W
      • 提示 :使用我們在上一篇文章中顯示的DMSCoordInfoFormatter格式化緯度/經度雙DMSCoordInfoFormatter值;
      • 您可以為緯度和經度的小時/分鐘/秒使用單獨的文本字段,以便用戶可以輕松鍵入新值而不會弄亂特殊字符;
      • 保存更改后,確保OMPoint顯示在其新位置; 你需要添加PropertyChangeListener在SupplierLayer監聽在改變Supplier :

      清單15 – SupplierLayer.java(續)

    private final PropertyChangeListener listener = (PropertyChangeEvent evt) -> {if (evt.getPropertyName().equals("latitude") || evt.getPropertyName().equals("longitude")) {Supplier supplier = (Supplier) evt.getSource();OMGraphicList list = getList();for (OMGraphic omPoint : list) {if (omPoint.getAttribute(LOOKUP_OBJECT).equals(supplier)) {((OMPoint) omPoint).set(supplier.getLatitude(), supplier.getLongitude());break;}}repaint();}};public OMGraphicList init() {// ...// Add suppliers as OMPoints.for (Supplier supplier : suppliers) {// ...supplier.addPropertyChangeListener(listener);omList.add(omSupplier);}// ...}

    為使以上各項起作用,您需要將Supplier轉變為可觀察的:

    清單16 – Supplier.java(續)

    public class Supplier implements Serializable {@Transientprivate final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);// ...public void setSid(int sid) {int oldSid = this.sid;this.sid = sid;changeSupport.firePropertyChange("sid", oldSid, sid);}// ...public void setName(String name) {String oldName = this.name;this.name = name;changeSupport.firePropertyChange("name", oldName, name);}// ...public void setCity(String city) {String oldCity = this.city;this.city = city;changeSupport.firePropertyChange("city", oldCity, city);}// ...public void setType(TYPE type) {TYPE oldType = this.type;this.type = type;changeSupport.firePropertyChange("type", oldType, type);}// ...public void setLatitude(double latitude) {double oldLatitude = this.latitude;this.latitude = latitude;changeSupport.firePropertyChange("latitude", oldLatitude, latitude);}// ...public void setLongitude(double longitude) {double oldLongitude = this.longitude;this.longitude = longitude;changeSupport.firePropertyChange("longitude", oldLongitude, longitude);}// ...public void addPropertyChangeListener(PropertyChangeListener listener) {changeSupport.addPropertyChangeListener(listener);}public void removePropertyChangeListener(PropertyChangeListener listener) {changeSupport.removePropertyChangeListener(listener);}
    • 添加拖動功能,即用戶應該能夠將地圖上的供應商拖動到新位置
      • 使用上一篇文章中的提示;
      • 實現DrawingToolRequestor接口
      • 在findAndInit()定義并初始化DrawingTool的實例
      • 重寫select()和drawingComplete()方法
    • 添加創建新的供應商的功能(方法getItemsForMapMenu()在SupplierLayer )。 應該顯示SuppliersPropertiesDialogBox ,其中已經填充了用戶在地圖上單擊的坐標的緯度/經度字段; 然后用戶應填寫其他字段,并將新的供應商添加到數據庫中
    • 單擊“ Drawing Tool Launcher按鈕時,您可以在圖層上添加許多類型的圖形,而這可能不是您想要的。 由于我們希望我們的Supplier層僅顯示OMPoint , ompointloader像上一篇文章中所做的那樣,修改openmap.components僅omdrawingtool和ompointloader
    • 您可能會遇到的另一個問題是,當右鍵單擊OMPoint ,將顯示與通過getItemsForOMGraphicMenu()創建的彈出菜單不同的彈出菜單。 com.bbn.openmap.tools.drawing.OMDrawingTool包含dt.setBehaviorMask(OMDrawingTool.QUICK_CHANGE_BEHAVIOR_MASK) 。 OMDrawingTool定義了許多行為掩碼,如上一教程中所述。 作為解決方法,我們創建了自己的OMDrawingTool 。

    結論

    在本教程中,我們創建了一個三層獨立應用程序,該應用程序使用JPA從關系數據庫中檢索數據,并將其顯示為OpenMap的層。 我們看到了如何使用NetBeans Lookup API將視圖與控制器松散耦合。

    您應該已經對如何開發此類應用程序有所了解,但是請不要在實際的特別是關鍵的應用程序中使用此代碼。 代碼是錯誤的,既不高效也不是線程安全的(例如,有關如何從不同線程中的數據庫檢索數據的信息,請參見com.bbn.openmap.layer.location.LayerLocationLayer )。

    您還可以使用其他技術來替換各個層,例如:

    • 用純Java 8 lambda框架替換JPA來訪問數據庫( Speedment )
    • 使用DukeScript將JPA粘合到您的視圖

    例如,由于您的視圖依賴于IDBManager而不是特定的實現(例如JPA的EntityManager ),因此它不受模型的任何更改的影響(只要Supplier和IDBManager的方法不變)。 然后,您可以將JPA替換為Speedment,而無需更改視圖。

    如果時間和空間允許,我們可能會在以后的文章中進行調查。

    參考資料

  • OpenMap開發人員指南
  • OpenMap開發人員提示
  • 鮑爾等 等 (2016),《 Java Persistence with Hibernate》 ,第二版,Manning。
  • Coehlo H.,Kiourtzoglou B., Java持久性API迷你書 , JavaCodeGeeks 。
  • Epple T.(2009),“ NetBeans查找說明!”, DZone
  • Epple T.(2016),“ JPA和Dukescript ”
  • Goncalves A.(2013年),《 Java EE 7入門》,Apress。
  • Keith M.和Schincariol M.(2013), Pro JPA 2 –精通Java?Persistence API ,第二版,APress。
  • Kostaras I. 博客 ,“松耦合”

  • 翻譯自: https://www.javacodegeeks.com/2016/06/openmap-tutorial-5-3-tier-gis-application.html

    pcl_openmap

    總結

    以上是生活随笔為你收集整理的pcl_openmap_OpenMap教程5 – 3层GIS应用程序的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    91在线蜜桃臀| 免费视频一区 | 欧美日韩国产二区三区 | 九九久久精品 | 国精产品999国精产品视频 | 国产精品2区 | 久久欧美在线电影 | 久久人91精品久久久久久不卡 | 亚洲精品一区中文字幕乱码 | 日本成人黄色片 | 国产高清在线免费视频 | 伊色综合久久之综合久久 | 麻豆免费在线播放 | 久久久久久黄 | 成人禁用看黄a在线 | 天天干国产| 欧美aaa大片 | 夜夜干夜夜 | 国产精品第72页 | 国产精品福利av | 看国产黄色片 | 91精品小视频 | 国产麻豆精品在线观看 | 在线看片a| 婷婷色中文网 | 久久夜色精品国产欧美乱极品 | 亚洲国产精品久久久久婷婷884 | 欧美一区二区三区激情视频 | 国产成人精品一区二 | 日日日爽爽爽 | 亚洲经典精品 | 一区二区三区四区五区在线 | 日韩中字在线 | 国产一区av在线 | 粉嫩aⅴ一区二区三区 | 9ⅰ精品久久久久久久久中文字幕 | 高清av在线 | 国产玖玖在线 | 亚州天堂 | 天天做日日做天天爽视频免费 | 亚洲欧美精品在线 | 亚洲精品tv久久久久久久久久 | 久久99国产一区二区三区 | 国产成人高清av | 久久精品99国产国产精 | 久操伊人 | 亚洲精品午夜久久久久久久 | 97国产在线| 亚洲精品视频一二三 | 亚洲综合色视频 | 久久久美女 | 一级特黄av | 经典三级一区 | 黄色成品视频 | 激情五月网站 | 国产福利av | 欧美精品你懂的 | av中文字幕剧情 | 草久久影院 | 中文超碰字幕 | 91在线91拍拍在线91 | 亚洲国产精品va在线看 | 日本最新一区二区三区 | 九九免费视频 | 97超碰站 | 亚洲视频综合在线 | 美女国内精品自产拍在线播放 | 午夜av网站| 欧美一区二区三区在线 | 免费观看丰满少妇做爰 | 欧美日韩视频一区二区三区 | 懂色av懂色av粉嫩av分享吧 | 91超国产 | 一级免费黄色 | 日韩理论影院 | 国产91av视频在线观看 | 特级毛片网 | 玖玖国产精品视频 | 亚洲一级片免费观看 | 国产视频精品免费 | 久久伊99综合婷婷久久伊 | 日日夜夜天天久久 | 日本中文不卡 | 亚洲美女精品区人人人人 | 国产成人精品久 | 婷婷日日 | 五月综合激情婷婷 | 久久天天躁夜夜躁狠狠85麻豆 | 激情综合色综合久久 | av丝袜制服 | 粉嫩一二三区 | 最近最新最好看中文视频 | 国产精品久久久久久久久久久不卡 | 日韩欧美在线一区 | 中文字幕 影院 | 久久精品免费 | 国产亚洲精品日韩在线tv黄 | 日韩精品一区二区三区水蜜桃 | 91视频com | 欧美日韩二区在线 | 丁香六月婷婷激情 | 久久久久免费看 | 欧美精品中文 | 免费韩国av | 国偷自产中文字幕亚洲手机在线 | av日韩在线网站 | 不卡中文字幕av | 黄色小说网站在线 | 中文字幕一区二区三区四区久久 | 欧美日韩中文字幕在线视频 | 一本一道久久a久久精品 | 亚洲激情影院 | 亚洲国产成人久久 | 天天操夜| 欧美大码xxxx| 99色国产 | 伊人资源视频在线 | 日韩在线视频观看免费 | 超级av在线 | 国产精美视频 | 福利区在线观看 | 亚洲黄色免费 | 久久精品在线视频 | 欧美性色综合网站 | 91理论电影| 国产精品久久久久av福利动漫 | 日韩av片免费在线观看 | 色婷婷免费视频 | 天天射天天干天天插 | 日韩欧美高清一区二区 | 日韩久久精品一区 | 99精品亚洲 | 在线观看www视频 | 91九色蝌蚪视频在线 | 亚洲一区二区视频在线 | 五月天婷婷狠狠 | 国产精品嫩草在线 | 97超碰在线播放 | 福利视频第一页 | 五月网婷婷 | 色在线最新| 奇米影视8888在线观看大全免费 | 免费日韩高清 | 亚洲成av人片一区二区梦乃 | 中文字幕日本在线观看 | 久久噜噜少妇网站 | 一区二区精品在线视频 | 久久精品日本啪啪涩涩 | 国产精品视频全国免费观看 | 久久国产精品视频免费看 | 在线视频 国产 日韩 | 99热播精品 | 中文字幕成人一区 | 在线观看韩国av | va视频在线 | 免费观看一区二区三区视频 | 日本九九视频 | 亚洲欧洲xxxx| 久久久国产精品亚洲一区 | 在线观看网站你懂的 | 在线观看日韩一区 | 免费色视频 | 97超碰在 | 国产一区免费观看 | 中文字幕中文字幕在线一区 | 在线电影日韩 | 一区二区三区高清在线 | 97色狠狠| 久草视频在线播放 | 五月婷婷一区 | 亚洲在线免费视频 | 久久免费公开视频 | 欧美在线18| 91九色自拍| 97超碰网| 综合网欧美 | 狠狠色丁香九九婷婷综合五月 | 亚洲人久久| www.夜夜干.com | 久久福利综合 | 五月天综合激情网 | 亚洲成人黄色在线观看 | 久久久官网 | 中文在线字幕免 | 国产精品欧美精品 | 久久精品视频免费 | 日韩在线不卡视频 | 久久网站免费 | 最新国产在线视频 | 成人在线播放免费观看 | 91色影院| 精品国产一区二区三区在线 | 欧美乱淫视频 | 韩日三级在线 | 黄色一级大片在线免费看国产一 | av成人在线电影 | 美女视频久久 | 免费日韩一区二区三区 | 天天做天天爱天天综合网 | 中文日韩在线 | 久久字幕 | 在线观看色网站 | 日本精品一 | 国产一区二区三区黄 | 亚洲精品裸体 | 亚洲男男gaygay无套同网址 | 日本精品久久久一区二区三区 | 国产一区国产二区在线观看 | 欧美性色综合网站 | 五月婷婷激情网 | 久久久久久国产一区二区三区 | 国产精品免费在线 | 中文字幕免费高 | 国产一区二区在线免费视频 | 成人午夜影院在线观看 | 中文字幕免费高清在线 | 国产日产精品一区二区三区四区的观看方式 | 亚洲欧美成人 | 亚洲乱码中文字幕综合 | 深夜免费福利视频 | 日韩欧美视频在线 | 黄色免费网战 | 久久1区 | 少妇bbbb揉bbbb日本 | 亚洲免费精品视频 | 深夜男人影院 | 天天拍天天操 | 日韩黄色免费电影 | 久久久精品视频网站 | 久久9精品| 超碰人人av| 一区 二区电影免费在线观看 | 91在线观看视频网站 | 丁香免费视频 | 在线亚洲成人 | 亚洲免费不卡 | 精品久久久免费视频 | 成人a免费看 | 五月婷婷伊人网 | 国产黄大片 | 一区二区三区不卡在线 | 97在线播放视频 | www.看片网站 | 日本中文字幕在线观看 | 免费h视频 | 亚洲黄色av| 久久av中文字幕片 | 久久久久免费网站 | 成人蜜桃视频 | 欧美极品xxx| 欧美精品国产精品 | 国产看片网站 | 免费视频二区 | 一区二区视频在线观看免费 | 中文字幕中文字幕中文字幕 | 久久久久国产a免费观看rela | 首页中文字幕 | 天天天天天操 | 欧美精品一区二区在线播放 | 日韩网站视频 | 国产精品丝袜久久久久久久不卡 | 97在线观看免费高清完整版在线观看 | 天天拍天天操 | 午夜精品视频一区 | 一区二区三区精品在线视频 | 中文字幕一区av | av免费在线看网站 | 精品99免费 | 日韩精品国产一区 | 四虎成人免费观看 | 91免费版成人 | 欧美日韩国产二区 | 久草香蕉在线 | 亚洲国产成人精品在线观看 | 黄色一级大片免费看 | 成年人在线播放视频 | 午夜精品久久久久 | 国产精品精品 | 久久免费精品一区二区三区 | 在线探花| 国产精品18久久久 | 2021av在线| 91成人在线看 | 国产一区二区三区高清播放 | 色综合久久中文字幕综合网 | 2023年中文无字幕文字 | 最新色视频 | 男女靠逼app| 狠狠88综合久久久久综合网 | 人人射人人澡 | 五月激情五月激情 | 国产一区在线视频播放 | 天天舔天天射天天操 | 日本激情动作片免费看 | 91mv.cool在线观看 | 啪啪午夜免费 | 国产91勾搭技师精品 | 国产精品久久久久久久久久久久午夜 | 91在线观看高清 | 色网址99 | 中文字幕免费在线看 | 一级c片| av片中文字幕 | 亚洲欧美日韩一区二区三区在线观看 | 日韩精品1区2区 | 激情久久婷婷 | 国产在线传媒 | 福利av影院 | 日韩激情片在线观看 | 91大神精品视频在线观看 | 婷婷国产一区二区三区 | 中文字幕精品一区二区三区电影 | 97超碰在线久草超碰在线观看 | 久久精品中文字幕少妇 | 丁香花在线视频观看免费 | 精品国产1区二区 | 亚洲国产精品女人久久久 | 激情动态 | 久久精品久久综合 | 久久精品一区 | 欧美国产日韩中文 | 久久精品婷婷 | 日日操日日插 | 亚洲综合成人专区片 | 九九欧美视频 | 国产高清在线一区 | 久热免费在线观看 | 在线观看中文 | 免费看毛片在线 | 91大神免费在线观看 | 国产最顶级的黄色片在线免费观看 | 国产99精品在线观看 | 久久 在线 | 四虎成人免费观看 | 国产成人精品一区二区三区福利 | 免费看成人av | 在线播放av网址 | 天天·日日日干 | 岛国大片免费视频 | 在线看小早川怜子av | 一区精品久久 | 日本在线观看一区 | 黄av免费在线观看 | 久久精品视频一 | 在线亚洲欧美视频 | 黄色片网站免费 | 丰满少妇高潮在线观看 | 日韩三级在线观看 | 亚洲激精日韩激精欧美精品 | 5月丁香婷婷综合 | 亚洲精品色婷婷 | 高清国产在线一区 | 婷婷视频在线观看 | 免费视频区 | 国产中文| 在线一区观看 | 五月天色婷婷丁香 | 国产破处在线视频 | 丁香婷婷综合色啪 | 免费看黄色小说的网站 | av电影免费在线看 | 丁香婷婷综合激情五月色 | 欧美伦理一区 | 日韩av一区二区三区在线观看 | 日韩色中色 | www.黄色网.com | 超碰在线人人艹 | 黄色一级免费网站 | 精品亚洲午夜久久久久91 | 欧美最新另类人妖 | 亚洲精品视频在线观看免费 | 日韩精品久久中文字幕 | 国内精品久久久久影院优 | 91九色视频国产 | 久久久久久久久久电影 | 天操夜夜操 | 欧美一区三区四区 | 91亚洲激情 | 国产在线观看污片 | 日韩av一区二区在线 | 美女视频是黄的免费观看 | 日韩高清一区 | 狠狠婷婷 | 色爽网站 | 欧美aaa视频 | 伊人天堂网 | 国产成人精品一区二区三区在线观看 | 亚洲精品999 | 久久精品美女 | 天天色天天射天天综合网 | 人人讲| 天天干夜夜想 | 亚州精品国产 | 综合色中文 | 国产成人av一区二区三区在线观看 | 亚洲人成网站精品片在线观看 | 亚洲成人av电影 | 亚洲黄色成人 | 五月的婷婷 | 不卡日韩av| 蜜桃传媒一区二区 | 国产精品中文在线 | 91av视频免费观看 | 精品国产一区在线观看 | 国产精品嫩草69影院 | 国产精品久久久久久爽爽爽 | 2021国产视频| 午夜视频在线观看一区二区三区 | 国内视频在线 | 亚洲精品视频在线播放 | 免费av小说 | 国产最新91 | 91麻豆精品 | 精品一区二三区 | 亚洲国产精品99久久久久久久久 | 午夜视频黄 | 最新日韩在线观看视频 | 国产日本亚洲 | 欧美91精品 | www.狠狠操| japanesexxxhd奶水 国产一区二区在线免费观看 | 免费看一级黄色大全 | 97在线资源| 91香蕉久久 | 三级av中文字幕 | 亚洲国产99| 在线观看免费福利 | 亚洲高清视频在线观看免费 | 国产精品久久久久影院 | 婷婷在线五月 | 日韩电影中文字幕在线 | 精品国产一区二区在线 | 亚洲精品国产自产拍在线观看 | 99这里只有精品99 | 亚洲三区在线 | 在线观看蜜桃视频 | 99久久久国产精品免费99 | 亚洲激情| 婷婷六月综合亚洲 | 成人cosplay福利网站 | 免费av成人在线 | 综合久久久久久久 | 国产精品初高中精品久久 | 黄色免费大全 | 色先锋av资源中文字幕 | 日韩免费中文 | 最新国产福利 | 狠狠躁日日躁夜夜躁av | 日日夜夜狠狠操 | 色综合五月 | 天堂av高清| 99精品国产免费久久久久久下载 | 久久久久亚洲精品中文字幕 | 99久久久国产精品免费99 | 美女网站黄在线观看 | 国产精品网红直播 | 国产视频在线观看一区 | 久久日本视频 | 天天射狠狠干 | 久久久色 | 久久高清免费观看 | 97色国产| 悠悠av资源片 | 日本中文字幕网 | 欧美一级日韩三级 | 黄网站污 | 激情五月***国产精品 | 欧美日本日韩aⅴ在线视频 插插插色综合 | 制服丝袜亚洲 | 欧美另类视频 | 成人精品99 | 久久精品9 | 日p视频在线观看 | 在线观看视频日韩 | 婷婷五情天综123 | 色吧av色av | 黄色aa久久| 欧美精品在线一区 | 亚洲国产精品成人综合 | 99国产精品| 国产精品高潮呻吟久久久久 | 国产精品一区二区三区久久久 | 欧美激情另类 | 久久国产经典视频 | 五月天激情视频在线观看 | av电影免费在线看 | 国产99久久久精品 | 96国产在线 | 91九色视频导航 | 亚洲精品视频免费在线观看 | 日韩免费电影网站 | 国产第一福利 | 国产艹b视频 | 欧美日韩在线免费视频 | 五月在线| 91麻豆视频网站 | 国产精品欧美一区二区三区不卡 | 成人在线视频论坛 | 粉嫩av一区二区三区四区五区 | 国产做a爱一级久久 | 天天干天天操天天干 | 国产在线观看你懂得 | 亚洲综合狠狠干 | 国产手机在线精品 | 日韩一二三在线 | 黄色免费av| v片在线看 | 黄色日本免费 | 丁香久久 | 久久精品视频中文字幕 | 视频在线观看入口黄最新永久免费国产 | 丝袜美腿在线 | 久久精品视频免费 | 国产网站av | 国产免费久久av | 久久精品综合视频 | 色搞搞 | 中文字幕 国产精品 | 成年人app网址 | 国产99久久精品 | 久久精品牌麻豆国产大山 | 人人射av | 国产亚洲精品精品精品 | 天天爽天天搞 | 久草www| 国产香蕉久久精品综合网 | 亚洲欧美视频 | 欧美日韩xxx| 91精品久久久久久久久 | 亚洲成av人影片在线观看 | 激情av网| 亚洲va天堂va欧美ⅴa在线 | 国产精品成人一区二区 | 亚洲国产中文在线 | 五月婷婷激情网 | 最近最新最好看中文视频 | 激情丁香综合 | 欧美成人tv | 国产精品麻豆视频 | 亚洲欧美国内爽妇网 | 欧美一级黄大片 | 久久av伊人 | 91亚洲永久精品 | 热久久视久久精品18亚洲精品 | 亚洲在线a | 久久99热精品这里久久精品 | 一区二区三区在线不卡 | 最新日韩精品 | 国产黄色片免费观看 | 91精品免费在线观看 | 91视频免费看网站 | 久久美女精品 | 免费观看成人av | 国产黄色免费看 | 日韩精品中文字幕在线观看 | 婷婷免费视频 | 久久免费视频国产 | 久久久免费观看视频 | 九九激情视频 | 99久久精品费精品 | 黄色a级片在线观看 | 精品国产成人在线影院 | 亚洲在线不卡 | www操操操 | 日本黄网站| 亚洲精品美女 | 日韩黄色免费看 | 亚洲一区视频免费观看 | 激情av五月婷婷 | 91久久爱热色涩涩 | 国产成人久久av免费高清密臂 | 午夜国产一区 | 婷婷午夜天 | 伊人久久国产精品 | 免费美女久久99 | 欧美乱熟臀69xxxxxx | 公开超碰在线 | 日韩在线高清 | 黄a网 | 99riav1国产精品视频 | 五月婷婷导航 | 夜夜躁狠狠燥 | 福利视频午夜 | 91在线观| 午夜视频亚洲 | 亚洲 欧美日韩 国产 中文 | 免费看一级黄色大全 | 国产高清视频网 | 国产又粗又猛又黄又爽的视频 | 国产精品视频最多的网站 | 久久婷婷五月综合色丁香 | 国产精品白丝av | 美女免费网视频 | 久久久免费国产 | 久久久久女人精品毛片九一 | 欧美福利网站 | 日韩欧美一区二区三区视频 | 午夜精品久久久久久久久久久 | 又污又黄的网站 | 国产盗摄精品一区二区 | 天天操天天操天天爽 | 欧美一级在线观看视频 | 久久福利电影 | 国产老太婆免费交性大片 | 国产一区二区三区高清播放 | 日韩啪啪小视频 | 99在线高清视频在线播放 | 中文字幕日本特黄aa毛片 | 香蕉久久久久久久 | 一区二区三区福利 | avwww在线观看| 日本性高潮视频 | 激情五月在线视频 | 99久久综合精品五月天 | 成年人免费看av | 国产精彩在线视频 | a级成人毛片 | 欧美午夜精品久久久久 | 国产成人无码AⅤ片在线观 日韩av不卡在线 | 激情婷婷久久 | 国产91学生粉嫩喷水 | 免费午夜视频在线观看 | 欧美一区二区三区特黄 | 手机av在线不卡 | 国产一区高清在线 | 久久久网站 | 伊人亚洲综合网 | 亚洲欧美视频网站 | 最近更新中文字幕 | 天天噜天天色 | 国产日韩在线视频 | 国产午夜影院 | 国产黄色大片免费看 | 婷婷在线免费视频 | 99久热在线精品 | 国产一级二级在线观看 | 伊人五月综合 | 人人干天天射 | 国产一区二区高清视频 | 97在线观看免费高清 | 久久99精品国产91久久来源 | 91av在线电影 | 亚洲精品乱码久久久久 | 一区二区伦理 | 国内小视频 | 超碰在线99| 久久国产精品免费观看 | 在线电影日韩 | a国产精品 | 黄色大片网 | 亚洲黄色三级 | 久久久久欧美精品999 | 91香蕉视频在线下载 | 久久一久久 | japanesexxxxfreehd乱熟 | 五月综合激情 | 国产日韩精品欧美 | 操操日 | 久久久久久久久久久免费视频 | 免费观看黄 | 天天天干天天天操 | 国产精品美女在线观看 | 亚洲国产中文字幕在线观看 | 久久久久精 | 日本超碰在线 | 久久蜜桃av | 在线观看激情av | 99热精品久久 | 日韩特黄av | 99精品电影| 97超碰国产精品女人人人爽 | 欧美aa级 | 久草新在线 | 午夜久久久影院 | 狠狠色丁香婷婷综合久小说久 | 日韩高清av在线 | 欧美日韩精品在线视频 | 精品av网站 | 久久久久女人精品毛片 | 国产精品 中文在线 | 五月天六月色 | 在线观看成人一级片 | 久久人网 | 国产打女人屁股调教97 | av一级免费 | 久久99久久久久 | 国产天天爽 | 久久99视频精品 | 91免费高清在线观看 | 国产黄色免费看 | 国产精品一区二区久久国产 | 免费看高清毛片 | 69人人| 久草在线这里只有精品 | 日韩一二三 | 九九热中文字幕 | 在线观看va | 欧美日本国产在线观看 | 亚洲激情小视频 | 国产在线资源 | 亚洲欧美视频在线 | 美女av免费看 | 99麻豆视频| 久久免费公开视频 | 亚洲国产三级 | 91黄色在线看 | 99c视频高清免费观看 | 在线观看视频一区二区三区 | 免费观看午夜视频 | 欧美激情第十页 | 337p日本欧洲亚洲大胆裸体艺术 | 久久dvd | 日韩欧美在线国产 | av高清影院 | 亚洲精品国产区 | 国产一级免费观看 | 国产精品一区免费在线观看 | 精品视频免费播放 | 国产一级免费在线观看 | av免费福利 | 国产免费不卡 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | av超碰在线 | 久久免费公开视频 | 成人久久久久久久久久 | 久久精品直播 | 在线成人国产 | 久草在线观看资源 | 一本到视频在线观看 | 国产高清成人 | 91精品在线免费 | 亚洲dvd | 91探花国产综合在线精品 | 五月婷婷在线观看视频 | 最新中文字幕在线播放 | 欧美va天堂va视频va在线 | 在线观看91精品视频 | 久久一久久| 久草在线免费看视频 | 亚洲综合成人av | 日韩精品视频在线免费观看 | 色在线最新 | 国产精品一区免费观看 | 免费网站色 | 欧洲亚洲女同hd | 国产免费黄视频在线观看 | 91av短视频 | 久久久国产精品电影 | 欧日韩在线视频 | 国产精品毛片久久久久久 | 爱干视频 | 欧美极品xxx | 伊人午夜 | 欧美成a人片在线观看久 | av网站免费线看精品 | av资源网在线播放 | av在线一二三区 | av在线等| 亚洲专区在线播放 | 91av色| 国产精品免费在线观看视频 | 人人澡人 | 日本三级中文字幕在线观看 | 91色一区二区三区 | 91爱爱免费观看 | 国产精品午夜久久久久久99热 | 色婷婷国产在线 | 中文在线a在线 | 精品久久99 | 精品久久久国产 | 偷拍精偷拍精品欧洲亚洲网站 | 国产一级久久 | 精品国产一区二区三区噜噜噜 | 婷婷色5月 | 亚洲欧洲日韩在线观看 | 久久久久久久久久久国产精品 | 中文字幕在线观看免费高清完整版 | 成年人视频在线免费观看 | 999国内精品永久免费视频 | a亚洲视频 | 人人爽人人av | 精品一二三四在线 | 欧美做受xxx| 国产a网站| 午夜av日韩 | 亚洲视频网站在线观看 | 欧美亚洲xxx | 国产黄色大片免费看 | 日韩精品欧美精品 | 国产精品久久久久久一区二区三区 | 欧美孕交vivoestv另类 | 亚洲一二三久久 | 久久蜜臀一区二区三区av | 成人a级网站 | 久久久三级视频 | 欧美aaa大片 | 久久久久这里只有精品 | 亚洲成a人片综合在线 | 曰本三级在线 | 一区三区视频在线观看 | 九九视频免费观看视频精品 | 欧洲在线免费视频 | 久久99精品久久久久久秒播蜜臀 | 黄a在线观看 | 日韩国产欧美在线播放 | 亚洲精品9| 99精品国产兔费观看久久99 | 成人污视频在线观看 | www激情com| 国产免费成人 | 干 操 插 | 久久在线免费观看 | 久久精品亚洲综合专区 | 天天插天天爱 | 狠狠躁夜夜a产精品视频 | 久久影院精品 | 国产精品综合久久久久 | 久久伊人色综合 | 九九热在线视频免费观看 | 97韩国电影 | 在线黄色av电影 | 在线精品视频免费播放 | 超碰在线最新地址 | 中文av字幕在线观看 | 中文字幕在线播放日韩 | 亚洲精品午夜久久久久久久 | 日韩一区二区三区在线看 | 在线观看黄 | 亚洲最新av在线网址 | 久久成人精品电影 | 国产高清免费视频 | 久久日韩精品 | 国产日韩欧美自拍 | 人人澡av | 精品99999| 亚洲综合国产精品 | 国产精品大片免费观看 | 在线精品在线 | 在线国产一区二区 | av在线播放网址 | 色综久久| 久久亚洲私人国产精品va | 国产又黄又猛又粗 | 久久www免费人成看片高清 | 麻豆视频在线观看 | 日韩在线观看一区二区 | 日本中文一级片 | 99爱在线观看 | 精品欧美一区二区在线观看 | 毛片播放网站 | 亚洲精品乱码久久久久久高潮 | 久久久免费 | 久久看片| av综合站| 一 级 黄 色 片免费看的 | 国产精品乱码久久久久 | 欧美成人一区二区 | 国产精品欧美一区二区三区不卡 | 狠狠狠狠狠狠干 | 色久网| 日韩精品中文字幕在线不卡尤物 | 高清一区二区三区av | 久久av一区二区三区亚洲 | 九九九免费视频 | 久久久精品国产一区二区三区 | 中文字幕乱码日本亚洲一区二区 | 黄色影院在线播放 | 国产视频1 | 国产精品s色 | 日韩一区二区三区不卡 | 中文字幕在线国产 | 久久视频在线看 | 黄色一级大片免费看 | 97av超碰 | 最新av免费 | 久久理论影院 | 超黄视频网站 | 88av网站| 在线导航福利 | 激情喷水 | 久久欧美在线电影 | 免费看一级片 | 在线观看色视频 | 国产精品视频app | 久久视影 | 日日爽 | 蜜臀av麻豆 | 九九爱免费视频 | 亚洲理论片 | www91在线观看 | 2019中文最近的2019中文在线 | 97精品视频在线 | 亚洲欧美日本一区二区三区 | 久久天天躁狠狠躁夜夜不卡公司 | 超碰com| 性色av一区二区 | 五月婷婷影院 | 久草在线免费在线观看 | 狠狠激情中文字幕 | 中日韩免费视频 | 五月视频 | 中文字幕成人在线观看 | 久久精品日产第一区二区三区乱码 | 欧美一二区视频 | 精品国产一区二区三区蜜臀 | www.色午夜 | 五月婷婷丁香综合 | 国产午夜剧场 | av大全在线播放 | 日韩av手机在线观看 | 日韩欧美国产激情在线播放 | 久久久久久久久久伊人 | 久久 一区| 日韩精品在线免费播放 | 808电影免费观看三年 | 日本在线中文 | www夜夜| 狠狠躁夜夜躁人人爽超碰91 | 国产香蕉视频 | 黄色一集片 | 久草91视频| 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 欧美激情在线看 | 美女黄频在线观看 | 人人草人人草 | 天天天干夜夜夜操 | 亚洲成av人电影 | 丁香久久久 | 在线观看亚洲视频 | 国产高清在线视频 | 久久高清视频免费 | 国产资源精品在线观看 | 久久久免费毛片 | 久久综合中文字幕 | 国产精品久久久影视 | 日韩免费电影一区二区三区 | 黄色三级免费 | 亚洲理论视频 | 国产精品久久久久久69 | 99激情网| 国产拍在线 | 亚洲波多野结衣 | 午夜精品一区二区三区视频免费看 | 国产中文字幕在线播放 | 福利一区二区 | 观看免费av| 玖玖在线资源 | 日韩xxx视频 | 久草在线中文视频 | 三上悠亚一区二区在线观看 | 一级黄色在线视频 | 中文字幕九九 | 国产精品免费在线视频 | 深爱婷婷激情 | 日韩有码第一页 | 91精品办公室少妇高潮对白 | 天天五月天色 | 久久综合九色综合97_ 久久久 | 成人a级大片 | 香蕉影视 | 蜜桃视频日韩 | 精品天堂av| 日韩欧美综合精品 | 色综合网| 中文字幕在线日亚洲9 | 狠狠干天天色 | 久草视频在线观 | 免费成人在线视频网站 | 欧美巨乳网 | 色六月婷婷| 日韩精品播放 | 国产1区2| 深夜免费福利在线 | 久久久久成人精品亚洲国产 | 国产一区免费观看 | 久久久久国产精品午夜一区 | 激情视频91 | 欧美肥妇free | 久久大香线蕉app | 成人av av在线 | 九九99 | 毛片美女网站 | 在线观看国产麻豆 | 亚洲春色综合另类校园电影 | 欧美精品乱码久久久久久按摩 | 欧美精品生活片 | 日本黄色免费网站 | 成年人av在线播放 | 亚洲综合色视频 | 91在线视频播放 | 国内亚洲精品 | 国产一区精品在线观看 | 日本精品二区 | 一级欧美黄 | 欧美精品久久久久久久久免 | 国产偷v国产偷∨精品视频 在线草 | 久久精品毛片 | 91视频在线免费 |