JavaGeoTools-Query Tutorial

Table of Contents

  • Introduction
  • Query
    • dependency import
    • code writing

Introduction

In the process of geographic data processing, querying and filtering data is a very common task. Of course, GeoTools also integrates tools for querying and filtering geographic data. This section will mainly talk about it

Query

Dependency import

First, import the dependencies

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <geotools.version>30-SNAPSHOT</geotools.version>
    </properties>
    <dependencies>
        <!-- Provides map projections -->
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-epsg-hsql</artifactId>
            <version>${<!-- -->geotools.version}</version>
        </dependency>
        <!-- Provides support for PostGIS. Note the different groupId -->
        <dependency>
            <groupId>org.geotools.jdbc</groupId>
            <artifactId>gt-jdbc-postgis</artifactId>
            <version>${<!-- -->geotools.version}</version>
        </dependency>
        <!-- Provides support for shapefiles -->
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-shapefile</artifactId>
            <version>${<!-- -->geotools.version}</version>
        </dependency>
        <!-- Provides GUI components -->
        <dependency>
            <groupId>org.geotools</groupId>
            <artifactId>gt-swing</artifactId>
            <version>${<!-- -->geotools.version}</version>
        </dependency>
    </dependencies>
  <repositories>
    <repository>
      <id>osgeo</id>
      <name>OSGeo Release Repository</name>
      <url>https://repo.osgeo.org/repository/release/</url>
      <snapshots><enabled>false</enabled></snapshots>
      <releases><enabled>true</enabled></releases>
    </repository>
    <repository>
      <id>osgeo-snapshot</id>
      <name>OSGeo Snapshot Repository</name>
      <url>https://repo.osgeo.org/repository/snapshot/</url>
      <snapshots><enabled>true</enabled></snapshots>
      <releases><enabled>false</enabled></releases>
    </repository>
  </repositories>

Code writing

Still create a class, this time we directly inherit JFrame, making the class we are going to create a form frame

@SuppressWarnings("serial")
public class QueryLab extends JFrame {<!-- -->
    private DataStore dataStore;
    private JComboBox<String> featureTypeCBox;
    private JTable table;
    private JTextField text;

    public static void main(String[] args) throws Exception {<!-- -->
        JFrame frame = new QueryLab();
        frame. setVisible(true);
    }

Then complete the initialization of the form in the constructor of the class

 public QueryLab() {<!-- -->
        setDefaultCloseOperation(JFrame. EXIT_ON_CLOSE);
        getContentPane().setLayout(new BorderLayout());

        text = new JTextField(80);
        text.setText("include"); // include selects everything!
        getContentPane().add(text, BorderLayout.NORTH);

        table = new JTable();
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.setModel(new DefaultTableModel(5, 5));
        table.setPreferredScrollableViewportSize(new Dimension(500, 200));

        JScrollPane scrollPane = new JScrollPane(table);
        getContentPane().add(scrollPane, BorderLayout.CENTER);

        JMenuBar menubar = new JMenuBar();
        setJMenuBar(menubar);

        JMenu fileMenu = new JMenu("File");
        menubar. add(fileMenu);

        featureTypeCBox = new JComboBox<>();
        menubar.add(featureTypeCBox);

        JMenu dataMenu = new JMenu("Data");
        menubar. add(dataMenu);
        pack();

Here a table is added to the form to display the queried data, and a MenuBar and Menu are added to accommodate the function buttons
Next add functionality to the buttons in the menu bar

 fileMenu.add(
                new SafeAction("Open shapefile...") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        connect(new ShapefileDataStoreFactory());
                    }
                });
        fileMenu. add(
                new SafeAction("Connect to PostGIS database...") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        connect(new PostgisNGDataStoreFactory());
                    }
                });
        fileMenu. add(
                new SafeAction("Connect to DataStore...") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        connect(null);
                    }
                });
        fileMenu. addSeparator();
        fileMenu. add(
                new SafeAction("Exit") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        System. exit(0);
                    }
                });
 dataMenu. add(
                new SafeAction("Get features") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        filterFeatures();
                    }
                });
        dataMenu. add(
                new SafeAction("Count") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        countFeatures();
                    }
                });
        dataMenu. add(
                new SafeAction("Geometry") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        queryFeatures();
                    }
                });
}

