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

Z FI WIKI
Přejít na: navigace, hledání
(JSP - Java Server Page)
(Prostředí)
 
(Není zobrazeno 25 mezilehlých verzí od stejného uživatele.)
Řádka 9: Řádka 9:
  
 
  module add netbeans-7.2 jdk-1.7.0_03 maven-3.0.4
 
  module add netbeans-7.2 jdk-1.7.0_03 maven-3.0.4
 +
 +
Pokud nemáte v NetBeans nakonfigurovaný TomCat, přidejte instanci
 +
z adresáře '''/packages/share/netbeans-7.2/apache-tomcat-7.0.27'''
 +
a zvolte si privátní adresář pro TomCat někde ve svém adresáři.
  
 
== Vytvoření projektu ==
 
== Vytvoření projektu ==
Řádka 33: Řádka 37:
 
         <ul>
 
         <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}/text/primo?a=1&b=ccc">text přímo ze servletu</a></li>
            <li><a href="${pageContext.request.contextPath}/text/zjsp">text z JSP</a></li>
 
 
             <li><a href="${pageContext.request.contextPath}/soubor">soubor</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}/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>
 
             <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>
 
         </ul>
 
     </body>
 
     </body>
Řádka 43: Řádka 53:
  
 
Výraz '''${pageContext.request.contextPath}''' vkládá před relativní odkazy prefix servletové aplikace.
 
Výraz '''${pageContext.request.contextPath}''' vkládá před relativní odkazy prefix servletové aplikace.
 +
 
== Servlet ==
 
== Servlet ==
  
Řádka 51: Řádka 62:
 
package cz.muni.fi.pa165.web1;
 
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.IOException;
 
import java.io.PrintWriter;
 
import java.io.PrintWriter;
 
import java.net.URLEncoder;
 
import java.net.URLEncoder;
import java.util.Arrays;
+
import java.util.*;
import java.util.Collections;
+
import java.util.zip.*;
import java.util.zip.ZipEntry;
+
import java.util.zip.ZipOutputStream;
+
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 javax.servlet.ServletOutputStream;
+
import javax.servlet.http.Cookie;
+
  
@WebServlet(urlPatterns = {"/text/*", "/soubor/*", "/presmerovani/*"})
+
@WebServlet(urlPatterns = {"/text/*", "/soubor/*", "/chranene/*", "/presmerovani/*"})
 
public class MyDemoServlet extends HttpServlet {
 
public class MyDemoServlet extends HttpServlet {
  
Řádka 99: Řádka 106:
 
             String url = request.getContextPath() + "/text/primo?z=" + URLEncoder.encode("?/ =", "utf-8");
 
             String url = request.getContextPath() + "/text/primo?z=" + URLEncoder.encode("?/ =", "utf-8");
 
