• Как освобождать Connection в Hibernate?

    @lexas
    предположу, что проблема не в хибернате, а в транзакшн менеджере. транзакции открываются, но не закрываются. session от hibernate тут не при чем.

    я бы посоветовал:
    а) определить явные границы транзакций
    б) подебажить кто открывает и почему не поппдает в закрытии (коммит или роллбак) транзакции
    Ответ написан
    Комментировать
  • Чем отличается Hibernate от spring Data и в принципе инструменты работы с БД?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Java
    Седой и строгий
    JDBC - это стандарт доступа к базам данных, JPA - это стандарт персистентности, Hibernate - это реализующий его ORM, Spring Data - это механизм организации репозиториев, а репозиторий - это абстракция, лежащая на уровень выше ORM. То есть Spring Data использует Hibernate, а Hibernate использует JDBC.
    Ответ написан
    3 комментария
  • Как именно работает map?

    zagayevskiy
    @zagayevskiy Куратор тега Java
    Android developer at Yandex
    size всего лишь возвращает, сколько ключей реально лежит в папке.
    Все твои рассуждения про "завели бакет", "кладем в новый бакет" неверны. Ты ничего не заводишь, это детали реализации хеш-таблицы. Бакет это связный список, в котором лежат пары ключ-значение, у которых хеш ключа равен по модулю количества бакетов. Это и есть тот список, который ты мечтаешь получить, и это так не работает. То есть ты его не получишь, тк это детали реализации.
    И далее, ты эту реализацию сломал своими мутабельными ключами. В списке теперь лежит ключ, у которого хеш не соответствует списку. Естественно, мапа не найдет по этому ключу ничего, тк будет искать в другом списке(бакете). Вывод - никогда не мутируй ключи.

    //заводим бакет который который будет всегда первым
    map.put(null, null);
    //значение перетерлось так как hashCode одинаков и equals вернул true
    map.put(null, "afterNull");


    Нет, всё не так. Нулл обрабатывается просто отдельно, под него отдельный элемент, это не бакет.

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

    Сколько в данный момент в мапе бакетов тебя вообще заботить не должно.

    Читай код. Видно, что ты где-то нахватался неправильно (или плохо) разжеванной теории, и пытаешься на этом выехать. Большинство твоих вопросов снимут сорсы хешмапы и, в крайнем случае, дебаггер.
    Ответ написан
    3 комментария
  • Как отправлять email определяя необходимость отправки в runtime?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Java
    Седой и строгий
    Spring Integration поможет и с отслеживанием изменений в БД и с отправкой email.
    Ответ написан
    Комментировать
  • Как отправлять email определяя необходимость отправки в runtime?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Не уверен, но если я правильно понимаю задачу, то вам по идее должны помочь Spring Email, @Scheduled для запуска по крону например, и @Async для асинхронной отправки. Но возможно, что есть варианты попроще
    Ответ написан
    1 комментарий
  • Что дает Java Spring?

    leahch
    @leahch
    3D специалист. Dолго, Dорого, Dерьмово.
    Вся и идея spring и ему подобных в технологиях DI и IoC.
    Первая технология DI - Dependency Injection - внедрение зависимостей. Смысл следующий, пусть у нас есть класс, который зависит от другого класса, тогда контейнер автоматически найдет все зависимости и сам проинициализирует нужный класс. Пример: пусть у нас есть интерфейс "Фрукт", класс "Яблоко", интерфейс "Паразит", класс "Червяк". В класса "Яблоко" указываем в одном из методов или конструкторе зависимость от интерфейса "Паразит". Теперь положим в контейнер классы "Червяк" и "Яблоко", и попросим контейнер создать дать нам инстанс класса "Яблоко".
    Контейнер выполнит следующие действия:
    - посмотрит, что без класса, реализующего интерфейс "Паразит", он не может создать "Яблоко".
    - посмотрит на зарегистрированные классы, не реализует ли кто интерфейс "Паразит" и обнаружит класс "Червяк"
    - создаст инстанс класса "Червяк"
    - создаст инстанс класса "Яблоко" и передаст ему инстанс класса "Червяк"
    - отдаст созданный инстанс "Яблоко" нам.

    Теперь мы можем создать класс "Ева" с зависимостью от интерфейса "Фрукт", положить его в контейнер, и положить в контейнер класс "Адам" с зависимостью от "Ева" и попросить создать нам инстанс класса "Адам" :-)
    MutablePicoContainer pico = new DefaultPicoContainer();
    pico.addComponent(Fruit.class);
    pico.addComponent(Worm.class);
    pico.addComponent(Eve.class);
    pico.addComponent(Adam.class);
    .....
    Adam adam = pico.getComponent(Adam.class);


    Вторая технология IoC - Inversion of Control - контроль управления - это как раз и есть одна из реализаций принципа DI, когда внедрение зависимостей происходит через посредника - фреймворк.

    Легче всего разобраться с этим (а уж потом переходить к spring) - поработать с простыми контейнерами типа picocontainer , nanocontainer и guice.
    - picocontainer.com/introduction.html
    - https://github.com/google/guice
    Ответ написан
    Комментировать
  • Как обработать значение в контроллере из выпадающего списка?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Здравствуйте!

    Напишу примерный код, вы уже адаптируйте под себя.
    В контроллере из дропдоун вы можете получить, как сам объект, так и id объекта, а потом в БД найти этот объект по ID.

    Вариант с поиском объекта по ID:
    Plant plant = plantRepository.findById(id);
    Можете использовать Optional, чтобы избежать NPE. Optional<Plant>
    Ответ написан
    2 комментария
  • Как создать скроллБар на thymeleaf возвращающий строку?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Скажу честно, не совсем понял, что вы имеете ввиду под "скроллбар"ом, в данном контексте...
    На основании этого текста:
    Но мне надо, допустим ,поднимать данные с базы поддерживаемых растений (только имена допустим), после эти имена надо каким то образом передать на страницу в скролл бар, чтобы пользователь уже из них выбрал растение и при сабмите

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

    Для реализации нужно сделать следующее:
    1) реализовать метод, который возвращает список (List) или массив строк с названиями растений. (в Repository).
    2) В GET запросе при открытии страницы через Model ( model.addAttribute("plants", repo.getPlants()) ) передать эту информацию.
    3) далее остается все это дело красиво завернуть в dropdown список.
    https://getbootstrap.com/docs/4.3/components/dropdowns/

    Возможные растение вы можете хранить, как в БД (если предполагается частое добавления и удаление разновидностей) или хранить в виде Enum.

    .... как обработать выбранное значение в контроллере ...

    зависит от того, что вы выберете. В методе контроллера можно принять объект и сохранить его, можно принять enum и сохранить его, можно принять String и используя String.valueOf(myString) сохранить enum и т.д.
    Ответ написан
    2 комментария
  • Сервлеты, многопоточность, как устроено?

    sergey-gornostaev
    @sergey-gornostaev Куратор тега Java
    Седой и строгий
    При запуске Tomcat создаст пул потоков и экземпляр сервлета. При поступлении запросов методы сервлета будут запускаться на потоках из пула. Сервлет не уничтожается до окончания работы сервера.

    Потоки можно создавать самостоятельно, но зачем? Особенно при использовании Spring, который предоставляет целую кучу удобных высокоуровневых абстракций для удобной работы с асинхронными задачами.

    С кэшированием надо крайне аккуратно, так как это как раз та область, в которой можно нарваться на проблемы многопоточности.
    Ответ написан
  • Как организовать клиентскую часть на thymeleaf?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Вот, пример метода в контроллере и соответственно шаблонизатор.

    Предположим, что у вас есть страница со списком "коробок".
    Например,

    @GetMapping("/boxes")
    public String getBoxesList(
    	Model model
    ) {
    
    	model.addAttribute("boxes", boxService.getBoxesList());
    	return "/boxes-template";
    }

    <!DOCTYPE html>
    <html>
    <head>
    	<title></title>
    </head>
    <body>
    
    	<!-- тут итерируем по списку -->
    	<div th:each="box : ${boxes}">
    		<span th:inline="text">[[${box.boxTitle}]]</span> <!-- или можно так -->
    		<span th:text="${box.boxTitle}">Название коробки</span>
    		<a th:href="'/boxes/edit/'+${box.boxId}">Изменить</a> <!--обратите внимание на эту ссылку -->
    	</div>
    
    </body>
    </html>


    По клику на кнопку изменить открываем форму с информацией о боксе
    @GetMapping("/boxes/edit/{id}") 
    public String boxEditForm(
    	@Pathvariable("id") Long id,
    	Model model
    ) {
    	Box box = boxRepository.findById(id);
    	model.addAttribute("box", box);
    	return "box-edit-template";
    }

    А все остальное уже делается также....

    Вы можете по-разному реализовать. Например, передавать id бокса не в виде pathVariable, а RequestParam. Можно использовать POST запрос, если вы не хотите передавать id в URL и т.д. Я описал простой вариант.

    Если я правильно понял ваш вопрос, то это то, что вам нужно...
    Ответ написан
    2 комментария
  • Как убрать лишние пробелы и отступы?

    ehabarov
    @ehabarov
    IT Specialist
    Попробуйте так:
    <%@ page trimDirectiveWhitespaces="true" %>

    Дополнительная информация:
    Strip whitespace from jsp output
    The Java EE 5 Tutorial: Eliminating Extra White Space
    Ответ написан
    2 комментария
  • Почему не получается добавить метод в interface, наследующийся от JpsRepo?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    List<GrowBox> findByUserId(Long userId);
    первое, что попадатся на глаза - вы хотите получить List. Если мне память не изменяет, то надо использовать
    List<GrowBox> findAllByUserUserId(Long userId) если мне память не изменяет, то должно быть как-то так
    а то получается, что вы хотите получаете один объект по userId, но при этом хотите получить List

    либо вы можете сделать следующее:
    List<GrowBox> findAllByUser(User user);
    в таком случае в метод нужно передать пользователя, а не его id.

    Кстати, обычно, IDE подсказывает как должно быть...

    No property userId found for type GrowBox!
    Caused by: org.springframework.data.mapping.PropertyReferenceException: No property userId found for type GrowBox!

    вы как бы получаете доступ к объекту User, а потом userId. А по вашему методу получается, что в таблице growBoxes вы ищете userId
    Ответ написан
    6 комментариев
  • Как в thymeleaf дублировать поле для сравнения?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Здравствуйте!
    Вы сильно заморочились, если честно... тут даже Spring ни причем, а больше базовые знания html + js
    Вот, ваша форма:
    <form th:action="@{/register}"
          th:object="${personForm}" method="POST">
        Login:
        <input type="text" th:field="*{name}" />
        <br/>
        Email:
        <input type="text" th:field="*{email}" />
        <br/>
        Password:
        <input type="text" th:field="*{password}">
        <br/>
        Confirm password:
        <input type="text" th:field="*{doublePassword}">
        <input type="submit" value="Create" />
    </form>


    1) небольшой совет используйте специфические инпуты. Например, если вам нужно поле майл, то используйте майл и т.д.
    Соответственно:
    <form th:action="@{/register}"
          th:object="${personForm}" method="POST">
        Login:
        <input type="text" th:field="*{name}" />
        <br/>
        Email:
        <input type="email" th:field="*{email}" />
        <br/>
        Password:
        <input type="password" th:field="*{password}">
        <br/>
        Confirm password:
        <input type="password">
        <input type="submit" value="Create" />
    </form>

    2) Определитесь с тем, где именно вы хотите валидировать совпадение пароля на клиенте или на сервере. Как по мне, на клиенте лучше, чтобы лищний раз не нагружать сервер.
    Если на клиенте, то средствами js, если на сервере, то средствами java. Рассмотрим оба варианта:
    - На сервере. Получаете оба пароля из формы, сравниваете через equals() и возвращаете нужный результат. Если пароль неверен, то можете добавить сообщение через model.addAttribute() и вывести в шаблоне
    @RequestMapping(value = {"/register"} , method = RequestMethod.POST)
    public String savePerson(Model model, @ModelAttribute("personForm") UserForm personForm) {
    
    
    	if(!personForm.getPassword.equals(personForm.getPasswordConfirmation)) {
    		model.addAttribute("passwordIncorrect", "Вы ввели некорректный пароль");
    		return "register";
    	}
    
        if(personForm.checkPassword() &&
                userRepository.findByEmail(personForm.getEmail()) == null &&
                userRepository.findByName(personForm.getName()) == null) {
    
            AppUser user = new AppUser(personForm.getName(),
                    personForm.getEmail(),
                    personForm.getPassword());
    
            user.setEnabled(true);
            user.setRoles(Collections.singleton(Role.USER));
            userRepository.save(user);
            return "home";
         }
    
        return "register";
    }


    - Обработка на клиенте средствами js. Идея заключается в том, что вы деактивируете кнопку "Регистрация" и только если пароли совпадают, то активируете кнопку.

    Тут материалов хватает. Наберите в гугл jquery password validation.
    Вот, пример:
    Скрипт - https://www.jqueryscript.net/form/Password-Strengt...
    Демо - https://www.jqueryscript.net/demo/Password-Strengt...
    Ответ написан
    1 комментарий
  • В чем проблема с аутентификацией через Spring?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    С учетом того, что есть готовое видео, которое один в один совпадает с вашим кодом и методом аутентификации через jdbcAuthentication() , то рекомендую посмотреть:
    https://www.youtube.com/watch?v=WDlifgLS8iQ
    и даже можете один в один воспроизвести у себя.

    Что касается вашего кода, то:
    1) добавьте в application.properties
    logging.level.org.springframework.security=DEBUG
    
    logging.level.org.hibernate.SQL=DEBUG
    logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
    logging.level.org.hibernate.type=TRACE


    и увидите нужный вам стек ошибок, в частости:
    2019-05-25 20:20:12.446 DEBUG 21154 --- [nio-8080-exec-2] o.s.s.p.JdbcUserDetailsManager           : Query returned no results for user ''
    2019-05-25 20:20:12.450 DEBUG 21154 --- [nio-8080-exec-2] o.s.s.a.dao.DaoAuthenticationProvider    : User '' not found
    org.springframework.security.authentication.BadCredentialsException: Bad credentials


    Причина кроится здесь: WebsecurityConfig
    .formLogin()
                    .loginPage("/login")
                    .usernameParameter("name")
                    .passwordParameter("password")

    Вы просто забыли указать usernameParameter & passwordParameter и соответственно, Spring Security ищет в БД пользователя с именем ' '

    5ce96d384bcd4860471431.png
    Ответ написан
    5 комментариев
  • Как корректно считать данные с веб страницы и положить в бд?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Здравствуйте!

    Первое, что сразу попадается на глаза -
    public interface UserRepo extends CrudRepository<ClientOrder, Integer> {
    }


    public class ClientOrder {
    
        @Id
        @GeneratedValue(strategy=GenerationType.AUTO)
        @Column(name = "id", nullable = false)
        private Long id;


    Обратите внимание, что создали вы тип Long, а используете Integer

    Соответственно, должно быть так
    public interface UserRepo extends CrudRepository<ClientOrder, Long>


    + это интерфейс, необязательно писать public

    + Надеюсь, что для сущности ClientOrder есть конструктор. Просто, в сниппете этого не увидел, решил уточнить. Если нет, то создайте:

    ClientOrder() {}

    По идее тут нужно раскомментировать строку
    public String savePerson(Model model,
                                 @ModelAttribute("personForm") ClientOrder personForm) {


    Проверку на пустоту лучше проводить не так:
    firstName != null && firstName.length() > 0
    а так:
    firstName != null && !firstName.isEmpty()
    так как у вас строка
    Ответ написан
    8 комментариев
  • Как авторизировать пользователя при работе с API?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    токены. При успешной авторизации создается, записывается куда (например в базу) и возвращаете пользователю токен (рандомная строка). Клиент его просто будет передавать в заголовках и по нему на сервере будет произведена аутентификация и авторизация.

    Если интересуют готовые варианты - WSSE
    Ответ написан
    Комментировать
  • Как добавлять данные постепенно в БД?

    @frozen_coder
    Java-developer
    Как вам уже заметили в комментариях, вам необходимо погуглить назначения методов HTTP, ибо метод GET вы используете некорректно.

    Про сессию уже написали. Ещё вариант - это использовать local strorage на стороне клиента и писать-читать из него (немного поработать с js).

    Если варианты выше не подходят, то можно в отдельной таблице хранить проекты заявок. Т.е. пользователь сначала создаёт проект заявки первым запросом - сохраняем его в отдельную таблицу, а потом на каждом шаге в эту запись добавляются данные с отдельных форм. В финале этот проект становится заявкой - удаляется из таблицы проектов и переносится в таблицу заявок. Это решение не зависит от состояния сессии и local storage. Пользователь может продолжить заполнять заявку с другого клиента в другой сессии, ведь мы храним его проект у себя в базе. Как бонус, таким макаром можно при необходимости организовать пользовательские шаблоны заявок (если форма большая и пользователем большая её часть вводится одинаковая), чтобы быстро создавать новые заявки из сохранённых шаблонов.

    Если требованиями not null полей можно немного принебречь, то можно ввести статусы заявки или флаг является ли заявка проектом и хранить их в одной таблице. Тоже, что и в предыдущем варианте, но только всё в одной таблице и в итоге мы просто меняем статус или флаг записи.

    Ещё вариант, если у вас есть html, который не меняется по ходу изменения форм (т.е. вы просто меняете куски страниц при переходе по формам), то можно завести скрытые поля, куда дублировать заполнение формы пользователем. В итоге у вас эти скрытые поля заполнены и именно их содержимое отправляется на сервер в итоге. Видел такое на старых проектах.

    В проектах с SPA такой проблемы нет, т.к. в таком случае на клиенте просто выполняется управление состоянием и роутингом
    Ответ написан
    Комментировать
  • Как добавлять данные постепенно в БД?

    bitniks
    @bitniks
    Go/PHP/Symfony developer
    Аккумулировать данные в сессии
    Ответ написан
    2 комментария