Java-kielinen verkkoprojektiesimerkki

Tämän laittaminen on jonkin verran viivästynyt, mutta olen laatinut arkkityypiksi kelpaavan verkkoprojektiesimerkin. Se on saatavissa tästä linkistä:

warproject.zip

Sitä voi kokeilla avaamalla paketin:

$ unzip -d warproject warproject.zip
$ cd warproject
$ mvn clean install
$ mvn jetty:run

ja täyttämällä lomakkeen osoitteessa http://localhost:8080/lomake

Painamalla nappia ”Lähetä”, ladataan uusi sivu, jossa toistetaan täytetyt tiedot ja painamalla nappia ”Lähetä AJAX”, muodostetaan AJAX-pyyntö, jonka perusteella vastaus tuotetaan Javascriptillä selaimen ruudulle. Seuraavassa selitetään tarkemmin sovelluksen eri osia ja mitä on muuttunut ”jarproject”-Maven-projektiin nähden.

Laitetaan seuraavaksi kokonaisuudessaan Maven-projektin selitystiedosto pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>fi.mikkonummelin</groupId>
    <artifactId>warproject</artifactId>
    <packaging>war</packaging>
    <version>0.1-SNAPSHOT</version>
    <name>${project.artifactId}</name>
    <url>http://www.mikkonummelin.fi</url>
    <!-- EXAMPLE! For release plugin.
    <scm>
        <developerConnection>scm:git:file:///home/mnummeli/Asiakirjat/java/jarproject</developerConnection>
        <tag>HEAD</tag>
    </scm>
    -->
    <properties>
        <commons-logging.version>1.1.3</commons-logging.version>
        <junit.version>4.11</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <servlet-api.version>3.1.0</servlet-api.version>
        <jsp-api.version>2.3.1</jsp-api.version>
        <jstl.version>1.2</jstl.version>
        <jackson-databind.version>2.3.0</jackson-databind.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet-api.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>${jsp-api.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>${jstl.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson-databind.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>${commons-logging.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.6</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.1.1.v20140108</version>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    <!-- EXAMPLE! For release plugin.
    <distributionManagement>
        <repository>
            <id>Local Releases</id>
            <name>My Local Releases Repository</name>
            <url>file:///home/mnummeli/maven-releases</url>
        </repository>
    </distributionManagement>
    -->
</project>

Uusina liitännäisinä tässä ovat maven-war-plugin ja jetty-maven-plugin. Ensinmainittu määrittelee, että projekti käännetään Java-sovelluspalvelimelle, kuten Tomcatille, Jettylle, JBossille tm. kelpaavaksi verkkosovellukseksi ja jälkimmäisenä mainittu taas määrittelee, että lähtökohtaisesti käytetään sisäänrakennettua Jettyä.

Mistä sitten tulivat sovelluksen verkkosivut ja niiden toiminnallisuus? Lomake on määritelty seuraavasti:

 <%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8"/>
        <link rel="stylesheet" type="text/css" href="/css/style.css" />
        <title>Lomake</title>
        <script src="/js/jquery-1.11.0.min.js"></script>
        <script src="/js/lomake.js"></script>
    </head>
    <body>
        <div class="m1">
            <h1>Täytä lomake</h1>
            <hr/>
            <form action="lomake/vastaus">
                <p style="float: left;">Nimi:</p><input type="text" id="nimi" name="nimi"/><div style="clear: both;"></div>
                <p style="float: left;">Osoite:</p><input type="text" id="osoite" name="osoite"/><div style="clear: both;"></div>
                <input type="submit" value="Lähetä"/>
                <button id="laheta_ajax" type="button">Lähetä AJAX-viesti</button>
            </form>
            <p id="ajaxvastauksentulos">

            </p>
        </div>
    </body>
</html>

ja vastaussivu samaan tapaan, tosin yksinkertaisempana. Kun selaimeen kirjoitti:

http://localhost:8080/lomake

tunnisti sovelluspalvelin ilmaisun ”/lomake” sovelman nimeksi ja kykeni ratkaisemaan sen huomioimalla tiedostosta LomakeServlet.java, annotaation WebServlet:

package fi.mikkonummelin.warproject;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;
import org.apache.commons.logging.*;

@WebServlet("/lomake/*")
public class LomakeServlet extends HttpServlet {

    private static final Log LOG = LogFactory.getLog(LomakeServlet.class);

    private void defaultAction(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        req.getRequestDispatcher("/WEB-INF/lomake.jsp").forward(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String pathName = req.getPathInfo();
        LOG.info("Pathname: " + pathName);
        if (pathName == null) {
            defaultAction(req, resp);
            return;
        }
        switch (pathName) {
            case "/vastaus": {
                String nimi = req.getParameter("nimi");
                String osoite = req.getParameter("osoite");
                req.setAttribute("nimi", nimi);
                req.setAttribute("osoite", osoite);
                req.getRequestDispatcher("/WEB-INF/vastaus.jsp").forward(req, resp);
                break;
            }
            case "/ajaxvastaus": {
                LOG.info("AJAX:ia kysytty!");
                String nimi = req.getParameter("nimi");
                String osoite = req.getParameter("osoite");
                resp.setContentType("application/json");
                LOG.info("nimi="+nimi+", osoite="+osoite);
                NimiJaOsoite njo = new NimiJaOsoite(nimi, osoite);
                ObjectMapper mapper;
                mapper = new ObjectMapper();
                mapper.writeValue(resp.getOutputStream(), njo);
                break;
            }

            default: {
                defaultAction(req, resp);
            }
        }
    }
}

ja vastaavasti vastaus tai AJAX-vastaus on prosessoitu omissa vaihtoehdoissaan tarkemman polkunimen perusteella. AJAX-vastaus vaatii lisäksi sen, että lomakkeessa mainittu nappi laheta_ajax on liitetty JQuery-JavaScript-kirjaston avulla seuraavanlaiseen JavaScript-ohjelmanpätkään:

$(document).ready(function() {
    $('#laheta_ajax').click(function() {
        $.ajax({
            url: '/lomake/ajaxvastaus',
            data: {
                nimi: $('#nimi').val(),
                osoite: $('#osoite').val()
            },
            type: 'GET',
            dataType: 'json',
            success: function(json) {
                $('#ajaxvastauksentulos').html('Hei ' + json.nimi +
                        "! Annoit osoitteeksesi " + json.osoite + ".");
            }
        });
    });
});

Mainittu JavaScript-pätkä myös muokkaa sivua sopivasti.