Java for Beginner
673 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Что выведет код?

import java.util.HashSet;
import java.util.Set;

public class Task201224_1 {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(2);
set.add(1);

System.out.println(set.size());
}
}


#Tasks
Варинаты ответа:
Anonymous Quiz
30%
5
0%
4
70%
3
0%
2
И куча банков🙈😂

https://t.me/Java_for_beginner_dev

#Mems
Создание CRUD API в Spring

Разработка CRUD API (Create, Read, Update, Delete) — стандартная задача для построения RESTful приложений. Использование Spring Boot и PostgreSQL позволяет быстро и эффективно создать такое API.

Шаг 1: Создание проекта Spring Boot

Перейдите на Spring Initializr.

Выберите:
Project: Maven.
Language: Java.
Dependencies: Spring Web, Spring Data JPA, PostgreSQL Driver, Validation (для валидации данных).
Скачайте проект и откройте его в IDE.


Шаг 2: Настройка подключения к PostgreSQL

Добавьте настройки базы данных в файл application.properties.

Пример application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/my_database
spring.datasource.username=postgres
spring.datasource.password=password

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect


Расшифровка настроек:
spring.datasource.url: URL подключения к PostgreSQL (с указанием базы данных).
spring.jpa.hibernate.ddl-auto: Автоматическое управление схемой базы данных (update, create, none).
spring.jpa.show-sql: Показывать SQL-запросы в консоли.
spring.jpa.properties.hibernate.dialect: Dialect Hibernate для PostgreSQL.


Шаг 3: Создание сущности (Entity)

Сущность представляет таблицу в базе данных.
import jakarta.persistence.*;
import jakarta.validation.constraints.*;

@Entity
@Table(name = "users")
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotBlank(message = "Name is mandatory")
private String name;

@Email(message = "Email should be valid")
@NotBlank(message = "Email is mandatory")
private String email;

@NotNull(message = "Age is mandatory")
private Integer age;
// Геттеры и сеттеры...
}


Примечания:
Аннотация @Entity связывает класс с таблицей в базе данных.
Аннотация @Id указывает первичный ключ.
Аннотация
@GeneratedValue используется для автоинкремента.
@Table(name = "users") указывает имя таблицы.
Аннотации валидации (@NotBlank, @Email, @NotNull) проверяют корректность данных.

Шаг 4: Создание слоя доступа к данным (Repository)

Интерфейс репозитория предоставляет методы для взаимодействия с базой данных.
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}


Особенности:
JpaRepository предоставляет стандартные CRUD-методы (save, findById, findAll, deleteById).
Не нужно реализовывать методы вручную.


Шаг 5: Реализация бизнес-логики (Service)

Слой Service инкапсулирует логику работы с данными.
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

@Service
public class UserService {

private final UserRepository userRepository;

@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

public List<User> getAllUsers() {
return userRepository.findAll();
}

public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found with id: " + id));
}

public User createUser(User user) {
return userRepository.save(user);
}

public User updateUser(Long id, User updatedUser) {
User existingUser = getUserById(id);
existingUser.setName(updatedUser.getName());
existingUser.setEmail(updatedUser.getEmail());
existingUser.setAge(updatedUser.getAge());
return userRepository.save(existingUser);
}

public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}


Примечания:
Методы инкапсулируют работу с UserRepository.
Если пользователь не найден, выбрасывается исключение.


#Java #Training #Spring #CRUD_API
Шаг 6: Создание REST-контроллера

Контроллер обрабатывает HTTP-запросы и возвращает данные клиенту.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserService userService;

@Autowired
public UserController(UserService userService) {
this.userService = userService;
}

@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}

@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
return ResponseEntity.ok(userService.getUserById(id));
}

@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
return ResponseEntity.status(201).body(userService.createUser(user));
}

@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @Valid @RequestBody User user) {
return ResponseEntity.ok(userService.updateUser(id, user));
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}


