<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Лайвкодинг - spring on IT Ментор | Java методичка</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/</link><description>Recent content in Лайвкодинг - spring on IT Ментор | Java методичка</description><generator>Hugo</generator><language>ru</language><atom:link href="https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/index.xml" rel="self" type="application/rss+xml"/><item><title>Найти первый не повторяющийся элемент в массиве целых чисел.</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/first-unique-element/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/first-unique-element/</guid><description>&lt;h4&gt;11. Найти первый не повторяющийся элемент в массиве целых чисел.&lt;/h4&gt;
 &lt;p&gt;Найти первый не повторяющийся элемент в массиве целых чисел.&lt;/p&gt;
&lt;p&gt;public class FirstUniqueElement {
public static void main(String[] args) {
int[] arr = {9, 4, 9, 6, 7, 4, 5};
int n = getFirstUnique(arr);
}
public static int getFirstUnique(int[]arr) {
}
}&lt;/p&gt;</description></item><item><title>Обеспечить выполнение метода в новой транзакции через Spring-прокси</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/transaction-proxy/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/transaction-proxy/</guid><description>&lt;h4&gt;8. Обеспечить выполнение метода в новой транзакции через Spring-прокси&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;br&gt;
🔥 Дан класс с методами &lt;code&gt;methodA()&lt;/code&gt; и &lt;code&gt;methodB()&lt;/code&gt;, оба помечены аннотацией &lt;code&gt;@Transactional&lt;/code&gt;, при этом &lt;code&gt;methodB()&lt;/code&gt; должен выполняться в новой транзакции (&lt;code&gt;PROPAGATION_REQUIRES_NEW&lt;/code&gt;). Но при вызове &lt;code&gt;methodB()&lt;/code&gt; изнутри &lt;code&gt;methodA()&lt;/code&gt; через &lt;code&gt;this.methodB()&lt;/code&gt; прокси Spring не срабатывает, и новая транзакция не создаётся. Нужно написать свой прокси (или использовать self-injection), чтобы &lt;code&gt;methodB()&lt;/code&gt; вызывался через прокси.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Код:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Transactional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;methodA&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; methodB(); &lt;span style="color:#75715e"&gt;// Внутренний вызов – прокси не применяется&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Transactional&lt;/span&gt;(propagation &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Propagation.&lt;span style="color:#a6e22e"&gt;REQUIRES_NEW&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;methodB&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// some logic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 Spring AOP создаёт прокси вокруг Spring-бина и перехватывает только &lt;strong&gt;внешние&lt;/strong&gt; вызовы через прокси.&lt;br&gt;
💡 Чтобы вызвать &lt;code&gt;methodB()&lt;/code&gt; через прокси, нужно получить ссылку на сам прокси-бина внутри класса и вызывать &lt;code&gt;self.methodB()&lt;/code&gt; вместо &lt;code&gt;this.methodB()&lt;/code&gt;.&lt;br&gt;
💡 Можно внедрить сам бин &lt;code&gt;TransactionService&lt;/code&gt; через Spring — он будет прокси-обёрткой.
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.aop.framework.AopContext;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.stereotype.Service;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.transaction.annotation.Propagation;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; org.springframework.transaction.annotation.Transactional;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TransactionService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Вариант 1: использование AopContext для получения прокси&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Transactional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;methodA&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// вместо this.methodB() – получаем текущий прокси&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ((TransactionService) AopContext.&lt;span style="color:#a6e22e"&gt;currentProxy&lt;/span&gt;()).&lt;span style="color:#a6e22e"&gt;methodB&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Transactional&lt;/span&gt;(propagation &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Propagation.&lt;span style="color:#a6e22e"&gt;REQUIRES_NEW&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;methodB&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// some logic in a new transaction&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Дополнительно&lt;/strong&gt;, чтобы &lt;code&gt;AopContext.currentProxy()&lt;/code&gt; работал, нужно включить &lt;code&gt;exposeProxy&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Обеспечить создание транзакции при внутреннем вызове через self-inject</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/self-injection/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/self-injection/</guid><description>&lt;h4&gt;10. Обеспечить создание транзакции при внутреннем вызове через self-inject&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;br&gt;
Дан код. Есть сервис с двумя методами a() и b(). Из b() вызывается a(). Если извне происходит вызов метода b(), сколько будет создано транзакций? Как поправить тот факт, что в таком вызове будет 0 транзакций, чтобы proxy создался и отработала вся логика? Напиши self-inject&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Код:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SomeService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Transactional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;() {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; a();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SomeService.&lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 Spring AOP создает прокси вокруг бина и перехватывает только &lt;strong&gt;внешние&lt;/strong&gt; вызовы.&lt;br&gt;
💡 Внутренний вызов через &lt;code&gt;this.a()&lt;/code&gt; &lt;strong&gt;обходит&lt;/strong&gt; прокси, поэтому аннотация &lt;code&gt;@Transactional&lt;/code&gt; не применяется.&lt;br&gt;
💡 Нужно вызывать &lt;code&gt;a()&lt;/code&gt; через прокси-бин: внедрить сам &lt;code&gt;SomeService&lt;/code&gt; в него же (self‑injection).
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SomeService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// self‑inject прокси&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; SomeService self;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SomeService&lt;/span&gt;(SomeService self) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;self&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; self;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Transactional&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// логика, работающая в транзакции&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;b&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// вместо this.a() использовать прокси&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; self.&lt;span style="color:#a6e22e"&gt;a&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Что происходит:&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Получить список ID сущностей через Spring Data JPA</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/heavydata-repo/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/heavydata-repo/</guid><description>&lt;h4&gt;9. Получить список ID сущностей через Spring Data JPA&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;br&gt;
📌 В интерфейсе &lt;code&gt;HeavyDataRepository&lt;/code&gt; необходимо реализовать метод, который возвращает список только &lt;code&gt;id&lt;/code&gt; сущностей &lt;code&gt;HeavyData&lt;/code&gt;, не загружая объекты целиком.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Код:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeavyDataRepository&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; JpaRepository&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;HeavyData, Integer&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Integer&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getHeavyDataIds&lt;/span&gt;(); &lt;span style="color:#75715e"&gt;// нужно получить только ID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;HeavyData&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;findAllByIsActive&lt;/span&gt;(Boolean isActive);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 В Spring Data JPA можно использовать аннотацию &lt;code&gt;@Query&lt;/code&gt; с JPQL: &lt;code&gt;select h.id from HeavyData h&lt;/code&gt;.&lt;br&gt;
💡 При необходимости использовать нативный SQL — &lt;code&gt;@Query(value = &amp;quot;SELECT id FROM heavy_data&amp;quot;, nativeQuery = true)&lt;/code&gt;.&lt;br&gt;
💡 Метод должен возвращать &lt;code&gt;List&amp;lt;Integer&amp;gt;&lt;/code&gt;, совпадая с типом выбранного поля.
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;HeavyDataRepository&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;extends&lt;/span&gt; JpaRepository&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;HeavyData, Integer&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 1) JPQL-запрос через @Query&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Query&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;SELECT h.id FROM HeavyData h&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Integer&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getHeavyDataIds&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// 2) (опционально) нативный SQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// @Query(value = &amp;#34;SELECT id FROM heavy_data&amp;#34;, nativeQuery = true)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// List&amp;lt;Integer&amp;gt; getHeavyDataIds();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;HeavyData&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;findAllByIsActive&lt;/span&gt;(Boolean isActive);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;📌 &lt;strong&gt;Что важно помнить:&lt;/strong&gt;&lt;br&gt;
✅ Аннотация &lt;code&gt;@Query&lt;/code&gt; позволяет явно задать выборку необходимых полей.&lt;br&gt;
✅ Возвращаемый тип метода (&lt;code&gt;List&amp;lt;Integer&amp;gt;&lt;/code&gt;) должен соответствовать типу поля в запросе.&lt;br&gt;
✅ Для нативных запросов указывайте &lt;code&gt;nativeQuery = true&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Реализовать REST API для поиска обуви с фильтрацией</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/shoes-service/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/shoes-service/</guid><description>&lt;h4&gt;4. Реализовать REST API для поиска обуви с фильтрацией&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;br&gt;
👞 &lt;strong&gt;Разработай сервис для поиска обуви!&lt;/strong&gt;&lt;br&gt;
Тебе нужно создать &lt;strong&gt;REST API&lt;/strong&gt; с эндпоинтом &lt;code&gt;POST /api/v1/search&lt;/code&gt;, который принимает запрос с фильтрами и возвращает список подходящих товаров.&lt;/p&gt;
&lt;p&gt;🔍 &lt;strong&gt;Фильтрация обуви:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Сапоги&lt;/strong&gt; → цвет &lt;strong&gt;красный&lt;/strong&gt; или &lt;strong&gt;зелёный&lt;/strong&gt;, цена &lt;strong&gt;от 5000 до 20000&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Туфли&lt;/strong&gt; → цена &lt;strong&gt;меньше 10000&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;📩 &lt;strong&gt;Пример запроса:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;сапоги&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;color&amp;#34;&lt;/span&gt;: [&lt;span style="color:#e6db74"&gt;&amp;#34;красный&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;зелёный&amp;#34;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;minPrice&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;5000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;maxPrice&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;20000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;📤 &lt;strong&gt;Пример ответа:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;сапоги&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;color&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;красный&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;15000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://example.com/shoe1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;сапоги&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;color&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;зелёный&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;price&amp;#34;&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;18000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://example.com/shoe2&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 &lt;strong&gt;Используй Spring Boot + Spring Data JPA&lt;/strong&gt; для работы с БД.&lt;br&gt;
💡 &lt;strong&gt;Создай сущность &lt;code&gt;Shoe&lt;/code&gt;&lt;/strong&gt; с полями &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, &lt;code&gt;price&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt;.&lt;br&gt;
💡 &lt;strong&gt;Напиши DTO-классы&lt;/strong&gt; для запроса и ответа.&lt;br&gt;
💡 &lt;strong&gt;Используй &lt;code&gt;JpaRepository&lt;/code&gt;&lt;/strong&gt; и напиши кастомный метод для поиска.&lt;br&gt;
💡 &lt;strong&gt;Контроллер должен принимать JSON-запрос&lt;/strong&gt; и возвращать список обуви.
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;p&gt;📌 &lt;strong&gt;1. Создаём сущность &lt;code&gt;Shoe&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Реализовать класс-сервис для работы с токенами с ограничением на количество использований</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/token-limited-usage/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/token-limited-usage/</guid><description>&lt;h4&gt;2. Реализовать класс-сервис для работы с токенами с ограничением на количество использований&lt;/h4&gt;
 &lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;ul&gt;
