Ответы пользователя по тегу Java
  • Почему хибернейт не апдейтит таблицу?

    @bobzer
    Java EE Developer
    Поиск в Гугле по фразе "hibernate.hbm2ddl.auto update not working" даёт следующую информацию о принципах работы "update":
    • Добавляет новые столбцы
    • Не удаляет столбцы
    • Не изменяет столбцы

    Для полноценной работы со структурой БД используйте системы миграции, например, Liquibase или FlywayDb. Функции, встроенные в Hibernate, малопригодны для реальных проектов, они подходят в основном для тестов.
    Ответ написан
  • Spring Security. Разные права для разных пользователей. (Как скрыть для Коли (одного из юзеров) возможность "Создать пост" ) ???

    @bobzer
    Java EE Developer
    Никакой фреймворк общего применения не знает требований Вашего конкретного приложения. Это значит, что доступ к каждому действию придётся так или иначе прописать в самом приложении. Если требуется тонкая настройка доступов, то нередко создаётся понятие "права на действие", множество которых можно собирать в роли. При этом приложение "знает" о правах (тонких настройках), а роли создаются произвольно в административной части приложения и наполняются нужными правами. Такой подход создаёт дополнительные сложности в программировании и в последующей эксплуатации, но это плата за гибкость. Для обеспечения максимальной гибкости, при разработке приложения на каждое действие, доступное пользователю, придётся создавать соответствующее право, и в приложении прописывать его проверку.
    Ответ написан
    1 комментарий
  • Как добавить новые данные в таблицу?

    @bobzer
    Java EE Developer
    Метод setMap следует вызывать только в случае если вы только что создали экземпляр @Entity, и ещё не сохраняли его в БД. Если же сущность уже сохранена в БД, или считана из БД, то вместо интерфейса Map, объявленного в классе сущности, подставляется его реализация, связанная с функциями работы с БД. "Движок" JPA (обычно Hibernate) "видя", что на месте Map такая реализация, как бы "знает", что это связанные записи, которые уже сохранены в БД. Если же подменить целиком Map, то это "знание" теряется и начинается непредвиденное поведение.

    Для модификации списка, хранимого в Map, следует вызывать методы Map.put и Map.remove:
    entity.getMap().put(...);
    entity.getMap().remove(child);

    Hibernate отследит эти обращения и при сохранении родительской сущности корректно добавит/удалит дочерние объекты.
    Ответ написан
    Комментировать
  • Как задеплоить приложение?

    @bobzer
    Java EE Developer
    Скачайте, разверните и запустите, например, Wildfly - это Opensource версия JBoss. Убедитесь, что после старта в логах нет ошибок, т.е. "пустой" сервер запустился корректно. Затем в папке /standalone/deployments создайте папку my.war. В папке my.war создайте текстовый файл index.html, в нём напишите строку "Hello, world". Последним шагом в папке /standalone/deployments создайте пустой текстовый файл с именем my.war.dodeploy. Убедитесь, что спустя несколько секунд в логах появилась запись Deployed "my.war". Зайдите по адресу localhost/my
    Ответ написан
  • Как избавится от дубля path JSTL на страницe jsp?

    @bobzer
    Java EE Developer
    <td>
        <sf:input path="login" id="login_id" class="form-control input-sm" readonly="${affiliateProgramConstantInfo.login != null}"/>
        <div class="has-error">
            <sf:errors path="login" class="help-inline"/>
        </div>
    </td>
    Ответ написан
    1 комментарий
  • Откуда ошибка "Column 'id' cannot be null" в Hibernate?

    @bobzer
    Java EE Developer
    Проверьте настройки дочерних сущностей. Мысль примерно такая - генерация ID настроена везде, но Hibernate не всегда "знает" о том, что в конкретном случае надо использовать эту генерацию. Например, вы сохраняете нового пользователя - сохранение проходит. Затем вы добавляете роль в список ролей пользователя, сохраняете - и возникает ошибка потому, что в маппинге списка ролей не указано CascadeType.PERSIST или CascadeType.ALL. Если вы не "сказали" Hibernate-у сохранять дочерние сущности, но добавили новый объект в список, то не будет попытки создать добавленный объект в БД. Если дело именно в дочерних объектах, то этим может объясняться и непостоянство возникновения ошибки: не добавляли дочерних объектов - всё ОК, добавили - ошибка.

    Проверьте все связи @OneToMany.
    Ответ написан
  • Как деплоются приложения Java EE?

    @bobzer
    Java EE Developer
    нужно обновить частично, только один модуль
    Соответственно, этот модуль должен быть самостоятельным артефактом Maven. Обычно, артефакт для EAR описывает формирование приложения из других модулей и конфигурационных файлов. Следует разбить приложение на артефакты (обычно jar/war), которые входят в состав EAR.

    Вообще, при сборке для промышленной среды надежнее собирать всё приложение (EAR в вашем случае) целиком. А при сборке для окружения разработчика вообще удобнее использовать не сборщик Maven, а среду разработки. Idea, например, прекрасно понимает формат конфигураций Maven и на их основе может создавать свои артефакты (и настоятельно порекомендует это сделать при обнаружении pom.xml). Если собирать артефакты с помощью Idea, то даже при сборке EAR целиком фактически будут обновляться только изменённые файлы, что ускоряет процесс сборки на порядки, в сравнении с Maven. Это достигается за счёт того, что у Idea есть свой контроль версий и она знает что именно следует пересобрать, а что можно оставить как есть. Наибольший выигрыш получается для exploded артефактов (которые не архивируются, а выкладываются в виде структуры папок с файлами), т.к. в таком случае не приходится перепаковывать модули целиком при изменении небольшого количества файлов в них.

    Для каждого артефакта Maven Idea создаст две версии своих артефактов - упакованную и не упакованную (exploded). В случае, если ваше приложение состоит из нескольких модулей, может потребоваться ручное вмешательство в сгенерированные артефакты, т.к. exploded-артефакт верхнего уровня в конфигурации по-умолчанию содержит подчинённые артефакты в упакованном виде. Потребуется удалить вариант в упакованном виде и на его место вставить exploded-вариант. Минус состоит в том, что при изменении артефакта Maven, Idea предложит перегенерировать и свои артефакты, все ручные настройки при этом пропадут. Но настройки топологии проекта меняются нечасто, поэтому лишней минутой работы по ручной реконфигурации обычно можно пренебречь...

    Если Вы только начали экспериментировать с Java EE, то создание EAR может быть неоправданным усложнением, т.к. во многих случаях веб-артефакт более низкого уровня - WAR - прекрасно справляется со всеми задачами Enterprise-приложения. При этом получается более простая структура, соответственно и с настройкой сборки проблем меньше.
    Ответ написан
    4 комментария
  • Как работает блокировка у Singleton на кластере?

    @bobzer
    Java EE Developer
    Как решается проблема, когда нужно иметь Singleton на нескольких серверах?

    1. Блокировка записи в БД. Если бизнес логика вносит какие-то изменения в БД, то перед этим осуществляйте чтение записи с блокировкой, SELECT ... FOR UPDATE (для JPA LockMode/LockModeType и прочее, в зависимости от реализации и версии). При этом, получаем актуальное состояние записи одновременно запрещая её изменять другим потокам (и другим узлам кластера) до тех пор, пока не завершится транзакция обработки записи. Сразу после чтения с блокировкой проверяем, подлежит ли она обработке или нет, на случай, если пока получали блокировку другой поток уже обработал запись. Обычно, сама запись содержит поле, сообщающее о том, следует ли её обрабатывать, например - некий статус. Если статус говорит о том, что запись уже обработана, то обработку не выполняем, завершаем транзакцию, переходим к следующей записи. Если не обработана - соответственно обрабатываем. Пока идёт обработка текущим потоком, другие потоки (узлы) останавливаются на моменте чтения с блокировкой, это поведение обеспечивает СУБД. После завершения обработки, смены статуса записи и подтверждения транзакции, запись высвобождается, и если другой поток пытался её обработать, то СУБД разрешает ему считать запись с блокировкой. Поток проверяет статус, "видит" что она уже обработана и не обрабатывает её. Плюсы: универсальность, независимость от контейнера, практически "непробиваемый". Минус: вероятно возникновение излишней нагрузки, в самом неприятном варианте - всю работу делает один узел, остальные потребляя те же мощности не делают ничего полезного. Если записей менее 100 тысяч в сутки, а узлов менее 5-10, то скорее всего, это не будет большой проблемой.
    2. Для Wildfly начиная с версии 10 есть альтернативный вариант - Singleton deployments. Этот сервис существовал в JBoss 5/6, но был "выпилен" в JBoss 7 (6 EAP) в угоду соответствия стандартам Java EE. Раньше работало так: вы разворачиваете свои кластерные синглтоны в отдельное приложение, и "ложите" в отдельную папку развертывания. Отличие Wildfy в том, что вместо отдельной папки, требуется добавить в приложение специфический дескриптор развёртывания. JBoss/Wildfly гарантирует, что все такие приложения будут запускаться только в одном экземпляре на весь кластер. Плюс: нет лишней нагрузки. Минус: надёжность под сомнением, например, "сломался" протокол UDP, все узлы потеряли друг друга и решили стать главными и развернули ваш синглтон. Вообще, во всём что касается атомарности, лучше СУБД (ИМХО) ещё ничего не придумано.
    3. Реализуете вариант 1 и разворачиваете его как вариант 2. При таком раскладе избавляетесь от минусов обоих подходов, получая все их плюсы.


    PS Касательно варианта 1. Если работа синглтонов не связана с обработкой записей БД, их всё равно можно синхронизировать таким же образом. Создаёте в любой таблице (например, в таблице каких-нибудь системных настроек) запись и синхронизируете синглтоны на ней.
    Ответ написан
    Комментировать
  • Почему Hibernate не подхватывает новые записи в базе?

    @bobzer
    Java EE Developer
    Проверьте как у вас завершаются транзакции после добавления записей, возможно, забыли сделать commit. Попробуйте добавить запись и проверить её наличие средствами самой БД (SQL-запросом), а не в вашем приложении.

    Плюс проверьте логику чтения данных, поработайте под отладчиком (или добавьте вывод сообщений в лог) и убедитесь в том, что приложение вызывает метод чтения периодически, а не только при старте.
    Ответ написан
    Комментировать
  • Как исправить Null id generated?

    @bobzer
    Java EE Developer
    У Вас нигде не определена стратегия генерации первичных ключей, ни на уровне СУБД, ни на уровне вашей бизнес-логики. Для генерации ID могу порекомендовать использовать имеющиеся в MySQL средства. Для этого определите поле первичного ключа в БД как:
    ID BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT
    а в маппингах сущностей укажите следующее:
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    protected Long id;

    При таком подходе значение первичного ключа создаётся непосредственно в момент вставки записи в таблицу. При выполнении команды INSERT значение поля ID не указывается, а MySQL сам подставит значение, применив для его генерации сиквенс (специфический объект СУБД, последовательно генерирующий числа, обычно начиная с 1).

    Настоятельно не рекомендую использовать примитивы для определения ID в сущности (private int id в Note), т.к. при создании нового экземпляра класса будет присвоено значение по умолчанию 0, что приводит к заблуждению - первичный ключ еще не генерировался, но у него уже есть какое-то значение.

    Обычно, класс сущности, описывающий идентификатор, выносится в родительский класс, а все сущности проекта наследуются от него, за счёт чего возникает возможность не описывать поле ID повторно во всех наследниках, избавляясь от дублирования кода. Но, сначала добейтесь работоспособности текущей структуры, а затем занимайтесь рефакторингом иерархии классов. Вот пример определения родительского класса:
    import javax.persistence.*;
    import java.io.Serializable;
    
    @MappedSuperclass
    public abstract class Identifier implements Serializable {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "ID")
        protected Long id;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Identifier that = (Identifier) o;
    
            if (getId() != null) {
                return getId().equals(that.getId());
            } else {
                return super.equals(o);
            }
        }
    
        public int hashCode() {
            return getId() != null ? getId().hashCode() : super.hashCode();
        }
    }


    UPD
    Маппинги сущностей БД обычно определяются с помощью аннотаций JPA, следующим образом:
    import javax.persistence.*;
    
    @Entity()
    @Table(name = "note")
    public class Note extends Identifier {
    //fields, getters, setters
    }
    Ответ написан
  • RMI или JSF чем будет правильнее?

    @bobzer
    Java EE Developer
    технология RMI выдержит?
    практически любая технология выдержит, если выдержат Ваши аппаратные ресурсы. В основном это сеть и дисковая подсистема, но может быть и нагрузка на ОЗУ сервера приложений, т.к. многие технологии прежде чем сохранить файл на диск, загружают его байтовое представление в ОЗУ сервера. Насчёт "~1000 человек" - эта цифра ни о чём не говорит, в данном случае следует считать количество и размер загружаемых/скачиваемых файлов а не абстрактных пользователей.

    Как правильно реализовать?
    Если Вы используете спецификацию JSF для построения клиентской части, то логично использовать средства загрузки файлов, предоставляемые библиотеками/фреймворками, реализующими эту спецификацию - практически все они имеют компоненты загрузки файлов на сервер. Я рекомендую использовать PrimeFaces - это активно развивающийся, богатый компонентами фреймворк. У них есть несколько вариантов компонента загрузки файла(-ов) на сервер, начать можно с этого

    Касательно RMI - он здесь вообще не к месту. JSF работает в браузере, используя протокол HTTP, поэтому и для загрузки файлов логично использовать тот же протокол.
    Ответ написан
    Комментировать
  • Java. Отправка письма через gmail host c аутентификацией proxy по логину и паролю?

    @bobzer
    Java EE Developer
    Я бы посоветовал для начала добиться работоспособности кода в окружении, в котором нет прокси сервера, т.к. не ясно с кем "бороться" - с почтовым сервером или с прокси. Недавно "бился" с Gmail, вот мои работающие настройки:
    mail.smtp.host              smtp.gmail.com
    mail.smtp.socketFactory.port	 465
    mail.smtp.socketFactory.class	 javax.net.ssl.SSLSocketFactory
    mail.smtp.auth                         true
    mail.smtp.port                         465
    mail.sender.email                    mymail@gmail.com
    mail.sender.email.password    mypassword
    mail.smtp.ssl.enable                true
    mail.smtp.ssl.trust                   *
    Ответ написан
    Комментировать
  • Как свинтить вместе JAX-WS веб-сервис и @XmlAnyElement?

    @bobzer
    Java EE Developer
    Обычно, сервера приложений уже содержат библиотеки для поддержки веб-сервисов. Вероятно, ваше приложение также содержит какие-то из таких библиотек, или зависимых.

    Попробуйте развернуть "чистый" сервер приложений, с нуля. Затем разверните ваше приложение, но удалите из него все библиотеки, а лучше вообще оставить только класс веб-сервиса и web.xml. Если в такой конфигурации веб-сервис развернётся, то поштучно добавляйте нужные библиотеки (зависимости maven), пересобирайте и деплойте заново, до тех пор, пока ошибка не повторится. Так поймёте какая именно библиотека конфликтует. Вероятно, её надо будет удалить из зависимостей, либо указать как Provided.
    Ответ написан
  • Hibernate cache lvl2 vs Redis?

    @bobzer
    Java EE Developer
    Во многих случаях, ответом на вопрос "как лучше кешировать" является "никак". У вас есть на руках конкретные данные о нагрузочном тестировании вашего приложения, в которых четко видно какая из частей Системы какие ресурсы потребляет? Если нет - то погуглите фразу "преждевременная оптимизация".

    Если бы у вас было действительно серьезное, высоконагруженное приложение, то таких вопросов вы бы здесь не задавали, а сами писали бы уже статьи на такие темы.

    Т.к. конкретный вопрос задан, то всё же отвечу. Любая более-менее развитая СУБД прекрасно умеет кешировать всё, что нужно и в общем случае справляется с этим лучше любых кешей. Если четко видите, что уже не справляется - оптимизируйте СУБД. Кеш Hibernate вряд ли даст ощутимый прирост, опять же в общем случае (количество информации в вопросе позволяет обсуждать только общий случай).

    Любые программные кеши требуют собственно программирования. Если вы точно знаете какие сущности надо кешировать и в каком режиме, и при этом типов немного, то возможно, проще всего будет просто создать некий Map прямо в вашем коде и всю работу с ним реализовать самому. Сторонние продукты есть смысл подключать, если логика кеширования и чистки кеша сложная, да ещё, например, требуются распределённый кеш. Тогда да - смотрите отдельные продукты.
    Ответ написан
    Комментировать
  • Как грамотно организовать удаление/переименование файла на Java?

    @bobzer
    Java EE Developer
    Что такое Java Web Start:
    • Позволяет активировать приложения одним щелчком мыши
    • Обеспечивает использование новейших версий приложений
    • Устраняет необходимость проведения сложных процедур установки и обновления
    Ответ написан
    Комментировать
  • Можно ли с помощью Apache Lucene определить, входит ли какая-то строка из набора в текст?

    @bobzer
    Java EE Developer
    Вот работающий пример поиска по неточному вхождению:
    public static void main(String[] args) throws Exception {
            String fieldName = "myField";
    
            //создание тестового индекса
            Directory directory = new RAMDirectory();//в "настоящей" Системе здесь должно быть FSDirectory.open(dir)
            RussianAnalyzer analyzer = new RussianAnalyzer(Version.LUCENE_46);
            IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_46, analyzer);
            IndexWriter writer = new IndexWriter(directory, config);
            writer.addDocument(createDocument(fieldName, "Я живу у мамы"));
            writer.addDocument(createDocument(fieldName, "В доме было холодно"));
            writer.commit();
            writer.close();
    
            //поиск
            int startFrom = 0;
            int pageSize = 20;
            DirectoryReader ireader = DirectoryReader.open(directory);
            IndexSearcher indexSearcher = new IndexSearcher(ireader);
            //FuzzyQuery осуществляет поиск неточных вхождений
            FuzzyQuery wildcardQuery = new FuzzyQuery(new Term(fieldName, "мама"));
            TopDocs topDocs = indexSearcher.search(wildcardQuery, startFrom + pageSize);
            ScoreDoc[] hits = topDocs.scoreDocs;
            for (int i = startFrom; i < topDocs.totalHits; i++) {
                if (i > (startFrom + pageSize) - 1) {
                    break;
                }
                Document hitDoc = indexSearcher.doc(hits[i].doc);
                if (hitDoc != null) {
                    System.out.println(hitDoc.get(fieldName));
                }
            }
        }

    Часть исходников взята с серьёзной промышленной Системы, так что если что-то кажется странным, не думайте, просто используйте. Когда всё заработает "как часы", тогда вернётесь к "странностям" и поразмыслите, стоит ли переделывать...
    Ответ написан
    Комментировать
  • Как правильно сделать полную копию объекта, со всеми потомками в hibernate?

    @bobzer
    Java EE Developer
    Точного ответа не дам, но есть что сказать по этому поводу:
    1. Проблема с Proxy обычно возникает на дочерних коллекциях, особенно когда они помечены как Lazy. Hibernate подставляет в коллекцию свой прокси-объект и при обращении к коллекции осуществляет чтение из БД.
    2. Судя по всему, Hibernate.initialize(entity) в вашем случае не делает ровным счётом ничего. Этот метод следует применять не к самой сущности, а ко всем Lazy-коллекциям сущности, по отдельности к каждой. Если сущность не является detached (не "оторвана" от сессии, в которой её считывали из БД), то Hibernate.initialize и вовсе не требуется, прокси-объекты коллекций (из п.п. 1) сами считают всё из БД при обращении к списку в коде.
    3. Ваш хак - первое что пришло мне в голову еще в начале чтения вопроса (если EntryKey - это первичный ключ сущности). Как только сущность "теряет" первичный ключ, она становится кандидатом на insert, если же первичный ключ есть - тогда Hibernate сделает update. Если аккуратно "обыграть" такие манипуляции с учетом этого правила и на дочерних объектах, то почему бы и нет?
    4. Вопросы клонирования объектов - это отдельная большая и непростая тема, даже без привязки её к сущностям БД (что ещё больше эту проблему усугубляет). Два основных варианта осуществления клонирования: 1 - использовать специфические библиотеки; 2 - писать всё руками (100500 set(get())-ов). Самый надежный и производительный вариант - 2, но он порождает много лишнего кода, который еще и поддерживать надо. Тем не менее, такой подход "живее всех живых", особенно если кол-во сущностей для клонирования можно пересчитать по пальцам.
    Ответ написан
    7 комментариев
  • Как дружат UI на JS и Java EE server-side?

    @bobzer
    Java EE Developer
    2. Написание Rest API
    Данный подход сейчас - мэйнстрим в разработке веб-проектов. Производительность высокая, механизм универсален и поддерживается практически всеми языками/фреймворками. Для примера: доводилось переходить со встроенных механизмов обмена данными с сервером GWT, на передачу тех же данных с помощью REST - при тех же объемах данных время возврата ответа значительно снижалось.
    Кроме производительности, удобство использования также на высоте - в большинстве случаев код лаконичен и ясен. Обращения к серверу можно осуществлять практически из любого места в вашем JS-клиенте. Главное - не забывать о асинхронности, и строить логику с учетом этого: код, зависящий от результатов запроса обрабатывать в callback-ах, переданных в вызов REST.
    Ответ написан
    5 комментариев
  • Из гуманитария в программисты, или как найти работу?

    @bobzer
    Java EE Developer
    У меня похожая ситуация, только в программисты я пришёл из строителей. Образование строительное, стаж работы на стройке 4 года после стройтеха. Пока работал на стройке вечерами изучал Pascal, как мог, без Интернета (конец прошлого века), благо приятель иногда приносил текстовики с какой-то инфой, ну, и конечно help самого Паскаля. За пару лет убедился в том, что мне это по душе, и что-то получается, решил как-то перебираться с улицы (стройки) в офис. Удалось устроиться на должность "бухгалтер-оператор", главное здесь было то, что это была первая работа в офисе и за компьютером. Нашел там себе возможность программировать, но слабую. После пары лет просиживания штанов там, стал смотреть вакансии (тогда это делалось путем просмотра местных газет). Вакансий было мало, но меня пригласили на собеседование, на котором я рассказал как писал игру на Паскале, работая с видеокартой на ассемблере, и том как к строчкам кода на машинном языке писал комментарии на ассемблере. Дали тестовое задание по аналитике (нужны были и аналитики и программисты, видимо дали то, что проще дать), связанное с таможней. Купил таможенный кодекс, что-то написал, принес - удивились (- откуда такие знания? - из книжек!), взяли на испытательный срок.

    Что такое СУБД и сервер приложений я тогда не знал, и первое время "горел" на работе - пахал как мог весь день, вечерами шел к тете и читал интернет (дома интернета не было). В общем взяли меня программистом, насколько помню толи $300 толи $400 начальный оклад был. Ну а потом втянулся, разобрался, стал одним из лучших, довелось и отделом разработки руководить, а сейчас нарасхват - работа меня сама находит... Одно большое НО - семьи не было. И даже при отсутствии семьи искал работу программистом не бросая текущую рутину.

    Итого: каменщик 4 года->завскладом 1 год -> оператором 2 года -> программистом стал в 27 лет
    Ответ написан
    2 комментария
  • Почему ломает форматирование при редактировании документов с помощью POI?

    @bobzer
    Java EE Developer
    Да, ваш файл и у меня тоже после копирования с POI теряет форматирование, да и вообще открывается с ошибками. Как я и предполагал, дело в самом файле: в нем слишком много всего наворочено, даже парольная защита на изменения... К сожалению, POI не всемогущий, и поддерживает далеко не все функции Excel. И дело не столько в разработчиках POI, сколько в формате, используемом Microsoft. Разработчики POI даже используют аббревиатуру HSSF - Horrible Spreadsheet Format (ужасный формат таблиц). Думаю, что в чистом виде в вашем случае решения проблемы с POI нет, надо искать обходной вариант. Можно попробовать использовать нативный API Microsoft (для Java затруднительно), либо как-то менять исходный файл, либо смириться с потерями и брать из файла только данные (а форматирование реализовывать в своём коде).

    Вообще, POI в основном используется для выгрузки данных Java-программ, а работа с произвольными существующими файлами применяется редко...
    Ответ написан
    Комментировать