Примечания:
Методы контроллера возвращают данные с помощью ResponseEntity.
Данные валидируются аннотацией
@Valid.
Используются стандартные HTTP-коды:
200 OK для успешных операций.
201 Created для создания ресурса.
204 No Content для удаления.


Шаг 7: Тестирование API

Пример запросов (с использованием Postman или curl):

Получение всех пользователей:
GET http://localhost:8080/api/users


Получение пользователя по ID:
GET http://localhost:8080/api/users/1


Создание пользователя:
POST http://localhost:8080/api/users
Content-Type: application/json

{
"name": "Jane Doe",
"email": "jane.doe@example.com",
"age": 28
}


Обновление пользователя:
PUT http://localhost:8080/api/users/1
Content-Type: application/json

{
"name": "John Smith",
"email": "john.smith@example.com",
"age": 35
}


Удаление пользователя:
DELETE http://localhost:8080/api/users/1


Дополнительные возможности

Обработка ошибок: Добавьте обработчик ошибок с помощью @ControllerAdvice:
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {
return ResponseEntity.status(404).body(ex.getMessage());
}
}


Тестирование с помощью MockMvc:
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {

@Autowired
private MockMvc mockMvc;

@Test
public void testGetAllUsers() throws Exception {
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk());
}
}


#Java #Training #Spring #CRUD_API
Доброго субботнего утра! ☀️

Как Ваши дела? Елку поставили?🎄

Готовлю на завтра выполнение тестового задания от одного из работодателей с hh.ru.🤌

Посмотрим, разберем, да что-нибудь напишем🤪😂

Всем хороших выходных🎉
Всем привет!

В 16:00 по МСК, я вновь жду Вас на встрече в Яндекс.Телемост!

Попробуем сделать тестовое задание от работодателя на hh.ru, обсудим детали)

Жду всех!✌️
Встреча создана!

https://telemost.yandex.ru/j/89268837201575

Залетаем!
Пишем тестовое задание от реального работодателя. Встреча от 22.12.2024

Запись нашей сегодняшней встречи -
YOUTUBE
RUTUBE

Крайне благодарен всем кто пришел, за участие!💪

На сегодняшней встрече мы начали писать тестовый сервис по документации реального работодателя с hh.ru:
— разобрали логику приложения
— создали сущность и Dto
— начали писать сервисы и контроллер


Смотрите, комментируйте, задавайте вопросы! Обязательно подписывайтесь на ютуб и рутюб каналы!!!

Всем хорошего настроения! 🫡✌️
Всем доброго утра!

Есть вопрос - вчера мы начали писать тестовый сервис хранения носков на складе. Стоит ли продолжить? И второй момент, что можно это сделать в середине недели. Вас это устроит, или привычнее вечер воскресения?
Anonymous Poll
88%
Да, продолжай в любой день!
8%
Да, но мне удобнее быть в воскресение
0%
Какой сервис, о чем ты?
0%
Не, не стоит продолжать, не интересно
4%
Хватит выкладывать всякую чушь!
Пагинация и фильтрация данных в REST API с использованием Spring

При работе с большими наборами данных в REST API критически важна поддержка пагинации и фильтрации. Они позволяют улучшить производительность приложения, сократить нагрузку на сервер и предоставить клиентам удобные способы получать нужные данные.

1. Пагинация (Pagination) в Spring

Пагинация позволяет разделить большие объемы данных на страницы и возвращать их по частям. В Spring Boot пагинация реализуется с помощью Spring Data JPA.

Подключение пагинации в проекте

Spring Data JPA предоставляет интерфейсы и аннотации для легкой реализации пагинации.

Добавьте параметр Pageable в методы репозитория:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {

Page<User> findAll(Pageable pageable);

}


Page — это контейнер, который содержит данные текущей страницы и мета-информацию (например, общее количество страниц).
Pageable — это интерфейс для параметров пагинации: номер страницы, размер страницы и сортировка.