&lt;li&gt;Для реализации сервиса с токенами нужно создать структуру данных, которая будет отслеживать количество использований токенов.&lt;/li&gt;
&lt;li&gt;Можно использовать &lt;strong&gt;HashMap&lt;/strong&gt; или &lt;strong&gt;Redis&lt;/strong&gt; для хранения токенов с их статусами.&lt;/li&gt;
&lt;li&gt;Нужно хранить:
&lt;ul&gt;
&lt;li&gt;Токен (например, строка).&lt;/li&gt;
&lt;li&gt;Количество оставшихся использований для этого токена.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;После использования токена количество оставшихся использований уменьшается.&lt;/li&gt;
&lt;li&gt;Если количество использований исчерпано, токен становится невалидным.&lt;/li&gt;
&lt;li&gt;Пример ограничения использования токенов:
&lt;ul&gt;
&lt;li&gt;Токен может быть использован 5 раз.&lt;/li&gt;
&lt;li&gt;После пятого использования токен становится недействительным.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;p&gt;Пример реализации сервиса для работы с токенами:&lt;/p&gt;</description></item><item><title>Реализовать миграцию JSON-поля с сохранением обратной совместимости</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/rename-attribute/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/rename-attribute/</guid><description>&lt;h4&gt;6. Реализовать миграцию JSON-поля с сохранением обратной совместимости&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Организовать переход на изменение названия принимающего атрибута с &lt;strong&gt;title&lt;/strong&gt; на &lt;strong&gt;name&lt;/strong&gt;. Нужно обеспечить обратную совместимость, чтобы клиенты, использующие старый формат (&lt;code&gt;&amp;quot;title&amp;quot;: &amp;quot;...&amp;quot;&lt;/code&gt;), могли продолжать работать, а новые — использовать &lt;code&gt;&amp;quot;name&amp;quot;: &amp;quot;...&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Исходный JSON:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Новый JSON:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;...&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 Используйте аннотацию &lt;strong&gt;@JsonAlias&lt;/strong&gt; для поддержки старого названия атрибута.&lt;br&gt;
💡 Основное имя атрибута задается с помощью &lt;strong&gt;@JsonProperty&lt;/strong&gt;.
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; com.fasterxml.jackson.annotation.JsonAlias;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; com.fasterxml.jackson.annotation.JsonProperty;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BookDTO&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Новое основное имя &amp;#34;name&amp;#34;, поддерживаем также &amp;#34;title&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@JsonProperty&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@JsonAlias&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; String name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Геттер&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; String &lt;span style="color:#a6e22e"&gt;getName&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Сеттер&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;setName&lt;/span&gt;(String name) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Объяснение решения:&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Реализовать сервис отправляющий сообщения через внешние библиотеки с возможностью добавления новые уведомлений</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/notification-service/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/notification-service/</guid><description>&lt;h4&gt;7. Реализовать сервис отправляющий сообщения через внешние библиотеки с возможностью добавления новые уведомлений&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;br&gt;
🔥 Написать сервис &lt;code&gt;Notificator&lt;/code&gt;, который отправляет сообщения через различные внешние библиотеки (Email, SMS и т.д.), с возможностью легко добавлять новые каналы уведомлений, используя возможности Java и Spring.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Код:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// внешняя библиотека 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EmailNotificationService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sendEmail&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; System.&lt;span style="color:#a6e22e"&gt;out&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;println&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Send from email service&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; System.&lt;span style="color:#a6e22e"&gt;out&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;println&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// внешняя библиотека 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SmsNotificationService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sendSms&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; System.&lt;span style="color:#a6e22e"&gt;out&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;println&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Send from sms service&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; System.&lt;span style="color:#a6e22e"&gt;out&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;println&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Ваш код начинается здесь&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NotificationService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(String message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EmailNotificationAdapter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; NotificationService {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; EmailNotificationService emailService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EmailNotificationAdapter&lt;/span&gt;(EmailNotificationService emailService) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;emailService&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; emailService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; emailService.&lt;span style="color:#a6e22e"&gt;sendEmail&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SmsNotificationAdapter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; NotificationService {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; SmsNotificationService smsService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SmsNotificationAdapter&lt;/span&gt;(SmsNotificationService smsService) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;smsService&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; smsService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; smsService.&lt;span style="color:#a6e22e"&gt;sendSms&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Notificator&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;NotificationService&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; channels;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Notificator&lt;/span&gt;(List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;NotificationService&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; channels) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;channels&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; channels;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;notifyAll&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; (NotificationService svc : channels) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; svc.&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 Введите общий интерфейс &lt;code&gt;NotificationService&lt;/code&gt; с методом &lt;code&gt;send(String message)&lt;/code&gt;.&lt;br&gt;
💡 Для каждой внешней библиотеки создайте &lt;strong&gt;адаптер&lt;/strong&gt; (Adapter), реализующий этот интерфейс и обёртывающий вызовы библиотеки.&lt;br&gt;
💡 Используйте &lt;strong&gt;конструкторную инъекцию&lt;/strong&gt; Spring для подключения внешних сервисов.&lt;br&gt;
💡 В &lt;code&gt;Notificator&lt;/code&gt; внедрите &lt;code&gt;List&amp;lt;NotificationService&amp;gt;&lt;/code&gt; — Spring автоматически соберёт все реализации.&lt;br&gt;
💡 Чтобы добавить новую библиотеку, достаточно реализовать ещё один адаптер &lt;code&gt;NotificationService&lt;/code&gt; и зарегистрировать его как Spring-бин.
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 1. Общий интерфейс&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;interface&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NotificationService&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(String message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 2. Адаптер для Email&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EmailNotificationAdapter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; NotificationService {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; EmailNotificationService emailService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;EmailNotificationAdapter&lt;/span&gt;(EmailNotificationService emailService) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;emailService&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; emailService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; emailService.&lt;span style="color:#a6e22e"&gt;sendEmail&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 3. Адаптер для SMS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SmsNotificationAdapter&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; NotificationService {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; SmsNotificationService smsService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;SmsNotificationAdapter&lt;/span&gt;(SmsNotificationService smsService) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;smsService&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; smsService;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; smsService.&lt;span style="color:#a6e22e"&gt;sendSms&lt;/span&gt;(message);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 4. Сервис-агрегатор уведомлений&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Notificator&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;NotificationService&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; channels;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Notificator&lt;/span&gt;(List&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;NotificationService&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; channels) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;channels&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; channels;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;notifyAll&lt;/span&gt;(String message) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; channels.&lt;span style="color:#a6e22e"&gt;forEach&lt;/span&gt;(svc &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; svc.&lt;span style="color:#a6e22e"&gt;send&lt;/span&gt;(message));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Использование в приложении&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@Component&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AppRunner&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;implements&lt;/span&gt; CommandLineRunner {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;final&lt;/span&gt; Notificator notificator;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;AppRunner&lt;/span&gt;(Notificator notificator) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;notificator&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; notificator;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;@Override&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;run&lt;/span&gt;(String... args) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; notificator.&lt;span style="color:#a6e22e"&gt;notifyAll&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;Hello, world!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
 &lt;/div&gt;
&lt;/details&gt;</description></item><item><title>Спроектировать и реализовать REST API для сущностей "Книги" и "Авторы"</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/crud-books/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/crud-books/</guid><description>&lt;h4&gt;5. Спроектировать и реализовать REST API для сущностей &amp;#34;Книги&amp;#34; и &amp;#34;Авторы&amp;#34;&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Условие задачи:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Опишите CRUD операции для сущностей, используя формат &amp;ldquo;GET /some/path 200;&amp;rdquo;.&lt;br&gt;
Нужно реализовать следующие операции для сущности книги (BookEntity) с учётом таблиц: books, authors, books_authors:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Получение всех книг&lt;/li&gt;
&lt;li&gt;Получение конкретной книги&lt;/li&gt;
&lt;li&gt;Обновление книги&lt;/li&gt;
&lt;li&gt;Создание книги&lt;/li&gt;
&lt;li&gt;Удаление книги&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 Лучше разделить вход/выход через DTO: &lt;code&gt;BookCreateDto&lt;/code&gt;, &lt;code&gt;BookUpdateDto&lt;/code&gt;, &lt;code&gt;BookResponseDto&lt;/code&gt;.&lt;br&gt;
💡 Для many-to-many удобно в сервисе: сохраняем &lt;code&gt;book&lt;/code&gt;, затем пересоздаём связи в &lt;code&gt;books_authors&lt;/code&gt;.&lt;br&gt;
💡 Возвращай корректные статусы: &lt;code&gt;201&lt;/code&gt; на create, &lt;code&gt;204&lt;/code&gt; на delete, &lt;code&gt;404&lt;/code&gt; если книги нет.&lt;br&gt;
💡 Для ручной проверки добавь &lt;code&gt;.http&lt;/code&gt; файлы: create/get/list/update/delete.
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;p&gt;DTO:&lt;/p&gt;</description></item><item><title>Спроектировать и реализовать REST API для управления договорами</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/http-post-contract/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/http-post-contract/</guid><description>&lt;h4&gt;3. Спроектировать и реализовать REST API для управления договорами&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Описание&lt;/strong&gt;&lt;br&gt;
Спроектировать REST Controller, который:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;создаёт новый договор&lt;/li&gt;
&lt;li&gt;возвращает договор по номеру договора&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В описании задачи предоставить модель &lt;code&gt;Contract&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Модель &lt;code&gt;Contract&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Contract&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; Long id;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; String number; &lt;span style="color:#75715e"&gt;// номер договора (уникальный)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; String clientId; &lt;span style="color:#75715e"&gt;// идентификатор клиента&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; String status; &lt;span style="color:#75715e"&gt;// например: NEW, ACTIVE, CLOSED&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; java.&lt;span style="color:#a6e22e"&gt;time&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Instant&lt;/span&gt; createdAt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// getters/setters/constructors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 Для создания договора обычно используют &lt;code&gt;POST /api/contracts&lt;/code&gt;.&lt;br&gt;
💡 Получение договора по номеру удобно сделать как &lt;code&gt;GET /api/contracts/{number}&lt;/code&gt;.&lt;br&gt;
💡 Лучше принимать на вход &lt;code&gt;ContractCreateDto&lt;/code&gt;, а наружу отдавать &lt;code&gt;ContractResponseDto&lt;/code&gt;.&lt;br&gt;
💡 Номер договора стоит валидировать (&lt;code&gt;@NotBlank&lt;/code&gt;) и сделать уникальным (если есть БД — unique constraint).&lt;br&gt;
💡 Если договор не найден — возвращать &lt;code&gt;404 Not Found&lt;/code&gt;.
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;p&gt;DTO:&lt;/p&gt;</description></item><item><title>Спроектировать и реализовать REST API для управления пользователем</title><link>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/api-user-management/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://zhukovsd.github.io/java-backend-interview-prep/livecoding/tasks/spring/api-user-management/</guid><description>&lt;h4&gt;1. Спроектировать и реализовать REST API для управления пользователем&lt;/h4&gt;
 &lt;p&gt;&lt;strong&gt;Описание&lt;/strong&gt;&lt;br&gt;
Нужно спроектировать и реализовать &lt;strong&gt;REST API&lt;/strong&gt; для управления пользователями:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;создать пользователя&lt;/li&gt;
&lt;li&gt;получить пользователя по id&lt;/li&gt;
&lt;li&gt;получить список пользователей&lt;/li&gt;
&lt;li&gt;обновить пользователя&lt;/li&gt;
&lt;li&gt;удалить пользователя&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В рамках задания используем Spring Boot (без БД можно в памяти, но можно легко заменить на JPA).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Модель &lt;code&gt;User&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;class&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;User&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; Long id;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; String name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; String email;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;private&lt;/span&gt; Integer age;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// getters/setters/constructors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote class="book-hint warning"&gt;
 &lt;strong&gt;Спойлеры к решению&lt;/strong&gt;
&lt;/blockquote&gt;

&lt;details &gt;&lt;summary&gt;Подсказки&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 💡 Для REST API обычно делают &lt;code&gt;@RestController&lt;/code&gt; и маппинги &lt;code&gt;POST/GET/PUT/DELETE&lt;/code&gt;.&lt;br&gt;
💡 Валидацию DTO удобно делать через &lt;code&gt;@Valid&lt;/code&gt; + &lt;code&gt;@NotBlank/@Email/@Min&lt;/code&gt;.&lt;br&gt;
💡 Хранилище можно сделать на &lt;code&gt;ConcurrentHashMap&amp;lt;Long, User&amp;gt;&lt;/code&gt; + генерация id через &lt;code&gt;AtomicLong&lt;/code&gt;.&lt;br&gt;
💡 Для ошибок хорошо вернуть &lt;code&gt;404&lt;/code&gt; если не нашли, и &lt;code&gt;400&lt;/code&gt; если валидация не прошла.&lt;br&gt;
💡 Для ручных тестов удобно подготовить &lt;code&gt;.http&lt;/code&gt; файлы (IDEA умеет выполнять).
 &lt;/div&gt;
&lt;/details&gt;

&lt;details &gt;&lt;summary&gt;Решение&lt;/summary&gt;
 &lt;div class="markdown-inner"&gt;
 &lt;p&gt;Ниже пример простого решения “в памяти” (без БД), но с корректными HTTP-статусами и DTO-валидацией.&lt;/p&gt;</description></item></channel></rss>