PA165/Cvičení webové aplikace 1 - Servlet API 3.0: Porovnání verzí

Z FI WIKI
Přejít na: navigace, hledání
(Manipulace DOM a CSS z JavaScriptu)
(AJAX)
Řádka 384: Řádka 384:
  
 
== AJAX ==
 
== AJAX ==
 +
 +
Využijeme knihovnu [http://jquery.com/ JQuery], která značně zjednodušuje práci s JavaScriptem.
 +
 +
Vytvořte si nový servlet '''MyAjaxServlet.java''' s obsahem
 +
<java>
 +
package cz.muni.fi.pa165.web1;
 +
 +
import javax.servlet.ServletException;
 +
import javax.servlet.annotation.WebServlet;
 +
import javax.servlet.http.HttpServlet;
 +
import javax.servlet.http.HttpServletRequest;
 +
import javax.servlet.http.HttpServletResponse;
 +
import java.io.IOException;
 +
 +
@WebServlet(urlPatterns = {"/ajax/*"})
 +
public class MyAjaxServlet extends HttpServlet {
 +
 +
    @Override
 +
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 +
 +
    }
 +
 +
    @Override
 +
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 +
 +
    }
 +
 +
    @Override
 +
    protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 +
        System.out.println("přišel požadavek na smazání souboru"+request.getPathInfo());
 +
        response.setContentType("text/html;charset=utf-8");
 +
        response.getWriter().println("provedeno");
 +
    }
 +
}
 +
</java>
 +
 +
a novou JSP stránku '''ajax.jsp''' s obsahem:
 +
<xml>
 +
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
 +
<html>
 +
<head>
 +
    <title>Ukázka AJAX</title>
 +
    <!-- zavedení JQuery -->
 +
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
 +
</head>
 +
<body>
 +
<h1>Ukázka AJAX</h1>
 +
 +
 +
 +
</body>
 +
</html>
 +
</xml>

Verze z 6. 11. 2012, 12:26


Prostředí

  • NetBeans 7.2
  • Oracle JDK 7
  • Tomcat 7
  • Maven 3
module add netbeans-7.2 jdk-1.7.0_03 maven-3.0.4

Vytvoření projektu

Vytvořte v NetBeans nový projekt pro webovou aplikaci typu Maven tj. File - New project - Categories:Maven - Project: Web Application, položku Package zvolte jako cz.muni.fi.pa165.web1.

Vytvořený projekt zkuste spustit (klávesa F6), měl by se otveřít prohlížeč a v něm stránka s nápisem Hello World!.


úvodní stránka

Zeditujte soubor index.jsp a vyměňte jeho obsah za následující HTML5:

 
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <title>Domov</title>
    </head>
    <body>
        <h1>Sláva, funguje to!</h1>
        <ul>
            <li><a href="${pageContext.request.contextPath}/text/primo?a=1&b=ccc">text přímo ze servletu</a></li>
            <li><a href="${pageContext.request.contextPath}/soubor">soubor</a></li>
            <li><a href="${pageContext.request.contextPath}/presmerovani">přesměrování</a></li>
            <li><a href="${pageContext.request.contextPath}/chranene">chráněné heslem</a></li>
            <li><a href="${pageContext.request.contextPath}/text/ble">chyba</a></li>
        </ul>
        <h2>Bude fungovat</h2>
        <ul>
            <li><a href="${pageContext.request.contextPath}/text/zjsp">text z JSP</a></li>
            <li><a href="${pageContext.request.contextPath}/dhtml.html">JavaScript, DOM a CSS</a></li>
            <li><a href="${pageContext.request.contextPath}/ajax.jsp">AJAX</a></li>
        </ul>
    </body>
</html>

Výraz ${pageContext.request.contextPath} vkládá před relativní odkazy prefix servletové aplikace.

Servlet

V package cz.muni.fi.pa165.web1 vytvořte novou třídu servletu kliknutím pravým tlačítkem na balík, vyberte New - Java class a pojmenujte ji MyDemoServlet.

Přepište zdrojový kód třídy na:

 
package cz.muni.fi.pa165.web1;
 
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import javax.xml.bind.DatatypeConverter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.*;
import java.util.zip.*;
 