Использование Pageable в контроллере:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserRepository userRepository;

@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}

@GetMapping
public ResponseEntity<Page<User>> getAllUsers(Pageable pageable) {
Page<User> users = userRepository.findAll(pageable);
return ResponseEntity.ok(users);
}
}


Пример запроса с пагинацией:
GET /api/users?page=0&size=5&sort=name,asc
page — номер страницы (начинается с 0).
size — количество элементов на странице.
sort — параметры сортировки (поле,направление).


Пример ответа:
{
"content": [
{"id": 1, "name": "John", "email": "john@example.com"},
{"id": 2, "name": "Jane", "email": "jane@example.com"}
],
"pageable": {
"pageNumber": 0,
"pageSize": 5
},
"totalPages": 2,
"totalElements": 10,
"last": false
}


2. Фильтрация данных в REST API

Фильтрация позволяет клиентам задавать условия, по которым нужно отбирать данные.


Подходы к фильтрации

Фильтрация по параметрам запроса (Request Parameters): Используется для простой фильтрации данных.

Динамическая фильтрация с помощью Specification или Criteria:
Применяется для сложных и многоуровневых условий.

Фильтрация по параметрам запроса
Реализация простого поиска с фильтрацией:

Добавьте методы в репозиторий:
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface UserRepository extends JpaRepository<User, Long> {

List<User> findByNameContaining(String name);

List<User> findByAgeGreaterThanEqual(Integer age);

}


#Java #Training #Spring #Pagination #Filter
Добавьте фильтры в контроллер:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserRepository userRepository;

@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}

@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer age) {

if (name != null) {
return ResponseEntity.ok(userRepository.findByNameContaining(name));
} else if (age != null) {
return ResponseEntity.ok(userRepository.findByAgeGreaterThanEqual(age));
} else {
return ResponseEntity.ok(userRepository.findAll());
}
}
}


Примеры запросов:

Фильтрация по имени:
GET /api/users/search?name=John


Фильтрация по возрасту:
GET /api/users/search?age=30


Динамическая фильтрация с использованием Specification
Для сложных фильтров можно использовать Spring Data JPA Specification.

Добавьте зависимость:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>


Создайте Specification для фильтрации:
import org.springframework.data.jpa.domain.Specification;

public class UserSpecification {

public static Specification<User> hasName(String name) {
return (root, query, cb) -> cb.like(root.get("name"), "%" + name + "%");
}

public static Specification<User> hasAgeGreaterThan(Integer age) {
return (root, query, cb) -> cb.greaterThanOrEqualTo(root.get("age"), age);
}
}


Расширьте репозиторий:

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
}


Добавьте динамическую фильтрацию в контроллер:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserRepository userRepository;

@Autowired
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}

@GetMapping("/filter")
public ResponseEntity<List<User>> filterUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer age) {

Specification<User> spec = Specification.where(null);

if (name != null) {
spec = spec.and(UserSpecification.hasName(name));
}

if (age != null) {
spec = spec.and(UserSpecification.hasAgeGreaterThan(age));
}

return ResponseEntity.ok(userRepository.findAll(spec));
}
}


Пример запроса с фильтрацией:

GET /api/users/filter?name=Jane&age=25


3. Пагинация и фильтрация вместе

Совмещение пагинации и фильтрации:
@GetMapping("/filter")
public ResponseEntity<Page<User>> filterUsers(
@RequestParam(required = false) String name,
@RequestParam(required = false) Integer age,
Pageable pageable) {

Specification<User> spec = Specification.where(null);

if (name != null) {
spec = spec.and(UserSpecification.hasName(name));
}

if (age != null) {
spec = spec.and(UserSpecification.hasAgeGreaterThan(age));
}

Page<User> result = userRepository.findAll(spec, pageable);
return ResponseEntity.ok(result);
}


