ایجاد موجودیت ها
در بسته entities یک کلاس User ایجاد خواهیم کرد و در آن دو متغیر رشته خصوصی name و password وجود خواهد داشت . بیایید سازنده (پیشفرض و یکی که هر دو مقدار را میپذیرد)، getters/setters، متد 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 را در آن پیاده سازی کنیم ) در بسته مدل و آن را چیزی غیرعادی بنامیم. بیایید بگوییم مدل . بیایید یک شی لیست کاربر خصوصی در کلاس خود ایجاد کنیم و دو روش را پیاده سازی کنیم: یکی برای اینکه بتوانیم یک کاربر اضافه کنیم و دومی برای برگرداندن لیستی از رشته ها (نام کاربری). از آنجایی که شی کاربر ما شامل یک نام و رمز عبور است، و ما نمیخواهیم گذرواژههای کاربر را «افشای» کنیم، فقط فهرستی از نامها خواهیم داشت.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 شنیده اید ، پس احتمالاً در مورد الگوی طراحی دیگری شنیده اید - MVC (model-view-controller، در روسی model-view-controller، یا دقیقاً مانند مدل-view-controller انگلیسی). ماهیت آن جدا کردن منطق تجاری از ارائه است. یعنی کدی که تعیین می کند چه کاری انجام شود را از کدی که نحوه نمایش را تعیین می کند جدا کنید. View (نمایش یا به سادگی views) مسئول شکلی است که برخی از داده ها در آن ارائه می شوند. در مورد ما، نماها صفحات JSP ما هستند. به همین دلیل آنها را در پوشه ای به نام views قرار دادم . مدل داده های واقعی است که برنامه با آن کار می کند. در مورد ما، اینها کاربران هستند (لیست کاربران). خوب، کنترلرها حلقه اتصال بین آنها هستند. آنها دادهها را از مدل میگیرند و به viewها ارسال میکنند (یا برخی از دادهها را از Tomcat دریافت میکنند، آنها را پردازش میکنند و به مدل ارسال میکنند). منطق کسب و کار (اینکه برنامه دقیقاً چه کاری باید انجام دهد) باید در آنها توضیح داده شود، نه در مدل یا نما. بنابراین، هر کس کار خود را انجام می دهد:- مدل داده ها را ذخیره می کند.
- نماها نمایش زیبایی از داده ها را ترسیم می کنند.
- کنترل کننده ها پردازش داده ها را انجام می دهند.
<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 را به همراه فرم اضافه کردن کاربران برمی گرداند و اگر درخواست POST دریافت کرد، به این معنی است که فرم داده های خود را به آنجا ارسال کرده است (که ما آن را از زیر می گیریم. درخواست شی در متد ()doPost شایان ذکر است که فیلدهای ورودی دارای یک پارامتر نام هستند (برای یک فیلد با نام دارای نام مقدار و برای یک فیلد با رمز عبور دارای مقدار پاس است ). این یک نکته بسیار مهم است. از آنجایی که برای دریافت این داده ها (نام و رمز عبوری که وارد می شود) از درخواست (از قبل در داخل servlet)، دقیقاً از این نام و پاس استفاده می کنیم . اما در ادامه بیشتر در مورد آن. دکمه ارسال داده ها خود دوباره به شکل یک دکمه ساخته می شود ، و نه به عنوان یک فیلد خروجی، همانطور که معمولاً مرسوم است. من نمی دانم این گزینه چقدر جهانی است، اما برای من (مرورگر کروم) کار می کند.
پردازش درخواست POST با servlet
بیایید به سرور 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() قبلاً در اینجا پیاده سازی شده است که به سادگی کنترل را به نمای list.jsp منتقل می کند . اگر هنوز این را ندارید، آن را با روش مشابهی از AddServlet servlet انجام دهید . حال خوب است که لیستی از نام های کاربری را از مدل دریافت کرده و آنها را به view ارسال کنید تا آنها را دریافت کرده و به خوبی نمایش دهد. برای انجام این کار، دوباره از شی درخواستی که از Tomcat دریافت کردیم استفاده می کنیم . میتوانیم یک ویژگی به این شی اضافه کنیم و نامی به آن بدهیم، و در واقع، خود شی را که میخواهیم آن را به نمایش منتقل کنیم . با توجه به اینکه هنگام انتقال فرآیند اجرا از یک servlet به یک 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 ما قبلاً لیستی از نام های کاربری را از مدل تهیه کرده ایم و آن را در اینجا در شی درخواست ارسال کرده ایم. از آنجایی که ما لیستی از نام ها داریم، می توانیم آن را حلقه زده و هر نام را چاپ کنیم. همانطور که قبلاً گفتم، فایلهای 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 در خروجی سیستم می نویسد. اگر متد jsp System.out.println() را در داخل بخش با کد جاوا فراخوانی کنید، نتایج را در کنسول 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>");
%>
اکنون که میتوانیم دادهها را از servlets به view ها منتقل کنیم، میتوانیم کمی AddServlet خود را بهبود دهیم تا زمانی که کاربر با موفقیت اضافه شد، یک اعلان نمایش داده شود. برای انجام این کار، در متد doPost() پس از افزودن یک کاربر جدید به مدل، میتوانیم نام این کاربر را به ویژگیهای شی req اضافه کنیم و کنترل را به نمای 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-a با هدر.
- ظرف 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 استفاده کنید. در حال حاضر دارای کلاس های آماده با سبک است؛ تنها چیزی که باقی می ماند این است که کلاس های CSS را که می خواهیم اعمال کنیم در مکان های مناسب قرار دهیم. برای اینکه آنها را به صفحات خود اضافه کنیم، ابتدا یک فایل با سبک اضافه می کنیم. این میتواند با دو راه انجام شود:-
صفحات ما را مرور کنید و در قسمت head یک لینک مستقیم به فایل با استایل ها وارد کنید
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
این گزینه در صورتی مناسب است که به اینترنت متصل هستید. سپس، هنگامی که صفحات خود را در یک سرور محلی باز می کنید، سبک ها از اینترنت خارج می شوند.
-
اگر میخواهید همه سبکها را به صورت محلی داشته باشید و به اتصال اینترنت وابسته نباشید، فایل را با استایلها دانلود کنید و آن را در جایی داخل پوشه وب قرار دهید (مثلاً web/styles/w3.css )، سپس همه موارد ما را مرور کنید. صفحات ( index.html, add.jsp, list.jsp ) و پیوندی به این فایل با استایل ها در قسمت head وارد کنید
<link rel="stylesheet" href="styles/w3.css">
پس از آن، فقط تگ ها را مرور کنید و سبک هایی را که دوست دارید اضافه کنید. من در این مورد با جزئیات صحبت نخواهم کرد، اما بلافاصله نسخه های آماده سه فایل خود را با کلاس های سبک مرتب ارائه خواهم کرد.
index.html
<!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>
این همه است :) اگر هنوز سؤالی دارید یا نظری دارید، یا برعکس، چیزی درست نمی شود - نظر بدهید. UPD: اگر هنگام کلیک کردن روی دکمه ها با خطاهای 404 مشکل دارید، اگرچه همه چیز به درستی انجام شد، شاید باید پیکربندی استقرار را در ایده اصلاح کنید. برای انجام این کار، باید به Edit configurations بروید (در بالای دکمه شروع)، به تب Deployment در سمت راست پنجره بروید و مطمئن شوید که در زمینه Application به سادگی نشان داده شده است / خب، I' چند اسکرین شات از آنچه که از این همه به دست آمد پیوست خواهم کرد.
- یک servlet و jsp برای حذف یک کاربر و چند مورد دیگر برای تغییر/ویرایش یک کاربر موجود بسازید. شما یک برنامه وب واقعی CrUD را دریافت خواهید کرد :) در servlets));
- لیست (List) را با کار با پایگاه داده جایگزین کنید تا کاربران اضافه شده پس از راه اندازی مجدد سرور ناپدید نشوند :)
GO TO FULL VERSION