@WebServlet(urlPatterns = {"/text/*", "/soubor/*", "/chranene/*", "/presmerovani/*"})
public class MyDemoServlet extends HttpServlet {
 
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if ("/text".equals(request.getServletPath()) && "/primo".equals(request.getPathInfo())) {
            response.setContentType("text/html;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.println("<pre>text přímo ze servletu");
            out.println("serverInfo=" + getServletContext().getServerInfo());
            out.println("parametry:");
            for (String p : Collections.list(request.getParameterNames())) {
                out.println(p + "=" + request.getParameter(p));
            }
            return;
        } else if ("/text".equals(request.getServletPath()) && "/zjsp".equals(request.getPathInfo())) {
            request.setAttribute("seznam", Arrays.asList("mléko", "rohlíky", "salám"));
            request.getRequestDispatcher("/stranka2.jsp").forward(request, response);
            return;
        } else if ("/soubor".equals(request.getServletPath())) {
            response.setContentType("application/zip");
            response.setHeader("Content-disposition", "attachment; filename=\"neco.zip\"");
            ServletOutputStream sos = response.getOutputStream();
            ZipOutputStream zos = new ZipOutputStream(sos);
            zos.putNextEntry(new ZipEntry("neco.txt"));
            zos.write("nějaký text".getBytes());
            zos.putNextEntry(new ZipEntry("necojineho.txt"));
            zos.write("jiný text".getBytes());
            zos.close();
            return;
        } else if ("/presmerovani".equals(request.getServletPath())) {
            String url = request.getContextPath() + "/text/primo?z=" + URLEncoder.encode("?/ =", "utf-8");
            response.sendRedirect(response.encodeRedirectURL(url));
        } else if ("/chranene".equals(request.getServletPath())) {
            String auth = request.getHeader("Authorization");
            if (auth == null) {
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setHeader("WWW-Authenticate", "Basic realm=\"zadej heslo\"");
                return;
            }
            response.setContentType("text/html;charset=utf-8");
            PrintWriter out = response.getWriter();
            String[] creds = new String(DatatypeConverter.parseBase64Binary(auth.split(" ")[1])).split(":", 2);
            out.println("<pre>zadáno jméno a heslo " + creds[0] + ":" + creds[1]);
            return;
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "Nerozpoznane URL");
            return;
        }
    }
}

Opět spusťte aplikaci a proklikejte si odkazy.

Komentáře

Povšimněte si ve výše uvedeném kódu servletu následujících věcí:

  • třída servletu je mapována na URL pomocí anotace @WebServlet
  • mapované URL se skládá ze tří částí - contextPath, servletPath a pathInfo
  • metoda request.getParameterNames() vrací z historických důvodů java.util.Enumeration, na Iterable ji zkonvertujeme pomocí Collections.list()
  • všechny parametry requestu jsou typu String
  • při přeposlání (forward) na jiný servlet/JSP se data předávají pomocí metody setAttribute()
  • při zasílání binárního obsahu můžeme pomocí HTTP hlavičky Content-disposition určit, zda se má přímo zobrazit (hodnota inline) nebo uložit (hodnota attachment)
  • při přesměrování (redirect) je nutné před URL přidat contextPath, URL prohnat metodou encodeRedirectURL() a hodnoty případných parametrů musí být URL-encoded
  • u URL chráněného heslem jdou jméno a heslo nezašifrovaně, jen spojené dvojtečkou a zapsané pomocí Base64
  • místo obsahu a přesměrování můžeme poslat prohlížeči chybové hlášení metodou sendError()

JSP - Java Server Page

V předchozí ukázce nefungoval odkaz /text/zjsp, protože zatím neexistovala JSP stránka, na kterou se předávalo řízení.

Nyní vytvořte v adresáři src/main/webapp soubor stranka.jsp a zeditujte mu obsah na následující:

 
<%@page import="java.util.List"%>
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
  <title>JSP stránka</title>
  <style>
   #nadpis { color: red; }   
   table.zakladni { border-collapse: collapse; margin: 10px; }
   table.zakladni th, table.zakladni td {  border: solid 1px black; padding: 4px; }
  </style>
  <script>
      console.log("ahoj");
  </script>
</head>
<body>
  <h1 id="nadpis">JSP stránka</h1>
  <p>seznam</p>
  <table class="zakladni">
      <% List<String> seznam = (List<String>) pageContext.findAttribute("seznam");
      for(int i=0,n=seznam.size();i<n;i++) { %>          
      <tr>
          <td><%=i%></td>
          <td><%=seznam.get(i)%></td>
      </tr>
      <% } %>
  </table>