Added function buttons for Data and File menus respectively
Let’s take a look at the content added to the File menu

 fileMenu.add(
                new SafeAction("Open shapefile...") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        connect(new ShapefileDataStoreFactory());
                    }
                });

The SafeAction here has been mentioned in the previous tutorial, which is equivalent to defining a behavior in which the connect method is called and an instance of ShapefileDataStoreFactory is passed in. This is for reading shapefiles.
Take a look at the content added to the Data menu

dataMenu.add(
                new SafeAction("Get features") {<!-- -->
                    public void action(ActionEvent e) throws Throwable {<!-- -->
                        filterFeatures();
                    }
                });

The same is SafeAction, the difference is that different methods are added to it.
The following connect method is implemented to complete the data link

 private void connect(DataStoreFactorySpi format) throws Exception {<!-- -->
        JDataStoreWizard wizard = new JDataStoreWizard(format);
        int result = wizard. showModalDialog();
        if (result == JWizard.FINISH) {<!-- -->
            Map<String, Object> connectionParameters = wizard. getConnectionParameters();
            dataStore = DataStoreFinder.getDataStore(connectionParameters);
            if (dataStore == null) {<!-- -->
                JOptionPane.showMessageDialog(null, "Could not connect - check parameters");
            }
            updateUI();
        }
    }

The data is linked here, and the dataStore, that is, the data, is obtained through the getDataStore method of the DataStoreFinder.
The updateUI method is to update the table after reading the database

 private void updateUI() throws Exception {<!-- -->
        ComboBoxModel<String> cbm = new DefaultComboBoxModel<>(dataStore. getTypeNames());
        featureTypeCBox.setModel(cbm);

        table.setModel(new DefaultTableModel(5, 5));
    }

Now that the data has been loaded into the table, the next step is to filter the data

 private void filterFeatures() throws Exception {<!-- -->
        String typeName = (String) featureTypeCBox. getSelectedItem();
        SimpleFeatureSource source = dataStore. getFeatureSource(typeName);

        Filter filter = CQL.toFilter(text.getText());
        SimpleFeatureCollection features = source. getFeatures(filter);
        FeatureCollectionTableModel model = new FeatureCollectionTableModel(features);
        table.setModel(model);
    }

Filter the selected typeName column in the data through the text entered in the text text box, use CQL’s tiFilter to get the filtered object, and then use the getFeatures method of SimpleFeatureSource to filter the data, and the filtered elements form a new SimpleFeatureCollection.
The following is to obtain the statistics of the number of filtered elements.

 String typeName = (String) featureTypeCBox.getSelectedItem();
        SimpleFeatureSource source = dataStore. getFeatureSource(typeName);

        Filter filter = CQL.toFilter(text.getText());
        SimpleFeatureCollection features = source. getFeatures(filter);

        int count = features. size();
        JOptionPane.showMessageDialog(text, "Number of selected features:" + count);
    }

In addition to filtering, of course you can also query

 private void queryFeatures() throws Exception {<!-- -->
        String typeName = (String) featureTypeCBox. getSelectedItem();
        SimpleFeatureSource source = dataStore. getFeatureSource(typeName);

        FeatureType schema = source. getSchema();
        String name = schema. getGeometryDescriptor(). getLocalName();

        Filter filter = CQL.toFilter(text.getText());

        Query query = new Query(typeName, filter, new String[] {<!-- -->name});

        SimpleFeatureCollection features = source. getFeatures(query);

        FeatureCollectionTableModel model = new FeatureCollectionTableModel(features);
        table.setModel(model);
    }

Use the Query object to implement query operations.