letsCode
letsCode
  • 123
  • 4 873 580
Онлайн игра на Java #6: Emitter, Pool
Пишем онлайн игру только на Java: сервер Spring Boot + LibGDX, клиент LibGDX HTML.
Пришло время заложить основу взаимодействия пользователей: на данном этапе наш танк начнёт стрелять. Для этого мы реализуем простой emitter - объект, порождающий другие объекты по заданным правилам. У нас эмиттер будет порождать снаряды, выпускаемые танком. В библиотеке libGDX есть свой встроенный эмиттер, но для наших целей он достаточно сложен и неудобен, поэтому (и в образовательных целях) мы реализуем свой. Дополнительно мы познакомимся с пулами объектов (Pooled objects) и встроенной libGDX коллекцией Pool.
Код из видео (клиент):
github.com/drucoder/gdx-panzer/tree/DraftEmitter
Код из видео (сервер, не менялся в этом видео):
github.com/drucoder/gdx-panzers-server/tree/RenderClients
Сайт библиотеки LibGDX:
libgdx.com/
Видео про горячие клавиши IDEA:
czcams.com/video/lArM1o0SoMw/video.html
Видео про HTTP протокол:
czcams.com/video/C_QZtajkDf0/video.html
Видео про создание сервера для игры с помощью Spring Boot:
czcams.com/video/DQ3E04FBPzo/video.html
Видео про отладку в браузере:
czcams.com/video/8ZKgsdxSdTc/video.html
Мерч
letscode.vsemaykishop.ru/
Поддержать проект:
➡ Стать спонсором czcams.com/users/letscodedrujoin
➡ Яндекс.Деньги money.yandex.ru/to/41001451675086
➡ PayPal paypal.me/letscodedru
➡ Qiwi qiwi.me/letscode
➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖
➡ Второй канал: czcams.com/users/geekChatDru
➡ Twitch: www.twitch.tv/drucoder
➡ Твиттер: letsCodeDru
➡ Канал в Telegram: t.me/letsCode_dru
➡ Чат в Telegram: t.me/joinchat/FeiP9xEhqHajfqhLr4z-Nw
zhlédnutí: 12 282

Video

