ایجاد موجودیت ها
در بسته entities ، کلاسی ایجاد خواهیم کردUser
که دارای دو متغیر رشته خصوصی است: name و password . سازنده (پیشفرض و یکی که هر دو مقدار را میگیرد) و دریافتکننده/تنظیمکننده ایجاد کنید و toString()
در صورت لزوم، متد را به همراه متدهای equals()
و لغو کنید hashCode()
. به عبارت دیگر، ما هر کاری را که یک توسعه دهنده محترم جاوا هنگام ایجاد یک کلاس انجام می دهد، انجام خواهیم داد.
public class User {
private String name;
private String password;
public User() {
}
public User(String name, String password) {
this.name = name;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (name != null ? !name.equals(user.name) : user.name != null) return false;
return password != null ? password.equals(user.password) : user.password == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (password != null ? password.hashCode() : 0);
return result;
}
}
اکنون می توانیم شروع به ایجاد لیستی از کاربران کنیم. ما کاربرانی را به آن اضافه می کنیم و کاربران را از آن می گیریم تا آنها را نمایش دهند. با این حال، ما یک مشکل داریم. ما اشیاء servlet خود را ایجاد نمی کنیم. تامکت این کار را برای ما انجام می دهد. متدهایی که در آنها لغو می کنیم، قبلاً برای ما تعریف شده اند و نمی توانیم پارامترها را تعیین کنیم. پس چگونه یک لیست مشترک ایجاد کنیم که در هر دو سرور ما قابل مشاهده باشد؟ اگر فقط یک شی لیست در هر سرورلت ایجاد کنیم، کاربران را به یک لیست اضافه می کنیم، اما کاربران را از لیست دیگر در ListServlet نمایش می دهیم . بنابراین ما به یک شی نیاز داریم که توسط هر دو سرور به اشتراک گذاشته شود. به طور کلی، ما به یک شی نیاز داریم که توسط تمام کلاس های برنامه ما به اشتراک گذاشته شود: یک شی برای کل برنامه. امیدوارم در مورد الگوهای طراحی چیزی شنیده باشید. برای برخی از افراد، این ممکن است اولین نیاز واقعی به الگوی Singleton در برنامه آنها باشد. میتوانید با بررسیهای مضاعف و همگامسازی مقداری Singleton شیرین را انتخاب کنید (بله، برنامه ما چند رشتهای است، زیرا سرولتهای Tomcat روی رشتههای جداگانه اجرا میشوند). اما من قصد دارم از تکنیک اولیه سازی اولیه استفاده کنم، زیرا برای اهداف ما در اینجا کاملاً کافی است.
ایجاد یک مدل
یک کلاس ایجاد کنید (و الگوی Singleton را پیاده سازی کنید ) در بسته مدل و آن را چیزی غیرعادی بنامید. به عنوان مثال، مدل . ما یک لیست خصوصی از کاربران در کلاس خود ایجاد می کنیم و دو روش را پیاده سازی می کنیم: یکی برای افزودن کاربر و دیگری برای برگرداندن لیستی از رشته ها (نام کاربری). از آنجایی که شی کاربر ما شامل نام کاربری و رمز عبور است و نمیخواهیم رمزهای عبور کاربر را فاش کنیم، فقط فهرستی از نامها خواهیم داشت.public class Model {
private static Model instance = new Model();
private List<User> model;
public static Model getInstance() {
return instance;
}
private Model() {
model = new ArrayList<>();
}
public void add(User user) {
model.add(user);
}
public List<String> list() {
return model.stream()
.map(User::getName)
.collect(Collectors.toList());
}
}
کمی در مورد MVC
از آنجایی که قبلاً در مورد singleton شنیده اید ، احتمالاً در مورد الگوی طراحی دیگری مدل-view-controller (MVC) شنیده اید . هدف آن جدا کردن منطق تجاری از دیدگاه است. یعنی برای جدا کردن کدی که تعیین می کند چه کاری باید انجام شود از کدی که نحوه نمایش موارد را تعیین می کند. نما مسئول نحوه ارائه داده ها است . در مورد ما، نماها صفحات JSP ما هستند . دقیقاً به همین دلیل است که آنها را در پوشه ای به نام views قرار دادم . مدل داده ای است که برنامه در واقع با آن کار می کند. در مورد ما، این کاربران (لیست کاربران) هستند. و کنترلرها رابط بین آنها هستند. آنها داده ها را از مدل می گیرند و به view ها ارسال می کنند (یا مقداری داده از تامکت دریافت می کنند ، آن را پردازش می کنند و به مدل ارسال می کنند). شما منطق کسب و کار خود (آنچه برنامه باید انجام دهد) را در آنها تعریف می کنید، نه در مدل یا نما. بنابراین، هر بخش کار خود را انجام می دهد:- مدل داده ها را ذخیره می کند.
- نماها نمایش های زیبایی از داده ها ارائه می دهند.
- کنترل کننده ها پردازش داده ها را انجام می دهند.
<form method="post">
<label>Name:
<input type="text" name="name"><br />
</label>
<label>Password:
<input type="password" name="pass"><br />
</label>
<button type="submit">Submit</button>
</form>
در اینجا فرم دارای یک ویژگی متد با مقدار post است . این نشان می دهد که داده های این فرم به عنوان یک درخواست POST به سرور می رود . ویژگی action مشخص نشده است، به این معنی که درخواست به همان آدرسی که ما از ( /add ) به این صفحه آمدیم ارسال می شود . بنابراین، پس از دریافت یک درخواست GET ، سرولت ما محدود به این آدرس، JSP را با فرم add-user برمی گرداند. و اگر یک درخواست POST دریافت کرد ، آنگاه میدانیم که فرم دادههای خود را در اینجا ارسال کرده است (که از شی درخواست در متد استخراج میکنیم ، پردازش میکنیم و برای ذخیره به مدل ارسال میکنیم). شایان ذکر است که فیلدهای ورودی دارای پارامتری به نام نام (برای نامهای کاربری یا پاس برای رمزهای عبور) هستند. این نکته بسیار مهمی است. بنابراین، برای دریافت این داده ها (نام کاربری و رمز عبوری که وارد می شود) از درخواست (داخل servlet)، از این فیلدهای name و pass استفاده می کنیم. اما در ادامه بیشتر در مورد آن. دکمه من برای ارسال داده دوباره به عنوان یک دکمه ساخته شد ، نه به عنوان یک فیلد خروجی همانطور که مرسوم است. نمیدانم این رویکرد چقدر مورد استفاده قرار گرفته است، اما برای من (مرورگر کروم) کار میکند. doPost()
مدیریت Servlet درخواست های POST
بیایید به AddServlet برگردیم . به شما یادآوری میکنم که برای اجازه دادن به سرور ما برای "گرفتن" درخواستهای GET ، ماdoGet()
متد را در کلاس HttpServlet لغو کردیم . برای آموزش سرولت ما برای گرفتن درخواستهای POST ، باید doPost()
روش را نیز لغو کنیم. Tomcat اشیاء درخواست و پاسخ مشابهی را که ما با آنها کار خواهیم کرد به آن ارسال می کند. برای شروع، نام درخواست و پارامترهای عبور ارسال شده توسط فرم را استخراج کنید (اگر نام های مختلفی را در فرم مشخص کرده اید، از آن نام ها استفاده کنید). پس از آن، با استفاده از داده های دریافتی، یک شی کاربر ایجاد کنید. سپس شی مدل را دریافت کرده و کاربر ایجاد شده را به مدل اضافه می کنیم.
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String password = req.getParameter("pass");
User user = new User(name, password);
Model model = Model.getInstance();
model.add(user);
}
انتقال داده به نمای
بیایید به ListServlet برویم . روشdoGet()
قبلاً اجرا شده است. به سادگی کنترل را به view منتقل می کند ( list.jsp ). اگر هنوز این مورد را ندارید، آن را با روشی مشابه در AddServlet ایجاد کنید . حال خوب است لیست نام های کاربری را از مدل دریافت کرده و به نمای نمایش ارسال کنید تا آنها را دریافت کرده و به زیبایی نمایش دهد. برای انجام این کار، دوباره از شی درخواستی که از Tomcat دریافت کردیم استفاده می کنیم . ما می توانیم یک ویژگی به این شی اضافه کنیم و نوعی نام به آن بدهیم. در واقع، میتوانیم شیء مورد نظر را به view اضافه کنیم . با توجه به اینکه هنگام انتقال کنترل از سرور به view، همان درخواست و اشیاء پاسخی را که سرورلت دریافت کرده است، از view عبور می دهیم، می توانیم لیست نام های خود را به شی درخواست اضافه کنیم و سپس لیست نام های کاربری خود را از درخواست دریافت کنیم. شی در نمای کار ما با کلاس ListServlet تمام شده است ، بنابراین من کد کل کلاس را در اینجا ارائه خواهم کرد:
package app.servlets;
import app.model.Model;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
public class ListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Model model = Model.getInstance();
List<String> names = model.list();
req.setAttribute("userNames", names);
RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/list.jsp");
requestDispatcher.forward(req, resp);
}
}
اجرای کد جاوا در فایل های JSP
وقت آن است که به list.jsp نگاه کنید . فقط زمانی اجرا می شود که ListServlet کنترل را به آن منتقل کند. علاوه بر این، ما قبلاً لیستی از نام های کاربری را از مدل موجود در servlet آماده کرده ایم و آن را در اینجا در شی درخواست ارسال کرده ایم. از آنجایی که ما لیستی از نام ها را داریم، می توانیم با استفاده از یکfor
حلقه روی آن تکرار کنیم و هر نام را نمایش دهیم. همانطور که قبلاً گفتم، فایلهای JSP میتوانند کد جاوا را اجرا کنند (این چیزی است که آنها را از صفحات HTML ایستا متفاوت میکند). برای اجرای برخی از کدها، تنها کاری که باید انجام دهیم این است که ساختار زیر را در محل مناسب قرار دهیم:
<!-- html code -->
<%
// Java code
%>
<!-- html code -->
در این ساختار، به چندین متغیر دسترسی پیدا می کنیم:
- درخواست - شی درخواست ما، که از servlet ارسال کردیم، جایی که به سادگی req نامیده می شد .
- پاسخ - شی پاسخ (به نام resp در servlet)؛
- out - یک شی JspWriter (که یک Writer معمولی را به ارث می برد )، که می توانیم از آن برای "نوشتن" چیزی مستقیماً در خود صفحه HTML استفاده کنیم . عبارت out.println ("سلام، دنیا!") بسیار شبیه System.out.println ("سلام، دنیا!") است ، اما آنها را اشتباه نگیرید!
- out.println() در یک صفحه HTML "نوشتن" می کند ، در حالی که System.out.println در جریان خروجی سیستم می نویسد . اگر System.out.println() را در یک بخش JSP با کد جاوا فراخوانی کنید ، نتایج را در کنسول Tomcat خواهید دید ، اما نه در صفحه.
<ul>
<%
List<String> names = (List<String>) request.getAttribute("userNames");
if (names != null && !names.isEmpty()) {
for (String s : names) {
out.println("<li>" + s + "</li>");
}
}
%>
</ul>
اگر لازم است لیست را فقط در صورت وجود کاربر نمایش دهیم و در غیر این صورت هشداری مبنی بر اینکه هنوز هیچ کاربری وجود ندارد را نمایش دهیم، میتوانیم این بخش را کمی بازنویسی کنیم:
<%
List<String> names = (List<String>) request.getAttribute("userNames");
if (names != null && !names.isEmpty()) {
out.println("<ui>");
for (String s : names) {
out.println("<li>" + s + "</li>");
}
out.println("</ui>");
} else out.println("<p>There are no users yet!</p>");
%>
اکنون که می دانیم چگونه داده ها را از servlet ها به view ها منتقل کنیم، می توانیم AddServlet خود را به گونه ای بهبود دهیم که یک اعلان درباره اضافه شدن موفقیت آمیز یک کاربر نمایش دهد. برای انجام این کار، در doPost()
روش، پس از افزودن یک کاربر جدید به مدل، میتوانیم این نام کاربری را به ویژگیهای آبجکت req اضافه کنیم و کنترل را به یک view برگردانیم ( add.jsp ). و اکنون یک بخش با کد جاوا به آن اضافه می کنیم، که در آن بررسی می کنیم که آیا درخواست دارای چنین ویژگی است یا خیر، و اگر این ویژگی را دارد - سپس پیامی نشان می دهیم که کاربر با موفقیت اضافه شده است. پس از این تغییرات، کد کامل AddServlet چیزی شبیه به این خواهد بود :
package app.servlets;
import app.entities.User;
import app.model.Model;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class AddServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
requestDispatcher.forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
String password = req.getParameter("pass");
User user = new User(name, password);
Model model = Model.getInstance();
model.add(user);
req.setAttribute("userName", name);
doGet(req, resp);
}
}
در اینجا، در انتهای متد، doPost()
یک ویژگی با نام کاربری که به مدل اضافه شده است ایجاد می کنیم و سپس متد را فراخوانی می کنیم doGet()
که درخواست و پاسخ فعلی را به آن ارسال می کنیم. این doGet()
متد اکنون کنترل را به view منتقل می کند، که شی درخواست را با نام کاربر اضافه شده به عنوان یک ویژگی دریافت می کند. کاری که باید انجام دهیم این است که add.jsp را اصلاح کنیم تا در صورت عدم وجود چنین ویژگی، اعلان را نمایش دهد. در اینجا نسخه نهایی add.jsp آمده است :
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Add new user</title>
</head>
<body>
<div>
<h1>Super app!</h1>
</div>
<div>
<%
if (request.getAttribute("userName") != null) {
out.println("<p>User '" + request.getAttribute("userName") + "' added!</p>");
}
%>
<div>
<div>
<h2>Add user</h2>
</div>
<form method="post">
<label>Name:
<input type="text" name="name"><br />
</label>
<label>Password:
<input type="password" name="pass"><br />
</label>
<button type="submit">Submit</button>
</form>
</div>
</div>
<div>
<button onclick="location.href='/'">Back to main</button>
</div>
</body>
</html>
بدنه صفحه شامل موارد زیر است:
- یک div با هدر؛
- یک محفظه div برای محتوا، که شامل بررسی وجود ویژگی با نام کاربری می شود.
- یک div با فرم افزودن کاربر.
- و در پایین، یک پاورقی با یک دکمه برای بازگشت به صفحه اصلی.
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Users</title>
</head>
<body>
<div>
<h1>Super app!</h1>
</div>
<div>
<div>
<div>
<h2>Users</h2>
</div>
<%
List<String> names = (List<String>) request.getAttribute("userNames");
if (names != null && !names.isEmpty()) {
out.println("<ui>");
for (String s : names) {
out.println("<li>" + s + "</li>");
}
out.println("</ui>");
} else out.println("<p>There are no users yet!</p>");
%>
</div>
</div>
<div>
<button onclick="location.href='/'">Back to main</button>
</div>
</body>
</html>
بنابراین، ما یک برنامه وب کاملاً کارآمد داریم که می تواند کاربران را ذخیره و اضافه کند و همچنین لیستی از نام آنها را نمایش دهد. حالا فقط باید زیباش کنیم... :)
اضافه کردن سبک ها ما از چارچوب W3.CSS استفاده خواهیم کرد
در حال حاضر، برنامه ما کار می کند، اما کاملاً ظالمانه به نظر می رسد. بنابراین، بیایید یک پسزمینه اضافه کنیم، متن و دکمهها را رنگآمیزی کنیم، به فهرستها استایل اضافه کنیم، عناصر را تراز کنیم، تورفتگی اضافه کنیم و غیره. سبک های نوشتن به صورت دستی می تواند زمان زیادی را بگیرد و بر اعصاب ما تأثیر بگذارد. بنابراین من استفاده از چارچوب W3.CSS را پیشنهاد می کنم . در حال حاضر دارای کلاس های آماده برای استفاده با سبک ها است. ما فقط باید کلاس های CSS را که می خواهیم استفاده کنیم در مکان های مناسب مرتب کنیم. برای افزودن آنها به صفحات خود، ابتدا فایل استایل را وصل می کنیم. دو راه برای انجام این کار وجود دارد:-
صفحات ما را مرور کنید و لینک مستقیم زیر را به فایل سبک در قسمت head وارد کنید
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
اگر اتصال دائمی به اینترنت دارید، این گزینه مناسب است. هنگامی که صفحات خود را در سرور محلی باز می کنید، سبک ها از اینترنت خارج می شوند.
-
اما اگر میخواهید همه استایلها را به صورت محلی داشته باشید و به اتصال اینترنت وابسته نباشید، فایل استایل را دانلود کنید و آن را در جایی داخل پوشه وب قرار دهید (مثلاً web/styles/w3.css ). سپس تمام صفحات ما ( index.html، add.jsp، list.jsp ) را مرور کنید و لینک زیر را به فایل style در قسمت head اضافه کنید :
<link rel="stylesheet" href="styles/w3.css">
پس از آن، فقط تگ ها را مرور کنید و سبک های مورد علاقه خود را اضافه کنید. من در این مورد با جزئیات صحبت نمی کنم. در عوض، من فقط نسخههای آماده برای استفاده از سه فایل خود را با کلاسهای شطرنجی ارائه خواهم کرد.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Super app!</title>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
</head>
<body class="w3-light-grey">
<div class="w3-container w3-blue-grey w3-opacity w3-right-align">
<h1>Super app!</h1>
</div>
<div class="w3-container w3-center">
<div class="w3-bar w3-padding-large w3-padding-24">
<button class="w3-btn w3-hover-light-blue w3-round-large" onclick="location.href='/list'">List users</button>
<button class="w3-btn w3-hover-green w3-round-large" onclick="location.href='/add'">Add user</button>
</div>
</div>
</body>
</html>
add.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Add new user</title>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
</head>
<body class="w3-light-grey">
<div class="w3-container w3-blue-grey w3-opacity w3-right-align">
<h1>Super app!</h1>
</div>
<div class="w3-container w3-padding">
<%
if (request.getAttribute("userName") != null) {
out.println("<div class=\"w3-panel w3-green w3-display-container w3-card-4 w3-round\">\n" +
" <span onclick=\"this.parentElement.style.display='none'\"\n" +
" class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-green w3-border w3-border-green w3-hover-border-grey\">×</span>\n" +
" <h5>User '" + request.getAttribute("userName") + "' added!</h5>\n" +
"</div>");
}
%>
<div class="w3-card-4">
<div class="w3-container w3-center w3-green">
<h2>Add user</h2>
</div>
<form method="post" class="w3-selection w3-light-grey w3-padding">
<label>Name:
<input type="text" name="name" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
</label>
<label>Password:
<input type="password" name="pass" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
</label>
<button type="submit" class="w3-btn w3-green w3-round-large w3-margin-bottom">Submit</button>
</form>
</div>
</div>
<div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
<button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
</div>
</body>
</html>
list.jsp
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Users list</title>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
</head>
<body class="w3-light-grey">
<div class="w3-container w3-blue-grey w3-opacity w3-right-align">
<h1>Super app!</h1>
</div>
<div class="w3-container w3-center w3-margin-bottom w3-padding">
<div class="w3-card-4">
<div class="w3-container w3-light-blue">
<h2>Users</h2>
</div>
<%
List<String> names = (List<String>) request.getAttribute("userNames");
if (names != null && !names.isEmpty()) {
out.println("<ul class=\"w3-ul\">");
for (String s : names) {
out.println("<li class=\"w3-hover-sand\">" + s + "</li>");
}
out.println("</ul>");
} else out.println("<div class=\"w3-panel w3-red w3-display-container w3-card-4 w3-round\">\n"
+
" <span onclick=\"this.parentElement.style.display='none'\"\n" +
" class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-red w3-border w3-border-red w3-hover-border-grey\">×</span>\n" +
" <h5>There are no users yet!</h5>\n" +
"</div>");
%>
</div>
</div>
<div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
<button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
</div>
</body>
</html>
و بس. :) اگر هنوز سوال یا نظری دارید، یا اگر چیزی درست نشد، لطفاً نظر بدهید. و من چند اسکرین شات از چگونگی همه چیز را پیوست خواهم کرد.
- برای حذف یک کاربر یک servlet و JSP بسازید و یک جفت دیگر را برای ویرایش کاربر موجود اضافه کنید. نتیجه یک برنامه وب CRUD واقعی خواهد بود که با استفاده از servlets ساخته شده است. ;)
- لیست را با یک پایگاه داده جایگزین کنید تا کاربران اضافه شده پس از راه اندازی مجدد سرور ناپدید نشوند. :)
GO TO FULL VERSION