• Как оценить системные требования для серверной части приложения?

    @bobzer
    Java EE Developer
    Уже год мой софт работает в облаке. Взял Windows (да, я люблю графические интерфейсы и не знаю Linux) с 1ГБ памяти и динамически выделяемым процессором (от 800 до 2300 МГц). На одном виртуальном сервере стоит и СУБД MySQL и Tomcat с моим приложением. Большую часть времени сервер потребляет минимальную планку процессора (800 МГц), потребление памяти 98% времени не боле 800 МБ, обычно 600-700 МБ. Была нагрузка до 20 запросов в секунду, мощности хватило на то, чтобы работать стабильно, без подвисаний (и это все под Windows!). Сделайте так же, один-в-один, одного сервера может хватить надолго. Современные облака выделяют дополнительные ресурсы автоматически, не превышая указанного вами предела (предел нужен чтобы не разориться если вдруг что...), так что неожиданной нагрузки можно не бояться.
    Ответ написан
    Комментировать
  • Какой framework выбрать для написания Web Service?

    @bobzer
    Java EE Developer
    Обычно, веб-сервисы работают под управлением контейнера - сервера приложений. Практически все современные сервера приложений имеют из коробки поддержку веб-сервисов. В соответствии со спецификациями Java EE, при разработке веб-сервиса вы просто указываете определенные аннотации в своем Java-классе (@WebService, @WebMethod), что сообщить серверу контейнеру о том, что этот класс он должен развернуть как веб-сервис. При разработке вы не обязаны знать какой именно фреймворк будет ответственен за то, чтобы опубликовать ваш веб-сервис в контейнере (сервере приложений). Если у вас еще нет серверного приложения, то его надо создать, перед этим выбрав сервер приложений (например, TomEE, WildFly aka JBoss). Создаёте приложение (.war), которое содержит в себе класс с аннотациями веб-сервиса и, например, JBoss сам найдет этот класс и развернет веб-сервис. В качестве фреймворка веб-сервисов, сервера приложений обычно используют CXF.

    По поводу того, какой SOAP старый и плохой - это сугубо личные мнения, советую не заморачиваться, пока сами не разберетесь. Да, XML тяжелый в части расхода ресурсов железа (которое стоит дешевле труда программиста), но лично я пока не видел ни одного стандарта, который бы был так удобен при интеграции самых разнообразных информационных систем. Например, как-то пытался найти язык описания REST-сервисов, и не нашел ничего. Вот разверну я сложный REST-сервис, а потом каждому разработчику на пальцах объяснять что и откуда? А когда объясню, ему придется сесть и вручную все рисовать. REST/JSON хороши только пока вы используете их в пределах одной Системы, например, для обмена данными между клиентом и сервером. Но когда вы интегрируете несколько абсолютно разных платформ, которые к тому же разрабатывают программисты с разным уровнем профессионализма, тот стоит очень хорошо подумать...
    Ответ написан
    4 комментария
  • Какой web framework для java выбрать?

    @bobzer
    Java EE Developer
    Не ответ, а комментарий ко всем ответам - достали уже с этим Spring. По сути, Spring - это контейнер, в котором разворачивается приложение, и которому Spring предоставляет различные сервисы, в основном: управление транзакциями, развертывание веб-сервисов, Depedency Injection. При этом, сам Spring обычно работает под управлением внешнего контейнера - сервера приложений. Проблема в том, что современные сервера приложений (бесплатные - JBoss/WildFly, TomEE) предоставляют ТЕ ЖЕ САМЫЕ сервисы из коробки. Получается контейнер в контейнере, и попробуй разберись из какого из них ты получаешь тот или иной сервис. Во многих случаях ресурсы просто дублируются - те же бины JBoss находит в jar-ах сам и без каких-либо указаний сразу их деплоит. Плюс вы в Spring-е их же конфигурируете и деплоите второй раз. А если вы в аннотациях указали @Singleton, как себя поведет ваша Система?

    Spring - отличная штука, была, лет 5 назад, когда была спецификация J2EE. Сейчас все самое нужное, из того что он давал, уже есть в спецификациях JEE 6, и в серверах приложений, реализующих эти спецификации. Опытные люди говорят так: если у вас есть проект на Spring, работайте и дальше на Spring, если вы создаете проект с нуля - берите JEE 6, про Spring забудьте. Да, у Spring все еще появляются уникальные обертки над различными сервисами, за счет которых они еще пытаются доказать свою востребованность. Но, во-первых, то же, что дает Spring, практически всегда можно сделать другими способами. Во-вторых, в большинстве реальных проектов используется 3-5% сервисов Spring-а, и как я уже сказал, эти сервисы уже есть в серверах приложений.

    Если что, погуглите "Spring vs JEE 6" прежде чем холиварить...
    Ответ написан
    2 комментария
  • Лучшая практика DAO в Hibernate: почему всегда нужно писать как можно меньше запросов(query)?

    @bobzer
    Java EE Developer
    Столько всего можно сказать, что аж пальцы разбегаются.

    Во-первых, классика - не занимайтесь преждевременной оптимизацией. Вы ведь сделали замеры расхода ресурсов, перед тем как оптимизировать? Этот запрос хотя бы пару раз в секунду выполняется, не реже, нет? Вы ведь точно уверены, что именно это место "жрет" не менее 20% времени от общего времени обработки процесса? И вы ведь в курсе о том, что любые программные кеши - ничто в сравнении с тем, как умеет кешировать любая "приличная" СУБД?

    Во-вторых - построение HQL-запросов. Насколько мне известно, для One-To-Many нет разницы между сущностью и её ID. Вы замапили сущность, а не её ID, получив возможность доступа к объекту целиком при вычитывании из БД. Но это вам не мешает использовать просто ID при указании критериев выборки. Вам вовсе не нужно читать сущность из БД прежде чем передать ее в HQL-запрос, т.к. Hibernate-у не нужна сущность целиком, он всё равно "возьмет" лишь ID. Т.е., у вас есть ID, но в маппинге указана сущность - в HQL можно передать эмуляцию - создать new Proveder(), указать ему ID и передать в HQL объект Proveder без чтения его из БД.
    Ответ написан
    3 комментария
  • Hibernate many to many с дополнительными атрибутами?

    @bobzer
    Java EE Developer
    Думаю, что вам нужен one-to-many на самом деле, т.е. в сущности User хранится список сущностей Achievement. При этом сущность Achievement имеет поля, описывающие конкретное достижение конкретного пользователя (дата получения и другие параметры), а также ссылку на тип достижения (следующий уровень one-to-many). По поводу Set/List - как объявите в классе так и будет, но для сортировки требуется указать order-by в .hbm.xml.

    Примерно так:
    public class User {
        private List<Achievement> achievements;
        get...
        set...
    }
    
    public class Achievement {
        private User user;
        private Date createDate;
        private DicAchievementType type;//справочник типов достижений
        get...
        set...
    }


    User.hbm.xml
    <bag name="achievements" inverse="true" cascade="all,delete-orphan" order-by="CREATE_DATE">
        <key column="user_id"/>
        <one-to-many class="Achievement"/>
    </bag>


    Achievement.hbm.xml
    <many-to-one name="user" column="user_id" class="User"/>
    <many-to-one name="type" column="achievement_type_id" class="DicAchievementType"/>
    Ответ написан
    1 комментарий
  • Как составить Full-Text HQL-запрос, содержащий SQL contains?

    @bobzer
    Java EE Developer
    Hibernate прекрасно работает с SQL, сделайте так:
    Query query = session.createSQLQuery("select * from test_docs where Contains(xxtext,'Boaz')")
    .addEntity(TestDoc.class);

    Если работаете через EntityManager, то там есть createNativeQuery()
    Ответ написан
  • Как настроить SSL для связки nginx (front-end) с tomcat 7 (back-end)?

    @bobzer
    Java EE Developer
    Я правильно понимаю, что в топологии ваших серверов Nginx "смотрит в мир", а доступ к Tomcat-у(-ам) извне не предполагается? Т.е., стандартный подход: снаружи балансировщик, внутри сервера приложений на которые балансировщик перенаправляет запросы? В таких случаях Tomcat-ы должны быть закрыты полностью от любого доступа извне на уровне сети/прокси, т.е. они находятся в так называемой "демилитаризованной зоне" и не требуют защиты на уровне протокола обмена данными (HTTPS). Более того, обычно балансировщик при приеме соединения по HTTPS "раздевает" его, расшифровывает, и не имеет средств для повторного шифрования, да это и не нужно. Обычно, балансировщик, получивший данные по HTTPS-соединению передает их дальше на бакенды по протоколу AJP, который предназначен как раз для общения балансировщика с бакендами, т.к. по сравнению с обычным HTTP имеет средства для пинга доступности узлов на бакенде. Таким образом, в вашей конфигурации Nginx должны быть что-то вроде:
    proxy_pass        http://127.0.0.1:8009; #8009 - default AJP port on Tomcat
    Ответ написан
    Комментировать
  • Как настроить правильную кодировку в связке MySQL + Tomcat?

    @bobzer
    Java EE Developer
    Попытайтесь указать кодировку в url соединения в context.xml следующим образом:
    url="jdbc:mysql://ip:3306/name?useUnicode=true&amp;characterEncoding=UTF-8"
    Ответ написан
  • Как правильно работать с датами в клиент-сервеном приложении?

    @bobzer
    Java EE Developer
    А может и не надо ничего делать вообще? Стандартные типы дат в Java (java.util.Date/Calendar) имеют встроенную обработку временных зон и даже учитывают перевод на зимнее/летнее время. Достаточно в JVM клиентов и сервера в рантайме указать (TimeZone.setDefault) правильную временную зону (обычно она устанавливается автоматически), все остальное Java сделает сама. Вы уверены, что не пытаетесь решить несуществующую проблему?
    Ответ написан
  • Как разместить сервер в интернете?

    @bobzer
    Java EE Developer
    Если у вас на самом деле не "сервер для чата", а Java-приложение, которое разворачивается под управлением существующего сервера приложений, то можете почитать тут: Как развернуть Tomcat на сервере?
    Ответ написан
    Комментировать
  • Поддерживает ли Tomcat java 8? Если нет, то какие контейнеры поддерживают?

    @bobzer
    Java EE Developer
    Насколько я помню, для Java 8 рекомендуется Tomcat 8. Запускал Tomcat 8 под Java 8, разворачивал достаточно комплексное, сложное приложение - работало. Не стал использовать, т.к. первая же протестированная фича Java 8 не заработала в JSF (вина библиотек JSF, а не самого Tomcat). Ну и плюс мой хостинг пока предоставляет только Tomcat 7. Так что если есть возможность в продакшене развернуть Java 8 и Tomcat 8, то почему бы и нет?

    Насчет контейнеров. Tomcat 8 - отличный сервер приложений, на котором можно развернуть практически любое приложение. Но делать это придется ценой самостоятельной интеграции различных фреймворков в свое приложение. Например, чтобы равзернуть веб-сервисы, потребуется разобраться как это сделать, возможно даже развернуть "движок" веб-сервисов. А вот в JBoss (или WildFly) уже развернуто множество фреймворков, и для того, чтобы развернуть веб-сервис, достаточно добавить в свои исходники нужные аннотации, а "движок" веб-сервисов там уже есть.

    В более простом и легковесном Tomcat требуется больше усилий для того, чтобы подключать фреймворки к своему приложению, т.к. кроме непосредственно подключения к приложению, еще требуется развертывание самих фреймворков (обычно это не так уж и сложно, и в Гугле все есть).

    Более "тяжелый" JBoss сделал часть работы за вас, но у этой работы есть своя цена. Во-первых, стек технологий и их версий жестко завязан на конкретную версию JBoss-а: если потребуется развернуть более свежую версию конкретного фреймворка или даже API библиотеки, в большинстве случаев это просто невозможно. Или если ваше приложение использует какое-то-API-v2.jar, а в JBoss-е уже активно используется какое-то-API-v1.jar, то нередко потребуются танцы с бубнами для решения проблем совместимости. Плюс настройки: нередко вместо стандартных настроек фреймворка придется разбираться с их JBoss-овским вариантом.

    Таким образом, для сложных приложений JBoss может дать более быстрый старт, в сравнении с Tomcat-ом. Но впоследствии, когда после старта придет время специфических настроек и требований, JBoss может завести в тупик или, как минимум, заставить серьезно "забуксовать на ровном месте"

    Я, пожалуй, посоветую все же Tomcat
    Ответ написан
    3 комментария
  • Unable to load tag handler class в чем ошибка?

    @bobzer
    Java EE Developer
    Судя по тексту ошибки, сам класс HelloWorld забыли "положить" на сервер, либо он оказался в контексте, недоступном загрузчику классов, который загружает index.jsp. Т.е., либо класса вообще нет на сервере, либо он лежит там, откуда сервер его загрузить не догадался. В HelloWorld-ах классы обычно лежат в папке HelloWorld.war/WEB-INF/classes

    А вообще, JSP - технология давно устаревшая, ее современный вариант - JSF. Начиная со второй версии спецификации создание собственных компонентов (аналог тегов JSP) стало простой задачей...
    Ответ написан
  • Hibernate игнорирует настройки и работает с другой базой. В чём может быть проблема?

    @bobzer
    Java EE Developer
    Независимо от того, какая выбрана система сборки, все они компилируют классы в какую-либо отдельную папку, и обычно в нее же сохраняют дополнительные ресурсы, такие, как hibernate.cfg.xml. Самый простой путь - сделать поиск по файловой системе файла hibernate.cfg.xml и посмотреть его содержимое везде, где он найден. Думаю, что найдется версия с URL-ом "/test"...
    Ответ написан
    Комментировать
  • Как заблокировать таблицу в SQL?

    @bobzer
    Java EE Developer
    когда первая копия create_task считала данные,создала поток но еще не изменила статус записи, а вторая копия уже считала данные
    Лично я уже много лет в таких случаях использую конструкцию SELECT ... FOR UPDATE - т.е. считывание с одновременной блокировкой, которое осуществляется в пределах открытой транзакции. Первый поток считывает запись и блокирует ее на уровне СУБД. При этом любой другой поток(и), попытавшийся считать запись также с модификатором FOR UPDATE будет ожидать своей очереди до тех пор, пока первый не завершит транзакцию (изменив при этом статус обработки). Только после этого следующий поток продолжит исполнение, и завершит операцию чтения. При этом надо не забыть проверить статус - если после захвата блокировки мы видим, что статус "обработано", то текущий поток "опоздал" и должен завершиться без дальнейшей обработки записи.
    Ответ написан
    Комментировать
  • SQL запрос из 3 таблиц по 2-м связующим - возможно ли такое?

    @bobzer
    Java EE Developer
    Добавлю немного магии к ответу AMar4enko:

    SELECT books.title,
    GROUP_CONCAT(distinct CONCAT(authors.surname, ' ', authors.name) SEPARATOR ', ') as autors,
    GROUP_CONCAT(distinct topics.title ORDER BY topics.title ASC SEPARATOR ', ') as titles
    FROM books
    LEFT JOIN book_author ON book_author.book_id = books.id
    LEFT JOIN book_topic ON book_topic.book_id = books.id
    LEFT JOIN authors ON book_author.author_id = authors.id
    LEFT JOIN topics ON book_topic.topic_id = topics.id
    group by books.id


    Этот SQL-запрос решает проблему дублирования книг при нескольких авторах и нескольких рубриках
    Ответ написан
    1 комментарий
  • Можно ли описать связь один ко многим c возможностью изменять поле с внешним ключом?

    @bobzer
    Java EE Developer
    Несмотря на то, что на объектном уровне Hibernate требует объект Group, на самом деле ему для корректного сохранения в БД нужен лишь group_id. Можно создать пустой/фейковый (не считанный из БД) экземпляр Group и указать ему нужный вам group_id. После этого его можно смело передавать в user.setGroup(group); Если количество групп в Системе ограничено и все они известны заранее (подтекст вопроса это подразумевает), то можно хранить как константы экземпляры Group с заполненным полем ID.
    Ответ написан
    5 комментариев
  • JPA и Hibernate или Hibernate?

    @bobzer
    Java EE Developer
    JPA - это интерфейс языка JAVA, не имеющий реализации в самом языке. Если просто добавить аннотации JPA в свои классы, то не произойдет ровным счетом ничего. Для того, чтобы аннотации начали "работать", следует развернуть и настроить в проекте фреймворк, который "найдет" все классы с JPA-аннотациями и "состыкует" их с сущностями СУБД. Этим фреймворком у вас является Hibernate.

    По поводу "работать с hibernate можно и через JPA или отдельно от него" - тут в основном дело вкуса. У вас есть два варианта сообщить Hibernate какие классы "замапить" на таблицы БД:
    1. Добавить в классы аннотации JPA
    2. Создать XML-файлы, в которых будет описано сопоставление классов объектам БД.

    По доступной функциональности оба метода равны между собой, при этом аннотации JPA более современны. Я бы рекомендовал JPA, т.к. при открытии класса сразу будет видно, что он "замаплен", а в случае использования XML, "замапленный" класс визуально неотличим от других классов.
    Ответ написан
    1 комментарий
  • Как реализовать загрузку файла с ftp сервера на java?

    @bobzer
    Java EE Developer
    Скорее всего, операция загрузки завершилась ошибкой, а вы это не проверили. При возникновении ошибок, FTPClient не выбрасывает исключение, а просто сохраняет код ошибки, а вызванный метод возвращает false. При этом исполнение кода продолжается и доходит до корректного закрытия файла, из-за чего вы получаете файл размером 0 байт. Если retrieveFile вернул false, то смотрите ftpClient.getReplyString(), вместо того, чтобы корректно закрывать файл. Например, можно сделать так:
    if(!isDownloaded) {
        throw new Exception(ftpClient.getReplyString());
    }

    При этом конечно не забывать об освобождении ресурсов в блоке finally пока что не существующего в методе блока try...
    Ответ написан
    1 комментарий
  • Миграция с JBoss 6 на JBoss 7 - почему из WAR не виден EJB?

    @bobzer
    Java EE Developer
    проект, состоящий из одного EJB и одного WAR
    В JBoss (и в терминологии серверов приложений JEE в целом) нет понятия "проект". Правильно ли я понимаю, что под "проектом" подразумевается Enterprise Archive (EAR)? Если у вас нет EAR, то я не вижу способов считать чем-то единым отдельный WAR и отдельный EJB-модуль.

    Если есть EAR, попробуйте в папку META-INF добавить файл с именем jboss-deployment-structure.xml со следующим содержанием:
    <?xml version="1.0" encoding="UTF-8"?>
    <jboss-deployment-structure>
        <ear-subdeployments-isolated>false</ear-subdeployments-isolated>
    </jboss-deployment-structure>


    Создать EAR можно следующим образом. Создаете в папке deployments папку my.ear со следующей структурой:
    my.ear
    --META-INF
    ----application.xml
    ----jboss-deployment-structure.xml
    --myWeb1.war
    --myWeb2.war
    --myEjb1.jar
    --myEjb2.jar


    Содержимое application.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd">
    <application>
        <display-name>myApp</display-name>
        <initialize-in-order>true</initialize-in-order>
        <module>
            <java>myEjb1.jar</java>
        </module>
    
        <module>
            <java>myEjb2.jar</java>
        </module>
    
        <module>
            <web>
                <web-uri>myWeb1.war</web-uri>
                <context-root>myWeb1</context-root>
            </web>
        </module>
        
        <module>
            <web>
                <web-uri>myWeb2.war</web-uri>
                <context-root>myWeb2</context-root>
            </web>
        </module>
    </application>

    Библиотеки, не содержащие EJB (просто "носители" нужных общих классов), можно поместить в папку my.ear/lib
    Ответ написан
  • Hibernate, OneToMany Каскадной добавление/удаление детей

    @bobzer
    Java EE Developer
    Похоже на то, что ошибка возникает из-за лишних манипуляций с сущностями. Посмотрите под отладкой содержимое сессии, в ней собирается список всех объектов, подлежащих сохранению при вызове flush/commit. Скорее всего, кроме явно видимой в коде сущности user, в сессии в какой-то момент (может, userDAO.findUserItem ?) появляется ещё один экземпляр User, например в UserItemId. Вам надо добиться того, чтобы все взаимосвязи ссылались на один и тот же экземпляр объекта. Для этого попытайтесь выполнять все операции в одной сессии, т.е., если в потоке выполнения кода уже открыта одна сессия, не открывать других сессий (в userDAO.findUserItem ?) пока не будет закрыта текущая сессия.
    Ответ написан