Какой существует эффективный способ удостоверится, что все сервлеты доступны только для пользователя с верной сессией?
Сервлет фильтры используются для перехвата всех запросов между контейнером сервлетов и сервлетом. Поэтому логично использовать соответствующий фильтр для проверки необходимой информации (например валидности сессии) в запросе.
Сервлет фильтры используются для перехвата всех запросов между контейнером сервлетов и сервлетом. Поэтому логично использовать соответствующий фильтр для проверки необходимой информации (например валидности сессии) в запросе.
Как мы можем обеспечить transport layer security для нашего веб приложения?
Для обеспечения transport layer security необходимо настроить поддержку SSL сервлет контейнера. Как это сделать зависит от конкретной реализации сервлет-контейнера.
Для обеспечения transport layer security необходимо настроить поддержку SSL сервлет контейнера. Как это сделать зависит от конкретной реализации сервлет-контейнера.
Как организовать подключение к базе данных, обеспечить журналирование в сервлете?
При работе с большим количеством подключений к базе данных рекомендуется инициализировать их в servlet context listener, а также установить в качестве атрибута контекста для возможности использования другими сервлетами.
Журналирование подключается к сервлету стандартным для логгера способом (например для log4j это может быть property-файл или XML-конфигурация) , а далее эта информация используется при настройке соответствующего context listener.
При работе с большим количеством подключений к базе данных рекомендуется инициализировать их в servlet context listener, а также установить в качестве атрибута контекста для возможности использования другими сервлетами.
Журналирование подключается к сервлету стандартным для логгера способом (например для log4j это может быть property-файл или XML-конфигурация) , а далее эта информация используется при настройке соответствующего context listener.
Какие основные особенности появились в спецификации
Servlet 3?
Servlet Annotations. До Servlet 3 вся конфигурация содержалась в web.xml, что приводило к ошибкам и неудобству при работе с большим количестве сервлетов. Примеры аннотаций: @WebServlet, @WebInitParam, @WebFilter, @WebListener.
Web Fragments. Одностраничное веб приложение может содержать множество модулей: все модули прописываются в fragment.xml в папке META-INF\. Это позволяет разделять веб приложение на отдельные модули, собранные как .jar-файлы в отдельной lib\ директории.
Динамическое добавление веб компонентов. Появилась возможность программно добавлять фильтры и слушатели, используя ServletContext объект. Для этого применяются методы addServlet(), addFilter(), addListener(). Используя это нововведение стало доступным построение динамической системы, в которой необходимый объект будет создан и вызван только по необходимости.
Асинхронное выполнение. Поддержка асинхронной обработки позволяет передать выполнение запроса в другой поток без удержания всего сервера занятым.
Servlet 3?
Servlet Annotations. До Servlet 3 вся конфигурация содержалась в web.xml, что приводило к ошибкам и неудобству при работе с большим количестве сервлетов. Примеры аннотаций: @WebServlet, @WebInitParam, @WebFilter, @WebListener.
Web Fragments. Одностраничное веб приложение может содержать множество модулей: все модули прописываются в fragment.xml в папке META-INF\. Это позволяет разделять веб приложение на отдельные модули, собранные как .jar-файлы в отдельной lib\ директории.
Динамическое добавление веб компонентов. Появилась возможность программно добавлять фильтры и слушатели, используя ServletContext объект. Для этого применяются методы addServlet(), addFilter(), addListener(). Используя это нововведение стало доступным построение динамической системы, в которой необходимый объект будет создан и вызван только по необходимости.
Асинхронное выполнение. Поддержка асинхронной обработки позволяет передать выполнение запроса в другой поток без удержания всего сервера занятым.
👍2
Хотите быть в курсе передовых технологий в IT?
💻 Получите доступ к единой витрине технологий Сбера! На платформе SmartMarket можно решать любые IT-задачи: от создания приложений для виртуальных ассистентов до организации облачного хранения данных. JavaScript-разработчики могут:
— Использовать десятки современных инструментов, например, для создания приложений для виртуальных ассистентов с визуальным интерфейсом;
— Подключить к готовому проекту NLP-платформу и распознавание жестов;
— Монетизировать бизнес в один клик;
— Найти в одном месте документацию, API и спецификации для всех сервисов;
— Общаться с сообществом из 2500+ разработчиков, посещать митапы и многое другое!
А ещё вы получите бонусы от партнеров Сбера и доступ к аудитории экосистемы в 100 млн клиентов.
👉🏻 Подробности и бесплатная регистрация в SmartMarket Studio здесь.
💻 Получите доступ к единой витрине технологий Сбера! На платформе SmartMarket можно решать любые IT-задачи: от создания приложений для виртуальных ассистентов до организации облачного хранения данных. JavaScript-разработчики могут:
— Использовать десятки современных инструментов, например, для создания приложений для виртуальных ассистентов с визуальным интерфейсом;
— Подключить к готовому проекту NLP-платформу и распознавание жестов;
— Монетизировать бизнес в один клик;
— Найти в одном месте документацию, API и спецификации для всех сервисов;
— Общаться с сообществом из 2500+ разработчиков, посещать митапы и многое другое!
А ещё вы получите бонусы от партнеров Сбера и доступ к аудитории экосистемы в 100 млн клиентов.
👉🏻 Подробности и бесплатная регистрация в SmartMarket Studio здесь.
Какие способы аутентификации доступны сервлету?
Спецификация сервлетов определяет четыре типа проверки подлинности:
HTTP Basic Authentication - BASIC. При доступе к закрытым ресурсам появится окно, которое попросит ввести данные для аутентификации.
Form Based Login - FORM. Используется собственная html форма:
HTTP Digest Authentication - DIGEST. Цифровая аутентификация с шифрованием.
HTTPS Authentication - CLIENT-CERT. Аутентификация с помощью клиентского сертификата.
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/error.html</form-error-page>
</form-login-config>
</login-config>
Спецификация сервлетов определяет четыре типа проверки подлинности:
HTTP Basic Authentication - BASIC. При доступе к закрытым ресурсам появится окно, которое попросит ввести данные для аутентификации.
Form Based Login - FORM. Используется собственная html форма:
HTTP Digest Authentication - DIGEST. Цифровая аутентификация с шифрованием.
HTTPS Authentication - CLIENT-CERT. Аутентификация с помощью клиентского сертификата.
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<form-login-page>/login.html</form-login-page>
<form-error-page>/error.html</form-error-page>
</form-login-config>
</login-config>
👍2
Системы поддержки принятия врачебных решений, которые разработают участники конкурса AI’M DOCTOR должны будут делать выводы на основе анализа комплекса информации о пациенте, включая медицинскую карту и протоколы осмотров. Также эти системы должны будут уметь обращаться к внешним базам медицинских знаний. При этом важнейшей характеристикой будет способность к проведению дифференциальной диагностики.
Значительную роль сыграет способность системы объяснить свои заключения. Для того, чтобы добиться этого, необходимо осуществить настоящий технологический прорыв, перейдя от «слабого» к «объясняющему» искусственному интеллекту. В данный момент логика работы ИИ-систем (Искусственного интеллекта) скрыта.
Созданные системы должны стать надежными помощниками врачей, доступными в любое время и в любой день. А облачные технологии помогут сделать их доступными практически в любой точке планеты.
Подробнее о конкурсе НТИ Up Great AI’M DOCTOR: https://ai4med.upgreat.one/?utm_source=tg, FB и ВК
Значительную роль сыграет способность системы объяснить свои заключения. Для того, чтобы добиться этого, необходимо осуществить настоящий технологический прорыв, перейдя от «слабого» к «объясняющему» искусственному интеллекту. В данный момент логика работы ИИ-систем (Искусственного интеллекта) скрыта.
Созданные системы должны стать надежными помощниками врачей, доступными в любое время и в любой день. А облачные технологии помогут сделать их доступными практически в любой точке планеты.
Подробнее о конкурсе НТИ Up Great AI’M DOCTOR: https://ai4med.upgreat.one/?utm_source=tg, FB и ВК
Что такое Java Server Pages (JSP)?
JSP (JavaServer Pages) — платформонезависимая переносимая и легко расширяемая технология разработки веб-приложений, позволяющая веб-разработчикам создавать содержимое, которое имеет как статические, так и динамические компоненты. Страница JSP содержит текст двух типов: статические исходные данные, которые могут быть оформлены в одном из текстовых форматов HTML, SVG, WML, или XML, и JSP-элементы, которые конструируют динамическое содержимое. Кроме этого могут использоваться библиотеки JSP-тегов, а также EL (Expression Language), для внедрения Java-кода в статичное содержимое JSP-страниц.
Код JSP-страницы транслируется в Java-код сервлета с помощью компилятора JSP-страниц Jasper, и затем компилируется в байт-код JVM.
JSP-страницы загружаются на сервере и управляются Java EE Web Application. Обычно такие страницы упакованы в файловые архивы .war и .ear.
JSP (JavaServer Pages) — платформонезависимая переносимая и легко расширяемая технология разработки веб-приложений, позволяющая веб-разработчикам создавать содержимое, которое имеет как статические, так и динамические компоненты. Страница JSP содержит текст двух типов: статические исходные данные, которые могут быть оформлены в одном из текстовых форматов HTML, SVG, WML, или XML, и JSP-элементы, которые конструируют динамическое содержимое. Кроме этого могут использоваться библиотеки JSP-тегов, а также EL (Expression Language), для внедрения Java-кода в статичное содержимое JSP-страниц.
Код JSP-страницы транслируется в Java-код сервлета с помощью компилятора JSP-страниц Jasper, и затем компилируется в байт-код JVM.
JSP-страницы загружаются на сервере и управляются Java EE Web Application. Обычно такие страницы упакованы в файловые архивы .war и .ear.
Зачем нужен JSP?
JSP расширяет технологию сервлетов обеспечивая возможность создания динамических страницы с HTML подобным синтаксисом.
Хотя создание представлений поддерживается и в сервлетах, но большая часть любой веб-страницы является статической, поэтому код сервлета в таком случае получается чересчур перегруженным, замусоренным и поэтому при его написании легко допустить ошибку.
Еще одним преимуществом JSP является горячее развертывание - возможность заменить одну страницу на другую непосредственно в контейнере без необходимости перекомпилировать весь проект или перезапускать сервер.
Однако рекомендуется избегать написания серьёзной бизнес-логики в JSP и использовать страницу только в качестве представления.
JSP расширяет технологию сервлетов обеспечивая возможность создания динамических страницы с HTML подобным синтаксисом.
Хотя создание представлений поддерживается и в сервлетах, но большая часть любой веб-страницы является статической, поэтому код сервлета в таком случае получается чересчур перегруженным, замусоренным и поэтому при его написании легко допустить ошибку.
Еще одним преимуществом JSP является горячее развертывание - возможность заменить одну страницу на другую непосредственно в контейнере без необходимости перекомпилировать весь проект или перезапускать сервер.
Однако рекомендуется избегать написания серьёзной бизнес-логики в JSP и использовать страницу только в качестве представления.
Опишите, как обрабатываются JSP страницы, начиная от запроса к серверу, заканчивая ответом пользователю.
Когда пользователь переходит по ссылке на страницу page.jsp, он отправляет http-запрос на сервер GET /page.jsp. Затем, на основе этого запроса и текста самой страницы, сервер генерирует java-класс, компилирует его и выполняет полученный сервлет, формирующий ответ пользователю в виде представления этой страницы, который сервер и перенаправляет обратно пользователю.
Когда пользователь переходит по ссылке на страницу page.jsp, он отправляет http-запрос на сервер GET /page.jsp. Затем, на основе этого запроса и текста самой страницы, сервер генерирует java-класс, компилирует его и выполняет полученный сервлет, формирующий ответ пользователю в виде представления этой страницы, который сервер и перенаправляет обратно пользователю.
Расскажите об этапах (фазах) жизненного цикла JSP.
Если посмотреть код внутри созданной JSP страницы, то он будет выглядеть как HTML и не будет похож на java класс. Конвертацией JSP страниц в HTML код занимается контейнер, который так же создает и сервлет для использования в веб приложении.
Жизненный цикл JSP состоит из нескольких фаз, которыми руководит JSP контейнер:
Translation – проверка и парсинг кода JSP страницы для создания кода сервлета.
Compilation – компиляция исходного кода сервлета.
Class Loading – загрузка скомпилированного класса в память.
Instantiation – внедрение конструктора без параметра загруженного класса для инициализации в памяти.
Initialization – вызов init() метода объекта JSP класса и инициализация конфигурации сервлета с первоначальными параметрами, которые указаны в дескрипторе развертывания (web.xml). После этой фазы JSP способен обрабатывать запросы клиентов. Обычно эти фазы происходят после первого запроса клиента (т.е. ленивая загрузка), но можно настроить загрузку и инициализацию JSP на старте приложения по аналогии с сервлетами.
Request Processing – длительный жизненный цикл обработки запросов клиента JSP страницей. Обработка является многопоточной и аналогична сервлетам — для каждого запроса создается новый поток, объекты ServletRequest и ServletResponse, происходит выполнение сервис методов.
Destroy – последняя фаза жизненного цикла JSP, на которой её класс удаляется из памяти. Обычно это происходит при выключении сервера или выгрузке приложения.
Если посмотреть код внутри созданной JSP страницы, то он будет выглядеть как HTML и не будет похож на java класс. Конвертацией JSP страниц в HTML код занимается контейнер, который так же создает и сервлет для использования в веб приложении.
Жизненный цикл JSP состоит из нескольких фаз, которыми руководит JSP контейнер:
Translation – проверка и парсинг кода JSP страницы для создания кода сервлета.
Compilation – компиляция исходного кода сервлета.
Class Loading – загрузка скомпилированного класса в память.
Instantiation – внедрение конструктора без параметра загруженного класса для инициализации в памяти.
Initialization – вызов init() метода объекта JSP класса и инициализация конфигурации сервлета с первоначальными параметрами, которые указаны в дескрипторе развертывания (web.xml). После этой фазы JSP способен обрабатывать запросы клиентов. Обычно эти фазы происходят после первого запроса клиента (т.е. ленивая загрузка), но можно настроить загрузку и инициализацию JSP на старте приложения по аналогии с сервлетами.
Request Processing – длительный жизненный цикл обработки запросов клиента JSP страницей. Обработка является многопоточной и аналогична сервлетам — для каждого запроса создается новый поток, объекты ServletRequest и ServletResponse, происходит выполнение сервис методов.
Destroy – последняя фаза жизненного цикла JSP, на которой её класс удаляется из памяти. Обычно это происходит при выключении сервера или выгрузке приложения.
👍1😁1
Расскажите о методах жизненного цикла JSP.
Контейнер сервлетов (например, Tomcat, GlassFish) создает из JSP-страницы класс сервлета, наследующего свойства интерфейса javax.servlet.jsp.HttpJspBase и включающего следующие методы:
jspInit() — метод объявлен в JSP странице и реализуется с помощью контейнера. Этот метод вызывается один раз в жизненном цикле JSP для того, чтобы инициализировать конфигурационные параметры указанные в дескрипторе развертывания. Этот метод можно переопределить с помощью определения элемента JSP scripting и указания необходимых параметров для инициализации;
_jspService() — метод переопределяется контейнером автоматически и соответствует непосредственно коду JSP, описанному на странице. Этот метод определен в интерфейсе HttpJspPage, его имя начинается с нижнего подчеркивания и он отличается от других методов жизненного цикла тем, что его невозможно переопределить;
jspDestroy() — метод вызывается контейнером для удаления объекта из памяти (на последней фазе жизненного цикла JSP - Destroy). Метод вызывается только один раз и доступен для переопределения, предоставляя возможность освободить ресурсы, которые были созданы в jspInit().
Контейнер сервлетов (например, Tomcat, GlassFish) создает из JSP-страницы класс сервлета, наследующего свойства интерфейса javax.servlet.jsp.HttpJspBase и включающего следующие методы:
jspInit() — метод объявлен в JSP странице и реализуется с помощью контейнера. Этот метод вызывается один раз в жизненном цикле JSP для того, чтобы инициализировать конфигурационные параметры указанные в дескрипторе развертывания. Этот метод можно переопределить с помощью определения элемента JSP scripting и указания необходимых параметров для инициализации;
_jspService() — метод переопределяется контейнером автоматически и соответствует непосредственно коду JSP, описанному на странице. Этот метод определен в интерфейсе HttpJspPage, его имя начинается с нижнего подчеркивания и он отличается от других методов жизненного цикла тем, что его невозможно переопределить;
jspDestroy() — метод вызывается контейнером для удаления объекта из памяти (на последней фазе жизненного цикла JSP - Destroy). Метод вызывается только один раз и доступен для переопределения, предоставляя возможность освободить ресурсы, которые были созданы в jspInit().
Как скомпилировать исходники java вручную
В современной разработке многие рутинные процессы автоматизированы достаточно хорошо, поэтому вам не приходится каждый раз компилировать ваши исходники вручную. Я не сомневаюсь, что вы прекрасно знаете, как это делается. А для тех, кто забыл или решил освежить свои знания, рассмотрим небольшой пример.
https://te.legra.ph/Kak-skompilirovat-ishodniki-java-vruchnuyu-01-04
В современной разработке многие рутинные процессы автоматизированы достаточно хорошо, поэтому вам не приходится каждый раз компилировать ваши исходники вручную. Я не сомневаюсь, что вы прекрасно знаете, как это делается. А для тех, кто забыл или решил освежить свои знания, рассмотрим небольшой пример.
https://te.legra.ph/Kak-skompilirovat-ishodniki-java-vruchnuyu-01-04
Telegraph
Как скомпилировать исходники java вручную
В современной разработке многие рутинные процессы автоматизированы достаточно хорошо, поэтому вам не приходится каждый раз компилировать ваши исходники вручную. Я не сомневаюсь, что вы прекрасно знаете, как это делается. А для тех, кто забыл или решил освежить…
Какие методы жизненного цикла JSP могут быть переопределены?
Возможно переопределить лишь jspInit() и jspDestroy() методы.
Возможно переопределить лишь jspInit() и jspDestroy() методы.
Как можно предотвратить прямой доступ к JSP странице из браузера?
Прямой доступ к директории /WEB-INF/ из веб-приложения отсутствует. Поэтому JSP-страницы можно расположить внутри этой папки и тем самым запретить доступ к странице из браузера. Однако, по аналогии с описанием сервлетов, будет необходимо настроить дескриптор развертывания:
<servlet>
<servlet-name>Example</servlet-name>
<jsp-file>/WEB-INF/example.jsp</jsp-file>
<init-param>
<param-name>exampleParameter</param-name>
<param-value>parameterValue</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Example</servlet-name>
<url-pattern>/example.jsp</url-pattern>
</servlet-mapping>
Прямой доступ к директории /WEB-INF/ из веб-приложения отсутствует. Поэтому JSP-страницы можно расположить внутри этой папки и тем самым запретить доступ к странице из браузера. Однако, по аналогии с описанием сервлетов, будет необходимо настроить дескриптор развертывания:
<servlet>
<servlet-name>Example</servlet-name>
<jsp-file>/WEB-INF/example.jsp</jsp-file>
<init-param>
<param-name>exampleParameter</param-name>
<param-value>parameterValue</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Example</servlet-name>
<url-pattern>/example.jsp</url-pattern>
</servlet-mapping>
👍1
А как вы определяете свойства переменными окружения в Spring Boot приложениях?
https://habr.com/ru/post/588985/
https://habr.com/ru/post/588985/
👍2
Какая разница между динамическим и статическим содержимым JSP?
Статическое содержимое JSP (HTML, код JavaScript, изображения и т.д.) не изменяется в процессе работы веб приложения.
Динамические ресурсы созданы для того, чтобы отображать свое содержимое в зависимости от пользовательских действий. Обычно они представлены в виде выражений EL (Expression Language), библиотек JSP-тегов и пр.
Статическое содержимое JSP (HTML, код JavaScript, изображения и т.д.) не изменяется в процессе работы веб приложения.
Динамические ресурсы созданы для того, чтобы отображать свое содержимое в зависимости от пользовательских действий. Обычно они представлены в виде выражений EL (Expression Language), библиотек JSP-тегов и пр.
👍2
Как закомментировать код в JSP?
<!—- HTML комментарий; отображается на странице JSP —-> такие комментарии будут видны клиенту при просмотре кода страницы.
<%—- JSP комментарий; не отображается на странице JSP —-%> такие комментарии описываются в созданном сервлете и не посылаются клиенту. Для любых комментариев по коду или отладочной информации необходимо использовать именно такой тип комментариев.
<!—- HTML комментарий; отображается на странице JSP —-> такие комментарии будут видны клиенту при просмотре кода страницы.
<%—- JSP комментарий; не отображается на странице JSP —-%> такие комментарии описываются в созданном сервлете и не посылаются клиенту. Для любых комментариев по коду или отладочной информации необходимо использовать именно такой тип комментариев.
👍3
Какие существуют основные типы тегов JSP?
Выражение JSP: <%= expression %> - выражение, которое будет обработано с перенаправлением результата на вывод;
Скриплет JSP: <% code %> - код, добавляемый в метод service().
Объявление JSP: <%! code %> - код, добавляемый в тело класса сервлета вне метода service().
Директива JSP page: <%@ page att="value" %> - директивы для контейнера сервлетов с информацией о параметрах.
Директива JSP include: <%@ include file="url" %> - файл в локальной системе, подключаемый при трансляции JSP в сервлет.
Комментарий JSP: <%-- comment --%> - комментарий; игнорируется при трансляции JSP страницы в сервлет.
Выражение JSP: <%= expression %> - выражение, которое будет обработано с перенаправлением результата на вывод;
Скриплет JSP: <% code %> - код, добавляемый в метод service().
Объявление JSP: <%! code %> - код, добавляемый в тело класса сервлета вне метода service().
Директива JSP page: <%@ page att="value" %> - директивы для контейнера сервлетов с информацией о параметрах.
Директива JSP include: <%@ include file="url" %> - файл в локальной системе, подключаемый при трансляции JSP в сервлет.
Комментарий JSP: <%-- comment --%> - комментарий; игнорируется при трансляции JSP страницы в сервлет.
👍2👎2
Подборка каналов для программистов 🎯
Системное администрирование 📌
https://t.me/sysadminof Книги для админов, полезные материалы
https://t.me/i_odmin Все для системного администратора
https://t.me/i_odmin_book Библиотека Системного Администратора
https://t.me/i_odmin_chat Чат системных администраторов
Программирование, фронтенд, мобильная р-ка, книги 📌
https://t.me/game_devv GameDev: разработка игр
https://t.me/frontend_1 Подборки для frontend разработчиков
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://t.me/developer_mobila Мобильная разработка
https://t.me/BookPython Библиотека Python разработчика
https://t.me/programmist_of Книги по программированию
https://t.me/BookJava Библиотека Java разработчика
https://t.me/proglb Библиотека программиста
https://t.me/bfbook Книги для программистов
Шутки программистов 📌
https://t.me/itumor ITumor | программисты шутят
Защита, взлом, безопасность 📌
https://t.me/thehaking Канал о кибербезопасности
Книги, статьи для дизайнеров 📌
https://t.me/ux_web Статьи, книги для дизайнеров
Учим английский 📌
https://t.me/UchuEnglish Английский с нуля
Книги по математике 📌
https://t.me/Pomatematike Канал по математике
Арбитраж трафика 📌
https://t.me/partnerochkin CPA и арбитраж трафика
Крипта 📌
https://t.me/bitkoinoff Новости криптовалют 📈
Вакансии для программистов 📌
https://t.me/progjob Вакансии для программистов
Системное администрирование 📌
https://t.me/sysadminof Книги для админов, полезные материалы
https://t.me/i_odmin Все для системного администратора
https://t.me/i_odmin_book Библиотека Системного Администратора
https://t.me/i_odmin_chat Чат системных администраторов
Программирование, фронтенд, мобильная р-ка, книги 📌
https://t.me/game_devv GameDev: разработка игр
https://t.me/frontend_1 Подборки для frontend разработчиков
https://t.me/bookflow Лекции, видеоуроки, доклады с IT конференций
https://t.me/developer_mobila Мобильная разработка
https://t.me/BookPython Библиотека Python разработчика
https://t.me/programmist_of Книги по программированию
https://t.me/BookJava Библиотека Java разработчика
https://t.me/proglb Библиотека программиста
https://t.me/bfbook Книги для программистов
Шутки программистов 📌
https://t.me/itumor ITumor | программисты шутят
Защита, взлом, безопасность 📌
https://t.me/thehaking Канал о кибербезопасности
Книги, статьи для дизайнеров 📌
https://t.me/ux_web Статьи, книги для дизайнеров
Учим английский 📌
https://t.me/UchuEnglish Английский с нуля
Книги по математике 📌
https://t.me/Pomatematike Канал по математике
Арбитраж трафика 📌
https://t.me/partnerochkin CPA и арбитраж трафика
Крипта 📌
https://t.me/bitkoinoff Новости криптовалют 📈
Вакансии для программистов 📌
https://t.me/progjob Вакансии для программистов
👍4