PA165/Cvičení webové aplikace 1 - Servlet API 3.0: Porovnání verzí
(→Servlet) |
(→Prostředí) |
||
(Není zobrazeno 17 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}/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}/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 62: | Řádka 71: | ||
import java.net.URLEncoder; | import java.net.URLEncoder; | ||
import java.util.*; | import java.util.*; | ||
− | |||
import java.util.zip.*; | import java.util.zip.*; | ||
Řádka 82: | Řádka 90: | ||
} else if ("/text".equals(request.getServletPath()) && "/zjsp".equals(request.getPathInfo())) { | } else if ("/text".equals(request.getServletPath()) && "/zjsp".equals(request.getPathInfo())) { | ||
request.setAttribute("seznam", Arrays.asList("mléko", "rohlíky", "salám")); | request.setAttribute("seznam", Arrays.asList("mléko", "rohlíky", "salám")); | ||
− | request.getRequestDispatcher("/ | + | request.getRequestDispatcher("/stranka.jsp").forward(request, response); |
return; | return; | ||
} else if ("/soubor".equals(request.getServletPath())) { | } else if ("/soubor".equals(request.getServletPath())) { | ||
Řádka 99: | Řádka 107: | ||
response.sendRedirect(response.encodeRedirectURL(url)); | response.sendRedirect(response.encodeRedirectURL(url)); | ||
} else if ("/chranene".equals(request.getServletPath())) { | } else if ("/chranene".equals(request.getServletPath())) { | ||
− | String | + | String auth = request.getHeader("Authorization"); |
− | if ( | + | if (auth == null) { |
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); | ||
response.setHeader("WWW-Authenticate", "Basic realm=\"zadej heslo\""); | response.setHeader("WWW-Authenticate", "Basic realm=\"zadej heslo\""); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
return; | return; | ||
} | } | ||
response.setContentType("text/html;charset=utf-8"); | response.setContentType("text/html;charset=utf-8"); | ||
PrintWriter out = response.getWriter(); | PrintWriter out = response.getWriter(); | ||
− | String[] creds = new String(DatatypeConverter.parseBase64Binary( | + | String[] creds = new String(DatatypeConverter.parseBase64Binary(auth.split(" ")[1])).split(":", 2); |
out.println("<pre>zadáno jméno a heslo " + creds[0] + ":" + creds[1]); | out.println("<pre>zadáno jméno a heslo " + creds[0] + ":" + creds[1]); | ||
return; | return; | ||
Řádka 136: | Řá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 176: | Řádka 180: | ||
</xml> | </xml> | ||
− | Spusťte znovu aplikaci | + | 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 246: | Řádka 250: | ||
* 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>''' 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''' | * 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í | + | * 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ů | * 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, 16:33
Obsah
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 < > &
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.