Пример запроса:
GET /api/users/filter?name=Jane&page=0&size=5&sort=age,desc


#Java #Training #Spring #Pagination #Filter
Что выведет код?

import java.util.HashMap;
import java.util.Map;

public class Task231224_1 {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("a", 3);
map.put("c", null);

System.out.println(map.get("a") + " " + map.get("c"));
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
43%
1 null
4%
3 0
52%
3 null
0%
2 null
И поднять его теперь не так просто🤪😂

https://t.me/Java_for_beginner_dev

#Mems
Обработка ошибок в REST API с использованием Spring Boot

Эффективная обработка ошибок в REST API — важный аспект разработки, обеспечивающий ясность и удобство использования для клиентов. API должен возвращать информативные сообщения об ошибках в стандартизированном формате, указывать причины проблемы и, по возможности, предлагать пути решения.

1. Основные аспекты обработки ошибок


Использование HTTP-кодов:
1xx: Informational (информационные)
2xx: Success (успешно)
3xx: Redirection (перенаправление)
4xx: Client Error (ошибка клиента, например, неправильный запрос, ресурс не найден).
5xx: Server Error (ошибка сервера, например, проблемы на уровне базы данных или приложения).


Возврат стандартного формата ошибки: Сообщения об ошибках должны быть понятны и содержать:
- Код состояния HTTP.
- Сообщение об ошибке.
- Вспомогательную информацию (например, время ошибки или идентификатор запроса).


Обработка различных типов ошибок:
- Ошибки валидации.
- Отсутствие ресурсов.
- Некорректный формат запроса.
- Ошибки на уровне сервера.


2. Обработка ошибок с использованием @ControllerAdvice

Аннотация @ControllerAdvice позволяет централизованно обрабатывать исключения, возникающие в контроллерах.

Создайте класс для обработки исключений:
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.BAD_REQUEST.value(),
ex.getMessage(),
System.currentTimeMillis()
);
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage(),
System.currentTimeMillis()
);
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
}


Класс ответа на ошибку:
public class ErrorResponse {

private int status;
private String message;
private long timestamp;

public ErrorResponse(int status, String message, long timestamp) {
this.status = status;
this.message = message;
this.timestamp = timestamp;
}

// Геттеры и сеттеры...
}


Пользовательское исключение для отсутствия ресурса:
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}


#Java #Training #Spring #API_Errors
3. Обработка ошибок валидации

Spring Boot поддерживает валидацию запросов с помощью аннотаций javax.validation. Ошибки можно обрабатывать централизованно.

Добавьте валидацию в сущность:
import jakarta.validation.constraints.*;

@Entity
public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotBlank(message = "Name cannot be blank")
private String name;

@Email(message = "Invalid email address")
private String email;

@Min(value = 18, message = "Age must be at least 18")
private Integer age;

// Геттеры и сеттеры...
}


Обработайте ошибки валидации:

import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ControllerAdvice;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
}


Пример ответа при ошибке валидации:
{
"name": "Name cannot be blank",
"email": "Invalid email address"
}


4. Обработка ошибок на уровне контроллера

Если требуется специфичная обработка для одного контроллера, можно использовать аннотацию @ExceptionHandler внутри самого контроллера.
@RestController
@RequestMapping("/api/users")
public class UserController {

@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("User not found with id: " + id));
}

@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage(),
System.currentTimeMillis()
);
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
}
}


5. Настройка формата ответа

Вы можете настроить формат ответа об ошибке на уровне всего приложения с помощью аннотации @RestControllerAdvice (аналог @ControllerAdvice, но возвращает JSON по умолчанию).

@RestControllerAdvice
public class GlobalRestExceptionHandler {

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(Exception ex) {
ErrorResponse errorResponse = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"An unexpected error occurred",
System.currentTimeMillis()
);
return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
}


#Java #Training #Spring #API_Errors
6. Настройка ошибок Spring Boot