</body>
</html>

Spusťte znovu aplikaci a vyzkoušejte stránku. Ve Firefoxu po zmáčknutí Ctrl+Shift+K nebo v Chrome po zmáčknutí F12 můžete vidět JavaScriptovou konzolu s výpisem skriptu.

Komentáře

  • na začátku JSP stránky je důležité definovat kódování výstupu parametrem charset, jinak se použije iso-8859-1
  • pomocí CSS selektoru #nadpis nastavujeme vzhled právě jednoho prvku s atributem id="nadpis"
  • pomocí CSS selektoru .zakladni nastavujeme vzhled všech prvků s atributem class="zakladni"
  • v JavaScriptu můžeme psát trasovací výpisy pomocí console.log()
  • příkazy v jazyce Java se vkládají mezi <% %>
  • v JSP vždy existuje implicitní proměnná pageContext typu PageContext
  • v JSP vždy existuje implicitní proměnná out typu JspWriter
  • místo <%out.print(i);%> lze zkráceně psát <%=i%>
  • přímé vypisování textů je nebezpečné, mohou obsahovat speciální znaky z HTML <>& ale není standardní třída pro HTML-encoding pomocí entit &lt; &gt; &amp;

JSP stránka s JSTL

Místo kodu v Javě lze výhodně využít tzv. JSTL (JSP Standard Tag Library). Ta však není standardně součástí servletového containeru.

Aktivace JSTL

Do souboru pom.xml přidejte tuto závislost před tag </dependencies>:

 
   <dependency>
     <groupId>org.glassfish.web</groupId>
     <artifactId>javax.servlet.jsp.jstl</artifactId>
     <version>1.2.2</version>
   </dependency>

Použití

V servletu změňte forward ze stranka.jsp na stranka2.jsp a vytvořte soubor src/main/webapp/stranka2.jsp s následujícím obsahem:

 
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html>
<head>
    <title>JSP stránka</title>
    <style>
        #nadpis { color: green; }
        table.zakladni { border-collapse: collapse; margin: 10px; }
        table.zakladni th, table.zakladni td {  border: solid 1px black; padding: 4px; }
    </style>
    <script>
        console.log("ahoj");
    </script>
</head>
<body>
<h1 id="nadpis">JSP stránka</h1>
<p>seznam</p>
<table class="zakladni">
    <c:forEach items="${seznam}" var="s" varStatus="i">
    <tr>
        <td>${i.count}</td>
        <td><c:out value="${s}"/></td>
    </tr>
    </c:forEach>
</table>
</body>
</html>

Komentáře

  • na začátku JSP je třeba knihovny značek navázat na nějaké prefixy pomocí direktiv <%@ taglib %>
  • značka <c:forEach> iteruje svoje tělo přes položky zadané atributem items, v něm lze výhodně použít jazyk EL
  • značka <c:forEach> ukládá aktuální položku do atributu pageContext určeného atributem značky var
  • pomocí atributu značky varStatus lze získat objekt typu LoopTagStatus, pomocí kterého lze získat pozici (count - od 1) nebo index (od 0) v rámci iterace
  • značka <c:out> zajistí HTML-encoding speciálních znaků

Použití jazyka EL není nutné, jen výhodné. Alternativně jsme mohli použít jazyk Java:

 
<%@ page import="javax.servlet.jsp.jstl.core.LoopTagStatus" %>
...
    <c:forEach items='<%=pageContext.findAttribute("seznam")%>' var="s" varStatus="i">
    <tr>
        <td><%=((LoopTagStatus)pageContext.findAttribute("i")).getCount()%></td>
        <td><c:out value='<%=pageContext.findAttribute("s")%>'/></td>
    </tr>
    </c:forEach>

Manipulace DOM a CSS z JavaScriptu

Zatím jsme generovali stránky na serveru v konečné podobě. Lze však využít jazyka JavaScript k manipulaci CSS (Cascading Style Sheet) vlastností jednotlivých objektů tvořící DOM (Document Object model) strom HTML stránky.

