diff --git a/de/15.8/dev/webapp-plugin.rst b/de/15.8/dev/webapp-plugin.rst index 628acb35..b0e4a1d8 100644 --- a/de/15.8/dev/webapp-plugin.rst +++ b/de/15.8/dev/webapp-plugin.rst @@ -1,81 +1,337 @@ ================================== -WebApp-Plugin +Webanwendungs-Plugin ================================== Übersicht ========= -Mit WebApp-Plugins konnen Sie das Web-Interface von Fess erweitern. -Sie konnen neue Seiten hinzufugen, die Administrationsoberflache anpassen und mehr. +Webanwendungs-Plugins (``fess-webapp-*``) sind Plugins, die die Webanwendung +von |Fess| erweitern. Anders als andere Plugin-Typen fügen sie nicht direkt +Action-Klassen oder JSPs hinzu, sondern erweitern die Funktionalität, indem +sie dem DI-Container (Lasta Di) **Komponenten hinzufügen oder ersetzen**. +Typische Anwendungsfälle sind: + +- Hinzufügen neuer Komponenten (z. B. Helper, Services) +- Ersetzen von Komponenten des |Fess|-Kerns (durch Unterklassenbildung) +- Hinzufügen von REST-API-Endpunkten (``WebApiManager``) +- Erweiterung des Suchverhaltens (Query-Commands, Rank-Fusion usw.) + +.. note:: + + Webanwendungs-Plugins werden als JAR-Datei ausgeliefert; ihre Klassen und + DI-Konfigurationsdateien werden in den Klassenpfad der Webanwendung von + |Fess| geladen. Sie fügen keine JSP-Views hinzu. Wenn Sie das Design der + Suchoberfläche anpassen möchten, lesen Sie :doc:`theme-development`. Grundstruktur ============= +Am Beispiel von +`fess-webapp-example `__, +der Implementierungsvorlage für Webanwendungs-Plugins, besteht ein Plugin +aus einer „Implementierungsklasse" und einer „DI-Registrierungsdatei": + :: fess-webapp-example/ ├── pom.xml └── src/main/ - ├── java/org/codelibs/fess/app/web/example/ - │ └── ExampleAction.java - └── webapp/WEB-INF/view/example/ - └── index.jsp + ├── java/org/codelibs/fess/webapp/example/helper/ + │ ├── ExampleHelper.java # Hinzuzufügende Komponente + │ └── CustomSystemHelper.java # Ersetzen einer Kernkomponente + └── resources/ + ├── app++.xml # Hinzufügen einer Komponente (Merge) + └── fess+systemHelper.xml # Ersetzen einer Komponente + +.. note:: + + Das Paket der Implementierungsklasse folgt dem Schema + ``org.codelibs.fess.webapp.``. Die DI-Konfigurationsdateien + werden unter ``src/main/resources/`` abgelegt. Anders als bei + DataStore-Plugins enthält das Projekt kein ``src/main/webapp/`` und + keine JSPs. + +pom.xml und Manifest +==================== + +Webanwendungs-Plugins werden als jar mit ``fess-parent`` als übergeordnetem +POM gebaut. Bibliotheken wie ``fess`` und ``opensearch``, die zur Laufzeit +vom |Fess|-Kern bereitgestellt werden, werden mit dem Scope ``provided`` +deklariert. Zur Laufzeit benötigte Bibliotheken wie ``lastaflute``, +``dbflute-runtime`` und ``corelib`` werden mit dem normalen Scope +deklariert. + +Das Wichtigste bei einem Webanwendungs-Plugin ist, dem JAR-Manifest den +Eintrag ``Fess-WebAppJar: true`` hinzuzufügen. Durch diese Deklaration +mountet |Fess| die Klassen und DI-Konfigurationsdateien des Plugins in den +Klassenlader der Webanwendung. Diese Einstellung wird über +``maven-jar-plugin`` vorgenommen: + +.. code-block:: xml + + + + + maven-jar-plugin + + + + true + + + + + + + +.. warning:: + + Wird ``Fess-WebAppJar: true`` nicht gesetzt, werden die Klassen und + DI-Konfigurationsdateien des Plugins nicht in den Klassenpfad der + Webanwendung geladen, und das Hinzufügen bzw. Ersetzen von Komponenten + wird nicht wirksam. + +Den vollständigen Aufbau der pom.xml (übergeordnetes POM, Deklaration von +Abhängigkeiten usw.) finden Sie unter :doc:`plugin-architecture`. + +Erweiterungsmuster +================== + +Hinzufügen von Komponenten (app++.xml) +-------------------------------------- + +Die grundlegendste Erweiterungsmethode besteht darin, eigene Komponenten +hinzuzufügen. Lasta Di **merged** die ``app++.xml`` im Klassenpfad in den +``app``-Namensraum, der aus der ``app.xml`` des |Fess|-Kerns aufgebaut wird +(das ``++`` am Ende ist die Konvention für ein zusammenführendes Merge). +Da die hinzuzufügenden Komponenten Namen verwenden, die im |Fess|-Kern +nicht existieren, wird nichts überschrieben. + +.. code-block:: xml + + + + + + + + +Bei der Implementierung der Komponente wird für die Initialisierung +``@PostConstruct`` verwendet; Komponenten des |Fess|-Kerns werden über +``ComponentUtil`` abgerufen und wiederverwendet (nicht kopiert oder +überschrieben): + +.. code-block:: java + + package org.codelibs.fess.webapp.example.helper; + + import org.codelibs.fess.helper.SystemHelper; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + + public class ExampleHelper { + + protected String pluginName = "fess-webapp-example"; + + @PostConstruct + public void init() { + // Initialisierungslogik, die nach der Erzeugung durch DI einmalig aufgerufen wird + } + + public String getPluginLabel() { + // Wiederverwendung des Core-SystemHelper zum Ermitteln der laufenden Fess-Version + final SystemHelper systemHelper = ComponentUtil.getSystemHelper(); + final String version = systemHelper != null ? systemHelper.getProductVersion() : "unknown"; + return pluginName + " (Fess " + version + ")"; + } + } -Action-Implementierung -====================== +.. tip:: + + Ziehen Sie zunächst dieses „Hinzufügen von Komponenten" in Betracht. + Solange keine Kernfunktionen geändert werden müssen, ist dies sicherer + und besser wartbar als ein Ersetzen. + +Ersetzen von Kernkomponenten (fess+componentName.xml) +------------------------------------------------------ + +Wenn Sie das Verhalten einer Komponente des |Fess|-Kerns ändern möchten, +bilden Sie eine Unterklasse der Zielklasse und registrieren diese in einer +DI-Konfigurationsdatei mit dem Namen ``+.xml`` +**erneut unter demselben Komponentennamen**. Da ``systemHelper`` +beispielsweise in der ``fess.xml`` des |Fess|-Kerns deklariert ist, lautet +die Ersetzungsdatei ``fess+systemHelper.xml`` (nicht +``app+systemHelper.xml``). .. code-block:: java - package org.codelibs.fess.app.web.example; + package org.codelibs.fess.webapp.example.helper; + + import java.nio.file.Path; - import org.codelibs.fess.app.web.base.FessSearchAction; - import org.lastaflute.web.Execute; - import org.lastaflute.web.response.HtmlResponse; + import org.codelibs.fess.helper.SystemHelper; - public class ExampleAction extends FessSearchAction { + public class CustomSystemHelper extends SystemHelper { - @Execute - public HtmlResponse index() { - return asHtml(path_Example_IndexJsp); + @Override + protected void parseProjectProperties(final Path propPath) { + try { + super.parseProjectProperties(propPath); + } catch (final Exception e) { + // eigene Verarbeitung + } + System.setProperty("fess.webapp.plugin", "true"); } } -JSP-Template -============ +.. warning:: -``src/main/webapp/WEB-INF/view/example/index.jsp``: + Das Ersetzen (einzelnes ``+``) ersetzt die Komponentendefinition + **vollständig**. Aus diesem Grund müssen in der Ersetzungsdatei alle + ````-Einträge, die in der Kerndefinition vorhanden sind, + erneut angegeben werden. Wenn Sie beispielsweise ``systemHelper`` + ersetzen, müssen Sie die Zuordnung der Design-JSP-Namen + (``addDesignJspFileName``) vollständig aus der ``fess.xml`` des Kerns + kopieren und übernehmen. Diese müssen mit jedem |Fess|-Release + synchronisiert werden; fehlt ein Eintrag, können bestimmte Bildschirme + (z. B. ``chat`` / ``login``) nicht mehr aufgelöst werden. Dieser + Wartungsaufwand ist der Grund, warum das Hinzufügen dem Ersetzen + vorgezogen werden sollte. -.. code-block:: jsp +Hinzufügen einer REST-API (fess_api++.xml) +------------------------------------------- - <%@ page contentType="text/html; charset=UTF-8" %> - - - - Example Page - - -

Custom Page

-

This is a custom page added by plugin.