Онлайн игра на Java #5: вывод нескольких пользователей на экран
zhlédnutí 6KPřed 2 lety
Пишем онлайн игру только на Java: сервер Spring Boot LibGDX, клиент LibGDX HTML. На текущем этапе у нас сервер полностью рассчитывает перемещение игроков и рассылает получившийся стейт по клиентам. А значит мы можем легко вывести нескольких игроков на экран сразу в нескольких браузерах. Код из видео (клиент): github.com/drucoder/gdx-panzer/tree/RenderClients Код из видео (сервер): github.com/dr...
Онлайн игра на Java #4: расчёт позиции игрока на сервере и передача данных на клиента
zhlédnutí 6KPřed 2 lety
Java это язык и платформа не только для разработки enterprise решений, а универсальная экосистема для решения любых проблем. В том числе и создание мультимедиа контента. С помощью библиотеки LibGDX можно создавать кроссплатформенные мультимедиа приложения и игры. На последних мы и сосредоточимся в этой серии видео. С помощью Spring Framework можно создавать сложные серверные приложения, обслужи...
Онлайн игра на Java #3: передача состояния клиента на сервер
zhlédnutí 7KPřed 2 lety
Java это язык и платформа не только для разработки enterprise решений, а универсальная экосистема для решения любых проблем. В том числе и создание мультимедиа контента. С помощью библиотеки LibGDX можно создавать кроссплатформенные мультимедиа приложения и игры. На последних мы и сосредоточимся в этой серии видео. С помощью Spring Framework можно создавать сложные серверные приложения, обслужи...
Онлайн игра на Java #2: сервер на Spring
zhlédnutí 16KPřed 2 lety
Java это язык и платформа не только для разработки enterprise решений, а универсальная экосистема для решения любых проблем. В том числе и создание мультимедиа контента. С помощью библиотеки LibGDX можно создавать кроссплатформенные мультимедиа приложения и игры. На последних мы и сосредоточимся в этой серии видео. С помощью Spring Framework можно создавать сложные серверные приложения, обслужи...
Онлайн игра на Java #1: управление
zhlédnutí 33KPřed 2 lety
Java это язык и платформа не только для разработки enterprise решений, а универсальная экосистема для решения любых проблем. В том числе и создание мультимедиа контента. С помощью библиотеки LibGDX можно создавать кроссплатформенные мультимедиа приложения и игры. На последних мы и сосредоточимся в этой серии видео. Мерч letscode.vsemaykishop.ru/ В данном видео мы создадим основу нашей HTML игры...
Простой анализатор диска на JavaFX
zhlédnutí 12KPřed 2 lety
Java это не только про вэб. На джава можно просто писать мощные и функциональные приложения, способные работать в любой операционной системе. Без плясок с бубном вокруг модного нынче Electron. Для создания десктопных приложений у Java есть 3 инструмента: AWT, Swing и великолепный JavaFX, который мы краем рассмотрим в этом видео Пробуем создать утилиту для просмотра занятого пространства на диск...
Оповещения из GitHub на рабочем столе
zhlédnutí 9KPřed 2 lety
Java это не только про вэб и сервера. В стандартной библиотеке языка имеется отличный инструментарий для создания десктопных приложений. Причём не обязательно с окнами и прочими прелестями. Для нашей задачи - оповещать пользователя о новых pull requests - будет достаточно только иконки в трее и всплывающих нотификаций. Можно добавить контекстное меню к иконке в трее и получить мгновенный доступ...
Web чат на чистой Java (Vaadin)
zhlédnutí 24KPřed 2 lety
Web чат на Java фреймворке Vaadin, без единой строки HTML, JS, CSS За Java давно закрепилась слава слишком многословного языка. При этом люди часто забывают, что многословность это не черта самой платформы и экосистемы, а отдельновзятых неудачных решений в прошлом. Времена, когда на джаве нужно было написать пару десятков файлов конфигураций, давно прошли. Современные версии языка вкупе с совре...
Телеграм бот-игра на JAVA в 100 строк
zhlédnutí 25KPřed 2 lety
Пишем телеграм бота, реализующего простую игру в стиле "камень-ножницы-бумага" на чистой джава библиотека telegram api. Для пущей сложности я делаю это без БД и при этом пытаюсь выдернуть информацию о том, в каком чате происходит дело (может пригодиться для хранения какой-либо статистики) Для тех, кто попытается это запускать: НЕ РАБОТАЕТ КОРРЕКТНО, ЕСЛИ НЕ ВКЛЮЧЕН INLINE MODE У БОТА И БОТ НЕ Д...
Serverless Framework для Java + AWS
zhlédnutí 11KPřed 2 lety
Serverless Framework помогает избавиться от рутинной работы по настройке окружения для вашего кода. По простоте использования этот фреймворк ушёл не далеко от Heroku, но позволяет разворачивать ваш код написанный на любом из популярных языков в самых популярных облачных инфраструктурах: AWS, MS Azure, Google Cloud Platform и некоторых других. Работа с этим фреймворком в самой простой реализации...
Docker toolkit: ctop vs lazydocker
zhlédnutí 6KPřed 2 lety
Docker toolkit: ctop & lazydocker При работе с докером через консоль часто приходится совершать какие-то избыточные и однообразные действия, которые легко можно автоматизировать с помощью одной из этих двух утилит. При этом никто не запрещает использовать их совместно, как это делаю я =) Первая из них ctop - более наглядно показывает запущенные процессы и позволяет провалиться в шелл контейнера...
Обработка HTTP запросов. Простой HTTP сервер. #2
zhlédnutí 15KPřed 3 lety
Http server. Попробуем реализовать обработку входящих http запросов по схеме, которая используется в java se servlet модели Поддержать проект: ➡ Стать спонсором czcams.com/users/letscodedrujoin ➡ Яндекс.Деньги money.yandex.ru/to/41001451675086 ➡ PayPal paypal.me/letscodedru ➡ Qiwi qiwi.me/letscode Для более удобной обработки входящих запросов и отдачи контента клиенту мы реализуем объекты, схож...
Простой HTTP сервер. #1
zhlédnutí 27KPřed 3 lety
Http server. Чтобы использовать технологию эффективно, нужно понимать, как она работает. Чтобы понять, как она работает, можно попытаться повторить её. Поддержать проект: ➡ Стать спонсором czcams.com/users/letscodedrujoin ➡ Яндекс.Деньги money.yandex.ru/to/41001451675086 ➡ PayPal paypal.me/letscodedru ➡ Qiwi qiwi.me/letscode Реализовать Http сервер на java se не особо сложно. Возможно сделать э...
JMX - админка на минималках
zhlédnutí 16KPřed 3 lety
JMX - Java Management Extension - механизм управления приложением через специальный протокол взаимодействия. Поддержать проект: ➡ Стать спонсором czcams.com/users/letscodedrujoin ➡ Яндекс.Деньги money.yandex.ru/to/41001451675086 ➡ PayPal paypal.me/letscodedru ➡ Qiwi qiwi.me/letscode JMX - Java Management Extension. Часто случается история, когда нужно добавить в приложение какую-то настройку, к...
Apache Camel. Малоизвестный комбайн
zhlédnutí 25KPřed 4 lety
Apache Camel. Малоизвестный комбайн
WebFlux: JWT
zhlédnutí 18KPřed 4 lety
WebFlux: JWT
Markdown - напиши README за 2 минуты
zhlédnutí 49KPřed 4 lety
Markdown - напиши README за 2 минуты
🔒WebFlux. Spring Security
zhlédnutí 15KPřed 4 lety
🔒WebFlux. Spring Security
🏷 Создание JSP тэга и своей библиотеки тэгов (Java Servlet)
zhlédnutí 7KPřed 4 lety
🏷 Создание JSP тэга и своей библиотеки тэгов (Java Servlet)
HTTP протокол на пальцах
zhlédnutí 128KPřed 4 lety
HTTP протокол на пальцах
WebFlux. R2DBC с Postgres в Spring (плюс миграции с Flyway)
zhlédnutí 23KPřed 4 lety
WebFlux. R2DBC с Postgres в Spring (плюс миграции с Flyway)
WebFlux. Реактивный web с Spring Java
zhlédnutí 61KPřed 4 lety
WebFlux. Реактивный web с Spring Java
Project Reactor - реактивная Java
zhlédnutí 48KPřed 4 lety
Project Reactor - реактивная Java
Project Loom. Асинхронная многопоточность в Java 15
zhlédnutí 17KPřed 4 lety
Project Loom. Асинхронная многопоточность в Java 15
Новое в JDK 14 (синтаксис)
zhlédnutí 26KPřed 4 lety
Новое в JDK 14 (синтаксис)
Как быстро писать HTML без боли (Emmet)
zhlédnutí 9KPřed 4 lety
Как быстро писать HTML без боли (Emmet)
N+1 и дефолтные методы. Spring Boot + Webix
zhlédnutí 13KPřed 4 lety
N 1 и дефолтные методы. Spring Boot Webix
🖼️ JSTL для JSP (Java Servlet)
zhlédnutí 13KPřed 4 lety
🖼️ JSTL для JSP (Java Servlet)
Диалог для таблицы для выбора значения. Spring Boot + Webix
zhlédnutí 4KPřed 4 lety
Диалог для таблицы для выбора значения. Spring Boot Webix

