VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - CVIČENÍ Zbyněk Šlajchrt http://java.vse.cz/4it447/HomePage Část 3.
Program Doplění e-mail klienta o identifikaci uživatele Základní práce s filtry Přesměrování dotazu forward, include, redirect zabránění znovuodeslání formuláře problematika tlačítka Zpět prohlížeče Tvorba jednoduchých JSP stránek využití EL 2.0 Řízení vyrovnávací paměti prohlížeče Cache-Control: public, max-age, no-cache, no-store
Příprava projektu Stáhněte si kostru projektu Otevřete projekt v IDE http://java.vse.cz/4it447/Cviceni Otevřete projekt v IDE
Filter FrontControllerFilter Vytvořte třídu FrontControllerFilter Deklarujte implementaci javax.servlet.Filter Implementujte všechny metody init a destroy nechte prázdné doFilter bude obsahovat logiku kontroleru
Metoda doFilter @Override /** * Směruje zpracování akcí do příslušných privátních metod. */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { // Přetypujeme na HTTP objekty HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; // sdělíme kontejneru, v jakém kódování // očekáváme data od klienta request.setCharacterEncoding("UTF-8"); // Větvení podle akce. String action = httpRequest.getParameter("action"); if (action != null && action.equals("doLogin")) { doLogin(httpRequest, httpResponse); } else if (action != null && action.equals("doLogout")) { doLogout(httpRequest, httpResponse); } else { noAction(httpRequest, httpResponse, filterChain); }
Metoda doLogin /** * Reaguje na akci doLogin. Z dotazu zjistí nick. Pokud * není přítomen, vrátí řízení na login.jsp. Jinak * vytvoří cookie a nastaví do něj nick z dotazu. Každý * další dotaz by měl nést toto cookie. Přítomnost cookie * v dotazu se chápe jako identifikace aktuálního uživatele. */ private void doLogin(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // login.jsp předává parametr nick String nickname = request.getParameter("nick"); if ("".equals(nickname)) { forwardToLogin(request, response); return; } // Název cookie je cookieNick, hodnota je vlastní nick Cookie cookie = new Cookie("cookieNick", nickname); // Nastavíme 24 hodin platnost. //cookie.setMaxAge(60 * 60 * 24); // Hodnota -1 by způsobila, že cookie platí pouze // do zavření prohlížeče. cookie.setMaxAge(-1); response.addCookie(cookie); // Přesměrujeme aktuální dotaz na emailový formulář response.sendRedirect("mailForm.jsp");
Metoda forwardToLogin /** * Předává řízení na <code>login.jsp</code>. */ private void forwardToLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Získáme dispečera stránky RequestDispatcher loginDispatcher = request.getRequestDispatcher("login.jsp"); loginDispatcher.forward(request, response); }
Metoda doLogout /** * Odhlašuje uživatele smazáním cookie v prohlížeči. */ private void doLogout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Zkusíme najít cookie, které chceme smazat Cookie cookie = findNickCookie(request); if (cookie != null) { // Nastavení maxAge na 0 vede ke smazání cookie cookie.setMaxAge(0); response.addCookie(cookie); } // Předáme řízení login.jsp forwardToLogin(request, response);
Metoda findNickCookie /** * Hledá cookie s názvem <code>cookieNick</code> * * @param request dotaz * @return cookie nebo null */ private Cookie findNickCookie(HttpServletRequest request) { Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if ("cookieNick".equals(cookie.getName())) { return cookie; } return null;
Metoda noAction /** * Voláno pokud v dotazu není specifikovaná akce */ private void noAction(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { // Zkusíme najít cookie 'cookieNick' Cookie cookie = findNickCookie(request); if (cookie != null) { // Cookie přišlo -> uživatel je přihlášen. // Nastavíme nick uživatele jako atribut dotazu, // aby jej šlo vypisovat na stránkách. request.setAttribute("user", cookie.getValue()); // Předáme řízení standardním způsobem filterChain.doFilter(request, response); } else { // Cookie se nenašlo -> uživatel není přihlášen. // Předáme řízení na login stránku. forwardToLogin(request, response); }
Registrace filtru Otevřete soubor WEB-INF/web.xml Doplňte prvek deklarace filtru Doplňte prvek pro mapování filtru filtr bude mapován na všechna URI /* <filter> <filter-name>FronControllerFilter</filter-name> <filter-class> cz.vse.javaee.cviceni3.FrontControllerFilter </filter-class> <async-supported>true</async-supported> </filter> <filter-mapping> <url-pattern>/*</url-pattern> </filter-mapping>
Formulář pro přihlašování Vytvořte JSP stránku login.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>Login</title></head> <body> <h1>Login</h1> <form action="login" method="post"> <label for="nick">Nickname:</label><br/> <input id="nick" name="nick" type="text"/><br/> <input name="action" type="hidden" value="doLogin"/><br/> <input type="submit" value="Log in"/> </form> </body> </html>
Úprava formuláře pro odesílání Vypíšeme identifikovaného uživatele na stránku ${expression} – Expression Language (EL2) Sestavování výrazů nad hodnotami a beany v parametrech dotazu - ${param['nameParam']} atributech - ${requestScope['nameParam']} requestScope, sessionScope, applicationScope proměnných - ${variable} Výpis vlastností beanu ${userBean.address.city}
Úprava formuláře pro odesílání Do stránky mailForm.jsp přidáme tlačítko pro odhlášení uživatele Akce logout je pouze formální Všechny dotazu jdou přes FrontControllerServlet Ten se orientuje pomocí parametru action Pokud je action=logout tak provede logout a přesměruje na login.jsp <form action="logout" method="post"> <input type="hidden" name="action" value="doLogout"/> <input type="submit" value="Logout"/> </form>
Deploy (manuálně) Spustit glassfish http://localhost:4848 Applications/Deploy Launch
Problém č. 1 Refresh stránky způsobí nové odeslání zprávy Příčina: Stránka resumé je asociována s URI pro odesílání emailu. Prohlížeč si drží data dotazu, která byla odeslána pro získání aktuální stránky a která použije při obnově Řešení: použije se přesměrování (redirect) Instukce prohlížeči, aby se metodou GET obrátil na nějaké URI
Problém č. 1 - řešení V servletu MailServlet přesměrujeme dotaz na sebe Upravte konec metody doPost takto: // zavoláme pomocnou metodu - zatím nedělá nic sendMail(to, subject, message); // Odpověď bude obsahovat resumé HttpSession session = request.getSession(); session.setAttribute("resume.to", to); session.setAttribute("resume.subject", subject); session.setAttribute("resume.message", message); response.sendRedirect(request.getRequestURI()); output.flush();
Problém č. 1 - řešení Přesměrování používá metodu GET, dotaz se nám vrátí do MailServlet v metodě doGet @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); response.setCharacterEncoding("UTF-8"); PrintWriter output = response.getWriter(); // Odpověď bude obsahovat resumé HttpSession session = request.getSession(); output.println("Email odeslán"); output.println("Komu:" + session.getAttribute("resume.to")); output.println("Předmět:" + session.getAttribute("resume.subject")); output.println("Zpráva:" + session.getAttribute("resume.message")); output.flush(); }
Problém č. 2 Tlačítko Zpět zobrazí obsah políček ve formuláři Příčina Kešování stránek na prohlížeči Řešení Je třeba nastavit hlavičku v odpovědi, která ovládá keš Cache-Control: no-store Pozn.: Projeví se až po smazání keše
Problém č. 2 – řešení Na začátku JSP stránky emailForm.jsp nastavte hlavičku Cache-Control: Skriptlety: <% Java kód %> Mezi <% a %> lze psát kód v Javě V podstatě se píše kód, který bude součástí generovaného servletu <% response.addHeader("Cache-Control", "no-store"); %>
Domácí úkol Vytvořte JSP stránku pro resumé odeslání zprávy. Stránka bude generovat HTML dokument s těmito údaji: Aktuální uživatel (nickname) Příjemce zprávy Předmět zprávy Zpráva Aktuální datum Stránka bude zobrazena přesměrováním (redirect) po odeslání zprávy servletem MailServlet
Dodatek 1: Efekt Cache-Control Testováno na Firefox 3.5.8 no-cache Prohlížeč posílá další dotaz na server Tlačítko Back nikoliv, bere obsah z historie no-store Prohlížeč posílá další dotaz na server, taktéž Back hláška při pohybu zpět na stránku získanou POST public, max-age=<čas v sekundách> používá se keš nezadáno – chování jako při no-cache
Linky http://www.hacktoolrepository.com/tool/52/CAL9000