Langkah pertama di Spring, Rest API, fokus pada PUT bersama dengan frontend

Sedikit tentang diri saya: Saat ini saya adalah seorang siswa Skillbox dan mengambil kursus “Java-developer”. Dalam hal tidak beriklan, saya menceritakan sedikit tentang diri saya. Dia mulai belajar Java pada Mei 2019, sebelum itu dia belajar sedikit HTML, CSS dan JS sendiri.

Sebenarnya, itu mendorong saya untuk menulis artikel ini dengan kesadaran tentang bagaimana frontend bekerja dengan backend bersama dan kurangnya pemahaman tentang permintaan PUT. Di mana-mana di mana saya "google" API Istirahat diimplementasikan dengan permintaan POST dan GET, kadang-kadang dengan DELETE dan tidak ada contoh frontend. Saya ingin menyampaikan, pertama-tama, sama seperti saya mengimplementasikan REST API bersama frontend, sehingga pemahaman akan datang. Tetapi artikel ini dimaksudkan tidak hanya untuk pemula yang saya, tetapi juga untuk pengguna berpengalaman teknologi Spring, karena dalam komentar saya ingin melihat ajaran lurus dari kawan-kawan yang lebih tua. Lagi pula, saya akan menggambarkan keputusan saya berdasarkan pengalaman saya (baca kurangnya pengalaman).

Saya mengalami masalah memahami Spring, dan khususnya dengan permintaan PUT, yaitu mengubah data elemen dalam database. Saya juga akan menjelaskan permintaan POST dan GET. Secara umum, CRUD standar (benar jika saya salah). Dan juga sedikit frontend, yaitu, karena di sana, permintaan dikirim ke server dan respons diproses.

Saya menggunakan:

  • Maven
  • MySQL
  • IntelliJ IDEA

Saya juga ingin membuat reservasi bahwa frontend sebagian dalam proyek pelatihan, saya menerapkan pertanyaan PUT dan DELETE.

Seluruh proyek dapat dilihat di GitHub .

Retasan langsung kecil: Saat membuat proyek dengan pakar, versi java melonjak ke urutan kelima, untuk memperbaikinya di pom.xml kita menulis yang berikut ini, di mana angkanya adalah versi.

Buka Hack Kehidupan
<properties>
    <maven.compiler.target>11</maven.compiler.target>
    <maven.compiler.source>11</maven.compiler.source>
</properties>


Koneksi Musim Semi


Sebagai permulaan, di pom.xml kita menghubungkan boot Spring sebagai orangtua, ini dijelaskan oleh fakta bahwa koneksi dependensi lebih lanjut tidak bertentangan dengan versi:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.4.RELEASE</version>
</parent>

Sekarang kami menghubungkan web Spring yang bertanggung jawab untuk meluncurkan aplikasi:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Kami membuat dan menjalankan aplikasi


Anda harus mulai menulis aplikasi di direktori yang benar, yaitu src / main / java / main , ya, itu benar, saya belum menemukan penjelasan penjelasan untuk ini, saya pikir saya akan mencari tahu dengan waktu.

Dan segera lay out seluruh struktur aplikasi.

gambar

Hal pertama yang saya lakukan adalah membuat kelas Main.java untuk menjalankan aplikasi dengan anotasi @SpringBootApplication:

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

Dan Anda sudah dapat mengklik jalankan dan bahkan server saya akan mulai!

gambar

Diluncurkan pada port 8080. Anda dapat pergi ke alamat http://localhost:8080/dan kami akan melihat kesalahan 404 karena belum ada halaman.

Dalam keadilan, Anda perlu menerapkan frontend.

Anda harus menyertakan dependensi di pom.xml ke templat HTML.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Untuk memulai, halaman awal index.html di direktori src / main / resources / templates .

Di sini dengan markup polos seperti itu
<!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>


Kami juga menulis gaya di direktori src / main / resources / static / css, create styles.css

Lihat gaya
* {
    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;
}


Anda dapat mencoba untuk memulai aplikasi dan pergi http://localhost:8080/dan Anda dapat mengagumi halaman awal, meskipun sejauh ini tanpa tindakan.

Dan tentu saja js dengan plugin jQuery di direktori src / main / resources / static / js , sekali lagi saya akan melakukan reservasi, sudah ada jQuery dan bagian dari main.js yang ditulis dalam proyek pelatihan .
Semua hub yang sama tentang Jawa dan Spring, sehingga link ke js kode lengkap pikir akan cukup:
Link ke jquery-3.4.0.min.js
Link ke main.js .

Di bawah ini akan menjadi perhatian khusus terhadap permintaan GET dan PUT. Baik dari sisi server, dan dari frontend.

Sekarang Anda dapat mencoba memulai proyek dan memastikan bahwa frontend berfungsi dan tindakan juga (tombol add meluncurkan form).

Interaksi DB


Langkah selanjutnya adalah entitas untuk berinteraksi dengan database, untuk ini kami menghubungkan dependensi data jpa Spring:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Dan di direktori src / main / java / main / model saya membuat POJO class Todo melampirkan anotasi @Entity.

Kami menyatakan bidang, saya akan memiliki: id, nama, deskripsi, tanggal.