Komentáře

  • @vitalyglushchenko8112

    Ужасная подача инфы. И за это еще уто-то платит?

  • @mizantropoff
    @mizantropoff Před 2 dny

    Чтобы не было багов с удаленим, и чтобы сокеты работали нормально <<<App.vue>>> <script> import { addHandler } from "../utils/ws"; import { mapState, mapMutations, mapActions } from "vuex"; export default { computed: mapState(['profile']), methods: { ...mapMutations([ 'addMessageMutation', 'updateMessageMutation', 'removeMessageMutation', 'addCommentMutation' ]), ...mapActions(['reloadPageAction']), showMessages() { this.$router.push('/') }, showProfile() { this.$router.push('/profile') } }, created() { addHandler(data => { if(data.otype === 'MESSAGE') { switch (data.etype) { case 'CREATE': { this.addMessageMutation(data.body) this.reloadPageAction() break } case 'UPDATE': this.updateMessageMutation(data.body) break case 'REMOVE': { this.removeMessageMutation(data.body) this.reloadPageAction() break } default: console.error(`Looks like the event type is unknown "${data.etype}"`) } } else if (data.otype === "COMMENT") { switch (data.etype) { case 'CREATE': this.addCommentMutation(data.body) break default: console.error(`Looks like the event type is unknown "${data.etype}"`) } } else { console.error(`looks like the object type is unknown "${data.otype}" "${data.etype}"`) } }) }, beforeMount() { if(!this.profile) { this.$router.replace('/auth') } } } </script> <template> <v-app> <v-toolbar app> <v-toolbar-title>Sarafan</v-toolbar-title> <v-btn v-if="profile" flat :disabled="$route.path === '/'" @click="showMessages">Messages</v-btn> <v-spacer></v-spacer> <v-btn flat v-if="profile" :disabled="$route.path === '/profile'" @click="showProfile">{{profile.name}}</v-btn> <v-btn icon="mdi-export" href="/logout" v-if="profile"> </v-btn> </v-toolbar> <v-main class="d-flex align-top justify-md-center"> <v-container> <router-view></router-view> </v-container> </v-main> </v-app> </template> <style> </style> <<<store.js>>> import {createStore} from 'vuex' import messagesApi from "../api/messages.js"; import commentApi from "../api/comment.js"; export const store = createStore({ state() { return { messages: messages, ...frontendData, } }, getters: { sortedMessages: state => { return (state.messages || {}).sort((a, b) => -(a.id - b.id)) } }, mutations: { addMessageMutation(state, message) { if(state.messages.length < 3) { state.messages = [ ...state.messages, message ] } else { state.messages = [ ...state.messages.slice(0, state.messages.length-1), message ] } }, updateMessageMutation(state, message) { const updateIndex = state.messages.findIndex(item => item.id === message.id) state.messages = [ ...state.messages.slice(0, updateIndex), message, ...state.messages.slice(updateIndex+1) ] }, removeMessageMutation(state, message) { const deletionIndex = state.messages.findIndex(item => item.id === message.id) if(deletionIndex > -1) { state.messages = [ ...state.messages.slice(0, deletionIndex), ...state.messages.slice(deletionIndex + 1) ] } }, addCommentMutation(state, comment) { const updateIndex = state.messages.findIndex(item => item.id === comment.message.id) const message = state.messages[updateIndex] if(message.comments !== null) { if(!message.comments.find(it => it.id === comment.id)) { state.messages = [ ...state.messages.slice(0, updateIndex), { ...message, comments: [ ...message.comments, comment ] }, ...state.messages.slice(updateIndex + 1) ] } } else { state.messages = [ ...state.messages.slice(0, updateIndex), { ...message, comments: [ comment ] }, ...state.messages.slice(updateIndex + 1) ] } }, addMessagePageMutation(state, messages) { const targetMessages = state.messages .concat(messages) .reduce((res, val) => { res[val.id] = val; return res }, {}); state.messages = Object.values(targetMessages) }, updateTotalPagesMutation(state, totalPages){ state.totalPages = totalPages }, updateCurrentPageMutation(state, currentPage){ state.currentPage = currentPage } }, actions: { async addMessageAction({commit, state}, message) { const response = await messagesApi.add(message) const index = state.messages.findIndex(item => item.id === response.data.id) if (index > -1) { commit('updateMessageMutation', response.data) } else { await this.reloadPageAction() // ***здесь js на меня не ругается почему то!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } }, async updateMessageAction({commit}, message) { const response = await messagesApi.update(message) commit('updateMessageMutation', response.data) }, async removeMessageAction({commit, state}, message) { const response = await messagesApi.remove(message.id) if(response.status === 200) { // ***await this.reloadPageAction() а здесь js на меня не ругался, хоть и выполнял действия корректно!!!!! поэтому я сделал await this.dispatch('reloadPageAction') } }, async addCommentAction({commit, state}, comment){ const response = await commentApi.add(comment) commit('addCommentMutation', response.data) }, async loadNextPageAction({commit, state}) { const response = await messagesApi.page(state.currentPage + 1) commit('addMessagePageMutation', response.data.messages) commit('updateTotalPagesMutation', response.data.totalPages) commit('updateCurrentPageMutation', Math.min(response.data.currentPage, (response.data.totalPages - 1))) }, async reloadPageAction({commit, state}) { const response = await messagesApi.page(state.currentPage) commit('addMessagePageMutation', response.data.messages) commit('updateTotalPagesMutation', response.data.totalPages) commit('updateCurrentPageMutation', Math.min(response.data.currentPage, (response.data.totalPages - 1))) }, async startPageAction({commit, state}) { const response = await messagesApi.page(0) state.messages = [] commit('addMessagePageMutation', response.data.messages) commit('updateTotalPagesMutation', response.data.totalPages) commit('updateCurrentPageMutation', Math.min(response.data.currentPage, (response.data.totalPages - 1))) }, }, })

    • @mizantropoff
      @mizantropoff Před 2 dny

      <<<LazyLoader.js>>> <script > import {mapActions} from "vuex" export default { name: 'LazyLoader', methods: mapActions(['loadNextPageAction', 'startPageAction']), mounted() { window.addEventListener('scroll', () => { if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight) { console.log('Прокрутка достигла конца страницы!') this.loadNextPageAction() } if (document.documentElement.scrollTop <= 0) { console.log('Прокрутка достигла начала списка!') this.messages = [] this.startPageAction() } }) }, beforeDestroy() { window.onscroll = null } } </script> <template> <span> </span> </template> <style scoped> </style>

  • @oniscenco
    @oniscenco Před 7 dny

    Спасибо!

  • @mizantropoff
    @mizantropoff Před 10 dny

    Этот вопрос мучил меня давно, и вот сейчас все стало на свои места. Не заметил, чтобы это корректировал автор (слдующие видео не смотрел пока :-)... Когда мы делали addCommentAction в store.js, мы написали следующее async addCommentAction({commit, state}, comment){ const response = await commentApi.add(comment) commit('addCommentMutation', comment) } Для меня с самого начала было непонятно, почему мы коммитим comment, а не ответ сервера ( в моем случае - axios - это response.data). в CommentService мы тоже делали возврат коммента в первоначальном виде public Comment create(Comment comment, User user) { comment.setAuthor(user); commentRepository.save(comment); return comment; } До сегодняшнего дня вроде работало и так, и так, НО сегодня - то ли дело в использовании userpic, то ли - в том, что в Сервисе мы поправили код : public Comment create(Comment comment, User user) { comment.setAuthor(user); Comment commentFromDb= commentRepository.save(comment); wsSender.accept(EventType.CREATE, commentFromDb); return commentFromDb; } У меня перестали добавляться комментари на страницу, хотя сервер отрабатывал корректно и коммент сохранялся в базе. В логах была ссылка на то что userpic undefinded Опять потратил часа два, пока не вспомнил про мучавший меня вопрос. Поменял addCommentAction: async addCommentAction({commit, state}, comment){ const response = await commentApi.add(comment) commit('addCommentMutation', response.data) } Все заработало. Сложная тема, много фронта, и такие досадные мелкие ошибки прям мнжатся как тараканы

  • @mizantropoff
    @mizantropoff Před 10 dny

    01:35 Как я понимаю, у нас wsSender - дженерик, поэтому в нем ООП(полиформизм ) не работает, а мы жестко указали в нем Class<Views.IdName>, и не можем подсунуть его чилдрена. Я попробовал ввести второй параметр, пока проверил - месседжи работают, с комментариями посмотрим public <T, N> BiConsumer<EventType, T> getSender(ObjectType objectType, Class<N> view)

  • @mizantropoff
    @mizantropoff Před 10 dny

    не знаю, как у АВТОРА работают мутации комментария в таком виде. Сегодня, в 2024 году, такой синтаксис не прокатывает. При дробавлении первого комментария к любому сообщению сервер отрабатывал (axios), сообщение в базу добавлялось, но не отображалось в списке, и форма не чистилась (text). После обновление страницы комментарий добавлялся, и остальные начинали тоже добавляться. Долго разбирался в чем дело, Сначала думал, что неверно отрабатывает именно axios и addCommentAction() , пробовал танцы с бубнами, но безуспешно. Думал на ошибку в <template></template> в CommentList.vue - прежде всего потому что vuetify мне не дал добавить :key="'item' + index" в тег <<comment-item>, а заставил поместить в тот же тег, где и "v-for": <template v-for="(item, index) in comments" :key="'item' + index" > <v-divider v-if="index > 0" :key="index"></v-divider> <comment-item :comment="item" ></comment-item> </template> <comment-form :message-id="messageId"></comment-form> </v-list> ( в новой версии vuetify пришлось на лету импровизировать, половины тегов уже нет, layout кстапти, исполняет совсем другую функцию, и grid строится как в бутстрапе - на рядах и колонках). Потом додумался залезть в консоль store.js:2 Uncaught (in promise) TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator)) at _iterableToArray (store.js:2:1) at _toConsumableArray (store.js:2:1) at Store.addCommentMutation (store.js:49:31)............ Promise.catch callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:211 callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:220 invoker @ runtime-dom.esm-bundler.js:691 - at Store.addCommentMutation (store.js:49:31) - именно в этом месте находилась мутация комментария, а именно - ...message.comments, Связав это с самой первой строкой лога "TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator))", и с тем, что именно первый комментарий вызывает проблему, остальные начинают добавляться после обновления страницы как по маслу, самое лучшее что я смог придумать - это сделать проверку , в результате : addCommentMutation(state, comment) { const updateIndex = state.messages.findIndex(item => item.id === comment.message.id) const message = state.messages[updateIndex] if(message.comments !== null) { state.messages = [ ...state.messages.slice(0, updateIndex), { ...message, comments: [ ...message.comments, comment ] }, ...state.messages.slice(updateIndex + 1) ] } else { state.messages = [ ...state.messages.slice(0, updateIndex), { ...message, comments: [ comment ] }, ...state.messages.slice(updateIndex + 1) ] } } Это очень некрасиво. может, я завтра еще почитаю, подумаю. как убрать эту проблему элегантнее, но пока моих знаний не хватает. если кто знает - подскажите плиз. Но в целом, если кто мучается также, то это решило мою проблему. Вообще , я считаю неправильно, что мы в store.js не создаем хранилище для комментариев, было бы интересно посмотреть на эту конструкцию вложенности, так как я с JS не очень хорошо знаком

  • @winter-lb7id
    @winter-lb7id Před 11 dny

    13:50 - byte - это 127 лет а int это 2 лярда

  • @mizantropoff
    @mizantropoff Před 14 dny

    а я не понял - мы добавили сообщениям автора, но АВТОРУ сообщения не добавили. Как это маппится?

  • @mizantropoff
    @mizantropoff Před 14 dny

    20-ая минута. После вызова profile переходит сразу на /логин, вообще скомкано там какая то шняга у автора происходит, и он так быстренько слился). На фгер переходим только из корня. Видно хук неверный

  • @mizantropoff
    @mizantropoff Před 16 dny

    опачки. почти в самом начале - а как вас пускает на страницу /auth если вы разавторизованы?) Разве для этого не нужно внести изменения в WebSecurityConfig? Просто вы сказали, что в сервер уже сегодня не полезем больше

  • @mizantropoff
    @mizantropoff Před 21 dnem

    Злой я на автора , пипец.! Я все понимаю. бесплатно, вроде как даренному коню.. да лучшеб ты по 500 рублей за каждое видео собирал со всех, но давал понимание, что и зачем мы делаем. А так - копипаст... Фи...... Вот возьмем начало этого видео.. "А тут у нас вообще какая то хрень происходит". ----- Почему? Из за чего? Непонятно. но давайте все переделывать.

  • @mizantropoff
    @mizantropoff Před 21 dnem

    Ни хрена не понял как это все работает, и почему у меня, несмотря на то что я сделал все точно по видео (кроме замены vue.recources на axios ) в App.vue в функции addHandler не находятся значения в условиях data.objectType и data.eventType, то есть программа не заходит в тело if() и switch берет по дефолту. Сообщения обновляются, удаляются, создаются, но вся муть с enums оказалась бесполезной, получается? Дизлайк

    • @antoshmakintosh5229
      @antoshmakintosh5229 Před 3 dny

      Солидарен касательно enuma и вообще непонятно как должны переменные из класса java быть видны на фронте напрямую. В моем случае objectType и eventType подтягиваюся из сторонних классов, а не тех что по гайду. Плюс все CRUD операции перестали работать из-за данных изменений. Непонятно как это работало 6 лет назад и непонятно как должно работать сейчас

    • @mizantropoff
      @mizantropoff Před 2 dny

      @@antoshmakintosh5229 1. Переобзови переменные eNum в WsEventDto так, чтобы они не совпадали с другими стандартными , например eType и oType 2. Когда будешь доставать их в App.vue в addHandlet() из data() - посмотри , как они в консоли в объекте обозначаются (Network, события в сокете). У меня почему то они выдаются не в CamelCase, а просто строчными буквами - otype, etype 3. Фронт и бэк мы связываем посредством конфигурации на бэке WebSocket с регистрацией эндпойнтов, а на фронте - в ws.js через stompClient, с теми же самыми эндпойнтами. Как то так. Андрей схалявил конечно по вебсокетам, там тема очень большая, сюда же брокеры сообщений типа Rabbits и Apache Kafka

  • @Top-BestOf
    @Top-BestOf Před 22 dny

    Хочу на курсы к вам , как можно связаться с вами ?

  • @mizantropoff
    @mizantropoff Před 23 dny

    Ну наконец то. часов пять мучился, с этой переадресацией, дал разрешение в фильтр чейн на страницу SockJS(см. коментарий к прошлому уроку). А тут надо было просто условие в main.js поставить.

  • @mizantropoff
    @mizantropoff Před 23 dny

    Спасибо за пагинацию, надеюсь в сарафане с REST тоже это будет рассмотрено. Но я очень разочарован классом Page, у которого практически нет сеттеров. Из за этого приходится шаблон засорять логикой. И непонятно, как это решить в Rest. А в коде этого урока я бы поменял кое что - после смены size параметр page я бы устанавливал на ноль, так как иначе получается не очень дружелюбный интерфейс - человек перешел на скажем 5 страницу, потом решил уменьшить количество отображаемых на каждой странице сообщений, и при определенных условиях видит пустую страницу. В запарке не все сразу догадаются, что надо снова выбирать страницу, и какую. Если бы класс Page был поинтереснее, можно было бы это сделать в Спринге, при этом оставаясь примерно в той же области, в которой ты был. в принципе пейджер можно написать ручками через запросы в базу, или через стримы, но не хочу сейчас с этим заморачиваться. Может у Спринга появился за эти годы что то попродвинутее, надо посмотреть.

  • @user-bn9wc8db6s
    @user-bn9wc8db6s Před 24 dny

    Очень интересно, но ни фига не понятно))))

  • @mizantropoff
    @mizantropoff Před 24 dny

    В общем , плохо раскрыта тема с маппингами, все эти /changeMessage, /app, /topic/activity, /gs-guide-websocket. Последний воспринимается как какая то обязательная константа, но я переворошил кучу источников - ее можно называть как хочешь, в том числе часто используется тот же мапинг, что и @MessageMapping. Но сейчас не об этом. Почему то не сказано, опять же, если я правильно понял из других источников, , что SockJS - это как раз и есть формирующий очередь сообщений, когда WebSocket по каким то причинам недоступен... И у него как раз есть какой то iFrame, встраиваемый в index Хочу понять, что это за фича - нигде не нашел толком описаие, промучился несколько часов. У меня при запуске после авторизации страница загружалась не localhost:8080, а localhost:8080/gs-guide-websocket/*** , с надписью "don't panic, it is for cross-origin magic. Проблема возникала еще перед авторизацией - , как я понял, опять же, не сумев подключиться к серверу и создать соединение из за асекьюрити при первом неавторизованном заходе на страницу, уже шла переадресация на /gs-guide-websocket. И после авторизации шел переход на запрашенную перед авторизацией страницу. Как я понял, адрес возникает имменно при создании ws.js stompClient = Stomp.over(() => new SockJS('/gs-guide-websocket')). Я пробовал его заменить маппингом как у @MessageMapping (много где в интернете так и делается), адрес менялся в адресной строке localhost:8080/changeMessage/***** , но показывался тот же , или вообще непонятно что. Последнее что я попробовал сделать - дать доступ в SecuriytFilterChain маппингу /gs-guide-websocket без авторизации . После этого непонятная переадресация прекратилась, и все заработало - уж не знаю, правильно ли нет, визуально вроде да, а вот какие в результате этого могут быть проблемы с безопасностью, или их не возникнет - не знаю. Если кто может мне как то разъяснить или кинуть ссылку где доходчиво почитать об этом , буду признателен

  • @Top-BestOf
    @Top-BestOf Před měsícem

    Здравствуйте. Как можно с вами связаться ? В лс если можно было бы.

    • @Alex-ke9nu
      @Alex-ke9nu Před 28 dny

      да уже видимо никак)

    • @letsCodeDru
      @letsCodeDru Před 26 dny

      зойчем?

    • @letsCodeDru
      @letsCodeDru Před 26 dny

      ойфсё

    • @Alex-ke9nu
      @Alex-ke9nu Před 20 dny

      @@letsCodeDru Та потому что мы рыбы и нам нужна помощь)

  • @user-wp6dl4ts4g
    @user-wp6dl4ts4g Před měsícem

    спасибо

  • @vesh95
    @vesh95 Před měsícem

    Нашел ответ

  • @vesh95
    @vesh95 Před měsícem

    Я всю жизнь жил на laravel и для меня было очень диким то, что база данных перенинициализируется при перезапуске, теряются данные. Это как продуктовых средах вообще работает когда мы выкатываем новую версию приложения? Или там просто проперти другие вгружаются?

  • @Niko-eh2rk
    @Niko-eh2rk Před měsícem

    Там нужно ведь отдельно ставить виртуальный веб сервер как на php

  • @ИванШаповалов-о2у

    Добрый день! Я новичок, в файлах всё как на видео, но при запуске приложения ошибки (Редактор VS Code) WARN 1688 --- [ restartedMain] unknown.jul.logger : ConnectException occurred while connecting to localhost:5432 2024-07-11 17:32:44.004 ERROR 1688 --- [ restartedMain] org.postgresql.Driver : Connection error: org.postgresql.util.PSQLException: ╧юфёюхфшэхэшх яю рфЁхёє localhost:5432 юЄъыюэхэю. ╧ЁютхЁ№Єх ўЄю їюёЄ ш яюЁЄ єърчрэ√ яЁртшы№эю ш ўЄю postmaster яЁшэшьрхЄ TCP/IP-яюфёюхфшэхэш . 2024-07-11 17:32:45.018 ERROR 1688 --- [ restartedMain] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization. org.postgresql.util.PSQLException: ╧юфёюхфшэхэшх яю рфЁхёє localhost:5432 юЄъыюэхэю. ╧ЁютхЁ№Єх ўЄю їюёЄ ш яюЁЄ єърчрэ√ яЁртшы№эю ш ўЄю postmaster яЁшэшьрхЄ TCP/IP-яюфёюхфшэхэш . Caused by: java.net.ConnectException: Connection refused: connect Caused by: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is org.postgresql.util.PSQLException: ╧юфёюхфшэхэшх яю рфЁхёє localhost:5432 юЄъыюэхэю. ╧ЁютхЁ№Єх ўЄю їюёЄ ш яюЁЄ єърчрэ√ яЁртшы№эю ш ўЄю postmaster яЁшэшьрхЄ TCP/IP-яюфёюхфшэхэш . Caused by: org.postgresql.util.PSQLException: ╧юфёюхфшэхэшх яю рфЁхёє localhost:5432 юЄъыюэхэю. ╧ЁютхЁ№Єх ўЄю їюёЄ ш яюЁЄ єърчрэ√ яЁртшы№эю ш ўЄю postmaster яЁшэшьрхЄ TCP/IP-яюфёюхфшэхэш . Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set Подскажите, пожалуйста, как это решить? Перелопатил весь гугл, в комментах нет, в других видосах не нашел. В других проектах находил, что у людей проблемы с postrgesql, но там решение в таких файлах, которых тут нет. Установил WSL Ubuntu. Создал БД. Запустил. Ввел команду проверки базы sweater. Попросил терминал пароль. Ввел 123. И в ответе: неверно. Как так?

  • @shaxzodamansurova1814
    @shaxzodamansurova1814 Před měsícem

    Добрый вечер, 3:55 минут стало не понятно на что нажали?

  • @user-lq7jv1do8s
    @user-lq7jv1do8s Před měsícem

    Ляяя... Скажите им там, что у олених нет рогов таких. Они только у оленей

    • @letsCodeDru
      @letsCodeDru Před 26 dny

      зависит от вида, на самом деле

  • @numberzero6833
    @numberzero6833 Před měsícem

    У кого ошибка "Error creating bean with name..." рекомендую поменять javax.persistence-api на jakarta.persistence-api

  • @user-hh5rf5jf7m
    @user-hh5rf5jf7m Před měsícem

    не работает

  • @smallworldoflynx3772
    @smallworldoflynx3772 Před 2 měsíci

    Огромное спасибо

  • @user-mr5pq1dc1t
    @user-mr5pq1dc1t Před 2 měsíci

    После слов "срать в порты" я понял что подписываюсь😅

  • @DrW1ne
    @DrW1ne Před 2 měsíci

    очень старое видео, но было интересно гдето день пытатся выявить что проблема в том что тут старый спригбут.

  • @Sulf8
    @Sulf8 Před 2 měsíci

    за grep console спасибо)

  • @b213videoz
    @b213videoz Před 2 měsíci

    Hipster stuff

  • @crazym8nd
    @crazym8nd Před 2 měsíci

    ожидал plain java а не всякие спрингбуты и ваадины)

  • @mizantropoff
    @mizantropoff Před 2 měsíci

    "Вам несложно, а мне приятно" - мне очень сложно) Андрей, я где то видел Ваши замечания о jQuery, о том, что он влечет за собой плохую архитектуру кода. то есть Вы понимаете, что такое - ПЛОХАЯ АРХИТЕКТУРА кода. Вопрос - а что такое плохая архитектура обучающего курса ? Зачем нам был нужен маппинг "/changeMessage"? зачем мы расширяем @SendTo "/activity"? Это какие то "встроенные" дефолты? Я не понял - где мы настроили маппинг, чтобы использовать абсолютные пути при импорте? Ну хотя бы пару вступительных слов про сокеты, стомпы и пр. Как это все работает - у меня понимание процентов на 30-40, не более. Лайкну конечно, и пойду топтать гугл и ютюб. чтобы понять хотя бы процентов 70-80 урока.

  • @mizantropoff
    @mizantropoff Před 2 měsíci

    3 недели спустя вернулся проверить свои нервы снова. Но сначала расскажу, что мне пришлось сделать, чтобы с учетом Vue3 приложение работало после шага, описанного в этом уроке. Во первых, чтобы резюмировать и самому лучше понять - что и зачем я делаю, ну а во-вторых, может кому пригодится. 1) Начнем с того, что установка версий npm, node, webpack и vue, описанных в этом видео, мне ничего не дала, и я установил все ПОСЛЕДНИЕ версии , актуальные на май 2024 года. Кроме vue-resource, которого уже нет в живых. Vue 3 напрочь отказался работать с vue-resource последней известной версии, нагугленный и установленный axios нельзя было применить , не будучи знатоком js (промисы, коллбэки и пр.) 2) После долгих мучений я ушел отсюда, чтобы разобраться с js. Хорошо , что у меня уже был в подписке отличный материал - 20 часов JS спокойным, медленным темпом, правда, на английском, (нс неплохим произношением, и для меня это не было проблемой). Автор этого курса , если захочет, уберет мою ссылку, но я не думаю, что это правильно, Андрей шикарный программист, но чтобы обучать других, ему было бы полезно посмотреть на образец того - как нужно снимать обучающие ролики, таких материалов очень немного в свободном доступе. Обратите внимание , там отличная МЕТОДИКА, постепенно, от простого сложного и с массой задач). Итак, у кого пробелы в JS - прошу сюда czcams.com/video/EerdGm-ehJQ/video.htmlsi=DRmq680D_0e1SEmH . Кстати, у этого китайца скоро выйдет курс по Node.js 3) После долгих поисков я нашел отличный пример Spring Rest + Vue.js приложения на Vue3. На ютюбе такого очень мало, максимум - GET запрос и ВСЕ! Вот ссылка howtodoinjava.com/spring-boot/vuejs-app-with-spring-boot/ . Ну и наконец, после всего этого я за пару часов скоректировал код Андрея под Vue3 , не меняя структуру и логику, всего лишь добавив Axios. Бэк я не менял. Итак, мой main.js: < import {createApp, h } from 'vue' import App from 'pages/App.vue' import Axios from 'axios' //import Resources from "vue-resource"; const app = createApp({ render: () => h(App), }) app.mount('#app') > В созданной директории resources/static/utils я создал apiClient.js: < import axios, { AxiosInstance } from "axios"; const API_URL = "localhost:9000"; const axiosInstance = axios.create({ baseURL: API_URL, headers: { "Content-Type": "application/json", }, }); export default axiosInstance; > В созданной директории resources/static/service я создал messageService.js: < import apiClient from "../utils/apiClient"; import Message from "../types/Message.js"; class MessageService { // get All Messages getAllMessages() { return apiClient.get("/message").then((response) => response.data); } getMessageById(id) { return apiClient.get(`/message/${id}`).then((response) => response.data); }; edit(id, msg){ return apiClient .put(`/message/${id}`, msg) .then((response) => response.data); } async delete(id) { return await apiClient .delete(`/message/${id}`) .then((response) => response.data); }; save(msg){ return apiClient.post("/message", msg).then((response) => response.data); }; } export default new MessageService(); > В MessagesList.vue я импортирую messagesService: < import messageService from "../../service/messageService"; > ... и меняю method : < deleteMessage(message) { try { messageService.delete(message.id).then(() => { this.messages.splice(this.messages.indexOf(this.message), 1) }) } catch (error) { console.error(error.toString()) } } > В MessageForm.vue я также импоритрую сервис и меняю method save(): save() { const message = {text: this.text} if(this.id) { messageService.edit(this.id, message) .then(data => { const index = getIndex(this.messages, data.id) this.messages.splice(index, 1, data) this.id= "" }) } else { messageService.save(message).then((data) => { this.messages.push(data) } ) } this.text = "" } Я пока не стал менять все кардинально, хотя там масса возможностей для оптимизации. Буду смотреть дальше. Помолясь.))) Андрей, не обижайся, ты крут, но для такого чайника, как я - слишком) PS. В методе save при сохранении НОВОГО сообщения как то странно работает data - вернее то работает, то нет. Как вариант, можно пушить message, предварительно присвоив id из полученной с бэка data ( message.id = data.id this.messages.push(message) По идее то же самое, но почему то у меня пару раз message грузился на страницу с пустым id, и только после обновления страницы id (загружались из базы).

  • @videoshlyapa
    @videoshlyapa Před 2 měsíci

    Если честно то для новичка только будет понятно как выйти а все остальное проходит быстро и хер понятно че к чему.

  • @MrJet84
    @MrJet84 Před 2 měsíci

    Не пользовался никогда. Спасибо

  • @ukrainesov21
    @ukrainesov21 Před 2 měsíci

    4:54 - не понимаю, как у тебя получилось использовать переменную типа BaseRequest в строчке 29, у меня пишет 'BaseRequest' is abstract; cannot be instantiated. Кроме того, даже если оставить как было SendMessage request, то в параметры никак не лезет переменная chatId типа long, т.к. там требуется тип String. Может что-то изменилось за пару лет в черном ящике и методы стали другими?

  • @user-xmyhoof-gd2.1-13
    @user-xmyhoof-gd2.1-13 Před 2 měsíci

    Самая имбовая часть мне кажется

  • @andreyromanov680
    @andreyromanov680 Před 2 měsíci

    Спасибо большое, все бы как ты объясняли. Лайк

  • @restartedpanda5995
    @restartedpanda5995 Před 3 měsíci

    Спасибо!!!

  • @lionelmessi6652
    @lionelmessi6652 Před 3 měsíci

    что делать,если выходит ошибка FluentToken.-, FluentToken.., FluentToken.COMMENT_LINE or FluentToken.Symbol expected, got '<' после перехода на ftl,вместо mustache

  • @evgenyhyvarinen8367
    @evgenyhyvarinen8367 Před 3 měsíci

    Очень крутая подача, за долгое время не видел столь крутых обзоров/туториалов на тек, респект от души а юмор залетает как дети в школу :)

  • @mizantropoff
    @mizantropoff Před 3 měsíci

    Из 2024 привет. Мучился с запуском, пока снова взял и не загрузил все новые версии фрейморков, в том числе node, и все поехало. Но радовался рано. Какое то время все работало, потом какая то странная ошибка стала вылетать : Cannot read properties of undefined (reading 'Vue') TypeError: Cannot read properties of undefined (reading 'Vue') at initBackend (chrome-extension://nhdogjmejiglipccpnnnanhbledajbpd/build/backend.js:2088:28) Понял, что причина в строке App.use(VueResource) (deprecated), убираю ее и все вроде нормально, но стоило раскоментировать messageApi с корректировкой как на видео - ни одна функия не работает, ну и когда опять подключаю Resourse - все равно не работает MessagesList.vue:20 Uncaught TypeError: this.$resource is not a function at Proxy.deleteMessage (MessagesList.vue:20:12) at Proxy.del (MessageRow.vue:9:14) at onClick._cache.<computed>._cache.<computed> (MessageRow.vue:21:46) at callWithErrorHandling (runtime-core.esm-bundler.js:195:1) at callWithAsyncErrorHandling (runtime-core.esm-bundler.js:202:1) at HTMLInputElement.invoker (runtime-dom.esm-bundler.js:696:31) deleteMessage @ MessagesList.vue:20 del @ MessageRow.vue:9 onClick._cache.<computed>._cache.<computed> @ MessageRow.vue:21 callWithErrorHandling @ runtime-core.esm-bundler.js:195 callWithAsyncErrorHandling @ runtime-core.esm-bundler.js:202 invoker @ runtime-dom.esm-bundler.js:696

  • @broalan
    @broalan Před 3 měsíci

    Охренеть ) Учу джаву 4 месяца уже, только только добрался до спринга. Думаю писал бы такое приложение неделю, а то и больше ) Скажи, Андрей, через сколько лет я так же смогу? 😌

    • @letsCodeDru
      @letsCodeDru Před měsícem

      Писал приложение пару-тройку дней в свободное от работы время) можешь поднять свой уровень до такого за пару лет в нормальном стартапе

  • @user-jk3cn7ck2f
    @user-jk3cn7ck2f Před 3 měsíci

    Хороший понятный видос. качественный.

  • @mizantropoff
    @mizantropoff Před 3 měsíci

    Нууууууууу, ребята, это твердый дизлайк. На лету мимоходом говорится про целый пласт сложнейших вещей, которые совершенно не относятся к Java и Spring Boot. Вы меня простите, но если уже делать курс на такой базе, нужно как то включать подачу тех знаний и логики, которые относятся ко всем упомянутым технологиям. Это не просто html, css, js, эти техники по значительности требуют не менее пристального изучения, чем Spring, а по объему - даже БОЛЬШЕГО. Смысла не понимаю так давать материал. С другой стороны, если кто уже владеет этими технологиями в совершенстве - неужели его устроит подача Спринга на таком уровне?! А кто не владеет - пойдет их изучать и вернется сюда через год, забыв уже все на свете. Конечно, можно откатиться на ранние версии и тупо повторить все за автором, но это не обучение, а ..... И все для того чтобы красоту навести? Зачем? Лучше закончить со спрингом, путь итог будет деревянным, но понятным и разобранным до основания. Путь мы бы видели на странице json ы сплошные. И отдельно разбирать уже украшения. Или отдельно пилить подробные видео про все упомянутые технологии и рекомендовать изучать их ДО данного курса сразу же, в описании. А тут все по верхам, я считаю. Никакого глубокого понимания. Все обо всем и ни о чем. Жаль. Придется уходить наверное, не нравится мне, как попугаю просто тупо копировать и вставлять.

  • @user-xb2dv2ew6j
    @user-xb2dv2ew6j Před 3 měsíci

    Насколько WebFlux актуален сегодня при том что завезли виртуальные потоки?

  • @mizantropoff
    @mizantropoff Před 3 měsíci

    Простите, я не понимаю, как это работает. А именно - мы просто указываем маппинг обработанный в контроллерею , как ресурс, и Vue компоненты подхватывают и нашу базу, и методы, которые даже называются по разному во Vue и в контроллере. Ну ладно , messages подхватываются, но методы? Мы ведь даже не указываем get, post, put, delete. И конечно, я не смог на лету все это адаптировать к Vue3, использую пока Vue 2. Потом буду думать как мигрировать. Пока не нашел нормального описания именно варианта с CDN во Vue3, большая часть материала касается приложений, у которых и серверная и клиентская часть на Vue. Если кто полезные ссылки даст - буду рад. Мне нравится этот вариант, так как для демонстрации два сервера городить не вижу смысла, а тут , как я понимаю, все работает на одном сервере - и фронт и бэк.

  • @anjelomanoranjan
    @anjelomanoranjan Před 3 měsíci

    Спасибо) бомбезное видео. А у тебя есть видео где ты при написании сервиса, программы, приложения... работаешь с HashMap?