             response.sendRedirect(response.encodeRedirectURL(url));
 
             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 {
 
         } else {
 
             response.sendError(HttpServletResponse.SC_NOT_FOUND, "Nerozpoznane URL");
 
             response.sendError(HttpServletResponse.SC_NOT_FOUND, "Nerozpoznane URL");
Řádka 120: Řádka 139:
 
* 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 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
 
* 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()
 
* místo obsahu a přesměrování můžeme poslat prohlížeči chybové hlášení metodou sendError()
  
Řádka 136: Řádka 156:
 
   <title>JSP stránka</title>
 
   <title>JSP stránka</title>
 
   <style>
 
   <style>
   #nadpis { color: navy; }   
+
   #nadpis { color: red; }   
 
   table.zakladni { border-collapse: collapse; margin: 10px; }
 
   table.zakladni { border-collapse: collapse; margin: 10px; }
 
   table.zakladni th, table.zakladni td {  border: solid 1px black; padding: 4px; }
 
   table.zakladni th, table.zakladni td {  border: solid 1px black; padding: 4px; }
Řádka 160: Řádka 180:
 
</xml>
 
</xml>
  
Spusťte znovu aplikaci z 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 z výpisem skriptu.
+
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 ===
 
=== Komentáře ===
Řádka 170: Řádka 190:
 
* příkazy v jazyce Java se vkládají mezi '''<% %>'''
 
* příkazy v jazyce Java se vkládají mezi '''<% %>'''
 
* v JSP vždy existuje implicitní proměnná '''pageContext''' typu [http://docs.oracle.com/javaee/6/api/index.html?javax/servlet/jsp/PageContext.html PageContext]
 
* v JSP vždy existuje implicitní proměnná '''pageContext''' typu [http://docs.oracle.com/javaee/6/api/index.html?javax/servlet/jsp/PageContext.html PageContext]
* místo <%out.println(i);%> lze zkráceně psát <%=i%>
+
* v JSP vždy existuje implicitní proměnná '''out''' typu [http://docs.oracle.com/javaee/6/api/index.html?javax/servlet/jsp/JspWriter.html 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 &lt;&gt;&amp; ale není standardní třída pro HTML-encoding pomocí entit &amp;lt; &amp;gt; &amp;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 '''&lt;/dependencies>''':
 +
<xml>
 +
  <dependency>
 +
    <groupId>org.glassfish.web</groupId>
 +
    <artifactId>javax.servlet.jsp.jstl</artifactId>
 +
    <version>1.2.2</version>
 +
  </dependency>
 +
</xml>
 +
 
 +
=== 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:
 +
<xml>
 +
<%@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>
 +
</xml>
 +
 
 +
=== 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 [http://docs.oracle.com/javaee/6/api/index.html?javax/servlet/jsp/jstl/core/LoopTagStatus.html 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:
 +
<xml>
 +
<%@ 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>
 +
</xml>
 +
 
 +
== 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:
 +
<xml>
 +
<!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>
 +
</xml>
 +
 
 +
Prohlédněte si stránku v prohlížeči a zkuste použít aktivní prvky ve stránce.
 +
 
 +
== 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;
 +
import java.io.PrintWriter;
 +
 
 +
@WebServlet(urlPatterns = {"/ajax/*"})
 +
public class MyAjaxServlet extends HttpServlet {
 +
 
 +
    @Override
 +
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 +
        if ("/html".equals(request.getPathInfo())) {
 +
            response.setContentType("text/html; charset=utf-8");
 +
            PrintWriter out = response.getWriter();
 +
            out.println("<p style=\"background-color: red;\">text načtený ze servletu</p>");
 +
            return;
 +
        } else {
 +
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
 +
        }
 +
 
 +
    }
 +
 
 +
    @Override
 +
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 +
        String a = request.getParameter("a");
 +
        String b = request.getParameter("b");
 +
        System.out.println("a = " + a);
 +
        System.out.println("b = " + b);
 +
        response.setContentType("text/html");
 +
        response.setCharacterEncoding("utf-8");
 +
        PrintWriter out = response.getWriter();
 +
        int c = Integer.parseInt(a) + Integer.parseInt(b);
 +
        out.println("" + c);
 +
        return;
 +
    }
 +
 
 +
    @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>
 +
    <!-- zavoláno po načtení dokumentu -->
 +
    <script>
 +
        $(document).ready(function () {
 +
            var odstavec1 = $('#odstavec1'); //odkaz na objekt
 +
            $('.button1').click(function () { //pri zmacknuti tlactka
 +
                odstavec1.show(500); //ukáže text
 +
            });
 +
            $('.button2').click(function () { //pri zmacknuti tlactka
 +
                odstavec1.hide(500); //schová text
 +
            });
 +
        });
 +
    </script>
 +
</head>
 +
<body>
 +
<h1>Ukázka AJAX</h1>
 +
 
 +
 
 +
<h2>JQuery základní operace</h2>
 +
 
 +
<p><a href="#" class="button1">Zobrazit text</a></p>
 +
 
 +
<p><a href="#" class="button2">Schovat text</a></p>
 +
 
 +
<p id="odstavec1">Lorem ipsum dolor sit amet, consectetur
 +
    adipiscing elit. Aliquam nisl turpis,
 +
    laoreet convallis varius quis, hendrerit lobortis odio.</p>
 +
 
 +
 
 +
<h2>JQuery AJAX s načtením HTML ze servletu</h2>
 +
 
 +
<p><a href="#" onclick="nactiText()">načíst ze servletu</a></p>
 +
<script>
 +
    function nactiText() {
 +
        $('#misto2').load('${pageContext.request.contextPath}/ajax/html', function () {
 +
            console.log('načteno')
 +
        });
 +
    }
 +
</script>
 +
<div id="misto2"></div>
 +
 
 +
 
 +
<h2>JQuery AJAX s metodou DELETE</h2>
 +
 
 +
<p><a href="#" onclick="smazSoubor()">smazat soubor</a></p>
 +
<script>
 +
    function smazSoubor() {
 +
        $.ajax(
 +
                '${pageContext.request.contextPath}/ajax/soubor.bin',
 +
                {
 +
                    type:'DELETE',
 +
                    success:function () {
 +
                        console.log('smazáno');
 +
                    },
 +
                    error:function () {
 +
                        console.log('nesmazáno');
 +
                    }
 +
                }
 +
        );
 +
    }
 +
</script>
 +
 
 +
 
 +
<h2>JQuery AJAX s předáním dat metodou POST</h2>
 +
 
 +
<form action="#">
 +
    a=<input id="fa" name="a" value="1"><br>
 +
    b=<input id="fb" name="b" value="2"><br>
 +
</form>
 +
<button onclick="spocitej()">spočítej</button>
 +
 
 +
<div id="misto3"></div>
 +
<script>
 +
    function spocitej() {
 +
        var a = $('#fa').val();
 +
        var b = $('#fb').val();
 +
        $.ajax({
 +
            type:'POST',
 +
            url:'${pageContext.request.contextPath}/ajax',
 +
            data: { 'a':a, 'b':b },
 +
            success: function (data) {
 +
                console.log('spočítáno '+data);
 +
                $('#misto3').html(data);
 +
            }
 +
        });
 +
    }
 +
</script>
 +
</body>
 +
</html>
 +
</xml>
 +
 
 +
Vyzkoušejte si.

Aktuální verze z 6. 11. 2012, 15:33


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

Pokud nemáte v NetBeans nakonfigurovaný TomCat, přidejte instanci z adresáře /packages/share/netbeans-7.2/apache-tomcat-7.0.27 a zvolte si privátní adresář pro TomCat někde ve svém adresáři.

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("/stranka.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;
import java.io.PrintWriter;
 
@WebServlet(urlPatterns = {"/ajax/*"})
public class MyAjaxServlet extends HttpServlet {
 
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if ("/html".equals(request.getPathInfo())) {
            response.setContentType("text/html; charset=utf-8");
            PrintWriter out = response.getWriter();
            out.println("<p style=\"background-color: red;\">text načtený ze servletu</p>");
            return;
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
 
    }
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String a = request.getParameter("a");
        String b = request.getParameter("b");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        response.setContentType("text/html");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        int c = Integer.parseInt(a) + Integer.parseInt(b);
        out.println("" + c);
        return;
    }
 
    @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>
    <!-- zavoláno po načtení dokumentu -->
    <script>
        $(document).ready(function () {
            var odstavec1 = $('#odstavec1'); //odkaz na objekt
            $('.button1').click(function () { //pri zmacknuti tlactka
                odstavec1.show(500); //ukáže text
            });
            $('.button2').click(function () { //pri zmacknuti tlactka
                odstavec1.hide(500); //schová text
            });
        });
    </script>
</head>
<body>
<h1>Ukázka AJAX</h1>
 
 
<h2>JQuery základní operace</h2>
 
<p><a href="#" class="button1">Zobrazit text</a></p>
 
<p><a href="#" class="button2">Schovat text</a></p>
 
<p id="odstavec1">Lorem ipsum dolor sit amet, consectetur
    adipiscing elit. Aliquam nisl turpis,
    laoreet convallis varius quis, hendrerit lobortis odio.</p>
 
 
<h2>JQuery AJAX s načtením HTML ze servletu</h2>
 
<p><a href="#" onclick="nactiText()">načíst ze servletu</a></p>
<script>
    function nactiText() {
        $('#misto2').load('${pageContext.request.contextPath}/ajax/html', function () {
            console.log('načteno')
        });
    }
</script>
<div id="misto2"></div>
 
 
<h2>JQuery AJAX s metodou DELETE</h2>
 
<p><a href="#" onclick="smazSoubor()">smazat soubor</a></p>
<script>
    function smazSoubor() {
        $.ajax(
                '${pageContext.request.contextPath}/ajax/soubor.bin',
                {
                    type:'DELETE',
                    success:function () {
                        console.log('smazáno');
                    },
                    error:function () {
                        console.log('nesmazáno');
                    }
                }
        );
    }
</script>
 
 
<h2>JQuery AJAX s předáním dat metodou POST</h2>
 
<form action="#">
    a=<input id="fa" name="a" value="1"><br>
    b=<input id="fb" name="b" value="2"><br>
</form>
<button onclick="spocitej()">spočítej</button>
 
<div id="misto3"></div>
<script>
    function spocitej() {
        var a = $('#fa').val();
        var b = $('#fb').val();
        $.ajax({
            type:'POST',
            url:'${pageContext.request.contextPath}/ajax',
            data: { 'a':a, 'b':b },
            success: function (data) {
                console.log('spočítáno '+data);
                $('#misto3').html(data);
            }
        });
    }
</script>
</body>
</html>

Vyzkoušejte si.