Perhatian khusus setDate(), saya lakukan hanya itu, pada input String dan kemudian konversi ke java.util.Date, dan bahkan dengan atStartOfDay().atZone(ZoneId.of("UTC"), saya juga memperhatikan anotasi bidang tanggal:

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;

    //getters and setters …
   
    public void setDate(String date) {
        this.date = Date.from(LocalDate.parse(date).atStartOfDay().atZone(ZoneId.of("UTC")).toInstant());
    }
}

Tambahkan dependensi di pom.xml untuk membuat koneksi ke MySQL:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.19</version>
</dependency>

Di direktori src / main / resources , buat properti application.prop dan tulis data untuk terhubung ke database:

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

Sekarang mari kita beralih ke membuat repositori. Di direktori src / main / java / main / model , buat antarmuka TodoRepository dengan anotasi @Repositorydan mewarisi CrudRepository <Todo, Integer>. Penyimpangan liris - seperti yang saya pahami, ini adalah gasket antara database dan controller, Spring bagus dalam hal ini, Anda tidak perlu membuat soket, Anda tidak perlu khawatir tentang interaksi dengan database, ia melakukan segalanya untuk Anda.

package main.model;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TodoRepository extends CrudRepository<Todo, Integer> {
}

Sebenarnya, komunikasi dengan basis data akan terjadi melalui repositori ini.

Sekarang saatnya membuat pengontrol di mana permintaan dari front-end, interaksi dengan database dan respons front-end akan diproses.

Dalam direktori src / main / java / main / controller , buat kelas TodoController dengan anotasi @RestController, deklarasikan variabel TodoRepository dan inisialisasi melalui konstruktor.

Mari kita mulai dengan permintaan POST. Kami membuat metode add () yang menerima Todo dan mengembalikan int (id), tandai dengan anotasi @PostMapping(“/todo-list/”)dan jalur tempat kami akan menambahkan. Kami mengambil repositori dan save()menyimpan objek Todo yang datang dengan permintaan ke database dalam metode . Hanya sulap.

@PostMapping("/todo-list/")
public int add(Todo todo) {
    Todo newTodo = todoRepository.save(todo);
    return newTodo.getId();
}

Secara umum, mirip dengan GET dan DELETE, tetapi menggunakan id dan mengembalikan Todo di shell ResponseEntity. Perhatikan juga parameter metode ini get()ditandai dengan anotasi, di bawah ini sedikit lebih rinci. Kemudian respons dihasilkan ResponseEntity.ok(todoOptional.get());, yaitu, kode 200, atau jika tidak ditemukan untuk id ini, mengembalikan kode 404 dengan badan nol.

@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());
}

Apa yang terjadi di sisi frontend?

Menggunakan contoh GET:

mengklik tautan di daftar todo => kami mengeluarkan id todo => permintaan terbentuk (perhatikan bahwa id itu sendiri tidak diteruskan ke metode. Id dalam metode get () diekstraksi dari (value = "/ todo-list / {id} ") untuk ini, kita perlu anotasi @PathVariabledalam parameter metode) => jawabannya datang dalam bentuk objek Todo => front-end melakukan apa yang dianggapnya cocok, dalam hal ini, Todo membuka deskripsi dan tanggal.

Sepotong kode main.js, DAPATKAN implementasi
$(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;
});


Mari kita buat pengontrol lain yang akan segera menampilkan daftar-todo di halaman awal. Kami juga bekerja dengan repositori dan mendapatkan daftar Todo, dan kemudian todoList secara ajaib diteruskan ke front-end:

@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";
    }
}

Di sini dengan koreksi seperti itu di index.html terjadi pemuatan dinamis 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>

Permintaan PUT


Di TodoController, kami membuat metode put()dengan anotasi @PutMappingpada input Map <String, String> dengan anotasi @RequestParamdan int, yang diekstraksi dari nilai, dibungkus dengan ResponseEntity pada output Todo. Dan juga repositori tidak memiliki metode pembaruan (), jadi semuanya terjadi sebagai berikut:

Todo diekstraksi dari database melalui todoRepository oleh id => parameter baru ditugaskan Todo => disimpan dalam database melalui repositori => respons frontend dikirim

@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());
}

Di ujung depan saat ini:

klik pada tombol "Ubah" => Data Todo dikumpulkan dari elemen => formulir diedit untuk mengubah kasus (nama formulir diganti nama dan tombol diganti dalam nilai input data Todo) => formulir dibuka => data untuk perubahan didorong masuk => klik tombol "Ubah" dalam formulir => pengumpulan data => permintaan PUT dihasilkan (path, data) => menerima respons dari objek Todo yang dimodifikasi, tetapi dengan id yang sama => frontend melakukan apa yang diinginkan, dalam hal ini penggantian data Melakukan.

Sepotong kode main.js, implementasi PUT
//Update _todo and show updating _todo form
$(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;
    });
});


Anda dapat membiasakan diri dengan proyek ini secara lebih rinci di github .

Ditulis untuk pemula dari pemula, tetapi saya ingin mendengar kritik konstruktif dari pengguna berpengalaman, sama kerennya jika Anda menjelaskan di komentar mengapa Peta <String, String> hadir di sisi pengontrol ketika meminta PUT, mengapa saya tidak bisa mengirim Todo ke sana.

Sumber:


All Articles