Java Struts2

Struts2 Autocomplete with Database using jQuery UI

Struts2 Autocomplete with Database using jQuery UI

This tutorial implements a live autocomplete search box in a Struts2 application backed by a MySQL database. When the user types, jQuery UI Autocomplete sends an AJAX request to a Struts2 action that queries the database and returns matching suggestions as JSON. This is the modern approach — the original <s:autocompleter> tag used the deprecated Dojo-based Struts2 AJAX plugin and should no longer be used.

How It Works

User types 3+ characters
    ↓
jQuery UI Autocomplete sends GET /suggest?term=Mah
    ↓
Struts2 SuggestAction.execute()
    ↓
DAO: SELECT name FROM state WHERE name LIKE 'Mah%'
    ↓
Action serializes List<String> to JSON
    ↓
jQuery UI renders dropdown of matching suggestions

MySQL Table

CREATE TABLE state (
    id   INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL
);

INSERT INTO state (name) VALUES
    ('Andhra Pradesh'), ('Arunachal Pradesh'), ('Assam'),
    ('Bihar'), ('Chhattisgarh'), ('Goa'), ('Gujarat'),
    ('Haryana'), ('Himachal Pradesh'), ('Jharkhand'),
    ('Karnataka'), ('Kerala'), ('Madhya Pradesh'),
    ('Maharashtra'), ('Manipur'), ('Meghalaya'), ('Mizoram'),
    ('Nagaland'), ('Odisha'), ('Punjab'), ('Rajasthan'),
    ('Sikkim'), ('Tamil Nadu'), ('Telangana'), ('Tripura'),
    ('Uttar Pradesh'), ('Uttarakhand'), ('West Bengal');

Maven Dependencies (pom.xml)

<dependencies>
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts2-core</artifactId>
        <version>2.5.33</version>
    </dependency>

    <!-- struts2-json-plugin converts action fields to JSON automatically -->
    <dependency>
        <groupId>org.apache.struts</groupId>
        <artifactId>struts2-json-plugin</artifactId>
        <version>2.5.33</version>
    </dependency>

    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.3.0</version>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

StateDAO.java

package com.java9r.dao;

import com.java9r.db.DBConnection;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class StateDAO {

    public List<String> searchByPrefix(String prefix) {
        List<String> results = new ArrayList<>();
        String sql = "SELECT name FROM state WHERE name LIKE ? ORDER BY name LIMIT 10";

        try (Connection con = DBConnection.getConnection();
             PreparedStatement ps = con.prepareStatement(sql)) {

            ps.setString(1, prefix + "%");   // starts-with match
            ResultSet rs = ps.executeQuery();

            while (rs.next()) {
                results.add(rs.getString("name"));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
        return results;
    }
}

SuggestAction.java

The action extends ActionSupport and returns a List<String> field. The JSON plugin serializes all getter fields to JSON automatically — so getSuggestions() becomes {"suggestions":["Maharashtra","Manipur"]}.

package com.java9r.action;

import com.java9r.dao.StateDAO;
import com.opensymphony.xwork2.ActionSupport;

import java.util.Collections;
import java.util.List;

public class SuggestAction extends ActionSupport {

    private static final long serialVersionUID = 1L;

    private String       term;         // jQuery UI sends "term" as the parameter name
    private List<String> suggestions = Collections.emptyList();

    private final StateDAO dao = new StateDAO();

    @Override
    public String execute() {
        if (term != null && term.length() >= 1) {
            suggestions = dao.searchByPrefix(term.trim());
        }
        return SUCCESS;
    }

    public String       getTerm()        { return term;        }
    public List<String> getSuggestions() { return suggestions; }

    public void setTerm(String term) { this.term = term; }
}

struts.xml

The suggest action uses the json package (from struts2-json-plugin) instead of struts-default. The type="json" result serializes the action's fields to a JSON response.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
    "http://struts.apache.org/dtds/struts-2.5.dtd">

<struts>
    <constant name="struts.devMode" value="false"/>

    <package name="default" namespace="/" extends="struts-default">
        <!-- Main page -->
        <action name="index">
            <result>/index.jsp</result>
        </action>
    </package>

    <!-- JSON package — extends json-default, not struts-default -->
    <package name="json" namespace="/" extends="json-default">

        <action name="suggest"
                class="com.java9r.action.SuggestAction">

            <result type="json">
                <!-- Only serialize the "suggestions" field — skip other getters -->
                <param name="includeProperties">suggestions.*</param>
            </result>

        </action>

    </package>
</struts>

index.jsp – Autocomplete Page

jQuery UI Autocomplete uses the source option with a function that receives the typed term and a response callback. The function calls the Struts2 action via AJAX and passes the matching suggestions to the callback.

<%@ page contentType="text/html; charset=UTF-8" %>
<!DOCTYPE html>
<html>
<head>
    <title>State Autocomplete</title>

    <!-- jQuery UI CSS -->
    <link rel="stylesheet"
          href="https://code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">

    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
</head>
<body>
<div class="container mt-5">

    <h3>Struts2 Autocomplete – Select a State</h3>
    <hr>

    <div class="col-md-4">
        <label for="stateName">State Name:</label>
        <input type="text" id="stateName" class="form-control"
               placeholder="Start typing...">

        <div class="mt-3" id="selectedValue"></div>
    </div>

</div>

<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
<script>
    $('#stateName').autocomplete({

        minLength: 1,   // start suggesting after 1 character

        // source: function — called on each keystroke
        source: function (request, response) {
            $.ajax({
                url: 'suggest',
                dataType: 'json',
                data: { term: request.term },   // "term" is the typed text
                success: function (data) {
                    // data.suggestions is the List<String> from SuggestAction
                    response(data.suggestions);
                },
                error: function () {
                    response([]);   // show nothing if request fails
                }
            });
        },

        // Called when user selects an item from the dropdown
        select: function (event, ui) {
            $('#selectedValue').html('Selected: <strong>' + ui.item.value + '</strong>');
        }
    });
</script>
</body>
</html>

How the JSON Response Looks

// GET /suggest?term=Mah
// Response:
{
    "suggestions": [
        "Madhya Pradesh",
        "Maharashtra"
    ]
}

jQuery UI Autocomplete accepts a plain array of strings for its response() callback. data.suggestions is exactly that — the serialized List<String> from the action.

Old Approach vs New Approach

Feature Old: <s:autocompleter> New: jQuery UI + JSON action
Plugin required struts2-dojo-plugin (deprecated, unmaintained) struts2-json-plugin (maintained)
UI library Dojo Toolkit (very old) jQuery UI (widely used, documented)
Customization Limited — only Dojo widget options Full control — any jQuery UI option
Response format Struts2 proprietary Standard JSON
Still works in Struts2 2.5+ No — dojo plugin removed from core Yes

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>
            org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

Summary

Struts2 autocomplete with a database has two parts: a Struts2 action that uses the JSON plugin to return a List<String> as JSON, and a jQuery UI Autocomplete widget on the front end that calls that action via AJAX and renders the dropdown. The term parameter is sent automatically by jQuery UI — the action simply reads it, queries the database with a LIKE prefix% search using PreparedStatement, and returns the results. The includeProperties parameter in struts.xml restricts the JSON output to only the suggestions field, avoiding the serialization of unintended action fields.

Topics: Java Struts2
← Newer Post Older Post →

Comments

https://www.blogger.com/comment/frame/6690124484600543990?po=5131990432793109495&hl=en&saa=85391&origin=https://www.java9r.com