Відмінності між версіями «Розробка простого RESTfull сервіса засабами Spring Boot»

Матеріал з Вікі ЦДУ
Перейти до: навігація, пошук
м
 
(не показані 5 проміжних версій ще одного учасника)
Рядок 5: Рядок 5:
  
 
Ми розглянемо створення простого [https://en.wikipedia.org/wiki/Representational_state_transfer RESTfull сервіса] із реалізацією [https://en.wikipedia.org/wiki/Create,_read,_update_and_delete CRUD] операцій та MySQL як сховищем даних. Для реалізації задуманого нам нам потрібні Java 8, система автоматичної збірки Maven та MySQL.
 
Ми розглянемо створення простого [https://en.wikipedia.org/wiki/Representational_state_transfer RESTfull сервіса] із реалізацією [https://en.wikipedia.org/wiki/Create,_read,_update_and_delete CRUD] операцій та MySQL як сховищем даних. Для реалізації задуманого нам нам потрібні Java 8, система автоматичної збірки Maven та MySQL.
 +
  
 
* Створюємо базу даних:  
 
* Створюємо базу даних:  
  
<source lang="sql">  
+
<source lang="mysql">  
 
CREATE DATABASE `springboot`;
 
CREATE DATABASE `springboot`;
  
Рядок 21: Рядок 22:
 
</source>
 
</source>
  
* Проект повинен мати таку структуру:
+
 
 +
* Файли проекту повинні мати таку структуру:
  
 
<source lang="bash">
 
<source lang="bash">
/
+
.
 
├── pom.xml
 
├── pom.xml
 
└── src
 
└── src
Рядок 33: Рядок 35:
 
         │          ├── Application.java
 
         │          ├── Application.java
 
         │          ├── controllers
 
         │          ├── controllers
        │          │   ├── MainController.java
 
 
         │          │   └── UserController.java
 
         │          │   └── UserController.java
 
         │          └── models
 
         │          └── models
Рядок 43: Рядок 44:
 
</source>
 
</source>
  
* Створюємо файл конфігурації Maven проекту /pom.xml із наступним вмістом:
+
 
 +
* Створюємо файл конфігурації Maven проекту pom.xml із наступним вмістом:
  
 
<source lang="xml">  
 
<source lang="xml">  
Рядок 102: Рядок 104:
  
  
* Описуємо модель User /src/main/java/com/example/models/User.java Зазначимо, що використання анотацій та реалізація методів геттерів/сеттерів є обов'язковими.
+
* Описуємо модель User. Зазначимо, що використання анотацій та реалізація методів геттерів/сеттерів є обов'язковими.
 
+
  
 
<source lang="java">
 
<source lang="java">
 +
// src/main/java/com/example/models/User.java
 +
 
package com.example.models;
 
package com.example.models;
  
Рядок 166: Рядок 169:
 
</source>
 
</source>
  
*
+
 
 +
* Створюємо клас Response, що представлятиме відповідь сервера у JSON форматі:
 +
 
 +
<source lang="java">
 +
// src/main/java/com/example/models/Response.java
 +
 
 +
package com.example.models;
 +
 
 +
public class Response {
 +
 
 +
    private String summary;
 +
    private Object result;
 +
 
 +
    public Response(String summary, Object result) {
 +
        this.summary = summary;
 +
        this.result = result;
 +
    }
 +
 
 +
    public String getSummary() {
 +
        return summary;
 +
    }
 +
 
 +
    public void setSummary(String summary) {
 +
        this.summary = summary;
 +
    }
 +
 
 +
    public Object getResult() {
 +
        return result;
 +
    }
 +
 
 +
    public void setResult(Object result) {
 +
        this.result = result;
 +
    }
 +
}
 +
</source>
 +
 
 +
 
 +
* Описуємо [https://en.wikipedia.org/wiki/Data_access_object DAO] інтерфейс UserDao для роботи із базою даних на рівні абстрактних методів findOne(), findAll(), delete(), update(). Окрім того наслідування від інтерфейсу CrudRepository<> дозволяє нам оголосити власні методи для роботи із базою даних, причому вони не потребують реалізації !
 +
 
 +
<source lang="java">
 +
// src/main/java/com/example/models/UserDao.java
 +
 
 +
package com.example.models;
 +
 
 +
import javax.transaction.Transactional;
 +
import org.springframework.data.repository.CrudRepository;
 +
 
 +
@Transactional
 +
public interface UserDao extends CrudRepository<User, Long> {
 +
 
 +
    public User findByEmail(String email);
 +
}
 +
</source>
 +
 
 +
 
 +
* Створюємо контроллер UserController.java який відповідатиме за обробку HTTP-запитів. Оскільки в залежностях проекта використовується бібліотека jsonpath то відповідь сервера (об'єкт типу Response) автоматично буде серіалізуватись у JSON формат:
 +
 
 +
<source lang="java">
 +
// src/main/java/com/example/controllers/UserController.java
 +
 
 +
package com.example.controllers;
 +
 
 +
import com.example.models.Response;
 +
import com.example.models.User;
 +
import com.example.models.UserDao;
 +
 
 +
import org.springframework.beans.factory.annotation.Autowired;
 +
import org.springframework.stereotype.Controller;
 +
import org.springframework.web.bind.annotation.RequestMapping;
 +
import org.springframework.web.bind.annotation.ResponseBody;
 +
 
 +
 
 +
@Controller
 +
public class UserController {
 +
 
 +
    @Autowired
 +
    private UserDao userDao;
 +
 
 +
    @RequestMapping("/create")
 +
    @ResponseBody
 +
    public Response create(String email, String name) {
 +
 
 +
        User user = null;
 +
 
 +
        try {
 +
            user = new User(email, name);
 +
            userDao.save(user);
 +
        } catch (Exception e) {
 +
 
 +
            return new Response(e.getMessage(), e);
 +
        }
 +
 
 +
        return new Response("Successfully created new user", user);
 +
    }
 +
 
 +
    @RequestMapping("/get")
 +
    @ResponseBody
 +
    public Response get(long id) {
 +
 
 +
        User user = userDao.findOne(id);
 +
        return new Response( user != null ?  "User successfully received" : "User not found", user);
 +
    }
 +
 
 +
    @RequestMapping("/get-by-email")
 +
    @ResponseBody
 +
    public Response getByEmail(String email) {
 +
 
 +
        User user;
 +
        try {
 +
            user = userDao.findByEmail(email);
 +
        } catch (Exception e) {
 +
            return new Response(e.getMessage(), e);
 +
        }
 +
 
 +
        return new Response( user != null ? "Successfully find user by email" : "User not found", user);
 +
    }
 +
 
 +
    @RequestMapping("/get-all")
 +
    @ResponseBody
 +
    public Response getAll() {
 +
 
 +
        return new Response("Successfully received all users", userDao.findAll());
 +
    }
 +
 
 +
    @RequestMapping("/update")
 +
    @ResponseBody
 +
    public Response updateUser(long id, String email, String name) {
 +
 
 +
        User user = userDao.findOne(id);
 +
 
 +
        if(user != null) {
 +
 
 +
            user.setEmail(email);
 +
            user.setName(name);
 +
            userDao.save(user);
 +
            return new Response("User successfully updated", user);
 +
        }
 +
        else {
 +
            return new Response("User not found", null);
 +
        }
 +
    }
 +
 
 +
    @RequestMapping("/delete")
 +
    @ResponseBody
 +
    public Response delete(long id) {
 +
 
 +
        User user = userDao.findOne(id);
 +
 
 +
        if(user != null) {
 +
 
 +
            userDao.delete(user);
 +
            return new Response("User successfully deleted", user);
 +
        }
 +
        else {
 +
            return new Response("User not found", null);
 +
        }
 +
    }
 +
}
 +
</source>
 +
 
 +
 
 +
* Описуємо точку входу додатка
 +
 +
<source lang="java">
 +
// src/main/java/com/example/Application.java
 +
package com.example;
 +
 
 +
import org.springframework.boot.SpringApplication;
 +
import org.springframework.boot.autoconfigure.SpringBootApplication;
 +
 
 +
@SpringBootApplication
 +
public class Application {
 +
 
 +
  public static void main(String[] args) {
 +
    SpringApplication.run(Application.class, args);
 +
  }
 +
 
 +
}
 +
</source>
 +
 
 +
 
 +
* Нарешті описуємо властивості Spring Boot проекту. Як бачимо всі налаштування описуються безпосередньо біля коду, що їх використовує, у application.properties містяться найбільш загальні налаштування:
 +
 
 +
<source lang="python">
 +
# src/main/resources/application.properties
 +
 
 +
server.port = 3000
 +
 
 +
# Data source
 +
spring.datasource.url = jdbc:mysql://localhost:3306/springboot
 +
 
 +
# DB username and password
 +
spring.datasource.username = your_db_username
 +
spring.datasource.password = your_db_password
 +
 
 +
</source>
 +
 
 +
 
 +
* Запускається проект за допомогою Maven
 +
<source lang="bash">
 +
mvn spring-boot:run
 +
</source>
 +
 
 +
 
 +
* Протестувати сервіс можна за допомогою додатка [https://www.getpostman.com/ Postman], утиліти [https://curl.haxx.se/ curl] або звичайного браузера. Наш сервіс приймає наступні запити:
 +
 
 +
# створення користувача - <span style="font-family:Courier;">localhost:3000/create?name=<name>&email=<email></span>
 +
# отримання інформації про користувача за id - <span style="font-family:Courier;">localhost:3000/get?id=<id></span>
 +
# отримання інформації про користувача за email - <span style="font-family:Courier;">localhost:3000/get-by-email?email=<email></span>
 +
# отримання інформації про всіх користувачів - <span style="font-family:Courier;">localhost:3000/get-all</span>
 +
# оновлення інформації про користувача за id - <span style="font-family:Courier;">localhost:3000/update?id=<id>&name=<name>&email=<email></span>
 +
# видалення користувача за id - <span style="font-family:Courier;">localhost:3000/delete?id=<id></span>
 +
 
 +
 
 +
Готовий проект доступний на [https://github.com/VTurturika/spring-boot-restfull-service GitHub]
 +
 
 +
[[ПКДзJ|На початок курсу]]

Поточна версія на 10:07, 11 січня 2017

Springboot.png

Spring Boot - це Java фреймворк, що є частиною Java-EE фреймоворку Spring Framework. Фактично, Spring Boot являє собою плагін для систем автоматичного збирання проектів Maven та Gradle. Він надає можливості для комфортної розробки та тестування Spring додатків. Окрім того, Spring Boot дозволяє упаковувати додаток в окремий jar-файл із вбудованим повноцінним контейнером Tomcat. Основною перевагою використання Spring Boot є зведення до мінімуму конфігураційних xml файлів, які зазвичай використовуються при розробці Spring додатку.

Власне сам Spring Framework надає надзвичайно широкі можливості для розробки enterprise java-додатків. Його можна описати як множину менших фреймворків, причому більшість цих дочірніх фреймворків можуть працювати незалежно один від одного, однак вони забезпечують найкращу функціональність саме при спільному використанні. Повноцінний огляд усього Spring Framework виходить далеко за межі цієї статті. Детальніше можна ознайомитись на офіційному сайті Проте, варто вказати найбільший недолік Spring - надмірне використання xml конфігурацій при налаштуванні. Саме тому як компроміс між функціональністю та зручністю був створений Spring Boot.

Ми розглянемо створення простого RESTfull сервіса із реалізацією CRUD операцій та MySQL як сховищем даних. Для реалізації задуманого нам нам потрібні Java 8, система автоматичної збірки Maven та MySQL.


  • Створюємо базу даних:
 
CREATE DATABASE `springboot`;
 
USE `springboot`;
 
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  `email` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


  • Файли проекту повинні мати таку структуру:
.
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           ├── Application.java
        │           ├── controllers
        │           │   └── UserController.java
        │           └── models
        │               ├── Response.java
        │               ├── UserDao.java
        │               └── User.java
        └── resources
            └── application.properties


  • Створюємо файл конфігурації Maven проекту pom.xml із наступним вмістом:
 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.example</groupId>
    <artifactId>spring-boot-REST+mysql</artifactId>
    <version>0.0.1-SNAPSHOT</version>
 
    <name>spring-boot-REST+mysql</name>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.5.RELEASE</version>
        <relativePath/>
    </parent>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.jayway.jsonpath</groupId>
            <artifactId>json-path</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <start-class>com.example.Application</start-class>
        <java.version>1.8</java.version>
    </properties>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>


  • Описуємо модель User. Зазначимо, що використання анотацій та реалізація методів геттерів/сеттерів є обов'язковими.
// src/main/java/com/example/models/User.java
 
package com.example.models;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
 
@Entity
@Table(name = "users")
public class User {
 
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
 
  @NotNull
  private String email;
 
  @NotNull
  private String name;
 
  public User() { }
 
  public User(long id) { 
    this.id = id;
  }
 
  public User(String email, String name) {
    this.email = email;
    this.name = name;
  }
 
  public long getId() {
    return id;
  }
 
  public void setId(long value) {
    this.id = value;
  }
 
  public String getEmail() {
    return email;
  }
 
  public void setEmail(String value) {
    this.email = value;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String value) {
    this.name = value;
  } 
}


  • Створюємо клас Response, що представлятиме відповідь сервера у JSON форматі:
// src/main/java/com/example/models/Response.java
 
package com.example.models;
 
public class Response {
 
    private String summary;
    private Object result;
 
    public Response(String summary, Object result) {
        this.summary = summary;
        this.result = result;
    }
 
    public String getSummary() {
        return summary;
    }
 
    public void setSummary(String summary) {
        this.summary = summary;
    }
 
    public Object getResult() {
        return result;
    }
 
    public void setResult(Object result) {
        this.result = result;
    }
}


  • Описуємо DAO інтерфейс UserDao для роботи із базою даних на рівні абстрактних методів findOne(), findAll(), delete(), update(). Окрім того наслідування від інтерфейсу CrudRepository<> дозволяє нам оголосити власні методи для роботи із базою даних, причому вони не потребують реалізації !
// src/main/java/com/example/models/UserDao.java
 
package com.example.models;
 
import javax.transaction.Transactional;
import org.springframework.data.repository.CrudRepository;
 
@Transactional
public interface UserDao extends CrudRepository<User, Long> {
 
    public User findByEmail(String email);
}


  • Створюємо контроллер UserController.java який відповідатиме за обробку HTTP-запитів. Оскільки в залежностях проекта використовується бібліотека jsonpath то відповідь сервера (об'єкт типу Response) автоматично буде серіалізуватись у JSON формат:
// src/main/java/com/example/controllers/UserController.java
 
package com.example.controllers;
 
import com.example.models.Response;
import com.example.models.User;
import com.example.models.UserDao;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
 
@Controller
public class UserController {
 
    @Autowired
    private UserDao userDao;
 
    @RequestMapping("/create")
    @ResponseBody
    public Response create(String email, String name) {
 
        User user = null;
 
        try {
            user = new User(email, name);
            userDao.save(user);
        } catch (Exception e) {
 
            return new Response(e.getMessage(), e);
        }
 
        return new Response("Successfully created new user", user);
    }
 
    @RequestMapping("/get")
    @ResponseBody
    public Response get(long id) {
 
        User user = userDao.findOne(id);
        return new Response( user != null ?  "User successfully received" : "User not found", user);
    }
 
    @RequestMapping("/get-by-email")
    @ResponseBody
    public Response getByEmail(String email) {
 
        User user;
        try {
            user = userDao.findByEmail(email);
        } catch (Exception e) {
            return new Response(e.getMessage(), e);
        }
 
        return new Response( user != null ? "Successfully find user by email" : "User not found", user);
    }
 
    @RequestMapping("/get-all")
    @ResponseBody
    public Response getAll() {
 
        return new Response("Successfully received all users", userDao.findAll());
    }
 
    @RequestMapping("/update")
    @ResponseBody
    public Response updateUser(long id, String email, String name) {
 
        User user = userDao.findOne(id);
 
        if(user != null) {
 
            user.setEmail(email);
            user.setName(name);
            userDao.save(user);
            return new Response("User successfully updated", user);
        }
        else {
            return new Response("User not found", null);
        }
    }
 
    @RequestMapping("/delete")
    @ResponseBody
    public Response delete(long id) {
 
        User user = userDao.findOne(id);
 
        if(user != null) {
 
            userDao.delete(user);
            return new Response("User successfully deleted", user);
        }
        else {
            return new Response("User not found", null);
        }
    }
}


  • Описуємо точку входу додатка
// src/main/java/com/example/Application.java
package com.example;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@SpringBootApplication
public class Application {
 
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
 
}


  • Нарешті описуємо властивості Spring Boot проекту. Як бачимо всі налаштування описуються безпосередньо біля коду, що їх використовує, у application.properties містяться найбільш загальні налаштування:
# src/main/resources/application.properties
 
server.port = 3000
 
# Data source
spring.datasource.url = jdbc:mysql://localhost:3306/springboot
 
# DB username and password
spring.datasource.username = your_db_username
spring.datasource.password = your_db_password


  • Запускається проект за допомогою Maven
mvn spring-boot:run


  • Протестувати сервіс можна за допомогою додатка Postman, утиліти curl або звичайного браузера. Наш сервіс приймає наступні запити:
  1. створення користувача - localhost:3000/create?name=<name>&email=<email>
  2. отримання інформації про користувача за id - localhost:3000/get?id=<id>
  3. отримання інформації про користувача за email - localhost:3000/get-by-email?email=<email>
  4. отримання інформації про всіх користувачів - localhost:3000/get-all
  5. оновлення інформації про користувача за id - localhost:3000/update?id=<id>&name=<name>&email=<email>
  6. видалення користувача за id - localhost:3000/delete?id=<id>


Готовий проект доступний на GitHub

На початок курсу