Spring Boot возвращает стандартные страницы ошибок, такие как Whitelabel Error Page. Для кастомизации ошибок используйте ErrorController.

Отключите Whitelabel Error Page:
server.error.whitelabel.enabled=false
Создайте собственный контроллер ошибок:
java
Копировать код
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.context.request.WebRequest;

import java.util.Map;

@Controller
public class CustomErrorController implements ErrorController {

private final ErrorAttributes errorAttributes;

public CustomErrorController(ErrorAttributes errorAttributes) {
this.errorAttributes = errorAttributes;
}

@RequestMapping("/error")
public ResponseEntity<Map<String, Object>> handleError(WebRequest webRequest) {
Map<String, Object> errors = errorAttributes.getErrorAttributes(webRequest, ErrorAttributeOptions.defaults());
HttpStatus status = HttpStatus.valueOf((int) errors.get("status"));
return new ResponseEntity<>(errors, status);
}
}


7. Пример API с обработкой ошибок

Пример запроса:
GET /api/users/999


Пример ответа:

{
"status": 404,
"message": "User not found with id: 999",
"timestamp": 1702745190123
}


8. Советы по обработке ошибок

Возвращайте только необходимую информацию:
Не отправляйте stack trace клиенту.
Показывайте сообщение об ошибке, понятное конечному пользователю.


Используйте стандартные HTTP-коды:
400 (Bad Request) — ошибка клиента.
401 (Unauthorized) — пользователь не авторизован.
404 (Not Found) — ресурс не найден.
500 (Internal Server Error) — ошибка сервера.


Добавьте логирование: Все ошибки должны логироваться для анализа.


#Java #Training #Spring #API_Errors
Микросервисы в контексте Spring

Микросервисная архитектура является одним из наиболее популярных подходов к созданию современных приложений, особенно в сочетании с фреймворком Spring. Она позволяет разрабатывать, развертывать и масштабировать приложения в виде независимых компонентов, каждый из которых решает определенную бизнес-задачу.


1. Что такое микросервисы?

Микросервисы — это подход к разработке программного обеспечения, при котором приложение разбивается на множество небольших, независимых сервисов. Каждый сервис выполняет одну задачу или отвечает за один функциональный модуль (например, управление пользователями, обработка заказов, инвентаризация).

Основные характеристики микросервисов:
Независимость: Каждый сервис можно разрабатывать, тестировать и развертывать отдельно.
Декомпозиция по бизнес-функциям: Каждый микросервис реализует отдельный бизнес-контекст.
Автономность: Сервисы могут использовать разные языки программирования, базы данных и технологии.
Четкие API: Сервисы взаимодействуют между собой с использованием REST, gRPC, AMQP или других протоколов.
Устойчивость: Отказ одного микросервиса не приводит к полному выходу системы из строя.


2. Виды микросервисов

Микросервисы можно разделить по нескольким критериям:

2.1. По роли в системе:

Core Services (основные сервисы):
Реализуют ключевые бизнес-функции.
Примеры: сервис управления пользователями, сервис обработки платежей.


Supporting Services (вспомогательные сервисы):
Выполняют второстепенные задачи, такие как отправка уведомлений или сбор логов.

Integration Services (интеграционные сервисы):
Предоставляют интерфейсы для взаимодействия с внешними системами.

API Gateway:
Центральный узел для маршрутизации запросов от клиентов к микросервисам.

2.2. По типу взаимодействия:

Синхронные:
Используют REST или gRPC для запроса и получения данных.
Примеры: взаимодействие клиентского приложения с сервисом через REST API.


Асинхронные:
Обмениваются событиями через системы очередей (RabbitMQ, Kafka, ActiveMQ).
Примеры: сервисы уведомлений или обработка фоновых задач.


3. Spring и микросервисы

Spring предоставляет богатый набор инструментов для создания микросервисов, включая:

