• Как делать GUI в Java?

    @ruslanys
    Согласен со всеми отписавшимися ребятами здесь. В качестве примера возьмите тот же Android: там тоже можно на XML верстку собирать, либо программно. По-умолчанию делают на XML, на Java только в необходимых случаях.
    Я думаю, такой же подход очень даже применим к десктопным приложениям на JavaFX.

    Ну и повторюсь: гораздо удобнее разделять логику и представление.
    Ответ написан
    Комментировать
  • Какой шаблонизатор более востребован на рынке Spring?

    @ruslanys
    Смешной вопрос. Шаблонизатор - лишь инструмент представления. Не бойтесь учить новое.

    Что касается выбора - Thymeleaf неплох, но есть нюансы.
    Например, Thymeleaf дает "рабочую" верстку, над которой дизайнер и программист могут работать параллельно, но это, пожалуй, единственный плюс.
    Из минусов, которые лично я отметил:
    1. Если на клиенте используется, например, Angular.JS, то в атрибутах тегов у вас будет несусветная каша, условно:
    <td th:text="${user.name}" ng-show="shouldShowUsername()">Username</td>

    В реальном проекте, где количество атрибутов нужно умножить на X - это оказалось трудно поддерживаемым .
    2. Учитывая тот факт, что Thymeleaf директиво-ориентированный шаблонизатор, его scope - это тег. К сожалению, не все теги одинаково хороши. А иногда их вовсе нет!
    Скажем, вы хотите отправлять plain-text сообщения по e-mail. Вам не нужна верстка и вы генерируете вовсе не HTML. В таком случае, с Thymeleaf будут проблемы, т.к. исключительно теги определяют его SCOPE. По-моему как-то костыльно эту проблему можно решить типа th:removetag, но тоже не всегда. В одном из случаев мы пытались генерировать блок стилей в head страницы и у Thymeleaf, насколько я помню, были проблемы с этим (возможно, починили).

    В любом случае, мы очень любили Thymeleaf и были его ярыми последователями, пока не столкнулись с концептуальными ограничениями завязки на директивы. Весь проект переписали на Freemarker (благо не много было генерации HTML на бекенде) - счастливы.
    Ответ написан
    Комментировать
  • Как заставить бота писать в группу?

    @ruslanys
    А в чем проблема? Для бота групповой чат аналогичен чату 1:1.
    Ответ написан
    Комментировать
  • Ошибка с потоками?

    @ruslanys
    Честно говоря, написана дичь какая-то. Я по коду даже не до конца разобрался в постановке задаче. Но проблема в коде очевидна - неправильная работа с сокетами.

    Я переписал пример, вот что у меня получилось:
    Сервер
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class ChatServer {
    
        public static void main(String[] args) throws IOException {
            try (ServerSocket serverSocket = new ServerSocket(5000)) {
                while (true) {
                    Socket clientSocket = serverSocket.accept();
                    System.out.println("New connection: " + clientSocket.getRemoteSocketAddress().toString());
    
                    ClientThread clientThread = new ClientThread(clientSocket);
                    clientThread.start();
                }
            }
        }
    
    
        private static class ClientThread extends Thread {
    
            private final Socket socket;
    
            private ClientThread(Socket socket) {
                this.socket = socket;
            }
    
            @Override
            public void run() {
                try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                     PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
    
                    String request;
                    while ((request = in.readLine()) != null) {
                        System.out.println("New message from " + socket.getRemoteSocketAddress().toString() + ": " + request);
    
                        StringBuilder sb = new StringBuilder(request);
                        String response = sb.reverse().toString();
                        out.println(response);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("Closing connection: " + socket.getRemoteSocketAddress().toString());
    
                    try {
                        socket.close();
                    } catch (IOException ignored) {}
                }
            }
        }
    
    }
    Клиент
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    
    public class ChatClient implements Runnable, ActionListener, OnMessageListener {
    
        private JTextArea messageArea;
        private JTextField messageField;
    
        private WorkerThread workerThread;
    
        public static void main(String[] args) {
            ChatClient client = new ChatClient();
            client.run();
        }
    
        private ChatClient() {
            initGui();
            initListeners();
        }
    
        private void initGui() {
            JFrame frame = new JFrame();
            JButton sendButton = new JButton("Send");
            sendButton.addActionListener(this);
            messageArea = new JTextArea(10, 10);
            messageField = new JTextField(20);
    
            JPanel mainPanel = new JPanel();
            mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
            mainPanel.add(messageArea);
            mainPanel.add(messageField);
            mainPanel.add(sendButton);
    
    
            frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    
            frame.setSize(500, 500);
            frame.setVisible(true);
        }
    
        private void initListeners() {
            Observer.getInstance().addListener(this);
        }
    
        @Override
        public void run() {
            try {
                workerThread = new WorkerThread("127.0.0.1", 5000);
                workerThread.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            if (workerThread == null) {
                return;
            }
    
            String request = messageField.getText();
            messageField.setText("");
    
            workerThread.sendMessage(request);
        }
    
        @Override
        public void onMessage(String message) {
            messageArea.append(message + System.lineSeparator());
        }
    
    
        private static class WorkerThread extends Thread {
    
            private final Socket socket;
            private final PrintWriter out;
    
            private WorkerThread(String host, int port) throws IOException {
                this.socket = new Socket(host, port);
                this.out = new PrintWriter(socket.getOutputStream(), true);
    
                System.out.println("Connection established...");
            }
    
            @Override
            public void run() {
                try (BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
                    String message;
                    while ((message = in.readLine()) != null) {
                        System.out.println("New message: " + message);
                        Observer.getInstance().fireEvent(message);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println("Connection closing...");
                    try {
                        out.close();
                        socket.close();
                    } catch (Exception ignored) {}
                }
            }
    
            public synchronized void sendMessage(String message) {
                out.println(message);
            }
        }
    }
    public class Observer {
    
        private static final Observer INSTANCE = new Observer();
    
        public static Observer getInstance() {
            return INSTANCE;
        }
    
    
        private final Set<OnMessageListener> listeners;
    
        private Observer() {
            listeners = Collections.synchronizedSet(new HashSet<>());
        }
    
        public void addListener(OnMessageListener listener) {
            this.listeners.add(listener);
        }
    
        synchronized void fireEvent(String message) {
            for (OnMessageListener listener : listeners) {
                listener.onMessage(message);
            }
        }
    
    }
    public interface OnMessageListener {
        void onMessage(String message);
    }


    Как-то так.
    Ответ написан
  • Как разбить MP4 файл на несколько видео в Java?

    @ruslanys
    Ну просто из Java вызывай консольную утилиту, на которую указал longclaps.
    Ответ написан
    Комментировать
  • Что можно сказать про JMS в JavaEE и Spring?

    @ruslanys
    JMS - это Java API, для работы с очередями сообщений, реализуя, так скажем, "Event-driven" архитектуру.
    AMQP, ActiveMQ - это протоколы. Многие путают, но разница в том, что JMS - все-таки, часть спецификации Java API, и описывает API для взаимодействия с очередями. В то время как остальные описывают протокол сообщений между узлами.
    Ответ написан
    Комментировать
  • Что делать процессами которые остались от тредов Java?

    @ruslanys
    А почему бы Вам не сделать запуск тредов внутри приложения? Важно понимать разницу между процессом и потоком:

    В реальной жизни самое главное отличие между ними с точки зрения производительности заключается в том, что поток выполнения использует одну и ту же область памяти, а процессы получают собственные области. Поэтому отдельные процессы требуют гораздо больше памяти.


    Мало того, запуск JVM каждые 40 секунд также имеет свои издержки.
    Правильно было бы запускать приложение 1 раз, а уж оно каждые 40 секунд запускает ваши `Advert` потоки.

    ИМХО
    Ответ написан
  • Вопрос про массив из byte?

    @ruslanys
    int - это 4 байта, а не 2.

    Но можете складывать таким образом:
    int i = 0;
    
    byte b1 = 3; // 11
    byte b2 = 5; // 101
    
    i = i | b1;
    i = i << 8;
    i = i | b2;
    
    System.out.println(i);


    Только учтите, что в Java нет unsigned типов, поэтому `byte b = 235` не может быть).
    Ответ написан
    Комментировать
  • Как правильно использовать HashMap?

    @ruslanys
    Для того, чтобы использовать свой тип в качестве ключа в HashMap необходимо переопределить методы equals и hashCode.

    Также рекомендуется значения, участвующие в расчете hashCode сделать константами (final).
    Ответ написан
  • Как создать SPA приложение Spring mvc + gwt?

    @ruslanys
    Каркас - скелет?

    Скорее Spring IoC (core/context).
    Используется в связке с GWT для предоставления DI, соответствия требованиям SOLID, подключения к БД и пр.

    Может быть речь идет о том, что server-side должен предоставлять API, написанный на Spring MVC, и клиентское SPA на GWT, обращающееся к API через AJAX запросы.

    spring4gwt мы используем в одном из проектов, работает безупречно. Не вижу проблем в том, что этот 1 класс не разбит по библиотекам разных версий.

    А вообще в 2017 я бы не стал делать выбор в пользу GWT.
    Ответ написан
    Комментировать
  • Как правильно организовать работу с сокетами?

    @ruslanys
    ServerSocket + ThreadPool - классическая модель обработки соединений. Попробуйте Netty. Его очень просто подружить с тем же Spring. Netty использует Java NIO, но Вам не придется руками разрешать вопросы с каналами и буферами. Java NIO использует неблокируемую (асинхронную) модель обработки соединений и сообщений, что качественно выведет Ваше приложение на другой уровень.
    Ответ написан
    Комментировать
  • Как возвращать HTML файла в качестве ответа сервера?

    @ruslanys
    Если я правильно понял, задача заключается в том, чтобы клиенту (браузеру) предлагалось скачать файл. Я прав?

    Для такого случая самое простое решение - добавить ключевое слово download к тэгу a:
    <a href="/file/123.html" download>Download</a>

    Но лучший вариант - это возвращать в ответе от сервера заголовок Content-Disposition:
    Content-Disposition: attachment; filename=123.html
    Ответ написан
    Комментировать
  • Какие вы используете JAVA библиотеки для работы с excel файлами?

    @ruslanys
    Попробуй jXLS (jxls.sourceforge.net/).

    Он построен на базе Apache POI, но ты можешь создавать XLS шаблоны, объявлять поведение заполнения нужных ячеек. Потом скармливаешь данные и шаблон в jXLS и получаешь то, что нужно.
    Ответ написан
    Комментировать
  • Как вставить данные в таблицу в Hibernate?

    @ruslanys
    Hibernate подразумевает, что работать Вы будете с объектами, а не с SQL запросами. В конце концов используйте JDBC, если хотите оставить вариант с SQL.

    В Hibernate задача будет решаться примерно так (хочу отметить, что по спецификации каждый объект должен иметь уникальный ключ - ID):
    @Entity
    @Table(name = "students")
    @Data
    public class Student extends BaseModel {
    
        @Id
        private Long id;
    
        @Column
        private Long studentId;
    
        @Column
        private String firstname;
    
        @Column
        private String lastname;
    
    }


    Сохранение:
    ...
    public Student add(Student student) {
        Session session = sessionFactory.getCurrentSession();
        student.setId(null); // добавить новую запись, а не изменить существующую
        session.save(student);
    
        return student;
    }
    ...
    Ответ написан
  • С какой книги начать изучать JAVA?

    @ruslanys
    Не книга, конечно, но очень хороший сайт: javarush.ru
    Ответ написан
    Комментировать
  • Репозиторий Spring Data Jpa блокирует поток при любом запросе?

    @ruslanys
    Используйте лучше Spring Boot - прекрасная тенденция.
    Ответ написан
    2 комментария
  • Как установить JAVA_HOME в debian?

    @ruslanys
    Я обычно указываю путь до JAVA_HOME в /etc/environment.
    Ответ написан
    Комментировать
  • Как написать серверную часть для Android клиента на Java?

    @ruslanys
    Вот что я тебе скажу: веб в качестве серверной стороны - это самых популярный вариант разработки серверного слоя. Вообще, для всех языков и технологий. Но! Насколько я тебя понимаю, ты хочешь сделать взаимодействие на сокетах! Идея не плохая, я когда-то тоже подобным болел. В таком случае, я хочу тебе посоветовать почитать в чем разница между Java IO и Java NIO. В качестве примера: Java NIO может обрабатывать в 4 раза больше подключений (проверено на собственном опыте). Есть одна проблема: на Java NIO писать серверную сторону гораздо сложнее! Но! Для этого есть 2 потрясающих фреймворка: Apache Mina/Netty. Mina плохо себя показал на Android, а вот Netty рекомендую! Если с фреймворком не разберешься, кинь сообщением ЛС, отправлю тебе пример проекта.
    Ответ написан