Vytvořte si novou statickou HTML stránku dhtml.html s obsahem:

 
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Dynamické HTML 5</title>
    <style>
        #nadpis {
            color: black;
        }
 
        p#volba2 span {
            display: inline-block;
            width: 60px;
            height: 20px;
            border-radius: 4px;
            border: 1px solid gray;
            padding: 5px;
            text-decoration: none;
        }
    </style>
    <script>
        console.log("začínáme");
 
        function changeTextColor(color) {
            console.log("barva=" + color);
            document.getElementById('nadpis').style.color = color;
        }
 
        function changeBackgroundColor(span) {
            document.getElementById('nadpis').style.backgroundColor = span.style.backgroundColor;
        }
    </script>
</head>
<body>
 
<h1 id="nadpis">Dynamické HTML 5</h1>
 
<label for="volba1">zvolte barvu textu nadpisu: </label>
<select id="volba1" onchange="changeTextColor(this.options[this.selectedIndex].value)">
    <option value="red">červená</option>
    <option value="green">zelená</option>
    <option value="blue">modrá</option>
</select>
<br>
 
<p>zvolte barvu pozadí nadpisu: </p>
 
<p id="volba2">
    <span onclick="changeBackgroundColor(this)" style="background-color: cyan;">azurová</span>
    <span onclick="changeBackgroundColor(this)" style="background-color: magenta;">fialová</span>
    <span onclick="changeBackgroundColor(this)" style="background-color: yellow;">žlutá</span>
    <span onclick="changeBackgroundColor(this)" style="background-color: black; color: gray;">černá</span>
</p>
 
<hr>
 
<p><a href="#" onclick="drawSomething()">kresli na plochu</a></p>
 
<canvas id="plocha" width="400" height="300" style="border: 1px solid gray;"></canvas>
 
<script>
    function drawSomething() {
        console.log("kreslím");
        var c = document.getElementById("plocha");
        var ctx = c.getContext("2d");
        //fill
        ctx.fillStyle = "#f8f8f8";
        ctx.fillRect(0, 0, c.width, c.height);
        //osy
        ctx.strokeStyle = "#000000";
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(20, c.height - 30);
        ctx.lineTo(c.width - 20, c.height - 30);
        ctx.stroke();
        ctx.moveTo(30, c.height - 20);
        ctx.lineTo(30, 20);
        ctx.stroke();
        //linky
        ctx.strokeStyle = "#a0a0a0";
        ctx.lineWidth = 1;
        for (i = 10; i < (c.width - 60); i += 10) {
            ctx.beginPath();
            ctx.moveTo(30 + i, c.height - 20);
            ctx.lineTo(30 + i, 30);
            ctx.stroke();
        }
        for (i = 10; i < (c.height - 60); i += 10) {
            ctx.beginPath();
            ctx.moveTo(20, c.height - 30 - i);
            ctx.lineTo(c.width - 30, c.height - 30 - i);
            ctx.stroke();
        }
        //popis os
        ctx.fillStyle = "#000000";
        ctx.font = '12pt Calibri';
        ctx.fillText("x", c.width - 20, c.height - 10);
        ctx.fillText("y", 10, 20);
        //graf
        ctx.strokeStyle = "#f00000";
        ctx.lineWidth = 3;
        ctx.beginPath();
        ctx.moveTo(40, 200);
        for (i = 10; i < (c.width - 80); i += 10) {
            ctx.lineTo(40 + i, 200 + 50 * Math.sin(i / 30));
            ctx.stroke();
        }
    }
</script>
 
</body>
</html>

Prohlédněte si stránku v prohlížeči a zkuste použít aktivní prvky ve stránce.

AJAX

Využijeme knihovnu JQuery, která značně zjednodušuje práci s JavaScriptem.

Vytvořte si nový servlet MyAjaxServlet.java s obsahem

 
package cz.muni.fi.pa165.web1;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
 
@WebServlet(urlPatterns = {"/ajax/*"})
public class MyAjaxServlet extends HttpServlet {
 
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
    }
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
    }
 
    @Override
    protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("přišel požadavek na smazání souboru"+request.getPathInfo());
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("provedeno");
    }
}

a novou JSP stránku ajax.jsp s obsahem:

 
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Ukázka AJAX</title>
    <!-- zavedení JQuery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
</head>
<body>
<h1>Ukázka AJAX</h1>
 
 
 
</body>
</html>