القليل عن نفسي: في الوقت الحالي أنا طالب في Skillbox وألتحق بالدورة "Java-developer". في أي حال من الأحوال لا الإعلان ، أقول القليل عن نفسي. بدأ في تعلم جافا في مايو 2019 ، قبل أن يدرس HTML و CSS و JS قليلاً بمفرده.في الواقع ، دفعتني إلى كتابة هذه المقالة مع إدراك كيفية عمل الواجهة الأمامية مع الواجهة الخلفية وعدم وجود فهم لطلب PUT. في كل مكان قمت فيه بـ "google" ، تم تنفيذ Rest API بطلبات POST و GET ، وأحيانًا باستخدام DELETE ولم تكن هناك أمثلة للواجهة الأمامية. أود أن أنقل ، أولاً وقبل كل شيء ، نفس الشيء الذي أقوم فيه بتطبيق واجهة برمجة تطبيقات REST مع الواجهة الأمامية ، حتى يتحقق التفاهم. لكن المقالة مخصصة ليس فقط للمبتدئين الذين أنا ، ولكن أيضًا للمستخدمين ذوي الخبرة لتقنيات الربيع ، لأنني في التعليقات أريد أن أرى التعاليم الصالحة للرفاق الأكبر سنًا. بعد كل شيء ، سأصف قراري بناءً على خبرتي (اقرأ نقص الخبرة).لقد واجهت مشكلة فهم الربيع ، وتحديداً مع طلب PUT ، أي تغيير بيانات عنصر في قاعدة البيانات. سأصف أيضًا طلبات POST و GET. بشكل عام ، CRUD القياسي (صحيح إذا كنت مخطئًا). وكذلك واجهة أمامية صغيرة ، أي أنه يتم إرسال طلب إلى الخادم ومعالجة الاستجابة.انا إستعملت:أريد أيضًا أن أقدم حجزًا بأن الواجهة الأمامية كانت جزئية في مشروع التدريب ، وقمت بتنفيذ استفسارات PUT و DELETE.يمكن الاطلاع على المشروع بأكمله على GitHub .اختراق مباشر صغير: عند إنشاء مشروع باستخدام مخضرم ، يقفز إصدار جافا إلى الإصدار الخامس ، لإصلاح ذلك في pom.xml ، نكتب ما يلي ، حيث يكون الرقم هو الإصدار.افتح Life Hack<properties>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
</properties>
اتصال الربيع
بالنسبة للمبتدئين ، في pom.xml نقوم بتوصيل Boot Spring كأصل ، يتم تفسير ذلك من خلال حقيقة أن المزيد من اتصال التبعيات لا يتعارض مع الإصدار:<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>
الآن نقوم بتوصيل Spring web وهي المسؤولة عن إطلاق التطبيق:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
نقوم بإنشاء وتشغيل التطبيق
تحتاج إلى البدء في كتابة التطبيق في الدليل الصحيح ، وهو src / main / java / main ، نعم ، هذا صحيح ، لم أجد بعد شرحًا توضيحيًا لذلك ، أعتقد أنني سأكتشف ذلك مع مرور الوقت.وعلى الفور وضع الهيكل الكامل للتطبيق.
أول شيء فعلته هو إنشاء فئة Main.java لتشغيل التطبيق مع تعليق توضيحي @SpringBootApplication
:@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
ويمكنك بالفعل النقر فوق تشغيل وحتى سيبدأ الخادم الخاص بي!
تم إطلاقه على المنفذ 8080. يمكنك الذهاب إلى العنوان http://localhost:8080/
وسنرى الخطأ 404 لأنه لا توجد صفحات حتى الآن.في الإنصاف ، تحتاج إلى تنفيذ واجهة أمامية.تحتاج إلى تضمين التبعية في pom.xml لقالب HTML.<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
للبدء ، صفحة index.html الرئيسية في دليل src / main / resources / templates .هنا مع مثل هذا الترميز العادي<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ToDo List</title>
<script src="/js/jquery-3.4.0.min.js"></script>
<script src="/js/main.js"></script>
<link rel="stylesheet" type="text/css" href="/css/styles.css">
</head>
<body>
<div id="todo-form">
<form>
<label> :
</label>
<input id="todo-form-name" type="text" name="name" value="">
<label>:
</label>
<input id="todo-form-description" type="text" name="description" value="">
<label> :
</label>
<input id="todo-form-date" type="date" name="date" value="">
<hr>
</form>
</div>
<h1> </h1>
<button id="show-add-todo-list"> </button>
<br><br>
<div id="todo-list">
</div>
</body>
</html>
نكتب أيضًا الأنماط في دليل src / main / resources / static / css ، وننشئ styles.cssعرض الأنماط* {
font-family: Arial, serif;
}
#todo-form {
display: none;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
background-color: #88888878;
}
#todo-form form {
background-color: white;
border: 1px solid #333;
width: 300px;
padding: 20px;
}
#todo-form h2 {
margin-top: 0;
}
#todo-form label {
display: block;
}
#todo-form form > * {
margin-bottom: 5px;
}
h4 {
margin-bottom: 0;
}
يمكنك محاولة بدء التطبيق والذهاب http://localhost:8080/
ويمكنك الإعجاب بصفحة البداية ، حتى الآن بدون إجراء.وبالطبع js مع المكوّن الإضافي jQuery في دليل src / main / resources / static / js ، سأحجز مرة أخرى ، jQuery وبعض ملفات main.js المكتوبة موجودة بالفعل في مشروع التدريب .وكل نفس المحور حول جافا والربيع، وذلك وصلات إلى شبيبة كود كامل يعتقدون يكون كافيا:لينك لمسج-3.4.0.min.js
لينك لmain.js .أدناه سيكون هناك اهتمام خاص لطلب GET و PUT. سواء من جانب الخادم ، أو من الواجهة الأمامية.يمكنك الآن محاولة بدء المشروع والتأكد من عمل الواجهة الأمامية والإجراء أيضًا (يعمل زر الإضافة على تشغيل النموذج).تفاعل DB
الخطوة التالية هي الكيان للتفاعل مع قاعدة البيانات ، لذلك نربط تبعية jpa لبيانات الربيع:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
وفي دليل src / main / java / main / model أقوم بإنشاء فئة POJO Todo لإرفاق تعليق توضيحي @Entity
.نعلن الحقول ، سيكون لدي: id ، الاسم ، الوصف ، التاريخ.اهتمام خاص setDate()
، لقد فعلت ذلك بالضبط ، عند إدخال String ثم التحويل إلى java.util.Date ، وحتى مع ذلك atStartOfDay().atZone(ZoneId.of("UTC")
، ألاحظ أيضًا التعليقات التوضيحية في حقل التاريخ:package main.model;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
@Entity
public class Todo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private String description;
@Temporal(TemporalType.DATE)
private Date date;
public void setDate(String date) {
this.date = Date.from(LocalDate.parse(date).atStartOfDay().atZone(ZoneId.of("UTC")).toInstant());
}
}
أضف تبعية في pom.xml لإنشاء اتصال بـ MySQL:<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
في دليل src / main / resources ، قم بإنشاء application.properties وكتابة البيانات للاتصال بقاعدة البيانات:spring.datasource.url=jdbc:mysql://localhost:3306/todolist?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=none
الآن دعنا ننتقل إلى إنشاء المستودع. في دليل src / main / java / main / model ، قم بإنشاء واجهة TodoRepository مع التعليقات التوضيحية @Repository
ووراثة CrudRepository <Todo، Integer>. الاستطراد الغنائي - كما أفهمها ، هذه حشية بين قاعدة البيانات ووحدة التحكم ، الربيع جيد في هذا ، لا تحتاج إلى إنشاء مآخذ ، لا داعي للقلق بشأن التفاعل مع قاعدة البيانات ، فهي تفعل كل شيء من أجلك.package main.model;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface TodoRepository extends CrudRepository<Todo, Integer> {
}
في الواقع ، سيحدث الاتصال بقاعدة البيانات من خلال هذا المستودع.حان الوقت الآن لإنشاء وحدة تحكم حيث تتم معالجة الطلبات من الواجهة الأمامية والتفاعل مع قاعدة البيانات واستجابات الواجهة الأمامية.في دليل src / main / java / main / controller ، قم بإنشاء فئة TodoController مع تعليق توضيحي @RestController
، وقم بتعريف متغير TodoRepository وتهيئته من خلال المنشئ.لنبدأ بطلب POST. نقوم بإنشاء طريقة add () بقبول Todo وإرجاع int (id) ، @PostMapping(“/todo-list/”)
ووضع علامة مع التعليق التوضيحي والمسار الذي سنضيفه. نأخذ المستودع save()
ونحفظ كائن Todo الذي جاء مع الطلب إلى قاعدة البيانات في الطريقة . مجرد سحر.@PostMapping("/todo-list/")
public int add(Todo todo) {
Todo newTodo = todoRepository.save(todo);
return newTodo.getId();
}
بشكل عام ، على غرار GET و DELETE ، ولكن باستخدام id وإرجاع Todo في shell ResponseEntity shell. لاحظ أيضًا أن معلمة الطريقة تم get()
تمييزها بتعليق توضيحي ، أدناه أكثر تفصيلاً قليلاً. ثم يتم إنشاء استجابة ResponseEntity.ok(todoOptional.get());
، أي الرمز 200 ، أو إذا لم يتم العثور عليها بواسطة هذا المعرف ، فتُرجع الرمز 404 مع نص فارغ.@GetMapping("/todo-list/{id}")
public ResponseEntity<Todo> get(@PathVariable int id){
Optional<Todo> todoOptional = todoRepository.findById(id);
if(todoOptional.isEmpty()){
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
return ResponseEntity.ok(todoOptional.get());
}
ماذا يحدث على الجانب الأمامي؟باستخدام مثال GET:النقر فوق ارتباط في قائمة todo => نقوم بسحب id todo => يتم تكوين طلب (لاحظ أن المعرّف نفسه لم يتم تمريره إلى الطريقة. يتم استخراج المعرّف في طريقة get () من (value = "/ todo-list / {id} ") لهذا ، نحتاج إلى تعليق توضيحي @PathVariable
في معلمة الطريقة) => تأتي الإجابة على شكل كائن Todo => الواجهة الأمامية تفعل ما تراه مناسبًا ، في هذه الحالة ، لدى Todo وصف وتاريخ.قطعة من كود main.js ، تنفيذ GET$(document).on('click', '.todo-link', function(){
var link = $(this);
var todoId = link.data('id');
$.ajax({
method: "GET",
url: '/todo-list/' + todoId,
success: function(response)
{
if($('.todo-div > span').is('#' + todoId)){
return;
}
link.parent().append(codeDataTodo(response, todoId));
},
error: function(response)
{
if(response.status == 404) {
alert(' !');
}
}
});
return false;
});
لنقم بإنشاء وحدة تحكم أخرى ستعرض على الفور قائمة المهام على صفحة البداية. نعمل أيضًا مع المستودع ونحصل على قائمة Todo ، ثم يتم تمرير todoList بطريقة سحرية إلى الواجهة الأمامية:@Controller
public class DefaultController {
@Autowired
TodoRepository todoRepository;
@RequestMapping("/")
public String index(Model model){
Iterable<Todo> todoIterable = todoRepository.findAll();
ArrayList<Todo> todoList = new ArrayList<>();
for(Todo todo : todoIterable){
todoList.add(todo);
}
model.addAttribute("todoList", todoList);
return "index";
}
}
هنا مع مثل هذه التصحيحات في index.html يحدث التحميل الديناميكي لـ todoList:<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div id="todo-list">
<div class="todo-div" th:each="todo : ${todoList}" th:attr="id=${todo.id}">
<a href="#" class="todo-link" th:attr="data-id=${todo.id}" th:text="${todo.name}"></a>
<br>
</div>
</div>
طلب وضع
في TodoController ، نقوم بإنشاء طريقة put()
تحتوي على تعليق توضيحي @PutMapping
في خريطة الإدخال <سلسلة ، سلسلة> مع تعليق توضيحي @RequestParam
و int ، يتم استخراجه من القيمة ، عند إخراج Todo ملفوف في ResponseEntity. وأيضًا لا يحتوي المستودع على طريقة التحديث () ، لذلك يحدث كل شيء على النحو التالي:يتم استخراج Todo من قاعدة البيانات عبر todoRepository بواسطة id => يتم تعيين المعلمات الجديدة Todo => يتم حفظها في قاعدة البيانات من خلال المستودع => يتم إرسال استجابة الواجهة@PutMapping(value = "todo-list/{id}")
public ResponseEntity<Todo> put(@RequestParam Map<String, String> mapParam, @PathVariable int id){
Optional<Todo> todoOptional = todoRepository.findById(id);
if(todoOptional.isEmpty()){
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
todoOptional.get().setName(mapParam.get("name"));
todoOptional.get().setDescription(mapParam.get("description"));
todoOptional.get().setDate(mapParam.get("date"));
todoRepository.save(todoOptional.get());
return ResponseEntity.ok(todoOptional.get());
}
في الواجهة الأمامية في هذا الوقت:انقر على زر "تغيير" => يتم جمع بيانات Todo من العنصر => يتم تحرير النموذج لتغيير الحالة (تتم إعادة تسمية اسم النموذج ويتم استبدال الزر في قيمة إدخال Todo data) => يتم فتح النموذج => يتم دفع بيانات التغيير في => انقر فوق الزر "تغيير" في النموذج => جمع البيانات => يتم إنشاء طلب PUT (المسار ، البيانات) => تلقي استجابة من كائن Todo المعدل ، ولكن بنفس المعرف => الواجهة الأمامية تفعل ما تريد ، في هذه الحالة استبدال البيانات لكى يفعل.قطعة من كود main.js ، تنفيذ PUT
$(document).on('click', '#show-update-todo-list', function(){
var buttonUpdate = $(this);
var todoId = buttonUpdate.data('id');
var todoName = buttonUpdate.data('name');
var todoDescription = buttonUpdate.data('description');
var todoDate = buttonUpdate.data('date');
todoFormNameAndButton(' ', '', 'update-todo');
todoInputValue(todoName, todoDescription, todoDate);
$('#todo-form').css('display', 'flex');
$('#update-todo').click(function() {
var data = $('#todo-form form').serialize();
$.ajax({
method: "PUT",
url: '/todo-list/' + todoId,
data: data,
success: function(response) {
$('#todo-form').css('display', 'none');
response.date = response.date.slice(0,10);
$('.todo-div#' + todoId + ' > a').text(response.name);
$('.todo-div#' + todoId +' > span').replaceWith(codeDataTodo(response, todoId));
}
});
return false;
});
});
يمكنك التعرف على المشروع بمزيد من التفاصيل حول جيثب .إنه مكتوب للمبتدئين من المبتدئين ، لكني أود سماع النقد البناء من المستخدمين ذوي الخبرة ، إنه أمر رائع إذا أوضحت في التعليقات لماذا تأتي Map <String، String> على جانب وحدة التحكم عند السؤال عن PUT ، لماذا لا يمكنني إرسال Todo هناك.مصادر: