Alkalmazások fejlesztése

13. gyakorlat

Horváth Győző
Egyetemi adjunktus
1117 Budapest, Pázmány Péter sétány 1/c., 2.420-as szoba
Tel: (1) 372-2500/1816
horvath.gyozo@inf.elte.hu

Tartalomjegyzék

  • Webalkalmazás embedded jettyvel
  • Spring Web MVC használata
  • Thymeleaf template engine használata
  • CRUD műveletek in-memory listával

Webalkalmazás embedded jettyvel

Maven

  • Parancssori build eszköz.
  • POM = Project Object Model
  • A projektet a pom.xml-ben írjuk le
  • A super pom miatt konfiguráció nélkül tud alap dolgokat a projektünk.

Könyvtárstruktúra kialakítása

|-src
|   |-main
|      |-java
|      |   |-hu
|      |       |-elte
|      |           |-HelloWorld.java
|      |-webapp
|          |-WEB-INF
|              |-web.xml
|-pom.xml

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>hu.elte</groupId>
    <artifactId>my-spring-app</artifactId>
    <version>1.0.0</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.3.8.v20160314</version>
            </plugin>
        </plugins>
    </build>
</project>

pom.xml

  • Ezzel írjuk le a projektünket.
  • groupId: domain névhez hasonló azonosító
  • artifactId: a projekt azonosítója a groupon belül
  • dependencies: függőségek.
  • javax.servlet-api: javax.servlet package-ben lévő osztályok.
  • build: jetty-maven-plugin

HelloWorld.java

package hu.elte;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloWorld extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("Hello, world!");
    }
}

Ez a mi kis servletünk, ez fogja majd kiszolgálni a http kérést.

web.xml

A web container olvassa be, így tudunk végpontokhoz servleteket kötni

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    <servlet>
        <servlet-name>my-hello</servlet-name>
        <servlet-class>hu.elte.HelloWorld</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>my-hello</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

Indítás

  • szerver: mvn jetty:run
  • böngésző: localhost:8080

Spring Web MVC

  • Végpontokhoz metódusok rendelése
  • Placeholderek behelyettesítése, pl. /show/{id}
  • Viewk kezelése

pom.xml módosítása

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>
</dependencies>

A javax.servlet-api-t ki is törölhetjük, mivel már nem servleteket írunk.

Kontroller

  • Töröljük ki a HelloWorld.java-t!
  • Hozzuk létre a hu.elte.MainController.java-t!
  • @Controller, @RequestMapping annotációk
package hu.elte;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;
import java.io.Writer;

@Controller
public class MainController {

    @RequestMapping("/")
    public void mainPage(Writer responseWriter) throws IOException {
        responseWriter.write("hello from spring!");
    }
}

web.xml módosítása

  • Nem saját servletünk lesz, a spring dispatcher servletére bízzuk a routingot.
  • Ehhez kell a springnek egy config fájl (pl. spring.xml), amit a contextConfigLocation-ben adunk meg.
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>spring.xml</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

spring.xml

  • Hozzuk létre az src/main/webapp/spring.xml fájlt!
  • context:component-scan
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="hu.elte" />

</beans>

Próbáljuk ki!

Thymeleaf template engine

Thymeleaf konfiguráció

<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring4</artifactId>
    <version>3.0.2.RELEASE</version>
</dependency>
<bean id="templateResolver"
      class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
    <property name="prefix" value="/views/" />
    <property name="suffix" value=".html" />
    <property name="templateMode" value="HTML5" />
</bean>
<bean id="templateEngine"
      class="org.thymeleaf.spring4.SpringTemplateEngine">
    <property name="templateResolver" ref="templateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine" />
</bean>

View renderelése

Hozzuk létre az src/main/webapp/views/index.html-t!

Controller metódus: return "index"

Adatok átadása a view-nak

  • String helyett ModelAndView-val térünk vissza.
  • View-t kiegészítjük
  • Nézzük meg, hogy néz ki a view közvetlenül megnyitva!
ModelAndView result = new ModelAndView("index");
result.addObject("title", "My page");
return result;
<h1 th:text="${title}">Oldal címe</h1>

CRUD műveletek in-memory listával

Receptek listázása

  • Hozzuk létre a Recipe osztályt (name, description)
    • Generáljunk hozzá konstruktort (paraméteres és üres is kell)
    • Generáljunk hozzá gettereket, settereket
  • Vegyünk fel a MainControllerben egy recipes listát!
    • Adatbázis helyett egy memóriában lévő objektummal dolgozunk
  • Tegyünk bele néhány elemet
  • Adjuk át a viewnak ezt a listát!
  • Jelenítsük meg a view-ban!
<table>
    <tr th:each="recipe, iterStat:${recipes}">
        <td th:text="${recipe.name}">Recept 1</td>
        <td th:text="${recipe.description}">Leírás 1</td>
        <td>
            <a th:href="@{'/recipe/'+${iterStat.index}}">Szerkesztés</a>
        </td>
    </tr>
</table>

Receptek szerkesztése

  • Hozzuk létre a metódusokat (GET és POST)!
  • POST-nál rakjunk be egy Recipe típusú paramétert
  • Hozzunk létre egy viewt!
@RequestMapping(path = "/recipe/{id}", method = RequestMethod.GET)
public ModelAndView edit(@PathVariable int id) {
    //...
}

Receptek létrehozása

  • Hozzuk létre a GET és POST metódusokat!
  • Új recept létrehozása után irányítsuk át annak szerkesztésére!

return "redirect:/recipe/" + (recipes.size() - 1);

Receptek törlése

  • Vegyünk fel egy új oszlopot a szerkesztés mellé!
  • Tegyünk bele egy formot!
  • Hozzuk létre a megfelelő metódust!