- - +Um einen neuen REST-API-Endpunkt hinzuzufügen, implementieren Sie +``WebApiManager``. Erben Sie von ``BaseApiManager`` und registrieren Sie +sich selbst in ``@PostConstruct`` bei der ``WebApiManagerFactory``. Der +registrierte API-Manager wird bei jeder Anfrage von ``WebApiFilter`` +aufgerufen. Registrieren Sie die Komponente in ``fess_api++.xml``: -API-Erweiterung -=============== +.. code-block:: xml + + + + + + + .. code-block:: java - public class ApiExampleAction extends FessApiAction { + package org.codelibs.fess.webapp.example.api; + + import java.io.IOException; + + import org.codelibs.fess.api.BaseApiManager; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + import jakarta.servlet.FilterChain; + import jakarta.servlet.ServletException; + import jakarta.servlet.http.HttpServletRequest; + import jakarta.servlet.http.HttpServletResponse; + + public class ExampleApiManager extends BaseApiManager { + + public ExampleApiManager() { + // Pfadpräfix, das von diesem Manager verarbeitet wird + setPathPrefix("/api/example"); + } + + @PostConstruct + public void register() { + ComponentUtil.getWebApiManagerFactory().add(this); + } + + @Override + public boolean matches(final HttpServletRequest request) { + // Prüft, ob dieser Manager die Anfrage verarbeiten soll + return request.getServletPath().startsWith(pathPrefix); + } + + @Override + public void process(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain chain) throws IOException, ServletException { + // Verarbeitung der Anfrage und Schreiben der Antwort + } - @Execute - public JsonResponse get$data() { - return asJson(new ApiResult.ApiResponse() - .result(Map.of("message", "Hello from plugin")) - .status(Status.OK)); + @Override + protected void writeHeaders(final HttpServletResponse response) { + // Setzen der Antwort-Header (bei Bedarf) } } +Als Implementierungsbeispiele bieten sich +`fess-webapp-v1-api `__, +das ``/api/v1`` bereitstellt, sowie +`fess-webapp-classic-api `__, +das ``/json`` / ``/suggest`` bereitstellt, als Referenz an. + +Anpassung der Suchoberfläche +============================ + +Webanwendungs-Plugins können keine JSP-Views hinzufügen. JSP-Views befinden +sich unter ``WEB-INF/view/`` im WAR des |Fess|-Kerns, während das +Plugin-JAR in den Klassenpfad (``WEB-INF/classes``) gemountet wird. Wenn +Sie das Design der Suchoberfläche ändern möchten, nutzen Sie eine der +folgenden Möglichkeiten: + +- **Theme**: Passt das Design der Suchoberfläche (HTML/CSS/JavaScript) an. + Siehe :doc:`theme-development`. +- **Ersetzen von systemHelper**: Über das oben beschriebene „Ersetzen von + Kernkomponenten" lässt sich die Zuordnung der Design-JSP-Namen ändern + (die JSP-Dateien selbst werden jedoch weiterhin vom |Fess|-Kern + bereitgestellt). + +Build und Installation +======================= + +:: + + mvn clean package + +Im Verzeichnis ``target/`` wird eine JAR-Datei erzeugt (z. B. +``fess-webapp-example-15.8.0.jar``). Installieren Sie das erzeugte JAR +entweder über die Administrationsoberfläche, oder legen Sie es im +Verzeichnis ``app/WEB-INF/plugin/`` ab und starten Sie |Fess| neu. Details +zum Installationsvorgang finden Sie unter :doc:`../admin/plugin-guide`. + +Beispiele veröffentlichter Plugins +================================== + +Im |Fess|-Projekt sind die folgenden Webanwendungs-Plugins veröffentlicht. +Sie sind als Referenz für die Entwicklung auf +`GitHub `__ verfügbar: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Plugin + - Beschreibung + * - ``fess-webapp-example`` + - Implementierungsvorlage für Plugins + * - ``fess-webapp-v1-api`` + - ``/api/v1`` REST-API + * - ``fess-webapp-classic-api`` + - ``/json`` / ``/suggest`` Legacy-REST-API + * - ``fess-webapp-mcp`` + - MCP-Server (Model Context Protocol) + * - ``fess-webapp-semantic-search`` + - Neuronale Suche/Vektorsuche + * - ``fess-webapp-multimodal`` + - Multimodale Suche (Bild und Text) + Referenzinformationen ===================== - :doc:`plugin-architecture` - Plugin-Architektur +- :doc:`theme-development` - Theme-Anpassung +- :doc:`../admin/plugin-guide` - Plugin-Installation - :doc:`overview` - Entwicklerdokumentation Übersicht + diff --git a/en/15.8/dev/webapp-plugin.rst b/en/15.8/dev/webapp-plugin.rst index 268c3e14..ca16f05f 100644 --- a/en/15.8/dev/webapp-plugin.rst +++ b/en/15.8/dev/webapp-plugin.rst @@ -5,78 +5,327 @@ Web App Plugin Overview ======== -Web App plugins allow you to extend the Fess web interface. -You can add new pages, customize the admin console, and more. +Web App plugins (``fess-webapp-*``) extend the |Fess| web application. +Unlike other plugin types, they do not add Action classes or JSPs +directly; instead, they extend functionality by **adding or replacing +components** in the DI container (Lasta Di). Typical use cases +include: + +- Adding new components (helpers, services, etc.) +- Replacing components in the |Fess| core (via subclassing) +- Adding REST API endpoints (``WebApiManager``) +- Extending search behavior (query commands, rank fusion, etc.) + +.. note:: + + Web App plugins are distributed as JAR files, and their internal + classes and DI configuration files are loaded onto the classpath of + the |Fess| web application. They do not add JSP views. If you want + to customize the design of the search screen, see + :doc:`theme-development`. Basic Structure =============== +Taking `fess-webapp-example `__, +the implementation template for Web App plugins, as an example, a +plugin consists of an "implementation class" and a "DI registration +file": + :: fess-webapp-example/ ├── pom.xml └── src/main/ - ├── java/org/codelibs/fess/app/web/example/ - │ └── ExampleAction.java - └── webapp/WEB-INF/view/example/ - └── index.jsp + ├── java/org/codelibs/fess/webapp/example/helper/ + │ ├── ExampleHelper.java # Component to add + │ └── CustomSystemHelper.java # Replacement for a core component + └── resources/ + ├── app++.xml # Adds components (merge) + └── fess+systemHelper.xml # Replaces a component -Action Implementation +.. note:: + + The implementation class package uses + ``org.codelibs.fess.webapp.``. DI configuration files + are placed under ``src/main/resources/``. Unlike Data Store + plugins, there is no ``src/main/webapp/`` directory or JSP files. + +pom.xml and Manifest ===================== +Web App plugins are built as a jar with ``fess-parent`` as the parent +POM. Libraries such as ``fess`` and ``opensearch``, which are supplied +by the |Fess| core at runtime, are declared with ``provided`` scope, +while libraries required at runtime such as ``lastaflute``, +``dbflute-runtime``, and ``corelib`` are declared with normal scope. + +The most important part of a Web App plugin is adding +``Fess-WebAppJar: true`` to the JAR manifest. This declaration tells +|Fess| to mount the plugin's classes and DI configuration files onto +the web application's classloader. This is configured via the +``maven-jar-plugin``: + +.. code-block:: xml + + + + + maven-jar-plugin + + + + true + + + + + + + +.. warning:: + + If ``Fess-WebAppJar: true`` is not set, the plugin's classes and DI + configuration files will not be loaded onto the web application's + classpath, and component addition/replacement will not take + effect. + +For the overall structure of pom.xml (parent POM, how to declare +dependencies, etc.), see :doc:`plugin-architecture`. + +Extension Patterns +================== + +Adding Components (app++.xml) +------------------------------ + +The most basic way to extend the plugin is to add your own +components. Lasta Di **merges** ``app++.xml`` found on the classpath +into the ``app`` namespace built from the |Fess| core's ``app.xml`` +(the trailing ``++`` is the convention for an additive merge). Since +the components you add use names that do not exist in the |Fess| +core, nothing is overwritten. + +.. code-block:: xml + + + + + + + + +In the component implementation, use ``@PostConstruct`` for +initialization, and retrieve and reuse |Fess| core components via +``ComponentUtil`` (do not copy or override them): + .. code-block:: java - package org.codelibs.fess.app.web.example; + package org.codelibs.fess.webapp.example.helper; + + import org.codelibs.fess.helper.SystemHelper; + import org.codelibs.fess.util.ComponentUtil; - import org.codelibs.fess.app.web.base.FessSearchAction; - import org.lastaflute.web.Execute; - import org.lastaflute.web.response.HtmlResponse; + import jakarta.annotation.PostConstruct; - public class ExampleAction extends FessSearchAction { + public class ExampleHelper { - @Execute - public HtmlResponse index() { - return asHtml(path_Example_IndexJsp); + protected String pluginName = "fess-webapp-example"; + + @PostConstruct + public void init() { + // Initialization logic invoked once after creation by DI + } + + public String getPluginLabel() { + // Reuse the core SystemHelper to get the running Fess version + final SystemHelper systemHelper = ComponentUtil.getSystemHelper(); + final String version = systemHelper != null ? systemHelper.getProductVersion() : "unknown"; + return pluginName + " (Fess " + version + ")"; } } -JSP Template -============ +.. tip:: + + Consider this "component addition" approach first. Unless you need + to change core functionality, it is safer and easier to maintain + than replacement. -``src/main/webapp/WEB-INF/view/example/index.jsp``: +Replacing Core Components (fess+componentName.xml) +---------------------------------------------------- -.. code-block:: jsp +If you want to change the behavior of a |Fess| core component, +subclass the target class and **re-register it under the same +component name** in a DI configuration file named +``+.xml``. For example, since ``systemHelper`` +is declared in the |Fess| core's ``fess.xml``, the replacement file is +``fess+systemHelper.xml`` (not ``app+systemHelper.xml``). - <%@ page contentType="text/html; charset=UTF-8" %> - - - - Example Page - - -

Custom Page

-

This is a custom page added by plugin.

- - +.. code-block:: java + + package org.codelibs.fess.webapp.example.helper; + + import java.nio.file.Path; + + import org.codelibs.fess.helper.SystemHelper; + + public class CustomSystemHelper extends SystemHelper { + + @Override + protected void parseProjectProperties(final Path propPath) { + try { + super.parseProjectProperties(propPath); + } catch (final Exception e) { + // Custom handling + } + System.setProperty("fess.webapp.plugin", "true"); + } + } -API Extension -============= +.. warning:: + + Replacement (a single ``+``) replaces the component definition + **in its entirety**. This means the replacement file must include + every ```` entry that the core definition performs. + For example, when replacing ``systemHelper``, you must copy and + describe all of the design JSP name mappings + (``addDesignJspFileName``) from the core's ``fess.xml``. These must + be kept in sync with each |Fess| release, and any omission will + make some screens (such as ``chat`` / ``login``) impossible to + resolve. This maintenance cost is why addition is recommended over + replacement. + +Adding a REST API (fess_api++.xml) +------------------------------------ + +To add a new REST API endpoint, implement ``WebApiManager``. Extend +``BaseApiManager`` and register itself with the +``WebApiManagerFactory`` in ``@PostConstruct``. The registered API +manager is invoked by ``WebApiFilter`` for every request. Register the +component in ``fess_api++.xml``: + +.. code-block:: xml + + + + + + + .. code-block:: java - public class ApiExampleAction extends FessApiAction { + package org.codelibs.fess.webapp.example.api; + + import java.io.IOException; + + import org.codelibs.fess.api.BaseApiManager; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + import jakarta.servlet.FilterChain; + import jakarta.servlet.ServletException; + import jakarta.servlet.http.HttpServletRequest; + import jakarta.servlet.http.HttpServletResponse; - @Execute - public JsonResponse get$data() { - return asJson(new ApiResult.ApiResponse() - .result(Map.of("message", "Hello from plugin")) - .status(Status.OK)); + public class ExampleApiManager extends BaseApiManager { + + public ExampleApiManager() { + // Path prefix handled by this manager + setPathPrefix("/api/example"); + } + + @PostConstruct + public void register() { + ComponentUtil.getWebApiManagerFactory().add(this); + } + + @Override + public boolean matches(final HttpServletRequest request) { + // Determine whether this manager should handle the request + return request.getServletPath().startsWith(pathPrefix); + } + + @Override + public void process(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain chain) throws IOException, ServletException { + // Process the request and write the response + } + + @Override + protected void writeHeaders(final HttpServletResponse response) { + // Set response headers (as needed) } } +For implementation examples, see +`fess-webapp-v1-api `__, +which provides ``/api/v1``, and +`fess-webapp-classic-api `__, +which provides ``/json`` / ``/suggest``. + +Customizing the Search Screen +============================== + +Web App plugins cannot add JSP views. JSP views are located under +``WEB-INF/view/`` in the |Fess| core WAR, while plugin JARs are mounted +onto the classpath (``WEB-INF/classes``). To change the design of the +search screen, use one of the following: + +- **Theme**: Customizes the design (HTML/CSS/JavaScript) of the + search screen. See :doc:`theme-development`. +- **Replacing systemHelper**: Using the "Replacing Core Components" + approach described above, you can change the design JSP name + mapping (however, the JSP files themselves are still provided by the + |Fess| core). + +Build and Installation +======================== + +:: + + mvn clean package + +A JAR file (e.g., ``fess-webapp-example-15.8.0.jar``) is generated in +the ``target/`` directory. Install the generated JAR from the admin +console, or place it in the ``app/WEB-INF/plugin/`` directory and +restart |Fess|. For details on the installation procedure, see +:doc:`../admin/plugin-guide`. + +Examples of Published Plugins +=============================== + +The |Fess| project publishes the following Web App plugins. They are +published on `GitHub `__ as a reference +for development: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Plugin + - Description + * - ``fess-webapp-example`` + - Plugin implementation template + * - ``fess-webapp-v1-api`` + - ``/api/v1`` REST API + * - ``fess-webapp-classic-api`` + - Legacy REST API for ``/json`` / ``/suggest`` + * - ``fess-webapp-mcp`` + - MCP (Model Context Protocol) server + * - ``fess-webapp-semantic-search`` + - Neural search / vector search + * - ``fess-webapp-multimodal`` + - Multimodal (image/text) search + Reference ========= - :doc:`plugin-architecture` - Plugin Architecture +- :doc:`theme-development` - Theme customization +- :doc:`../admin/plugin-guide` - Plugin installation - :doc:`overview` - Developer Documentation Overview - diff --git a/es/15.8/dev/webapp-plugin.rst b/es/15.8/dev/webapp-plugin.rst index 47c97439..ffca02c1 100644 --- a/es/15.8/dev/webapp-plugin.rst +++ b/es/15.8/dev/webapp-plugin.rst @@ -1,81 +1,338 @@ ================================== -Plugin de Aplicacion Web +Plugin de Aplicación Web ================================== -Vision General +Visión General ============== -Con los plugins de aplicacion web puede extender la interfaz web de Fess. -Es posible agregar nuevas paginas, personalizar la pantalla de administracion, etc. +Los plugins de aplicación web (``fess-webapp-*``) son plugins que amplían +la aplicación web de |Fess|. A diferencia de otros tipos de plugins, no +añaden directamente clases Action ni JSP, sino que amplían la +funcionalidad **añadiendo o sustituyendo componentes** en el contenedor +DI (Lasta Di). Los usos representativos son los siguientes: -Estructura Basica +- Adición de nuevos componentes (helpers, servicios, etc.) +- Sustitución de componentes del núcleo de |Fess| (mediante subclases) +- Adición de endpoints de API REST (``WebApiManager``) +- Ampliación del comportamiento de búsqueda (comandos de consulta, + fusión de rangos, etc.) + +.. note:: + + Los plugins de aplicación web se distribuyen como JAR, y sus clases + internas y archivos de configuración DI se cargan en el classpath de + la aplicación web de |Fess|. No permiten añadir vistas JSP. Si desea + personalizar el diseño de la pantalla de búsqueda, consulte + :doc:`theme-development`. + +Estructura Básica ================= +Tomando como ejemplo `fess-webapp-example +`__, la plantilla de +implementación de un plugin de aplicación web, un plugin se compone de +una «clase de implementación» y un «archivo de registro DI»: + :: fess-webapp-example/ ├── pom.xml └── src/main/ - ├── java/org/codelibs/fess/app/web/example/ - │ └── ExampleAction.java - └── webapp/WEB-INF/view/example/ - └── index.jsp + ├── java/org/codelibs/fess/webapp/example/helper/ + │ ├── ExampleHelper.java # Componente a añadir + │ └── CustomSystemHelper.java # Sustitución de un componente del núcleo + └── resources/ + ├── app++.xml # Adición de componentes (fusión) + └── fess+systemHelper.xml # Sustitución de componentes + +.. note:: + + El paquete de las clases de implementación utiliza + ``org.codelibs.fess.webapp.``. Los archivos de + configuración DI se colocan en ``src/main/resources/``. A diferencia + de los plugins de almacén de datos, no incluyen ``src/main/webapp/`` + ni JSP. + +pom.xml y el Manifiesto +======================= + +Los plugins de aplicación web se construyen como jar con ``fess-parent`` +como POM padre. Las bibliotecas ``fess`` y ``opensearch``, que son +proporcionadas en tiempo de ejecución por el propio |Fess|, se declaran +con el ámbito ``provided``, mientras que las bibliotecas necesarias en +tiempo de ejecución, como ``lastaflute``, ``dbflute-runtime`` y +``corelib``, se declaran con el ámbito habitual. + +Lo más importante en un plugin de aplicación web es añadir +``Fess-WebAppJar: true`` al manifiesto del JAR. Gracias a esta +declaración, |Fess| monta las clases del plugin y sus archivos de +configuración DI en el cargador de clases de la aplicación web. Esta +configuración se realiza con ``maven-jar-plugin``: + +.. code-block:: xml + + + + + maven-jar-plugin + + + + true + + + + + + + +.. warning:: + + Si no se añade ``Fess-WebAppJar: true``, las clases del plugin y los + archivos de configuración DI no se cargarán en el classpath de la + aplicación web, y la adición o sustitución de componentes no surtirá + efecto. + +Para conocer la configuración completa de pom.xml (el POM padre, la +forma de declarar las dependencias, etc.), consulte +:doc:`plugin-architecture`. + +Patrones de Extensión +====================== + +Adición de Componentes (app++.xml) +----------------------------------- + +La forma más básica de extensión es añadir sus propios componentes. +Lasta Di **fusiona** el archivo ``app++.xml`` presente en el classpath +con el espacio de nombres ``app`` construido a partir del ``app.xml`` +del propio |Fess| (el sufijo ``++`` es la convención para la fusión +aditiva). Dado que los componentes añadidos utilizan nombres que no +existen en el propio |Fess|, no se sobrescribe nada. + +.. code-block:: xml + + + + + + + + +En la implementación del componente, utilice ``@PostConstruct`` para la +inicialización, y reutilice los componentes del propio |Fess| +obteniéndolos mediante ``ComponentUtil`` (no los copie ni los +sobrescriba): + +.. code-block:: java + + package org.codelibs.fess.webapp.example.helper; + + import org.codelibs.fess.helper.SystemHelper; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + + public class ExampleHelper { + + protected String pluginName = "fess-webapp-example"; + + @PostConstruct + public void init() { + // Procesamiento de inicialización invocado una sola vez tras la creación por DI + } + + public String getPluginLabel() { + // Reutiliza el SystemHelper del núcleo para obtener la versión de Fess en ejecución + final SystemHelper systemHelper = ComponentUtil.getSystemHelper(); + final String version = systemHelper != null ? systemHelper.getProductVersion() : "unknown"; + return pluginName + " (Fess " + version + ")"; + } + } + +.. tip:: + + Considere primero esta opción de «adición de componentes». A menos + que sea necesario modificar la funcionalidad del núcleo, es más + segura y ofrece mejor mantenibilidad que la sustitución. + +Sustitución de Componentes del Núcleo (fess+componentName.xml) +------------------------------------------------------------------ -Implementacion de Action -======================== +Si desea modificar el comportamiento de un componente del propio +|Fess|, cree una subclase de la clase de destino y **vuelva a +registrarla con el mismo nombre de componente** en un archivo de +configuración DI denominado ``+.xml``. Por +ejemplo, dado que ``systemHelper`` está declarado en ``fess.xml`` del +propio |Fess|, el archivo de sustitución será ``fess+systemHelper.xml`` +(no ``app+systemHelper.xml``). .. code-block:: java - package org.codelibs.fess.app.web.example; + package org.codelibs.fess.webapp.example.helper; - import org.codelibs.fess.app.web.base.FessSearchAction; - import org.lastaflute.web.Execute; - import org.lastaflute.web.response.HtmlResponse; + import java.nio.file.Path; - public class ExampleAction extends FessSearchAction { + import org.codelibs.fess.helper.SystemHelper; - @Execute - public HtmlResponse index() { - return asHtml(path_Example_IndexJsp); + public class CustomSystemHelper extends SystemHelper { + + @Override + protected void parseProjectProperties(final Path propPath) { + try { + super.parseProjectProperties(propPath); + } catch (final Exception e) { + // Procesamiento propio + } + System.setProperty("fess.webapp.plugin", "true"); } } -Plantilla JSP -============= +.. warning:: + + La sustitución (con un único ``+``) reemplaza **por completo** la + definición del componente. Por ello, el archivo de sustitución debe + incluir todos los elementos ```` que realiza la + definición del núcleo. Por ejemplo, al sustituir ``systemHelper``, es + necesario copiar y describir todo el mapeo de nombres de JSP de + diseño (``addDesignJspFileName``) desde el ``fess.xml`` del núcleo. + Esto debe sincronizarse en cada versión de |Fess|, y cualquier + omisión hará que algunas pantallas (como ``chat`` o ``login``) no + puedan resolverse. Este coste de mantenimiento es la razón por la + que se recomienda la adición en lugar de la sustitución. -``src/main/webapp/WEB-INF/view/example/index.jsp``: +Adición de una API REST (fess_api++.xml) +------------------------------------------- -.. code-block:: jsp +Para añadir un nuevo endpoint de API REST, implemente +``WebApiManager``. Herede de ``BaseApiManager`` y regístrese a sí mismo +en ``WebApiManagerFactory`` mediante ``@PostConstruct``. El gestor de +API registrado es invocado por ``WebApiFilter`` en cada solicitud. +Registre el componente en ``fess_api++.xml``: - <%@ page contentType="text/html; charset=UTF-8" %> - - - - Pagina de Ejemplo - - -

Pagina Personalizada

-

Esta es una pagina personalizada agregada por un plugin.

- - +.. code-block:: xml -Extension de API -================ + + + + + + .. code-block:: java - public class ApiExampleAction extends FessApiAction { + package org.codelibs.fess.webapp.example.api; + + import java.io.IOException; + + import org.codelibs.fess.api.BaseApiManager; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + import jakarta.servlet.FilterChain; + import jakarta.servlet.ServletException; + import jakarta.servlet.http.HttpServletRequest; + import jakarta.servlet.http.HttpServletResponse; + + public class ExampleApiManager extends BaseApiManager { + + public ExampleApiManager() { + // Prefijo de la ruta que gestiona este manejador + setPathPrefix("/api/example"); + } + + @PostConstruct + public void register() { + ComponentUtil.getWebApiManagerFactory().add(this); + } + + @Override + public boolean matches(final HttpServletRequest request) { + // Determina si este manejador procesa la solicitud + return request.getServletPath().startsWith(pathPrefix); + } - @Execute - public JsonResponse get$data() { - return asJson(new ApiResult.ApiResponse() - .result(Map.of("message", "Hello from plugin")) - .status(Status.OK)); + @Override + public void process(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain chain) throws IOException, ServletException { + // Procesamiento de la solicitud y escritura de la respuesta + } + + @Override + protected void writeHeaders(final HttpServletResponse response) { + // Configuración de las cabeceras de la respuesta (según sea necesario) } } -Informacion de Referencia -========================= +Como ejemplos de implementación, resultan útiles como referencia +`fess-webapp-v1-api `__, +que proporciona ``/api/v1``, y `fess-webapp-classic-api +`__, que +proporciona ``/json`` y ``/suggest``. + +Personalización de la Pantalla de Búsqueda +============================================ + +Los plugins de aplicación web no pueden añadir vistas JSP. Esto se debe +a que las vistas JSP se ubican en ``WEB-INF/view/`` del WAR del propio +|Fess|, mientras que el JAR del plugin se monta en el classpath +(``WEB-INF/classes``). Si desea modificar el diseño de la pantalla de +búsqueda, utilice una de las siguientes opciones: + +- **Tema**: personaliza el diseño de la pantalla de búsqueda + (HTML/CSS/JavaScript). Consulte :doc:`theme-development`. +- **Sustitución de systemHelper**: mediante la «sustitución de + componentes del núcleo» descrita anteriormente, puede cambiar el + mapeo de nombres de JSP de diseño (aunque los propios archivos JSP + los proporciona el núcleo de |Fess|). + +Construcción e Instalación +============================ + +:: + + mvn clean package + +En el directorio ``target/`` se generará un archivo JAR (por ejemplo, +``fess-webapp-example-15.8.0.jar``). El JAR generado se puede instalar +desde la consola de administración, o bien colocarlo en el directorio +``app/WEB-INF/plugin/`` y reiniciar |Fess|. Para más detalles sobre el +procedimiento de instalación, consulte :doc:`../admin/plugin-guide`. + +Ejemplos de Plugins Públicos +============================== + +En el proyecto |Fess| se publican los siguientes plugins de aplicación +web. Se publican en `GitHub `__ como +referencia para el desarrollo: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Plugin + - Descripción + * - ``fess-webapp-example`` + - Plantilla de implementación de plugins + * - ``fess-webapp-v1-api`` + - API REST ``/api/v1`` + * - ``fess-webapp-classic-api`` + - API REST heredada ``/json`` / ``/suggest`` + * - ``fess-webapp-mcp`` + - Servidor MCP (Model Context Protocol) + * - ``fess-webapp-semantic-search`` + - Búsqueda neuronal/búsqueda vectorial + * - ``fess-webapp-multimodal`` + - Búsqueda multimodal (imágenes y texto) + +Información de Referencia +=========================== - :doc:`plugin-architecture` - Arquitectura de plugins -- :doc:`overview` - Vision general de documentacion para desarrolladores +- :doc:`theme-development` - Personalización de temas +- :doc:`../admin/plugin-guide` - Instalación de plugins +- :doc:`overview` - Visión general de documentación para desarrolladores diff --git a/fr/15.8/dev/webapp-plugin.rst b/fr/15.8/dev/webapp-plugin.rst index e347d592..9592fbfe 100644 --- a/fr/15.8/dev/webapp-plugin.rst +++ b/fr/15.8/dev/webapp-plugin.rst @@ -1,81 +1,338 @@ -================================== -Plugin WebApp -================================== +======================== +Plugin d'application Web +======================== -Vue d'ensemble -============== +Aperçu +====== -Les plugins WebApp permettent d'etendre l'interface web de Fess. -Vous pouvez ajouter de nouvelles pages, personnaliser l'interface d'administration, etc. +Les plugins d'application Web (``fess-webapp-*``) sont des plugins qui +étendent l'application Web de |Fess|. Contrairement aux autres types de +plugins, ils n'ajoutent pas directement de classes Action ou de JSP, mais +étendent les fonctionnalités en **ajoutant ou remplaçant des composants** +dans le conteneur DI (Lasta Di). Les cas d'usage représentatifs sont les +suivants : + +- Ajout de nouveaux composants (helpers, services, etc.) +- Remplacement de composants du cœur de |Fess| (par sous-classement) +- Ajout de points de terminaison d'API REST (``WebApiManager``) +- Extension du comportement de recherche (commandes de requête, fusion de + classements, etc.) + +.. note:: + + Les plugins d'application Web sont distribués sous forme de fichier JAR ; + les classes internes et les fichiers de configuration DI qu'ils + contiennent sont chargés dans le classpath de l'application Web de + |Fess|. Ils n'ajoutent pas de vues JSP. Pour personnaliser le design de + l'écran de recherche, reportez-vous à :doc:`theme-development`. Structure de base ================= +En prenant comme exemple +`fess-webapp-example `__, +le modèle d'implémentation d'un plugin d'application Web, un plugin se +compose d'une « classe d'implémentation » et d'un « fichier d'enregistrement +DI » : + :: fess-webapp-example/ ├── pom.xml └── src/main/ - ├── java/org/codelibs/fess/app/web/example/ - │ └── ExampleAction.java - └── webapp/WEB-INF/view/example/ - └── index.jsp + ├── java/org/codelibs/fess/webapp/example/helper/ + │ ├── ExampleHelper.java # Composant ajouté + │ └── CustomSystemHelper.java # Remplacement d'un composant du cœur + └── resources/ + ├── app++.xml # Ajout de composant (fusion) + └── fess+systemHelper.xml # Remplacement de composant + +.. note:: + + Le package des classes d'implémentation utilise + ``org.codelibs.fess.webapp.``. Les fichiers de + configuration DI sont placés dans ``src/main/resources/``. Contrairement + aux plugins DataStore, ils n'incluent pas de ``src/main/webapp/`` ni de + JSP. + +pom.xml et manifeste +==================== + +Les plugins d'application Web sont construits comme un jar ayant +``fess-parent`` pour POM parent. Les bibliothèques telles que ``fess`` ou +``opensearch``, fournies à l'exécution par |Fess| lui-même, doivent être +déclarées avec la portée ``provided``, tandis que les bibliothèques +nécessaires à l'exécution telles que ``lastaflute``, ``dbflute-runtime`` ou +``corelib`` sont déclarées avec la portée habituelle. + +Le point le plus important pour un plugin d'application Web est d'ajouter +``Fess-WebAppJar: true`` au manifeste du JAR. Cette déclaration permet à +|Fess| de monter les classes du plugin et ses fichiers de configuration DI +dans le chargeur de classes de l'application Web. Cette configuration se +fait via ``maven-jar-plugin`` : + +.. code-block:: xml + + + + + maven-jar-plugin + + + + true + + + + + + + +.. warning:: + + Si ``Fess-WebAppJar: true`` n'est pas ajouté, les classes du plugin et + les fichiers de configuration DI ne seront pas chargés dans le classpath + de l'application Web, et l'ajout ou le remplacement de composants ne + sera pas effectif. + +Pour la structure complète du pom.xml (POM parent, déclaration des +dépendances, etc.), reportez-vous à :doc:`plugin-architecture`. + +Modèles d'extension +==================== + +Ajout d'un composant (app++.xml) +--------------------------------- + +La méthode d'extension la plus élémentaire consiste à ajouter vos propres +composants. Lasta Di **fusionne** le fichier ``app++.xml`` présent sur le +classpath dans l'espace de noms ``app`` construit à partir du fichier +``app.xml`` de |Fess| lui-même (le suffixe ``++`` est la convention +indiquant une fusion additive). Comme les composants ajoutés utilisent des +noms qui n'existent pas dans |Fess| lui-même, rien n'est écrasé. + +.. code-block:: xml + + + + + + + + +Dans l'implémentation du composant, utilisez ``@PostConstruct`` pour +l'initialisation, et récupérez les composants de |Fess| lui-même via +``ComponentUtil`` pour les réutiliser (sans les copier ni les écraser) : + +.. code-block:: java + + package org.codelibs.fess.webapp.example.helper; + + import org.codelibs.fess.helper.SystemHelper; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + + public class ExampleHelper { + + protected String pluginName = "fess-webapp-example"; + + @PostConstruct + public void init() { + // Traitement d'initialisation appelé une seule fois après la création par le conteneur DI + } + + public String getPluginLabel() { + // Réutilise le SystemHelper du cœur pour récupérer la version de Fess en cours d'exécution + final SystemHelper systemHelper = ComponentUtil.getSystemHelper(); + final String version = systemHelper != null ? systemHelper.getProductVersion() : "unknown"; + return pluginName + " (Fess " + version + ")"; + } + } + +.. tip:: + + Envisagez d'abord cet « ajout de composant ». À moins qu'il ne soit + nécessaire de modifier une fonctionnalité du cœur, cette approche est + plus sûre et plus facile à maintenir que le remplacement. + +Remplacement d'un composant du cœur (fess+componentName.xml) +-------------------------------------------------------------- -Implementation de l'Action -========================== +Si vous souhaitez modifier le comportement d'un composant du cœur de +|Fess|, sous-classez la classe cible et **réenregistrez-la sous le même nom +de composant** dans un fichier de configuration DI nommé +``+.xml``. Par exemple, ``systemHelper`` étant +déclaré dans le fichier ``fess.xml`` de |Fess| lui-même, le fichier de +remplacement sera ``fess+systemHelper.xml`` (et non +``app+systemHelper.xml``). .. code-block:: java - package org.codelibs.fess.app.web.example; + package org.codelibs.fess.webapp.example.helper; - import org.codelibs.fess.app.web.base.FessSearchAction; - import org.lastaflute.web.Execute; - import org.lastaflute.web.response.HtmlResponse; + import java.nio.file.Path; - public class ExampleAction extends FessSearchAction { + import org.codelibs.fess.helper.SystemHelper; - @Execute - public HtmlResponse index() { - return asHtml(path_Example_IndexJsp); + public class CustomSystemHelper extends SystemHelper { + + @Override + protected void parseProjectProperties(final Path propPath) { + try { + super.parseProjectProperties(propPath); + } catch (final Exception e) { + // Traitement personnalisé + } + System.setProperty("fess.webapp.plugin", "true"); } } -Template JSP -============ +.. warning:: + + Le remplacement (un seul ``+``) remplace **entièrement** la définition + du composant. Pour cette raison, le fichier de remplacement doit + contenir tous les éléments ```` définis par la définition + du cœur. Par exemple, pour remplacer ``systemHelper``, vous devez copier + intégralement le mapping des noms de JSP de design + (``addDesignJspFileName``) depuis le ``fess.xml`` du cœur. Ces éléments + doivent être synchronisés à chaque nouvelle version de |Fess|, et tout + oubli empêchera la résolution de certains écrans (``chat``, ``login``, + etc.). Ce coût de maintenance explique pourquoi l'ajout est recommandé + plutôt que le remplacement. -``src/main/webapp/WEB-INF/view/example/index.jsp``: +Ajout d'une API REST (fess_api++.xml) +--------------------------------------- -.. code-block:: jsp +Pour ajouter un nouveau point de terminaison d'API REST, implémentez +``WebApiManager``. Héritez de ``BaseApiManager`` et enregistrez-vous auprès +de ``WebApiManagerFactory`` via ``@PostConstruct``. Le gestionnaire d'API +enregistré est invoqué par ``WebApiFilter`` à chaque requête. Enregistrez +le composant dans ``fess_api++.xml`` : - <%@ page contentType="text/html; charset=UTF-8" %> - - - - Example Page - - -

Page personnalisee

-

Ceci est une page personnalisee ajoutee par un plugin.

- - +.. code-block:: xml -Extension API -============= + + + + + + .. code-block:: java - public class ApiExampleAction extends FessApiAction { + package org.codelibs.fess.webapp.example.api; + + import java.io.IOException; + + import org.codelibs.fess.api.BaseApiManager; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + import jakarta.servlet.FilterChain; + import jakarta.servlet.ServletException; + import jakarta.servlet.http.HttpServletRequest; + import jakarta.servlet.http.HttpServletResponse; + + public class ExampleApiManager extends BaseApiManager { + + public ExampleApiManager() { + // Préfixe du chemin traité par ce gestionnaire + setPathPrefix("/api/example"); + } + + @PostConstruct + public void register() { + ComponentUtil.getWebApiManagerFactory().add(this); + } + + @Override + public boolean matches(final HttpServletRequest request) { + // Détermine si ce gestionnaire doit traiter la requête + return request.getServletPath().startsWith(pathPrefix); + } - @Execute - public JsonResponse get$data() { - return asJson(new ApiResult.ApiResponse() - .result(Map.of("message", "Hello from plugin")) - .status(Status.OK)); + @Override + public void process(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain chain) throws IOException, ServletException { + // Traitement de la requête et écriture de la réponse + } + + @Override + protected void writeHeaders(final HttpServletResponse response) { + // Configuration des en-têtes de réponse (si nécessaire) } } -Informations complementaires +Comme exemples d'implémentation, vous pouvez vous référer à +`fess-webapp-v1-api `__, +qui fournit ``/api/v1``, ou à +`fess-webapp-classic-api `__, +qui fournit ``/json`` / ``/suggest``. + +Personnalisation de l'écran de recherche +========================================= + +Les plugins d'application Web ne peuvent pas ajouter de vues JSP. En effet, +les vues JSP sont placées dans ``WEB-INF/view/`` du WAR de |Fess| +lui-même, alors que le JAR du plugin est monté dans le classpath +(``WEB-INF/classes``). Pour modifier le design de l'écran de recherche, +utilisez l'une des approches suivantes : + +- **Thème** : personnalise le design (HTML/CSS/JavaScript) de l'écran de + recherche. Reportez-vous à :doc:`theme-development`. +- **Remplacement de systemHelper** : comme décrit ci-dessus dans + « Remplacement d'un composant du cœur », vous pouvez modifier le mapping + des noms de JSP de design (les fichiers JSP eux-mêmes restent toutefois + fournis par |Fess| lui-même). + +Build et installation +====================== + +:: + + mvn clean package + +Le fichier JAR (par exemple ``fess-webapp-example-15.8.0.jar``) est généré +dans le répertoire ``target/``. Vous pouvez installer le JAR généré depuis +l'écran d'administration, ou le placer dans le répertoire +``app/WEB-INF/plugin/`` puis redémarrer |Fess|. Pour plus de détails sur la +procédure d'installation, reportez-vous à :doc:`../admin/plugin-guide`. + +Exemples de plugins publiés ============================ +Le projet |Fess| publie les plugins d'application Web suivants. Ils sont +publiés sur `GitHub `__ comme référence pour +le développement : + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - Plugin + - Description + * - ``fess-webapp-example`` + - Modèle d'implémentation de plugin + * - ``fess-webapp-v1-api`` + - API REST ``/api/v1`` + * - ``fess-webapp-classic-api`` + - API REST historique ``/json`` / ``/suggest`` + * - ``fess-webapp-mcp`` + - Serveur MCP (Model Context Protocol) + * - ``fess-webapp-semantic-search`` + - Recherche neuronale / recherche vectorielle + * - ``fess-webapp-multimodal`` + - Recherche multimodale (image et texte) + +Informations complémentaires +============================= + - :doc:`plugin-architecture` - Architecture des plugins -- :doc:`overview` - Vue d'ensemble developpeur +- :doc:`theme-development` - Personnalisation des thèmes +- :doc:`../admin/plugin-guide` - Installation des plugins +- :doc:`overview` - Aperçu de la documentation développeur diff --git a/ja/15.8/dev/webapp-plugin.rst b/ja/15.8/dev/webapp-plugin.rst index e0e81ac2..daba54af 100644 --- a/ja/15.8/dev/webapp-plugin.rst +++ b/ja/15.8/dev/webapp-plugin.rst @@ -5,77 +5,310 @@ Webアプリプラグイン 概要 ==== -WebアプリプラグインでFessのWebインターフェースを拡張できます。 -新しいページの追加、管理画面のカスタマイズなどが可能です。 +Web アプリプラグイン(``fess-webapp-*``)は、|Fess| の Web アプリケーションを +拡張するプラグインです。他の種類のプラグインと異なり、Action クラスや JSP を +直接追加するのではなく、DI コンテナ(Lasta Di)に対して **コンポーネントを追加 +または置き換える** ことで機能を拡張します。代表的な用途は次のとおりです: + +- 新しいコンポーネント(ヘルパー・サービスなど)の追加 +- |Fess| 本体のコンポーネントの置き換え(サブクラス化) +- REST API エンドポイントの追加(``WebApiManager``) +- 検索動作の拡張(クエリコマンド、ランクフュージョンなど) + +.. note:: + + Web アプリプラグインは JAR として配布され、内部のクラスと DI 設定ファイルが + |Fess| の Web アプリケーションのクラスパスに読み込まれます。JSP ビューを + 追加するものではありません。検索画面のデザインをカスタマイズする場合は + :doc:`theme-development` を参照してください。 基本構造 ======== +Web アプリプラグインの実装テンプレートである +`fess-webapp-example `__ を +例にすると、プラグインは「実装クラス」と「DI 登録ファイル」で構成されます: + :: fess-webapp-example/ ├── pom.xml └── src/main/ - ├── java/org/codelibs/fess/app/web/example/ - │ └── ExampleAction.java - └── webapp/WEB-INF/view/example/ - └── index.jsp + ├── java/org/codelibs/fess/webapp/example/helper/ + │ ├── ExampleHelper.java # 追加するコンポーネント + │ └── CustomSystemHelper.java # コアコンポーネントの置き換え + └── resources/ + ├── app++.xml # コンポーネントの追加(マージ) + └── fess+systemHelper.xml # コンポーネントの置き換え + +.. note:: + + 実装クラスのパッケージは ``org.codelibs.fess.webapp.<プラグイン名>`` を使用します。 + DI 設定ファイルは ``src/main/resources/`` に配置します。データストアプラグインと + 異なり ``src/main/webapp/`` や JSP は含めません。 + +pom.xmlとマニフェスト +===================== + +Web アプリプラグインは ``fess-parent`` を親 POM とする jar としてビルドします。 +|Fess| 本体から実行時に提供される ``fess`` や ``opensearch`` は ``provided`` +スコープで宣言し、``lastaflute``・``dbflute-runtime``・``corelib`` など実行時に +必要なライブラリは通常のスコープで宣言します。 + +Web アプリプラグインで最も重要なのは、JAR マニフェストに ``Fess-WebAppJar: true`` +を付与することです。この宣言により、|Fess| はプラグインのクラスと DI 設定ファイルを +Web アプリケーションのクラスローダーへマウントします。この設定は +``maven-jar-plugin`` で行います: + +.. code-block:: xml + + + + + maven-jar-plugin + + + + true + + + + + + + +.. warning:: + + ``Fess-WebAppJar: true`` を付与しないと、プラグインのクラスや DI 設定ファイルは + Web アプリケーションのクラスパスに読み込まれず、コンポーネントの追加・置き換えが + 有効になりません。 + +pom.xml 全体の構成(親 POM・依存関係の宣言方法など)は +:doc:`plugin-architecture` を参照してください。 + +拡張パターン +============ + +コンポーネントの追加(app++.xml) +-------------------------------- + +最も基本的な拡張方法は、独自のコンポーネントを追加することです。 +Lasta Di は、クラスパス上の ``app++.xml`` を |Fess| 本体の ``app.xml`` から +構築される ``app`` 名前空間へ **マージ** します(末尾の ``++`` は追加マージの +規約です)。追加するコンポーネントは |Fess| 本体に存在しない名前を使用するため、 +何も上書きされません。 + +.. code-block:: xml + + + + + + + + +コンポーネントの実装では、初期化に ``@PostConstruct`` を使用し、|Fess| 本体の +コンポーネントは ``ComponentUtil`` から取得して再利用します(コピーや上書きは +しません): + +.. code-block:: java + + package org.codelibs.fess.webapp.example.helper; + + import org.codelibs.fess.helper.SystemHelper; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + + public class ExampleHelper { + + protected String pluginName = "fess-webapp-example"; + + @PostConstruct + public void init() { + // DI による生成後に一度だけ呼び出される初期化処理 + } + + public String getPluginLabel() { + // コアの SystemHelper を再利用して稼働中の Fess バージョンを取得 + final SystemHelper systemHelper = ComponentUtil.getSystemHelper(); + final String version = systemHelper != null ? systemHelper.getProductVersion() : "unknown"; + return pluginName + " (Fess " + version + ")"; + } + } + +.. tip:: + + まずはこの「コンポーネントの追加」を検討してください。コア機能を変更する必要が + ない限り、置き換えよりも安全でメンテナンス性に優れます。 + +コアコンポーネントの置き換え(fess+componentName.xml) +----------------------------------------------------- -Action実装 -========== +|Fess| 本体のコンポーネントの挙動を変更したい場合は、対象クラスをサブクラス化し、 +``+.xml`` という名前の DI 設定ファイルで **同じ +コンポーネント名で再登録** します。例えば ``systemHelper`` は |Fess| 本体の +``fess.xml`` で宣言されているため、置き換えファイルは ``fess+systemHelper.xml`` +になります(``app+systemHelper.xml`` ではありません)。 .. code-block:: java - package org.codelibs.fess.app.web.example; + package org.codelibs.fess.webapp.example.helper; - import org.codelibs.fess.app.web.base.FessSearchAction; - import org.lastaflute.web.Execute; - import org.lastaflute.web.response.HtmlResponse; + import java.nio.file.Path; - public class ExampleAction extends FessSearchAction { + import org.codelibs.fess.helper.SystemHelper; - @Execute - public HtmlResponse index() { - return asHtml(path_Example_IndexJsp); + public class CustomSystemHelper extends SystemHelper { + + @Override + protected void parseProjectProperties(final Path propPath) { + try { + super.parseProjectProperties(propPath); + } catch (final Exception e) { + // 独自の処理 + } + System.setProperty("fess.webapp.plugin", "true"); } } -JSPテンプレート -=============== +.. warning:: + + 置き換え(単一の ``+``)は、コンポーネント定義を **丸ごと** 置き換えます。 + このため、置き換えファイルにはコア定義が行っている ```` を + すべて記述する必要があります。例えば ``systemHelper`` を置き換える場合は、 + デザイン JSP 名のマッピング(``addDesignJspFileName``)をコアの ``fess.xml`` から + すべてコピーして記述しなければなりません。これらは |Fess| のリリースごとに + 同期する必要があり、漏れがあると一部の画面(``chat`` / ``login`` など)が + 解決できなくなります。この保守コストが、置き換えよりも追加が推奨される理由です。 -``src/main/webapp/WEB-INF/view/example/index.jsp``: +REST APIの追加(fess_api++.xml) +------------------------------- -.. code-block:: jsp +新しい REST API エンドポイントを追加するには、``WebApiManager`` を実装します。 +``BaseApiManager`` を継承し、``@PostConstruct`` で ``WebApiManagerFactory`` に +自身を登録します。登録された API マネージャーは、リクエストごとに ``WebApiFilter`` +から呼び出されます。``fess_api++.xml`` でコンポーネントを登録します: - <%@ page contentType="text/html; charset=UTF-8" %> - - - - Example Page - - -

Custom Page

-

This is a custom page added by plugin.

- - +.. code-block:: xml -API拡張 -======= + + + + + + .. code-block:: java - public class ApiExampleAction extends FessApiAction { + package org.codelibs.fess.webapp.example.api; + + import java.io.IOException; + + import org.codelibs.fess.api.BaseApiManager; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + import jakarta.servlet.FilterChain; + import jakarta.servlet.ServletException; + import jakarta.servlet.http.HttpServletRequest; + import jakarta.servlet.http.HttpServletResponse; + + public class ExampleApiManager extends BaseApiManager { + + public ExampleApiManager() { + // このマネージャーが処理するパスのプレフィックス + setPathPrefix("/api/example"); + } + + @PostConstruct + public void register() { + ComponentUtil.getWebApiManagerFactory().add(this); + } + + @Override + public boolean matches(final HttpServletRequest request) { + // このマネージャーがリクエストを処理するかどうかを判定 + return request.getServletPath().startsWith(pathPrefix); + } - @Execute - public JsonResponse get$data() { - return asJson(new ApiResult.ApiResponse() - .result(Map.of("message", "Hello from plugin")) - .status(Status.OK)); + @Override + public void process(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain chain) throws IOException, ServletException { + // リクエストの処理とレスポンスの書き込み + } + + @Override + protected void writeHeaders(final HttpServletResponse response) { + // レスポンスヘッダーの設定(必要に応じて) } } +実装例としては、``/api/v1`` を提供する +`fess-webapp-v1-api `__ や、 +``/json`` / ``/suggest`` を提供する +`fess-webapp-classic-api `__ が +参考になります。 + +検索画面のカスタマイズ +====================== + +Web アプリプラグインは JSP ビューを追加できません。JSP ビューは |Fess| 本体の WAR の +``WEB-INF/view/`` に配置されており、プラグイン JAR はクラスパス +(``WEB-INF/classes``)にマウントされるためです。検索画面のデザインを変更する場合は、 +次のいずれかを使用します: + +- **テーマ**: 検索画面のデザイン(HTML/CSS/JavaScript)をカスタマイズします。 + :doc:`theme-development` を参照してください。 +- **systemHelper の置き換え**: 上記の「コアコンポーネントの置き換え」により、 + デザイン JSP 名のマッピングを変更できます(ただし JSP ファイル自体は |Fess| 本体が + 提供します)。 + +ビルドとインストール +==================== + +:: + + mvn clean package + +``target/`` ディレクトリに JAR ファイル(例: ``fess-webapp-example-15.8.0.jar``)が +生成されます。生成した JAR は管理画面からインストールするか、 +``app/WEB-INF/plugin/`` ディレクトリに配置して |Fess| を再起動します。 +インストール手順の詳細は :doc:`../admin/plugin-guide` を参照してください。 + +公開プラグインの例 +================== + +|Fess| プロジェクトでは、以下の Web アプリプラグインが公開されています。 +開発の参考として `GitHub `__ で公開されています: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - プラグイン + - 説明 + * - ``fess-webapp-example`` + - プラグイン実装のテンプレート + * - ``fess-webapp-v1-api`` + - ``/api/v1`` REST API + * - ``fess-webapp-classic-api`` + - ``/json`` / ``/suggest`` レガシー REST API + * - ``fess-webapp-mcp`` + - MCP(Model Context Protocol)サーバー + * - ``fess-webapp-semantic-search`` + - ニューラル検索/ベクトル検索 + * - ``fess-webapp-multimodal`` + - マルチモーダル(画像・テキスト)検索 + 参考情報 ======== - :doc:`plugin-architecture` - プラグインアーキテクチャ +- :doc:`theme-development` - テーマのカスタマイズ +- :doc:`../admin/plugin-guide` - プラグインのインストール - :doc:`overview` - 開発者ドキュメント概要 diff --git a/ko/15.8/dev/webapp-plugin.rst b/ko/15.8/dev/webapp-plugin.rst index ffd3749e..80d94780 100644 --- a/ko/15.8/dev/webapp-plugin.rst +++ b/ko/15.8/dev/webapp-plugin.rst @@ -5,77 +5,314 @@ 개요 ==== -웹앱 플러그인으로 Fess의 웹 인터페이스를 확장할 수 있습니다. -새 페이지 추가, 관리 화면 커스터마이즈 등이 가능합니다. +웹앱 플러그인(``fess-webapp-*``)은 |Fess| 의 웹 애플리케이션을 확장하는 +플러그인입니다. 다른 종류의 플러그인과 달리 Action 클래스나 JSP 를 직접 +추가하는 것이 아니라, DI 컨테이너(Lasta Di)에 대해 **컴포넌트를 추가하거나 +교체** 함으로써 기능을 확장합니다. 대표적인 용도는 다음과 같습니다: + +- 새로운 컴포넌트(헬퍼·서비스 등)의 추가 +- |Fess| 본체 컴포넌트의 교체(서브클래스화) +- REST API 엔드포인트의 추가(``WebApiManager``) +- 검색 동작의 확장(쿼리 커맨드, 랭크 퓨전 등) + +.. note:: + + 웹앱 플러그인은 JAR 로 배포되며, 내부의 클래스와 DI 설정 파일이 + |Fess| 웹 애플리케이션의 클래스패스에 로드됩니다. JSP 뷰를 추가하는 + 것은 아닙니다. 검색 화면의 디자인을 커스터마이즈하려면 + :doc:`theme-development` 를 참조하십시오. 기본 구조 -======== +========= + +웹앱 플러그인의 구현 템플릿인 +`fess-webapp-example `__ 를 +예로 들면, 플러그인은 「구현 클래스」와 「DI 등록 파일」로 구성됩니다: :: fess-webapp-example/ ├── pom.xml └── src/main/ - ├── java/org/codelibs/fess/app/web/example/ - │ └── ExampleAction.java - └── webapp/WEB-INF/view/example/ - └── index.jsp + ├── java/org/codelibs/fess/webapp/example/helper/ + │ ├── ExampleHelper.java # 추가할 컴포넌트 + │ └── CustomSystemHelper.java # 코어 컴포넌트의 교체 + └── resources/ + ├── app++.xml # 컴포넌트의 추가(병합) + └── fess+systemHelper.xml # 컴포넌트의 교체 + +.. note:: + + 구현 클래스의 패키지는 ``org.codelibs.fess.webapp.<플러그인 이름>`` 을 + 사용합니다. DI 설정 파일은 ``src/main/resources/`` 에 배치합니다. + 데이터스토어 플러그인과 달리 ``src/main/webapp/`` 나 JSP 는 포함하지 + 않습니다. + +pom.xml과 매니페스트 +==================== + +웹앱 플러그인은 ``fess-parent`` 를 부모 POM 으로 하는 jar 로 빌드합니다. +|Fess| 본체에서 실행 시 제공되는 ``fess`` 나 ``opensearch`` 는 ``provided`` +스코프로 선언하고, ``lastaflute``·``dbflute-runtime``·``corelib`` 등 실행 +시 필요한 라이브러리는 일반 스코프로 선언합니다. + +웹앱 플러그인에서 가장 중요한 것은 JAR 매니페스트에 ``Fess-WebAppJar: true`` +를 부여하는 것입니다. 이 선언에 의해 |Fess| 는 플러그인의 클래스와 DI 설정 +파일을 웹 애플리케이션의 클래스로더에 마운트합니다. 이 설정은 +``maven-jar-plugin`` 으로 수행합니다: + +.. code-block:: xml + + + + + maven-jar-plugin + + + + true + + + + + + + +.. warning:: + + ``Fess-WebAppJar: true`` 를 부여하지 않으면 플러그인의 클래스나 DI + 설정 파일이 웹 애플리케이션의 클래스패스에 로드되지 않아, 컴포넌트의 + 추가·교체가 활성화되지 않습니다. + +pom.xml 전체 구성(부모 POM·의존 관계 선언 방법 등)은 +:doc:`plugin-architecture` 를 참조하십시오. + +확장 패턴 +========= + +컴포넌트 추가(app++.xml) +------------------------- + +가장 기본적인 확장 방법은 자체 컴포넌트를 추가하는 것입니다. Lasta Di 는 +클래스패스 상의 ``app++.xml`` 을 |Fess| 본체의 ``app.xml`` 로부터 구축되는 +``app`` 네임스페이스에 **병합** 합니다(끝의 ``++`` 는 추가 병합 규약입니다). +추가하는 컴포넌트는 |Fess| 본체에 존재하지 않는 이름을 사용하므로, 아무것도 +덮어쓰지 않습니다. + +.. code-block:: xml + + + + + + + + +컴포넌트 구현에서는 초기화에 ``@PostConstruct`` 를 사용하고, |Fess| 본체의 +컴포넌트는 ``ComponentUtil`` 에서 가져와 재사용합니다(복사나 덮어쓰기는 +하지 않습니다): + +.. code-block:: java + + package org.codelibs.fess.webapp.example.helper; + + import org.codelibs.fess.helper.SystemHelper; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + + public class ExampleHelper { + + protected String pluginName = "fess-webapp-example"; + + @PostConstruct + public void init() { + // DI 에 의한 생성 후 한 번만 호출되는 초기화 처리 + } + + public String getPluginLabel() { + // 코어의 SystemHelper 를 재사용하여 실행 중인 Fess 버전을 취득 + final SystemHelper systemHelper = ComponentUtil.getSystemHelper(); + final String version = systemHelper != null ? systemHelper.getProductVersion() : "unknown"; + return pluginName + " (Fess " + version + ")"; + } + } + +.. tip:: + + 먼저 이 「컴포넌트 추가」를 검토하십시오. 코어 기능을 변경할 필요가 + 없는 한, 교체보다 안전하고 유지보수성이 뛰어납니다. + +코어 컴포넌트 교체(fess+componentName.xml) +------------------------------------------- -Action 구현 -========== +|Fess| 본체 컴포넌트의 동작을 변경하고 싶은 경우, 대상 클래스를 +서브클래스화하고 ``+.xml`` 이라는 이름의 DI +설정 파일로 **동일한 컴포넌트 이름으로 재등록** 합니다. 예를 들어 +``systemHelper`` 는 |Fess| 본체의 ``fess.xml`` 에서 선언되어 있으므로, +교체 파일은 ``fess+systemHelper.xml`` 이 됩니다(``app+systemHelper.xml`` +이 아닙니다). .. code-block:: java - package org.codelibs.fess.app.web.example; + package org.codelibs.fess.webapp.example.helper; - import org.codelibs.fess.app.web.base.FessSearchAction; - import org.lastaflute.web.Execute; - import org.lastaflute.web.response.HtmlResponse; + import java.nio.file.Path; - public class ExampleAction extends FessSearchAction { + import org.codelibs.fess.helper.SystemHelper; - @Execute - public HtmlResponse index() { - return asHtml(path_Example_IndexJsp); + public class CustomSystemHelper extends SystemHelper { + + @Override + protected void parseProjectProperties(final Path propPath) { + try { + super.parseProjectProperties(propPath); + } catch (final Exception e) { + // 자체 처리 + } + System.setProperty("fess.webapp.plugin", "true"); } } -JSP 템플릿 -=============== +.. warning:: + + 교체(단일 ``+``)는 컴포넌트 정의를 **통째로** 교체합니다. 이 때문에 + 교체 파일에는 코어 정의가 수행하고 있는 ```` 를 모두 + 기술해야 합니다. 예를 들어 ``systemHelper`` 를 교체하는 경우, 디자인 + JSP 이름 매핑(``addDesignJspFileName``)을 코어의 ``fess.xml`` 로부터 + 전부 복사하여 기술해야 합니다. 이는 |Fess| 릴리스마다 동기화해야 하며, + 누락이 있으면 일부 화면(``chat`` / ``login`` 등)을 해결할 수 없게 + 됩니다. 이러한 유지보수 비용이 교체보다 추가가 권장되는 이유입니다. -``src/main/webapp/WEB-INF/view/example/index.jsp``: +REST API 추가(fess_api++.xml) +------------------------------- -.. code-block:: jsp +새로운 REST API 엔드포인트를 추가하려면 ``WebApiManager`` 를 구현합니다. +``BaseApiManager`` 를 상속하고, ``@PostConstruct`` 에서 +``WebApiManagerFactory`` 에 자신을 등록합니다. 등록된 API 매니저는 +요청마다 ``WebApiFilter`` 에서 호출됩니다. ``fess_api++.xml`` 에서 +컴포넌트를 등록합니다: - <%@ page contentType="text/html; charset=UTF-8" %> - - - - Example Page - - -

Custom Page

-

This is a custom page added by plugin.

- - +.. code-block:: xml -API 확장 -======= + + + + + + .. code-block:: java - public class ApiExampleAction extends FessApiAction { + package org.codelibs.fess.webapp.example.api; + + import java.io.IOException; + + import org.codelibs.fess.api.BaseApiManager; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + import jakarta.servlet.FilterChain; + import jakarta.servlet.ServletException; + import jakarta.servlet.http.HttpServletRequest; + import jakarta.servlet.http.HttpServletResponse; + + public class ExampleApiManager extends BaseApiManager { + + public ExampleApiManager() { + // 이 매니저가 처리하는 경로의 프리픽스 + setPathPrefix("/api/example"); + } + + @PostConstruct + public void register() { + ComponentUtil.getWebApiManagerFactory().add(this); + } + + @Override + public boolean matches(final HttpServletRequest request) { + // 이 매니저가 요청을 처리할지 여부를 판정 + return request.getServletPath().startsWith(pathPrefix); + } - @Execute - public JsonResponse get$data() { - return asJson(new ApiResult.ApiResponse() - .result(Map.of("message", "Hello from plugin")) - .status(Status.OK)); + @Override + public void process(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain chain) throws IOException, ServletException { + // 요청 처리 및 응답 작성 + } + + @Override + protected void writeHeaders(final HttpServletResponse response) { + // 응답 헤더 설정(필요한 경우) } } +구현 예로는 ``/api/v1`` 을 제공하는 +`fess-webapp-v1-api `__ 나, +``/json`` / ``/suggest`` 를 제공하는 +`fess-webapp-classic-api `__ +가 참고가 됩니다. + +검색 화면 커스터마이즈 +====================== + +웹앱 플러그인은 JSP 뷰를 추가할 수 없습니다. JSP 뷰는 |Fess| 본체 WAR 의 +``WEB-INF/view/`` 에 배치되어 있으며, 플러그인 JAR 는 클래스패스 +(``WEB-INF/classes``)에 마운트되기 때문입니다. 검색 화면의 디자인을 +변경하려면 다음 중 하나를 사용합니다: + +- **테마**: 검색 화면의 디자인(HTML/CSS/JavaScript)을 커스터마이즈합니다. + :doc:`theme-development` 를 참조하십시오. +- **systemHelper 교체**: 위의 「코어 컴포넌트 교체」를 통해 디자인 JSP + 이름 매핑을 변경할 수 있습니다(단, JSP 파일 자체는 |Fess| 본체가 + 제공합니다). + +빌드와 설치 +=========== + +:: + + mvn clean package + +``target/`` 디렉터리에 JAR 파일(예: ``fess-webapp-example-15.8.0.jar``)이 +생성됩니다. 생성한 JAR 는 관리 화면에서 설치하거나, ``app/WEB-INF/plugin/`` +디렉터리에 배치하고 |Fess| 를 재시작합니다. 설치 절차의 자세한 내용은 +:doc:`../admin/plugin-guide` 를 참조하십시오. + +공개 플러그인 예 +================ + +|Fess| 프로젝트에서는 다음의 웹앱 플러그인이 공개되어 있습니다. +개발 참고용으로 `GitHub `__ 에 공개되어 +있습니다: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - 플러그인 + - 설명 + * - ``fess-webapp-example`` + - 플러그인 구현의 템플릿 + * - ``fess-webapp-v1-api`` + - ``/api/v1`` REST API + * - ``fess-webapp-classic-api`` + - ``/json`` / ``/suggest`` 레거시 REST API + * - ``fess-webapp-mcp`` + - MCP(Model Context Protocol) 서버 + * - ``fess-webapp-semantic-search`` + - 뉴럴 검색/벡터 검색 + * - ``fess-webapp-multimodal`` + - 멀티모달(이미지·텍스트) 검색 + 참고 정보 -======== +========= - :doc:`plugin-architecture` - 플러그인 아키텍처 +- :doc:`theme-development` - 테마 커스터마이즈 +- :doc:`../admin/plugin-guide` - 플러그인 설치 - :doc:`overview` - 개발자 문서 개요 diff --git a/zh-cn/15.8/dev/webapp-plugin.rst b/zh-cn/15.8/dev/webapp-plugin.rst index ce3d56cf..6e024235 100644 --- a/zh-cn/15.8/dev/webapp-plugin.rst +++ b/zh-cn/15.8/dev/webapp-plugin.rst @@ -5,78 +5,302 @@ Web应用插件 概述 ==== -Web应用插件可以扩展Fess的Web界面。 -可以添加新页面、自定义管理界面等。 +Web应用插件(``fess-webapp-*``)是用于扩展 |Fess| 的Web应用程序的插件。 +与其他类型的插件不同,它并非直接添加 Action 类或 JSP,而是通过对 DI 容器 +(Lasta Di)**添加或替换组件** 来扩展功能。典型的用途如下: + +- 添加新组件(辅助类、服务等) +- 替换(子类化)|Fess| 本体的组件 +- 添加 REST API 端点(``WebApiManager``) +- 扩展搜索行为(查询命令、Rank Fusion 等) + +.. note:: + + Web应用插件以 JAR 文件的形式分发,其中的类和 DI 配置文件会被加载到 + |Fess| 的Web应用程序的类路径中。它并不能添加 JSP 视图。如果需要自定义 + 搜索界面的设计,请参考 :doc:`theme-development`。 基本结构 ======== +以Web应用插件的实现模板 +`fess-webapp-example `__ +为例,插件由"实现类"和"DI 注册文件"构成: + :: fess-webapp-example/ ├── pom.xml └── src/main/ - ├── java/org/codelibs/fess/app/web/example/ - │ └── ExampleAction.java - └── webapp/WEB-INF/view/example/ - └── index.jsp + ├── java/org/codelibs/fess/webapp/example/helper/ + │ ├── ExampleHelper.java # 要添加的组件 + │ └── CustomSystemHelper.java # 核心组件的替换 + └── resources/ + ├── app++.xml # 组件的添加(合并) + └── fess+systemHelper.xml # 组件的替换 -Action实现 -========== +.. note:: + + 实现类的包名使用 ``org.codelibs.fess.webapp.<插件名>``。DI 配置文件 + 存放在 ``src/main/resources/`` 中。与数据存储插件不同,这里不包含 + ``src/main/webapp/`` 或 JSP。 + +pom.xml与清单文件 +================= + +Web应用插件以 ``fess-parent`` 作为父 POM,构建为 jar。由 |Fess| 本体在 +运行时提供的 ``fess``、``opensearch`` 需以 ``provided`` 作用域声明; +``lastaflute``、``dbflute-runtime``、``corelib`` 等运行时所需的库,则以 +通常的作用域声明。 + +Web应用插件中最重要的一点,是在 JAR 清单文件中添加 +``Fess-WebAppJar: true``。通过这一声明,|Fess| 会将插件的类和 DI 配置 +文件挂载到Web应用程序的类加载器中。该设置通过 ``maven-jar-plugin`` +完成: + +.. code-block:: xml + + + + + maven-jar-plugin + + + + true + + + + + + + +.. warning:: + + 如果不添加 ``Fess-WebAppJar: true``,插件的类和 DI 配置文件将不会被 + 加载到Web应用程序的类路径中,组件的添加与替换也将不会生效。 + +关于 pom.xml 的完整构成(父 POM、依赖关系的声明方法等),请参考 +:doc:`plugin-architecture`。 + +扩展模式 +======== + +组件的添加(app++.xml) +----------------------- + +最基本的扩展方式是添加自己的组件。Lasta Di 会将类路径上的 ``app++.xml`` +**合并** 到由 |Fess| 本体的 ``app.xml`` 构建而成的 ``app`` 命名空间中 +(末尾的 ``++`` 是追加合并的约定)。由于添加的组件使用了 |Fess| 本体中 +不存在的名称,因此不会覆盖任何内容。 + +.. code-block:: xml + + + + + + + + +在组件的实现中,初始化使用 ``@PostConstruct``,|Fess| 本体的组件则通过 +``ComponentUtil`` 获取后复用(不进行复制或覆盖): + +.. code-block:: java + + package org.codelibs.fess.webapp.example.helper; + + import org.codelibs.fess.helper.SystemHelper; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + + public class ExampleHelper { + + protected String pluginName = "fess-webapp-example"; + + @PostConstruct + public void init() { + // 由 DI 生成后仅调用一次的初始化处理 + } + + public String getPluginLabel() { + // 复用核心的 SystemHelper 获取正在运行的 Fess 版本 + final SystemHelper systemHelper = ComponentUtil.getSystemHelper(); + final String version = systemHelper != null ? systemHelper.getProductVersion() : "unknown"; + return pluginName + " (Fess " + version + ")"; + } + } + +.. tip:: + + 请首先考虑这种"组件的添加"方式。只要不需要修改核心功能,它就比替换 + 更安全,也更易于维护。 + +核心组件的替换(fess+componentName.xml) +----------------------------------------- + +如果想要改变 |Fess| 本体组件的行为,需要将目标类子类化,并在名为 +``+.xml`` 的 DI 配置文件中 **以相同的组件名 +重新注册**。例如,由于 ``systemHelper`` 是在 |Fess| 本体的 ``fess.xml`` +中声明的,因此替换文件应为 ``fess+systemHelper.xml``(而不是 +``app+systemHelper.xml``)。 .. code-block:: java - package org.codelibs.fess.app.web.example; + package org.codelibs.fess.webapp.example.helper; + + import java.nio.file.Path; - import org.codelibs.fess.app.web.base.FessSearchAction; - import org.lastaflute.web.Execute; - import org.lastaflute.web.response.HtmlResponse; + import org.codelibs.fess.helper.SystemHelper; - public class ExampleAction extends FessSearchAction { + public class CustomSystemHelper extends SystemHelper { - @Execute - public HtmlResponse index() { - return asHtml(path_Example_IndexJsp); + @Override + protected void parseProjectProperties(final Path propPath) { + try { + super.parseProjectProperties(propPath); + } catch (final Exception e) { + // 自定义处理 + } + System.setProperty("fess.webapp.plugin", "true"); } } -JSP模板 -======= +.. warning:: -``src/main/webapp/WEB-INF/view/example/index.jsp``: + 替换(单个 ``+``)会 **整体** 替换组件定义。因此,替换文件中必须写出 + 核心定义所进行的所有 ````。例如,在替换 + ``systemHelper`` 时,必须将设计 JSP 名称的映射 + (``addDesignJspFileName``)从核心的 ``fess.xml`` 中全部复制过来并 + 写入。这些内容需要随 |Fess| 的每次发布进行同步,一旦有遗漏,部分画面 + (如 ``chat`` / ``login`` 等)将无法解析。这一维护成本,正是相比替换 + 更推荐使用添加方式的原因。 -.. code-block:: jsp +REST API的添加(fess_api++.xml) +--------------------------------- - <%@ page contentType="text/html; charset=UTF-8" %> - - - - Example Page - - -

Custom Page

-

This is a custom page added by plugin.

- - +要添加新的 REST API 端点,需要实现 ``WebApiManager``。继承 +``BaseApiManager``,并在 ``@PostConstruct`` 中向 ``WebApiManagerFactory`` +注册自身。注册后的 API 管理器会在每次请求时被 ``WebApiFilter`` 调用。 +通过 ``fess_api++.xml`` 注册组件: -API扩展 -======= +.. code-block:: xml + + + + + + + .. code-block:: java - public class ApiExampleAction extends FessApiAction { + package org.codelibs.fess.webapp.example.api; + + import java.io.IOException; + + import org.codelibs.fess.api.BaseApiManager; + import org.codelibs.fess.util.ComponentUtil; + + import jakarta.annotation.PostConstruct; + import jakarta.servlet.FilterChain; + import jakarta.servlet.ServletException; + import jakarta.servlet.http.HttpServletRequest; + import jakarta.servlet.http.HttpServletResponse; - @Execute - public JsonResponse get$data() { - return asJson(new ApiResult.ApiResponse() - .result(Map.of("message", "Hello from plugin")) - .status(Status.OK)); + public class ExampleApiManager extends BaseApiManager { + + public ExampleApiManager() { + // 该管理器所处理路径的前缀 + setPathPrefix("/api/example"); + } + + @PostConstruct + public void register() { + ComponentUtil.getWebApiManagerFactory().add(this); + } + + @Override + public boolean matches(final HttpServletRequest request) { + // 判断该管理器是否处理此请求 + return request.getServletPath().startsWith(pathPrefix); + } + + @Override + public void process(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain chain) throws IOException, ServletException { + // 处理请求并写入响应 + } + + @Override + protected void writeHeaders(final HttpServletResponse response) { + // 设置响应头(如有需要) } } +作为实现示例,可以参考提供 ``/api/v1`` 的 +`fess-webapp-v1-api `__, +以及提供 ``/json`` / ``/suggest`` 的 +`fess-webapp-classic-api `__。 + +搜索界面的自定义 +================ + +Web应用插件无法添加 JSP 视图。这是因为 JSP 视图存放在 |Fess| 本体 WAR 的 +``WEB-INF/view/`` 中,而插件 JAR 是挂载到类路径(``WEB-INF/classes``) +上的。如果需要修改搜索界面的设计,请使用以下方式之一: + +- **主题**:自定义搜索界面的设计(HTML/CSS/JavaScript)。请参考 + :doc:`theme-development`。 +- **替换 systemHelper**:通过上述"核心组件的替换"方式,可以更改设计 + JSP 名称的映射(但 JSP 文件本身仍由 |Fess| 本体提供)。 + +构建与安装 +========== + +:: + + mvn clean package + +会在 ``target/`` 目录下生成 JAR 文件(例如 +``fess-webapp-example-15.8.0.jar``)。生成的 JAR 可以从管理界面安装, +也可以放置到 ``app/WEB-INF/plugin/`` 目录后重启 |Fess|。安装步骤的详细 +信息请参考 :doc:`../admin/plugin-guide`。 + +公开插件示例 +============ + +|Fess| 项目公开了以下Web应用插件。这些插件已在 +`GitHub `__ 上公开,可作为开发参考: + +.. list-table:: + :header-rows: 1 + :widths: 35 65 + + * - 插件 + - 说明 + * - ``fess-webapp-example`` + - 插件实现的模板 + * - ``fess-webapp-v1-api`` + - ``/api/v1`` REST API + * - ``fess-webapp-classic-api`` + - ``/json`` / ``/suggest`` 旧版REST API + * - ``fess-webapp-mcp`` + - MCP(Model Context Protocol)服务器 + * - ``fess-webapp-semantic-search`` + - 神经搜索/向量搜索 + * - ``fess-webapp-multimodal`` + - 多模态(图像、文本)搜索 + 参考信息 ======== - :doc:`plugin-architecture` - 插件架构 +- :doc:`theme-development` - 主题自定义 +- :doc:`../admin/plugin-guide` - 插件安装 - :doc:`overview` - 开发者文档概述 -