आज हम सर्वलेट्स और JSP का उपयोग करके टिक-टैक-टो गेम लिखेंगे।
यह प्रोजेक्ट पिछले वाले से थोड़ा अलग होगा। इसमें न केवल कार्य शामिल होंगे, बल्कि यह भी बताया जाएगा कि उन्हें कैसे करना है। यही है, यह "कैसे करें ..." श्रृंखला से एक परियोजना होगी।
निर्देश:
- भंडार से कांटा: https://github.com/CodeGymCC/project-servlet.git
- प्रोजेक्ट के अपने संस्करण को अपने कंप्यूटर पर डाउनलोड करें।
- आईडिया में एप्लिकेशन लॉन्च सेट अप करें:
- Alt + Shift + F9 -> कॉन्फ़िगरेशन संपादित करें... -> Alt + डालें -> टॉम (खोज बार में) -> स्थानीय।
- उसके बाद, आपको "कॉन्फ़िगर" पर क्लिक करना होगा और इंगित करना होगा कि टॉमकैट के साथ संग्रह कहाँ से डाउनलोड और अनपैक किया गया था।
- "परिनियोजन" टैब में: Alt + सम्मिलित करें -> विरूपण साक्ष्य... -> tic-tac-toe:war विस्फोट -> ठीक है।
- "एप्लिकेशन संदर्भ" फ़ील्ड में: केवल "/" (स्लैश) छोड़ें।
- "लागू करें" दबाएं।
- सेटिंग्स विंडो बंद करें।
- अनुकूलित कॉन्फ़िगरेशन का पहला टेस्ट रन करें। यदि सब कुछ सही ढंग से किया जाता है, तो आपका डिफ़ॉल्ट ब्राउज़र खुल जाएगा, जिसमें यह होगा:
- "पोम.एक्सएमएल" फ़ाइल खोलें । "निर्भरता" ब्लॉक में 2 निर्भरताएँ हैं ।
javax.servlet-api
सर्वलेट्स के विनिर्देशन के लिए जिम्मेदार है। विकास के दौरान स्कोप "प्रदान किया गया" आवश्यक है, लेकिन रनटाइम पर इसकी आवश्यकता नहीं है (टॉमकैट में पहले से ही यह निर्भरता lib फ़ोल्डर में है)।jstl
- एक टेम्पलेट इंजन के रूप में माना जा सकता है।- "वेबएप" फ़ोल्डर में 3 फाइलें हैं :
index.jsp
- यह हमारा टेम्प्लेट है (HTML पेज के समान)। इसमें मार्कअप और स्क्रिप्ट्स होंगी। यह "इंडेक्स" नामक फ़ाइल है जिसे प्रारंभिक पृष्ठ के रूप में दिया गया है, यदि कोई कॉन्फ़िगरेशन नहीं है, जिसे हमने चरण 3 में देखा था।/static/main.css
- शैलियों के लिए फ़ाइल। पिछली परियोजना की तरह, यहाँ सब कुछ आप पर निर्भर है, जैसा आप चाहें पेंट करें।/static/jquery-3.6.0.min.js
- दृश्यपटल निर्भरता जो हमारा सर्वर स्थिर के रूप में वितरित करेगा।- "com.tictactoe" पैकेज में सभी Java कोड शामिल होंगे। अभी 2 वर्ग हैं:
Sign
- एनम, जो "क्रॉस / जीरो / शून्य" के लिए जिम्मेदार है ।Field
हमारा क्षेत्र है। इस वर्ग का एक "फ़ील्ड" मानचित्र है । डेटा संग्रहण का सिद्धांत इस प्रकार होगा: टिक-टैक-टो फ़ील्ड की कोशिकाओं को शून्य से क्रमांकित किया जाता है। पहली पंक्ति में 0, 1 और 2. दूसरी में: 3, 4 और 5. और इसी तरह। इसके भी 3 तरीके हैं। "GetEmptyFieldIndex" पहले खाली सेल की तलाश करता है (हाँ, हमारा प्रतिद्वंद्वी बहुत स्मार्ट नहीं होगा)। "चेकविन" जाँचता है कि क्या खेल समाप्त हो गया है। यदि तीन क्रॉस की एक पंक्ति है, तो यह एक क्रॉस देता है; यदि तीन शून्य की एक पंक्ति है, तो यह एक शून्य देता है। अन्यथा, यह खाली है. "getFieldData" - आरोही सूचकांक क्रम में क्रमबद्ध सूची के रूप में "फ़ील्ड" मानचित्र के मान लौटाता है ।- टेम्प्लेट के बारे में स्पष्टीकरण समाप्त हो गया है, अब आप कार्य प्रारंभ कर सकते हैं। आइए 3 बटा 3 टेबल बनाकर शुरू करें। ऐसा करने के लिए, निम्नलिखित कोड को "index.jsp" में जोड़ें :
फिर हम तालिका में संख्याओं को हटा देंगे और उन्हें एक क्रॉस, शून्य या एक खाली क्षेत्र से बदल देंगे। इसके अलावा, "सिर" टैग के अंदर, स्टाइल फ़ाइल शामिल करें। ऐसा करने के लिए, एक पंक्ति जोड़ें:<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">
शैली फ़ाइल की सामग्री आप पर निर्भर है। मैंने इसका इस्तेमाल किया:
दौड़ने के बाद मेरा परिणाम इस तरह दिखता है: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; }
- अब निम्न कार्यक्षमता जोड़ते हैं: जब किसी सेल पर क्लिक किया जाता है, तो सर्वर को एक अनुरोध भेजा जाएगा, जिसमें हम पैरामीटर के रूप में क्लिक किए गए सेल के इंडेक्स को पास करेंगे। इस कार्य को दो भागों में विभाजित किया जा सकता है: सामने से अनुरोध भेजें, सर्वर पर अनुरोध स्वीकार करें। आइए बदलाव के लिए मोर्चे पर शुरुआत करें।
आइए प्रत्येक "डी" टैग में "ऑनक्लिक" पैरामीटर जोड़ें । मूल्य में, हम वर्तमान पृष्ठ के परिवर्तन को निर्दिष्ट URL में इंगित करते हैं। तर्क के लिए जिम्मेदार सर्वलेट का URL "/ तर्क" होगा । और यह "क्लिक" नामक एक पैरामीटर लेगा । इसलिए हम उस सेल का इंडेक्स पास करेंगे जिस पर यूजर ने क्लिक किया था।
आप ब्राउज़र में डेवलपर पैनल के माध्यम से जांच सकते हैं कि सब कुछ सही ढंग से किया गया है। उदाहरण के लिए, क्रोम में, यह F12 बटन से खुलता है । इंडेक्स 4 वाले सेल पर क्लिक करने के परिणामस्वरूप, चित्र इस प्रकार होगा:<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>
हमें एक त्रुटि मिलती है क्योंकि हमने अभी तक एक सर्वलेट नहीं बनाया है जो सर्वर को "तर्क" पते पर भेज सके ।
- पैकेज "com.tictactoe" में एक वर्ग "LogicServlet" बनाएँ जो वर्ग "javax.servlet.http.HttpServlet" से लिया जाना चाहिए । कक्षा में, "doGet" विधि को ओवरराइड करें ।
और चलिए एक विधि जोड़ते हैं जो उस सेल की अनुक्रमणिका प्राप्त करेगी जिसे क्लिक किया गया था। आपको एक मैपिंग भी जोड़ने की आवश्यकता है (वह पता जिस पर यह सर्वलेट अनुरोध को रोकेगा)। मैं इसे एक एनोटेशन के माध्यम से करने का सुझाव देता हूं (लेकिन यदि आपको कठिनाइयाँ पसंद हैं, तो आप web.xml का उपयोग भी कर सकते हैं)। सामान्य सर्वलेट कोड:
अब, किसी भी सेल पर क्लिक करने पर, हमें सर्वर पर इस सेल का इंडेक्स मिलेगा (आप सर्वर को डिबग में चलाकर सुनिश्चित कर सकते हैं)। और जिस पेज से क्लिक किया गया था, उसी पेज पर रीडायरेक्ट हो जाएगा।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; } }
- अब हम क्लिक कर सकते हैं, लेकिन यह अभी कोई खेल नहीं है। खेल में तर्क होने के लिए, आपको अनुरोधों के बीच खेल की स्थिति (जहां क्रॉस हैं, जहां शून्य हैं) को बचाने की आवश्यकता है। ऐसा करने का सबसे आसान तरीका इस डेटा को सत्र में संग्रहीत करना है। इस दृष्टिकोण के साथ, सत्र सर्वर पर संग्रहीत किया जाएगा, और क्लाइंट को "JSESSIONID" नामक कुकी में एक सत्र आईडी प्राप्त होगी । लेकिन सत्र को हर बार बनाने की जरूरत नहीं है, बल्कि खेल की शुरुआत में ही। इसके लिए एक और सर्वलेट शुरू करते हैं, जिसे हम "InitServlet" कहेंगे । हम इसमें "doGet" पद्धति को ओवरराइड करेंगे, जिसमें हम एक नया सत्र बनाएंगे, एक खेल का मैदान बनाएंगे, इस खेल के मैदान को डालेंगे और प्रकार की एक सूची सत्र विशेषताओं में साइन इन करेंगे, और index.jsp को " आगे " भेजेंगे पृष्ठ। कोड:
और भूलने के लिए नहीं, आइए सर्वर शुरू करने के बाद ब्राउज़र में खुलने वाले स्टार्ट पेज को "/ start" में बदलें : अब सर्वर को पुनरारंभ करने के बाद और "अनुरोध शीर्षलेख"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" में है । हमें "doGet" पद्धति के साथ काम करने की आवश्यकता है । आइए इस व्यवहार को विधि में जोड़ें:
- हम सत्र से फ़ील्ड प्रकार का "फ़ील्ड" ऑब्जेक्ट प्राप्त करेंगे (हम इसे "एक्सट्रैक्टफ़ील्ड" विधि में ले जाएंगे )।
- एक क्रॉस लगाएं जहां उपयोगकर्ता ने क्लिक किया (अब तक बिना किसी चेक के)।
व्यवहार अभी तक नहीं बदला है, लेकिन यदि आप सर्वर को डिबग में शुरू करते हैं और उस लाइन पर एक ब्रेकपॉइंट सेट करते हैं जहां रीडायरेक्ट भेजा जाता है, तो आप "डेटा" ऑब्जेक्ट के "अंदर" देख सकते हैं । वहां, वास्तव में, क्लिक किए गए इंडेक्स के तहत "क्रॉस" दिखाई देता है ।@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; }
- अब फ्रंटएंड पर क्रॉस प्रदर्शित करने का समय आ गया है। ऐसा करने के लिए, हम “index.jsp” फ़ाइल और “JSTL” तकनीक के साथ काम करेंगे ।
- <सिर> अनुभाग में जोड़ें:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- प्रत्येक <td> ब्लॉक के अंदर तालिका में, इंडेक्स को एक निर्माण में बदलें जो आपको मूल्यों की गणना करने की अनुमति देता है। उदाहरण के लिए, सूचकांक शून्य के लिए:
<td onclick="window.location='/logic?click=0'">${data.get(0).getSign()}</td>
अब, जब आप किसी सेल पर क्लिक करते हैं, तो वहां एक क्रॉस दिखाई देगा:
- <सिर> अनुभाग में जोड़ें:
- हमने अपनी चाल चल दी है, अब "शून्य" की बारी है। और यहां कुछ चेक जोड़ते हैं, ताकि संकेत पहले से ही कब्जे वाली कोशिकाओं में न रखे जाएं।
- आपको यह जांचना होगा कि जिस सेल पर क्लिक किया गया था वह खाली है। अन्यथा, हम कुछ नहीं करते हैं और सत्र पैरामीटर को बदले बिना उपयोगकर्ता को उसी पृष्ठ पर भेजते हैं।
- चूंकि मैदान पर कोशिकाओं की संख्या विषम है, यह संभव है कि एक क्रॉस रखा गया हो, लेकिन शून्य के लिए कोई जगह नहीं है। इसलिए, एक क्रॉस लगाने के बाद, हम एक खाली सेल (फ़ील्ड वर्ग की getEmptyFieldIndex विधि) का सूचकांक प्राप्त करने का प्रयास करते हैं। यदि सूचकांक ऋणात्मक नहीं है, तो वहाँ एक शून्य लगा दें।
कोड:
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; } }
- इस स्तर पर, आप क्रॉस लगा सकते हैं, AI शून्य के साथ उत्तर देता है। लेकिन खेल को कब रोकना है इसकी कोई जांच नहीं है। यह तीन मामलों में हो सकता है:
- क्रॉस की अगली चाल के बाद, तीन क्रॉस की एक पंक्ति बनाई गई;
- अगली वापसी के बाद एक शून्य के साथ, तीन शून्य की एक पंक्ति बनाई गई थी;
- क्रॉस की अगली चाल के बाद, खाली सेल समाप्त हो गए।
इस पद्धति की ख़ासियत यह है कि यदि विजेता पाया जाता है, तो हम सत्र में एक और पैरामीटर जोड़ते हैं, जिसके उपयोग से हम निम्नलिखित पैराग्राफ में "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; }
- आइए "doGet" विधि में दो बार " checkWin " विधि में एक कॉल जोड़ें । क्रॉस सेट करने के बाद पहली बार, दूसरा - शून्य सेट करने के बाद।
// 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; } }
- व्यवहार के संदर्भ में, लगभग कुछ भी नहीं बदला है (सिवाय इसके कि यदि कोई एक चिन्ह जीतता है, तो शून्य अब नहीं रखा जाता है। आइए "index.jsp" में "विजेता" पैरामीटर का उपयोग करें और विजेता को प्रदर्शित करें। हम तालिका
c:set
के बाद निर्देशों का उपयोग करते हैं:c:if
यदि क्रॉस जीतता है, तो संदेश "क्रॉस जीत!" , यदि शून्य "नॉट विन!" . नतीजतन, हम दो शिलालेखों में से एक प्राप्त कर सकते हैं:<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>
- यदि कोई विजेता है, तो आपको बदला लेने में सक्षम होना चाहिए। ऐसा करने के लिए, आपको एक बटन की आवश्यकता है जो सर्वर को एक अनुरोध भेजेगा। और सर्वर वर्तमान सत्र को अमान्य कर देगा और अनुरोध को वापस "/ प्रारंभ" पर पुनर्निर्देशित कर देगा ।
- "index.jsp" में "सिर" अनुभाग में , स्क्रिप्ट "jquery" लिखें । इस लाइब्रेरी का उपयोग करके, हम सर्वर को एक अनुरोध भेजेंगे।
<script src="<c:url value="/static/jquery-3.6.0.min.js"/>"></script>
- "स्क्रिप्ट" अनुभाग में "index.jsp" में , एक फ़ंक्शन जोड़ें जो सर्वर को POST अनुरोध भेज सकता है। हम फ़ंक्शन को तुल्यकालिक बना देंगे, और जब सर्वर से कोई प्रतिक्रिया आती है, तो यह वर्तमान पृष्ठ को पुनः लोड करेगा।
<script> function restart() { $.ajax({ url: '/restart', type: 'POST', contentType: 'application/json;charset=UTF-8', async: false, success: function () { location.reload(); } }); } </script>
- "सी: इफ" ब्लॉक के अंदर , एक बटन जोड़ें, जिसे क्लिक करने पर, हमारे द्वारा लिखे गए फ़ंक्शन को कॉल करता है:
<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>
- चलिए एक नया सर्वलेट बनाते हैं जो "/पुनरारंभ करें" URL को सर्व करेगा ।
जीत के बाद, "फिर से प्रारंभ करें" बटन दिखाई देगा । इस पर क्लिक करने के बाद मैदान पूरी तरह से साफ हो जाएगा और खेल फिर से शुरू हो जाएगा।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" में "सिर" अनुभाग में , स्क्रिप्ट "jquery" लिखें । इस लाइब्रेरी का उपयोग करके, हम सर्वर को एक अनुरोध भेजेंगे।
- यह अंतिम स्थिति पर विचार करना बाकी है। क्या होगा यदि उपयोगकर्ता एक क्रॉस डालता है, कोई जीत नहीं होती है, और शून्य के लिए कोई जगह नहीं होती है? फिर यह एक ड्रा है, और हम इसे अभी प्रोसेस करेंगे:
- "LogicServlet" सत्र में , एक और पैरामीटर "ड्रा" जोड़ें , "डेटा" फ़ील्ड को अपडेट करें और "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; }
- "index.jsp" में हम इस पैरामीटर को प्रोसेस करेंगे:
ड्रा के परिणामस्वरूप, हमें संबंधित संदेश और फिर से शुरू करने का प्रस्ताव प्राप्त होगा:<c:if test="${draw}"> <h1>IT'S A DRAW</h1> <br> <button onclick="restart()">Start again</button> </c:if>
- "LogicServlet" सत्र में , एक और पैरामीटर "ड्रा" जोड़ें , "डेटा" फ़ील्ड को अपडेट करें और "index.jsp" पर रीडायरेक्ट भेजें :

यह खेल के लेखन को पूरा करता है।
कक्षाओं और फाइलों का कोड जिसके साथ उन्होंने काम किया
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;
}
}
पुनरारंभ सर्वलेट
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>
main.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