Ответы пользователя по тегу Spring
  • Spring boot - как происходит запуск?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Есть приложение, читающее файлы из файловой системы и загружающее в БД часть содержимого.

    Ну в данном случае для импорта БД нужно использовать sql скрипты и какую-нибудь либу. Например, flyway.

    Есть сервисные классы, в них ряд методов, но возвращаемые типы в методах повторяются.

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

    Хотелось бы сделать без спринг шелла, без команд в мейне.

    По идее flyway (или например, liquibase) лучше подходят для этих целей.
    Ответ написан
    Комментировать
  • Правильно ли я называю тесты?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день.
    Вопрос не глупый. Ведь, от правильного нейминга зависит то, насколько хорошо ваш код будет читаемым.
    Вот, информация о конвенции нейминга тестов.
    https://dzone.com/articles/7-popular-unit-test-naming
    Ответ написан
    Комментировать
  • Какую аннотацию лучше всего использовать для ролей ( для Hibernate ) в Spring?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день.
    Я обычно делаю это иным образом.
    1) создаю enum UserRole, UserPrivilege
    2) создаю entity Role. При необходимости можно еще добавить сет из Privilege для каждой роли
    3) Далее каждый entity содержит роль или сет ролей.
    4) сущность User связываю с сущностью UserRole

    Вот, исходники:
    Сущность User
    @Entity
    @Data
    @Table(name = "users")
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    @EqualsAndHashCode(callSuper = false)
    public class User {
    
      //...
    
      @JsonBackReference
      @ToString.Exclude
      @ManyToMany(fetch = FetchType.EAGER)
      @JoinTable(
          name = "users_roles",
          joinColumns = @JoinColumn(name = "user_id"),
          inverseJoinColumns = @JoinColumn(name = "role_id"))
      private Set<Role> roles;
    
    }


    Сущность Role
    @Entity
    @Data
    @EqualsAndHashCode(callSuper = false)
    @Table(name = "roles")
    public class Role implements GrantedAuthority {
    
      @Id
      @GeneratedValue(strategy = GenerationType.SEQUENCE)
      private Long roleId;
    
      @JsonBackReference
      @ToString.Exclude
      @ManyToMany(mappedBy = "roles")
      private Collection<User> users;
    
      @JsonBackReference
      @ToString.Exclude
      @ManyToMany
      @JoinTable(
          name = "roles_privileges",
          joinColumns = @JoinColumn(name = "role_id"),
          inverseJoinColumns = @JoinColumn(name = "privilege_id"))
      private Collection<Privilege> privileges;
    
      @Enumerated(EnumType.STRING)
      private UserRole name;
    
      public Role() {
        super();
      }
    
      public Role(UserRole name) {
        super();
        this.name = name;
      }
    
      @Override
      public String getAuthority() {
        return name.name();
      }
    }


    enum UserRole
    public enum UserRole {
      USER,
      ADMIN
    }


    сущность Privilege
    @Entity
    @Data
    @EqualsAndHashCode(callSuper = false)
    @Table(name = "privileges")
    public class Privilege {
    
      
    
      @Enumerated(EnumType.STRING)
      private UserPrivilege name;
    
      @JsonBackReference
      @ToString.Exclude
      @ManyToMany(mappedBy = "privileges")
      private Collection<Role> roles;
    
    
    }


    enum UserPrivilege
    public enum UserPrivilege {
      ADMIN_PRIVILEGE,
      READ_PRIVILEGE,
      WRITING_COMMENTS_PRIVILEGE
    }
    Ответ написан
    6 комментариев
  • Почему Spring Security отказывается пускать, несмотря на permitall()?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Я бы попробовал сделать следующее:
    1) изменить урл и попробовать заново. Например, /admin/**
    2) также попробуйте подебажить проект. Например, что возвращает:
    Role.ADMIN.getAuthority() и что ожидается на вход
    Ответ написан
    Комментировать
  • Как изучать Spring? Где нормальная документация?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Подскажите как лучше изучать spring, какой современный стек?

    Пожалуй, все фреймворки изучаются на основе книг, документаций, а также туториалов. Спринг не является исключением.

    Туториалы: John Thompson - (Spring Guru)
    https://www.udemy.com/courses/search/?q=john+thomp...
    Есть чуть попроще Dan Vega - Learn Spring Boot
    https://www.udemy.com/course/spring-boot-intro/
    Также Наиль Алишев - Spring Framework
    https://www.youtube.com/watch?v=5ePo08sqcpk

    Что касается книг, то можно начать с Spring Boot in Action (Spring Boot в действии)

    Что касается документаций:
    https://docs.spring.io/spring-boot/docs/current/re...
    https://www.baeldung.com/

    Ну и у baeldang есть неплохие курсы по Spring
    https://www.baeldung.com/learn-spring-course
    Ответ написан
    Комментировать
  • Почему не билдится класс?

    azerphoenix
    @azerphoenix Куратор тега Spring
    Java Software Engineer
    Добрый день!
    Обычно, такая проблема возникает по двум причинам:
    1) нет плагина lombok - https://projectlombok.org/setup/intellij
    2) не включена обработка аннотаций - https://www.jetbrains.com/help/idea/annotation-pro...

    Сообщите, если вышеуказанные советы не помогут.
    Ответ написан
    Комментировать
  • Разные ДТО для создания/получения объектов VS один ДТО, но запретить сериализацию null?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день.
    Как по мне лучше создавать отдельный DTO на каждую нужду вместо того, чтобы скомпоновать все в один.
    Например, UserCreationDTO, UserRequestDTO, UserResponseDTO и т.д.
    Ответ написан
    3 комментария
  • Стоит ли бросать кастомные ошибки, если этити не найдено в API?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день!
    Наверное, это зависит от того, как вы в команде договоритесь.
    Вы можете выбрасывать кастомные эксепшены, а далее ловить их в Controller или ControllerAdvice и отдавать соответствующее сообщение на клиент с кодом ошибки.
    Также можно обернуть entity в Optional и выбрасывать исключение orElseThrow() или возвращать другой объект (orElse()) или новый объект и т.д.

    Optional<Vote> voteOptional = voteRepository.findById(voteId);
            if(voteOptional.isEmpty()) {
                throw new ApiException("Vote with id " + id  + 
                        "is not in DB");
            }

    Можно же упростить:
    Vote vote = voteRepository.findById(voteId).orElseThrow(VoteNotFoundException::new);


    Но с другой стороны, если с фронта все правильно настроено, то таких ситуаций и не должно быть.

    не нужно надеяться на клиент. Например, человек может сам совершить запрос при помощи Postman и передать некорректное значение.
    Ответ написан
    8 комментариев
  • Стоит ли учить Spring если не знаю некоторые темы?

    azerphoenix
    @azerphoenix Куратор тега Spring
    Java Software Engineer
    Добрый день.
    Все вышеперечисленное вами составляют базис языка Java. Возможно, что на начальном этапе вам не нужна многопоточность, но в любом случае знание основ java будет не лишним.

    но я не знаю такие темы как Аннотации, Коллекции, Обобщения, Многопоточность и т. д.

    Аннотации используются во всех современных библиотеках и фреймворках. Нужно знать хотя бы как они работают. В Spring, Hibernate также используются аннотации.
    Коллекции (JCF) - как по мне обязательный минимум, который нужно знать. В Spring вам придется работать с коллекциями.
    Обобщения (generics) - также достаточно широко используется, в том числе и в Спринг. Например, банальный конвертер (интерфейс Converter<S, T> и т.д.).
    До изучения Spring я бы рекомендовал вам изучить следующее:
    1) основы языка Java (все то, что вы перечислили выше).
    2) Ознакомиться с Java EE (сервлеты), глянуть на jdbc
    3) Изучить SQL (поиграться чуть с БД - MySQL, PostgreSQL и т.д.)
    4) Изучить Hibernate (ORM для работы с БД).
    5) Изучить TCP / IP. Изучить http методы (GET, POST, PUT и т.д.). Возможно, ознакомиться с сокетами.
    и только потом уже с имеющимися знаниями изучить Spring. При изучении Spring уже можно смотреть в сторону АОП и потихоньку изучить Spring AOP и т.д.
    Вот, курс по Spring Framework - https://www.youtube.com/watch?v=5ePo08sqcpk
    Курсов по Spring Boot полно. Есть неплохие на Udemy. Не лишним будет также изучение документации самого фреймворка. Также можете прочитать книгу Spring Boot in Action.

    Стоит ли мне учить Spring и доучивать эти темы вместе или сначала учить эти темы потом перейти к Spring?

    Сперва изучите эти темы, а потом уже Spring.

    https://javastudy.ru/interview/jee-spring-question...
    Ответ написан
    2 комментария
  • Как настроить бины в подпроектах без application.properties?

    azerphoenix
    @azerphoenix Куратор тега Spring
    Java Software Engineer
    Araya, как отметил коллега Ерлан Ибраев и я, стоит поднять отдельный config server (Spring Cloud Config).
    В таком случае при первом старте приложения сперва стартанет config server. Затем все остальные сервисы (eureka server, gateway и др.). Все сервисы получат конфиги из config server. Притом можно все конфиги напрямую получать из github репозитория. Для каждого из микросервисов можно создать свой properties || yml. Или же можно задать общий на всех. Можно также задать отдельные конфиги согласно активному профилю. Также при необходимости можно динамически изменять конфиги (например, при помощи Spring Cloud Bus).

    Вот, скрин, который поможет разобраться в вопросе:
    6116aa4e864f8269423104.png
    Вы можете все конфиги из всех микросервисов вынести в отдельный гит репозиторий (или же можно хранить локально. (профиль - native)). Внутри микросервисов достаточно файла bootstrap.yml или bootstrap.properties. Соответственно, все файлы конфигов вы называете именем вашего микросервиса (обратите внимание на скриншот выше).
    Ответ написан
    Комментировать
  • Где будет правильно расположить методы конвертации дто -> ентити и наоборот?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день!

    Разместить прямо в дто в каждом.

    Почему бы вам не добавить методы конвертации в сервисный слой, где вы пишете вашу бизнес логику.
    Например, у вас есть entity User & dto - UserCreationDto. В сервисном слое UserService создайте 2 метода, которые конвертируют entity < -- > dto.
    Если вы используете встроенные возможности Spring (Converter<S, T>), то для каждого entity нужно создать свой класс. Что касается расположения пакетов, то есть разные практики. Например, в пакет user закинуть User, UserCreationDto, UserRepository, UserService, UserToDtoConverter и т.д.
    Если вы никак не кастомизируете процесс конвертации, то можно написать один базовый класс с использованием generics.
    Вот, простой пример для ModelMapper:
    @Service
    @RequiredArgsConstructor
    public class MapperService {
    
      private final ModelMapper modelMapper;
    
      /**
       * Note: outClass object must have default constructor with no arguments
       *
       * @param <D> type of result object.
       * @param <T> type of source object to map from.
       * @param entity entity that needs to be mapped.
       * @param outClass class of result object.
       * @return new object of <code>outClass</code> type.
       */
      public <D, T> D map(final T entity, Class<D> outClass) {
        return modelMapper.map(entity, outClass);
      }
    
      /**
       * Note: outClass object must have default constructor with no arguments
       *
       * @param entityList list of entities that needs to be mapped
       * @param outCLass class of result list element
       * @param <D> type of objects in result list
       * @param <T> type of entity in <code>entityList</code>
       * @return list of mapped object with <code><D></code> type.
       */
      public <D, T> List<D> mapAll(final Collection<T> entityList, Class<D> outCLass) {
        return entityList.stream().map(entity -> map(entity, outCLass)).collect(Collectors.toList());
      }
    
      /**
       * Maps {@code source} to {@code destination}.
       *
       * @param source object to map from
       * @param destination object to map to
       */
      public <S, D> D map(final S source, D destination) {
        modelMapper.map(source, destination);
        return destination;
      }
    }


    Создать отдельный класс DTOUtils и все туда скинуть ( но тогда там вперемешку будут методы конвертации всех классов )

    Не самая лучшая идея. Лучше так не делать. Вспоминаем про принцип единственной ответственности. (SOLID).

    Сделать пакет dtoutils и там создать много классов ( для каждого дто свой, они будут только хранить дто методы и все )

    Все зависит от вашего проекта. Иногда наличие одного пакета может быть оправданно, а иногда нет. Важно корректно сформировать структуру проекта.

    3 вариант выглядит как самый благоразумный, но создавать отдельный класс для одного метода это как-то не очень.

    Это вот, как раз тот случай, когда вы используете интерфейс Converter<S, T>
    https://docs.spring.io/spring-framework/docs/curre...
    Если не хотите создавать по одному классу на каждый dto, то можете глянуть на код указанный выше. Может, это будет для вас полезно
    Ответ написан
    4 комментария
  • Как обработать AuthenticationException в контроллере?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день!
    Исключения можно обработать на глобальном уровне при помощи @ControllerAdvice или же обработать на уровне контроллера.
    Обратите внимание на раздел "Global Exception Handling"по ссылке ниже

    Вот, тут ссылка на полезную статью по вашему вопросу:
    https://spring.io/blog/2013/11/01/exception-handli...
    Обратите внимание на раздел - Controller Based Exception Handling @ExceptionHandler

    Вопрос заключается в том, как обработать данное исключение, чтобы получить сообщение из исключения и поместить его во вьюшку?

    Лучше не выводить внутреннее состояние (исключения) вашего приложения на фронт, так как это может потенциально нарушить безопасность вашего приложения. Поймайте исключение, а во вью поместите другое сообщение. Например, "Аутентификация не удалась"
    Ответ написан
    5 комментариев
  • Почему не происходит авторизация в Spring security?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день.
    Сделаю смелое предположение:

    Вот, тут вы разрешили отправлять запросы на url/login
    .antMatchers("/").permitAll()
        			.antMatchers("/login").permitAll()


    А тут говорите, что страницей аутентификации является /auth
    .loginPage("/auth")

    В форме вы отправляете запрос на action="@{/auth}" А отправлять запрос на указанный урл вам просто не разрешено и вы получите 403 permission denied.
    Добавьте в конфиг:
    .antMatchers("/auth").permitAll()
    Ответ написан
  • Как в rest-контроллере принимать данные формы, у которой может меняться количество полей?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день.
    Обычно, есть отдельный контроллер ответственный за загрузку файлов. Можно создать некий RestController, на который аяксом отправляются загружаемые файлы, а в ответе возвращать id файла хранимого в БД после загрузки.

    Если вы решили реализовать тем способом, которым вы сейчас это делаете, то почему бы вам не попробовать использовать модель (DTO). Создайте pojo нужной структуры, если есть обязательные поля, которые должны присутствовать, то используйте либу spring validation.

    При необходимости, используйте ModelMapper или Struts или класс Converter<S, T> для конвертации dto в entity
    Ответ написан
  • Как зарегистрировать спринговый сервис в рантайме?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Вот, наглядная статья по теме:
    https://medium.com/@venkivenki4b6/spring-dynamical...
    Обратите внимание на пункт 4
    This can be done in many ways. We will be discussing the following with examples.
    
        GenericBeanDefinition
        BeanDefinitionBuilder
        BeanFactoryPostProcessor
        BeanDefinitionRegistryPostProcessor


    Вот, еще по теме:
    https://stackoverflow.com/questions/57157396/how-t...
    Ответ написан
    Комментировать
  • Почему аннотации @PreAuthorize, @HasRole и т.д. рекомендуется устанавливать в сервисе, а не в контроллере?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день.
    Вот, тут дан довольно неплохой ответ на ваш вопрос:
    https://stackoverflow.com/questions/14626969/shoul...
    Ответ написан
    Комментировать
  • Где создать sessionFactory в Spring проекте?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день.
    В чем именно заключается проблема?
    Судя по всему у вас есть hibernate.cfg.xml, а также есть HibernateUtil.
    Можно чуть подправить этот класс на такой вариант:
    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.boot.MetadataSources;
    import org.hibernate.boot.registry.StandardServiceRegistry;
    import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
    
    public class HibernateUtil {
    
      final static StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
          .configure()
          .build();
    
      private static final SessionFactory sessionFactory;
    
      static {
        try {
          sessionFactory = new MetadataSources(registry).buildMetadata()
              .buildSessionFactory();
        } catch (Throwable ex) {
          throw new ExceptionInInitializerError(ex);
        }
      }
    
      public static Session getSession()
          throws HibernateException {
        Session session = null;
        try {
          session = sessionFactory.getCurrentSession();
        } catch (org.hibernate.HibernateException he) {
          session = sessionFactory.openSession();
        }
        return session;
      }
    
    }


    Далее используя метод getSession() получаете сессию и делаете то, что нужно.
    Например,

    Session session = HibernateUtil.getSession();
          session.beginTransaction();
          note.setTitle("Example");
          session.merge(note);
          session.getTransaction().commit();
          session.close();


    как это сделать в Spring проекте где нету main`a

    Почему это в Spring проекте нет main метода?
    Вот, туториал по Spring Framework, где указан main метод - https://www.youtube.com/watch?v=nLCYk1ySY_U
    Ответ написан
    Комментировать
  • Как работать с файловой системой в Spring Boot?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Но потом, когда я загружу проект на сервер, то там же другая файловая система, другие директории и т.д. - как с этим быть?

    Ну во-первых, как отметил коллега Dmitry Roo нужно использовать относительные пути.
    Во-вторых, у вас должны быть несколько файлов конфигурации (с разными профилями). Например, для dev upload.path будет /home/Desktop/uploads, а для prod профиля будет uploads/ и т.д.

    Во-вторых - а как быть с безопасностью? Как-то же надо фильтровать то, что мне загружают? А то скрипт какой-нибудь загрузят или ещё что-то. Как это вообще отслеживать?

    Обычно, делают проверку MIME type, как на клиентской стороне, так и на стороне сервера.

    Например, средствами js можно запретить загрузку других файлов, кроме image/* и т.д.
    Тоже самое делаю на сервере. Проверяют формат загруженного файла и если он не соответствует ожидаемому MIME type, то выбрасывают исключение и удаляют файл.

    Как отслеживать оставшееся место на диске?

    Смотря, что подразумевается в данном случае. Если хостинг, то java.nio подойдет. А если это amazon s3 или другой сервис, то смотрите документацию к REST API.
    Ответ написан
    2 комментария
  • Как запретить десериализацию поля в jackson?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    нужно , чтобы в поле result попадал json как строка. Менять ответ контроллера (например обернуть в кавычки) я не могу.

    Можно написать свой кастомный конвертер для контроллера.
    https://stackoverflow.com/questions/57536693/how-t...

    Или вы имеете ввиду:

    аннотацию JsonIgnore?
    https://www.tutorialspoint.com/jackson_annotations...
    https://stackoverflow.com/questions/12505141/only-...

    Есть еще аннотации
    https://www.baeldung.com/jackson-bidirectional-rel...
    Ответ написан
    Комментировать
  • Можно ли так использовать спринг?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Добрый день
    имеет ли смысл только для работы с бд подключать springframework

    Может быть для работы с БД стоит подключать ORM фреймворки. Например, Hibernate, EclipseLink, MyBatis, ormlite.

    По факту spring это контейнер бинов (реализация IOC & DI). Соответственно, если вы хотите использовать DI в своем приложении, то можете использовать спринг. Ну или другую либу для DI (guice, dagger etc.)

    Например, если вы пишете JavaFX приложение, то есть хорошая либа для ьыстрой интеграции спринга
    https://github.com/rgielen/javafx-weaver/

    А просто для работы с БД используйте связку hibernate + hikaricp
    Ответ написан
    6 комментариев