Vandaag gaan we een Tic-Tac-Toe-spel schrijven met servlets en JSP.
Dit project zal een beetje anders zijn dan de vorige. Het bevat niet alleen taken, maar ook uitleg over hoe ze moeten worden uitgevoerd. Dat wil zeggen, het wordt een project uit de serie "HOW TO ...".
Instructie:
- Fork uit de repository: https://github.com/CodeGymCC/project-servlet.git
- Download uw versie van het project naar uw computer.
- Applicatie starten instellen in IDEA:
- Alt + Shift + F9 -> Configuraties bewerken... -> Alt + invoegen -> tom (in de zoekbalk) -> Lokaal.
- Daarna moet u op "CONFIGUREREN" klikken en aangeven waar het archief met Tomcat is gedownload en uitgepakt.
- Op het tabblad "Inzet": Alt + invoegen -> Artefact… -> Boter-kaas-en-eieren: oorlog ontploft -> OK.
- In het veld "Toepassingscontext": laat alleen "/" (slash) staan.
- Druk op "TOEPASSEN".
- Sluit het instellingenvenster.
- Maak de eerste testrun van de aangepaste configuratie. Als alles correct is gedaan, wordt uw standaardbrowser geopend, waarin het zal zijn:
- Open het bestand "pom.xml" . Er zijn 2 afhankelijkheden in het blok "afhankelijkheden" .
javax.servlet-api
is verantwoordelijk voor de specificatie van servlets. Scope "mits" is nodig tijdens de ontwikkeling, maar niet tijdens runtime (Tomcat heeft deze afhankelijkheid al in de map lib).jstl
- kan worden beschouwd als een sjabloon-engine.- Er zijn 3 bestanden in de map "webapp" :
index.jsp
- dit is ons sjabloon (vergelijkbaar met de HTML-pagina). Het zal markeringen en scripts bevatten. Het is het bestand met de naam "index" dat wordt gegeven als de eerste pagina, als er geen configuraties zijn, die we in stap 3 hebben gezien./static/main.css
- bestand voor stijlen. Net als in het vorige project, is alles hier aan jou, schilder zoals je wilt./static/jquery-3.6.0.min.js
- frontend-afhankelijkheid die onze server als statisch zal distribueren.- Het pakket "com.tictactoe" zal alle Java-code bevatten. Op dit moment zijn er 2 klassen:
Sign
- enum, dat verantwoordelijk is voor de "cross / zero / void" .Field
is ons vakgebied. Deze klasse heeft een "veld" -kaart . Het principe van gegevensopslag is als volgt: de cellen van het boter-kaas-en-eierenveld zijn genummerd vanaf nul. In de eerste regel 0, 1 en 2. In de tweede: 3, 4 en 5. En zo verder. Er zijn ook 3 methodes. "getEmptyFieldIndex" zoekt naar de eerste lege cel (ja, onze tegenstander zal niet erg slim zijn). "checkWin" controleert of het spel voorbij is. Als er een rij van drie kruisjes is, wordt een kruisje geretourneerd; als er een rij van drie nullen is, wordt een nul geretourneerd. Anders is het leeg. "getFieldData" - retourneert de waarden van de "veld" -kaart als een lijst gesorteerd in oplopende indexvolgorde.- De uitleg over de sjabloon is voltooid, nu kunt u met de taak beginnen. Laten we beginnen met het tekenen van een tabel van 3 bij 3. Voeg hiervoor de volgende code toe aan "index.jsp" :
We zullen dan de getallen in de tabel verwijderen en vervangen door een kruisje, nul of een leeg veld. Neem ook binnen de "head" -tag het stijlbestand op. Voeg hiervoor een regel toe:<table> <tr> <td>0</td> <td>1</td> <td>2</td> </tr> <tr> <td>3</td> <td>4</td> <td>5</td> </tr> <tr> <td>6</td> <td>7</td> <td>8</td> </tr> </table>
<link href="static/main.css" rel="stylesheet">
De inhoud van het stijlbestand is aan jou. Ik heb deze gebruikt:
Na het uitvoeren ziet mijn resultaat er als volgt uit:td { border: 3px solid black; padding: 10px; border-collapse: separate; margin: 10px; width: 100px; height: 100px; font-size: 50px; text-align: center; empty-cells: show; }
- Laten we nu de volgende functionaliteit toevoegen: wanneer er op een cel wordt geklikt, wordt er een verzoek naar de server gestuurd, waarin we de index van de cel waarop is geklikt als parameter doorgeven. Deze taak kan in twee delen worden verdeeld: een verzoek van voren verzenden, een verzoek op de server accepteren. Laten we voor de verandering eens vooraan beginnen.
Laten we een "onclick" -parameter aan elke "d" -tag toevoegen . In de waarde geven we de verandering van de huidige pagina naar de opgegeven URL aan. De servlet die verantwoordelijk is voor de logica heeft de URL “/logic” . En er is een parameter nodig met de naam "klik" . We geven dus de index door van de cel waarop de gebruiker heeft geklikt.
U kunt controleren of alles correct is gedaan via het ontwikkelaarspaneel in de browser. In Chrome wordt het bijvoorbeeld geopend met de F12- knop . Door op een cel met index 4 te klikken, ziet het beeld er als volgt uit: We krijgen een foutmelding omdat we nog geen servlet hebben gemaakt die de server naar het adres "logic" kan sturen .<table> <tr> <td onclick="window.location='/logic?click=0'">0</td> <td onclick="window.location='/logic?click=1'">1</td> <td onclick="window.location='/logic?click=2'">2</td> </tr> <tr> <td onclick="window.location='/logic?click=3'">3</td> <td onclick="window.location='/logic?click=4'">4</td> <td onclick="window.location='/logic?click=5'">5</td> </tr> <tr> <td onclick="window.location='/logic?click=6'">6</td> <td onclick="window.location='/logic?click=7'">7</td> <td onclick="window.location='/logic?click=8'">8</td> </tr> </table>
- Maak in het pakket "com.tictactoe" een klasse "LogicServlet" aan die moet worden afgeleid van de klasse "javax.servlet.http.HttpServlet" . Overschrijf in de klas de methode "doGet" .
En laten we een methode toevoegen die de index krijgt van de cel waarop is geklikt. U moet ook een toewijzing toevoegen (het adres waarop deze servlet het verzoek zal onderscheppen). Ik stel voor dit te doen door middel van een annotatie (maar als je van moeilijkheden houdt, kun je ook web.xml gebruiken). Algemene servletcode:
Als we nu op een willekeurige cel klikken, krijgen we de index van deze cel op de server (u kunt dit controleren door de server in foutopsporing uit te voeren). En er zal een omleiding zijn naar dezelfde pagina van waaruit de klik is gemaakt.package com.tictactoe; 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(name = "LogicServlet", value = "/logic") public class LogicServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { int index = getSelectedIndex(req); resp.sendRedirect("/index.jsp"); } private int getSelectedIndex(HttpServletRequest request) { String click = request.getParameter("click"); boolean isNumeric = click.chars().allMatch(Character::isDigit); return isNumeric ? Integer.parseInt(click) : 0; } }
- Nu kunnen we klikken, maar het is nog geen spel. Om ervoor te zorgen dat het spel logica heeft, moet je de status van het spel opslaan (waar de kruisjes zijn, waar de nullen zijn) tussen verzoeken. De eenvoudigste manier om dit te doen is door deze gegevens op te slaan in de sessie. Met deze aanpak wordt de sessie op de server opgeslagen en ontvangt de client een sessie-ID in een cookie met de naam "JSESSIONID" . Maar de sessie hoeft niet elke keer te worden gemaakt, maar alleen aan het begin van het spel. Laten we hiervoor een andere servlet starten, die we "InitServlet" zullen noemen . We zullen de "doGet" -methode daarin overschrijven , waarin we een nieuwe sessie zullen maken, een speelveld zullen creëren, dit speelveld en een lijst van het type zullen plaatsen Meld de sessieattributen aan en stuur " forward" naar de index.jsp bladzijde. Code:
En niet te vergeten, laten we de startpagina die in de browser wordt geopend na het starten van de server wijzigen in "/start" : Nu na het herstarten van de server en klikken op een willekeurige cel van het veld in het browserontwikkelaarsmenu in het gedeelte "Verzoekkopteksten" , zal er een cookie zijn met de sessie-ID:package com.tictactoe; 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.http.HttpSession; import java.io.IOException; import java.util.List; import java.util.Map; @WebServlet(name = "InitServlet", value = "/start") public class InitServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Create a new session HttpSession currentSession = req.getSession(true); // Create a playing field Field field = new Field(); Map<Integer, Sign> fieldData = field.getField(); // Get a list of field values List<Sign> data = field.getFieldData(); // Adding field parameters to the session (needed to store state between requests) currentSession.setAttribute("field", field); // and field values sorted by index (required for drawing crosses and zeroes) currentSession.setAttribute("data", data); // Redirect request to index.jsp page via server getServletContext().getRequestDispatcher("/index.jsp").forward(req, resp); } }
- Als we een repository hebben waarin we de status tussen verzoeken van de client (browser) kunnen opslaan, kunnen we beginnen met het schrijven van spellogica. De logica die we hebben is in "LogicServlet" . We moeten werken met de methode "doGet" . Laten we dit gedrag aan de methode toevoegen:
- we zullen het "field" -object van het veldtype uit de sessie halen (we zullen het meenemen naar de "extractField" -methode ).
- plaats een kruisje waar de gebruiker heeft geklikt (tot nu toe zonder vinkjes).
Het gedrag is nog niet veranderd, maar als je de server in debug start en een breekpunt instelt op de regel waar de omleiding naartoe wordt gestuurd, kun je de "ingewanden" van het "data"-object zien . Daar verschijnt inderdaad "CROSS" onder de index waarop is geklikt.@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Get the current session HttpSession currentSession = req.getSession(); // Get the playfield object from the session Field field = extractField(currentSession); // get the index of the cell that was clicked int index = getSelectedIndex(req); // put a cross in the cell that the user clicked on field.getField().put(index, Sign.CROSS); // Read the list of icons List<Sign> data = field.getFieldData(); // Update field object and icon list in session currentSession.setAttribute("data", data); currentSession.setAttribute("field", field); resp.sendRedirect("/index.jsp"); } private Field extractField(HttpSession currentSession) { Object fieldAttribute = currentSession.getAttribute("field"); if (Field.class != fieldAttribute.getClass()) { currentSession.invalidate(); throw new RuntimeException("Session is broken, try one more time"); } return (Field) fieldAttribute; }
- Nu is het tijd om het kruis op de frontend weer te geven. Om dit te doen, zullen we werken met het bestand "index.jsp" en de technologie "JSTL" .
- Voeg in de sectie <head> toe:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- Verander in de tabel binnen elk <td>-blok de index in een constructie waarmee u waarden kunt berekenen. Bijvoorbeeld voor index nul:
<td onclick="window.location='/logic?click=0'">${data.get(0).getSign()}</td>
Als u nu op een cel klikt, verschijnt daar een kruis:
- Voeg in de sectie <head> toe:
- We hebben onze zet gedaan, nu is het de beurt aan de "nul". En laten we hier een paar controles toevoegen, zodat de borden niet in reeds bezette cellen worden geplaatst.
- U moet controleren of de cel waarop is geklikt leeg is. Anders doen we niets en sturen we de gebruiker naar dezelfde pagina zonder de sessieparameters te wijzigen.
- Aangezien het aantal cellen op het veld oneven is, is het mogelijk dat er een kruisje is geplaatst, maar er is geen ruimte voor een nul. Daarom proberen we, nadat we een kruisje hebben geplaatst, de index van een onbezette cel te krijgen (de methode getEmptyFieldIndex van de klasse Field). Als de index niet negatief is, zet daar dan een nul. Code:
package com.tictactoe; import javax.servlet.RequestDispatcher; 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.http.HttpSession; import java.io.IOException; import java.util.List; @WebServlet(name = "LogicServlet", value = "/logic") public class LogicServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // Get the current session HttpSession currentSession = req.getSession(); // Get the playfield object from the session Field field = extractField(currentSession); // get the index of the cell that was clicked int index = getSelectedIndex(req); Sign currentSign = field.getField().get(index); // Check if the clicked cell is empty. // Otherwise, we do nothing and send the user to the same page without changes // parameters in the session if (Sign.EMPTY != currentSign) { RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/index.jsp"); dispatcher.forward(req, resp); return; } // put a cross in the cell that the user clicked on field.getField().put(index, Sign.CROSS); // Get an empty field cell int emptyFieldIndex = field.getEmptyFieldIndex(); if (emptyFieldIndex >= 0) { field.getField().put(emptyFieldIndex, Sign.NOUGHT); } // Read the list of icons List<Sign> data = field.getFieldData(); // Update field object and icon list in session currentSession.setAttribute("data", data); currentSession.setAttribute("field", field); resp.sendRedirect("/index.jsp"); } private int getSelectedIndex(HttpServletRequest request) { String click = request.getParameter("click"); boolean isNumeric = click.chars().allMatch(Character::isDigit); return isNumeric ? Integer.parseInt(click) : 0; } private Field extractField(HttpSession currentSession) { Object fieldAttribute = currentSession.getAttribute("field"); if (Field.class != fieldAttribute.getClass()) { currentSession.invalidate(); throw new RuntimeException("Session is broken, try one more time"); } return (Field) fieldAttribute; } }
- In dit stadium kunt u kruisjes plaatsen, AI antwoordt met nullen. Maar er is geen controle wanneer het spel moet worden gestopt. Dit kan in drie gevallen:
- na de volgende zet van het kruis vormde zich een rij van drie kruisen;
- na de volgende terugzet met een nul ontstond er een rij van drie nullen;
- na de volgende zet van het kruis eindigden lege cellen.
De eigenaardigheid van deze methode is dat als de winnaar wordt gevonden, we een andere parameter aan de sessie toevoegen, waarmee we de weergave in "index.jsp" in de volgende paragrafen zullen wijzigen./** * The method checks if there are three X/O's in a row. * returns true/false */ private boolean checkWin(HttpServletResponse response, HttpSession currentSession, Field field) throws IOException { Sign winner = field.checkWin(); if (Sign.CROSS == winner || Sign.NOUGHT == winner) { // Add a flag to indicate that someone has won currentSession.setAttribute("winner", winner); // Read the list of icons List<Sign> data = field.getFieldData(); // Update this list in session currentSession.setAttribute("data", data); // helmet redirect response.sendRedirect("/index.jsp"); return true; } return false; }
- Laten we een aanroep van de "checkWin "-methode twee keer toevoegen aan de "doGet"-methode . De eerste keer na het instellen van het kruis, de tweede - na het instellen van de nul.
// Check if the cross won after adding the user's last click if (checkWin(resp, currentSession, field)) { return; }
if (emptyFieldIndex >= 0) { field.getField().put(emptyFieldIndex, Sign.NOUGHT); // Check if the zero won after adding the last zero if (checkWin(resp, currentSession, field)) { return; } }
- Qua gedrag is er bijna niets veranderd (behalve dat als een van de tekens wint, er geen nullen meer worden geplaatst. Laten we de parameter "winnaar" gebruiken in "index.jsp" en de winnaar weergeven. We gebruiken richtlijnen achter de tabel:
c:set
c:if
Als kruisen winnen, wordt het bericht "CROSSES WIN!" , als de nullen "NOUGHTS WIN!" . Als gevolg hiervan kunnen we een van de volgende twee inscripties krijgen:<hr> <c:set var="CROSSES" value="<%=Sign.CROSS%>"/> <c:set var="NOUGHTS" value="<%=Sign.NOUGHT%>"/> <c:if test="${winner == CROSSES}"> <h1>CROSSES WIN!</h1> </c:if> <c:if test="${winner == NOUGHTS}"> <h1>NOUGHTS WIN!</h1> </c:if>
- Als er een winnaar is, moet je wraak kunnen nemen. Hiervoor heeft u een knop nodig die een verzoek naar de server stuurt. En de server zal de huidige sessie ongeldig maken en het verzoek terugsturen naar "/start" .
- Schrijf in "index.jsp" in het gedeelte "head" het script "jquery" . Met behulp van deze bibliotheek sturen we een verzoek naar de server.
<script src="<c:url value="/static/jquery-3.6.0.min.js"/>"></script>
- Voeg in "index.jsp" in het gedeelte "script" een functie toe die een POST-verzoek naar de server kan sturen. We zullen de functie synchroon maken en wanneer er een reactie van de server komt, wordt de huidige pagina opnieuw geladen.
<script> function restart() { $.ajax({ url: '/restart', type: 'POST', contentType: 'application/json;charset=UTF-8', async: false, success: function () { location.reload(); } }); } </script>
- Voeg binnen de "c:if" -blokken een knop toe die, wanneer erop wordt geklikt, de functie aanroept die we zojuist hebben geschreven:
<c:if test="${winner == CROSSES}"> <h1>CROSSES WIN!</h1> <button onclick="restart()">Start again</button> </c:if> <c:if test="${winner == NOUGHTS}"> <h1>NOUGHTS WIN!</h1> <button onclick="restart()">Start again</button> </c:if>
- Laten we een nieuwe servlet maken die de URL "/restart" zal bedienen .
Na de overwinning verschijnt de knop "Opnieuw beginnen" . Nadat je erop hebt geklikt, wordt het veld volledig leeggemaakt en begint het spel opnieuw.package com.tictactoe; 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(name = "RestartServlet", value = "/restart") public class RestartServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { req.getSession().invalidate(); resp.sendRedirect("/start"); } }
- Schrijf in "index.jsp" in het gedeelte "head" het script "jquery" . Met behulp van deze bibliotheek sturen we een verzoek naar de server.
- Het blijft om de laatste situatie te overwegen. Wat als de gebruiker een kruis heeft geplaatst, er geen overwinning was en er geen plaats is voor een nul? Dan is dit een loting en gaan we het nu verwerken:
- Voeg in de sessie "LogicServlet" nog een parameter "draw" toe, werk het veld "data" bij en stuur een omleiding naar "index.jsp" :
// If such a cell exists if (emptyFieldIndex >= 0) { … } // If there is no empty cell and no one wins, then it's a draw else { // Add a flag to the session that signals that a draw has occurred currentSession.setAttribute("draw", true); // Read the list of icons List<Sign> data = field.getFieldData(); // Update this list in session currentSession.setAttribute("data", data); // helmet redirect response.sendRedirect("/index.jsp"); return; }
- In "index.jsp" zullen we deze parameter verwerken:
Als resultaat van een trekking ontvangen we het bijbehorende bericht en een aanbod om opnieuw te beginnen:<c:if test="${draw}"> <h1>IT'S A DRAW</h1> <br> <button onclick="restart()">Start again</button> </c:if>
- Voeg in de sessie "LogicServlet" nog een parameter "draw" toe, werk het veld "data" bij en stuur een omleiding naar "index.jsp" :
Hiermee is het schrijven van het spel voltooid.
Code van klassen en bestanden waarmee ze werkten
InitServlet
package com.tictactoe;
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.http.HttpSession;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@WebServlet(name = "InitServlet", value = "/start")
public class InitServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Create a new session
HttpSession currentSession = req.getSession(true);
// Create a playing field
Field field = new Field();
Map<Integer, Sign> fieldData = field.getField();
// Get a list of field values
List<Sign> data = field.getFieldData();
// Adding field parameters to the session (needed to store state between requests)
currentSession.setAttribute("field", field);
// and field values sorted by index (required for drawing crosses and zeroes)
currentSession.setAttribute("data", data);
// Redirect request to index.jsp page via server
getServletContext().getRequestDispatcher("/index.jsp").forward(req, resp);
}
}
LogicServlet
package com.tictactoe;
import javax.servlet.RequestDispatcher;
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.http.HttpSession;
import java.io.IOException;
import java.util.List;
@WebServlet(name = "LogicServlet", value = "/logic")
public class LogicServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Get the current session
HttpSession currentSession = req.getSession();
// Get the playfield object from the session
Field field = extractField(currentSession);
// get the index of the cell that was clicked
int index = getSelectedIndex(req);
Sign currentSign = field.getField().get(index);
// Check if the clicked cell is empty.
// Otherwise, we do nothing and send the user to the same page without changes
// parameters in the session
if (Sign.EMPTY != currentSign) {
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/index.jsp");
dispatcher.forward(req, resp);
return;
}
// put a cross in the cell that the user clicked on
field.getField().put(index, Sign.CROSS);
// Check if the cross has won after adding the user's last click
if (checkWin(resp, currentSession, field)) {
return;
}
// Get an empty field cell
int emptyFieldIndex = field.getEmptyFieldIndex();
if (emptyFieldIndex >= 0) {
field.getField().put(emptyFieldIndex, Sign.NOUGHT);
// Check if the zero won after adding the last zero
if (checkWin(resp, currentSession, field)) {
return;
}
}
// If there is no empty cell and no one wins, then it's a draw
else {
// Add a flag to the session that signals that a draw has occurred
currentSession.setAttribute("draw", true);
// Read the list of icons
List<Sign> data = field.getFieldData();
// Update this list in session
currentSession.setAttribute("data", data);
// helmet redirect
resp.sendRedirect("/index.jsp");
return;
}
// Read the list of icons
List<Sign> data = field.getFieldData();
// Update field object and icon list in session
currentSession.setAttribute("data", data);
currentSession.setAttribute("field", field);
resp.sendRedirect("/index.jsp");
}
/**
* The method checks if there are three X/O's in a row.
* returns true/false
*/
private boolean checkWin(HttpServletResponse response, HttpSession currentSession, Field field) throws IOException {
Sign winner = field.checkWin();
if (Sign.CROSS == winner || Sign.NOUGHT == winner) {
// Add a flag to indicate that someone has won
currentSession.setAttribute("winner", winner);
// Read the list of icons
List<Sign> data = field.getFieldData();
// Update this list in session
currentSession.setAttribute("data", data);
// helmet redirect
response.sendRedirect("/index.jsp");
return true;
}
return false;
}
private int getSelectedIndex(HttpServletRequest request) {
String click = request.getParameter("click");
boolean isNumeric = click.chars().allMatch(Character::isDigit);
return isNumeric ? Integer.parseInt(click) : 0;
}
private Field extractField(HttpSession currentSession) {
Object fieldAttribute = currentSession.getAttribute("field");
if (Field.class != fieldAttribute.getClass()) {
currentSession.invalidate();
throw new RuntimeException("Session is broken, try one more time");
}
return (Field) fieldAttribute;
}
}
HerstartServlet
package com.tictactoe;
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(name = "RestartServlet", value = "/restart")
public class RestartServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
req.getSession().invalidate();
resp.sendRedirect("/start");
}
}
index.jsp _
<%@ page import="com.tictactoe.Sign" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<link href="static/main.css" rel="stylesheet">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<script src="<c:url value="/static/jquery-3.6.0.min.js"/>"></script>
<title>Tic-Tac-Toe</title>
</head>
<body>
<h1>Tic-Tac-Toe</h1>
<table>
<tr>
<td onclick="window.location='/logic?click=0'">${data.get(0).getSign()}</td>
<td onclick="window.location='/logic?click=1'">${data.get(1).getSign()}</td>
<td onclick="window.location='/logic?click=2'">${data.get(2).getSign()}</td>
</tr>
<tr>
<td onclick="window.location='/logic?click=3'">${data.get(3).getSign()}</td>
<td onclick="window.location='/logic?click=4'">${data.get(4).getSign()}</td>
<td onclick="window.location='/logic?click=5'">${data.get(5).getSign()}</td>
</tr>
<tr>
<td onclick="window.location='/logic?click=6'">${data.get(6).getSign()}</td>
<td onclick="window.location='/logic?click=7'">${data.get(7).getSign()}</td>
<td onclick="window.location='/logic?click=8'">${data.get(8).getSign()}</td>
</tr>
</table>
<hr>
<c:set var="CROSSES" value="<%=Sign.CROSS%>"/>
<c:set var="NOUGHTS" value="<%=Sign.NOUGHT%>"/>
<c:if test="${winner == CROSSES}">
<h1>CROSSES WIN!</h1>
<button onclick="restart()">Start again</button>
</c:if>
<c:if test="${winner == NOUGHTS}">
<h1>NOUGHTS WIN!</h1>
<button onclick="restart()">Start again</button>
</c:if>
<c:if test="${draw}">
<h1>IT'S A DRAW</h1>
<button onclick="restart()">Start again</button>
</c:if>
<script>
function restart() {
$.ajax({
url: '/restart',
type: 'POST',
contentType: 'application/json;charset=UTF-8',
async: false,
success: function () {
location.reload();
}
});
}
</script>
</body>
</html>
hoofd.css _
td {
border: 3px solid black;
padding: 10px;
border-collapse: separate;
margin: 10px;
width: 100px;
height: 100px;
font-size: 50px;
text-align: center;
empty-cells: show;
}
GO TO FULL VERSION