Spring Boot:
Упрощает создание самостоятельных приложений, которые легко запускать.
Предоставляет встроенные серверы (Tomcat, Jetty, Undertow).


Spring Cloud:
Специализированный модуль для работы с микросервисами.
Поддерживает маршрутизацию, конфигурацию, обнаружение сервисов и управление отказами.


Spring Data:
Упрощает работу с базами данных.

Spring Security:
Реализует безопасность микросервисов (авторизация, аутентификация, токены).

4. Взаимодействие микросервисов

Для взаимодействия между микросервисами используются два подхода:

4.1. Синхронное взаимодействие
Используется при необходимости мгновенного ответа.

Основные инструменты:
REST API:
Самый популярный способ взаимодействия микросервисов.
Формат данных: JSON или XML.


gRPC:
Высокопроизводительный протокол на базе HTTP/2.
Поддерживает сериализацию с использованием Protocol Buffers (Protobuf).


Пример REST API с Spring Boot:
Сервис UserService:
@RestController
@RequestMapping("/users")
public class UserController {

@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.findUserById(id);
return ResponseEntity.ok(user);
}
}


Сервис OrderService, вызывающий UserService:
import org.springframework.web.client.RestTemplate;

@Service
public class OrderService {

private final RestTemplate restTemplate;

@Autowired
public OrderService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

public User getUserDetails(Long userId) {
return restTemplate.getForObject("http://USER-SERVICE/users/" + userId, User.class);
}
}


#Java #Training #Spring #Microservices
4.2. Асинхронное взаимодействие
Используется для передачи событий и задач, которые могут быть обработаны позже.

Основные инструменты:
RabbitMQ:
Брокер сообщений для передачи сообщений через очереди.

Apache Kafka:
Распределённая платформа потоковой обработки данных.

Пример асинхронного взаимодействия с RabbitMQ:

Отправка сообщения:
import org.springframework.amqp.rabbit.core.RabbitTemplate;

@Service
public class NotificationService {

private final RabbitTemplate rabbitTemplate;

@Autowired
public NotificationService(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
}

public void sendNotification(String message) {
rabbitTemplate.convertAndSend("notificationsQueue", message);
}
}


Обработка сообщения:
import org.springframework.amqp.rabbit.annotation.RabbitListener;

@Service
public class NotificationListener {

@RabbitListener(queues = "notificationsQueue")
public void processNotification(String message) {
System.out.println("Received notification: " + message);
}
}


5. Развертывание микросервисов

Развертывание микросервисов — это ключевой этап, который можно реализовать с использованием контейнеров и оркестраторов.

5.1. Использование Docker
Создайте Dockerfile для каждого микросервиса:
FROM openjdk:17-jdk-slim
COPY target/microservice.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]


Создайте Docker Compose файл для нескольких микросервисов:
version: '3'
services:
user-service:
build: ./user-service
ports:
- "8081:8080"
order-service:
build: ./order-service
ports:
- "8082:8080"


5.2. Оркестрация с Kubernetes
Создайте Deployment для микросервиса:
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
spec:
replicas: 3
selector:
matchLabels:
app: user-service
template:
metadata:
labels:
app: user-service
spec:
containers:
- name: user-service
image: user-service:latest
ports:
- containerPort: 8080


Добавьте Service для доступа к Deployment:
apiVersion: v1
kind: Service
metadata:
name: user-service
spec:
selector:
app: user-service
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: ClusterIP


6. Spring Cloud для микросервисов

Spring Cloud упрощает создание микросервисов, предоставляя готовые решения для:
Обнаружения сервисов: Eureka, Consul.
Маршрутизации: Spring Cloud Gateway.
Конфигурации: Spring Cloud Config.
Устойчивости: Circuit Breaker (Resilience4j, Hystrix).


Пример использования Eureka для обнаружения сервисов:
Eureka Server:
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}


Eureka Client:
@EnableEurekaClient
@SpringBootApplication
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}


#Java #Training #Spring #Microservices