• Как создать разные классы под разные роли в Spring Security?

    azerphoenix
    @azerphoenix Куратор тега Java
    Я бы не создавал классы для каждой из роли, а реализовал бы следующим образом:
    1) Создать класс User. Пометить @MappedSuperclass. Вынести туда общие поля: username, password и др.
    2) Далее создать нужные классы и расширить класс User. Например, Customer, Author и др. И все поля специфичные для каждого из классов указать в них.
    3) Далее можно например, создать паттерн Builder, который при создание сущности по дефолту будет назначать соответствующие классу роли.

    P.S. Не забудьте также имплементировать интерфейс UserDetails нужный для Spring Security.
    Ответ написан
  • Как сделать exe файл java?

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

    Собственно вопрос, как решить данную проблему?

    Вот, ссылка-ответ на ваш первый вопрос
    https://stackoverflow.com/questions/50075705/jni-e...

    И возможно ли вообще перекинуть потом этот ехе файл чтобы он работал на пк без JDK?

    Вот, ссылка-ответ на ваш вопрос:
    https://eax.me/java-without-jvm/
    Ответ написан
  • Как сделать правильно ООП в телеграм боте?

    azerphoenix
    @azerphoenix Куратор тега Java
    Приветствую, коллега!
    Думаю, что тут не имеет значение тот факт, что вы пишете телеграм бота.
    Как мне кажется, вам нужно изучить ООП и паттерны проектирования.
    Я бы например, подключил бы либу для DI и создал бы сервисный слой, который уже внедрял бы в нужные места.

    Видел примеры на Spring, но сейчас для меня кор - это максимум.

    Как вариант, вы можете обойтись и без спринга пока что... Для DI можете использовать Guice или Dagger
    https://www.baeldung.com/guice


    Потом я захотел еще улучшить свой код и попробовать основные методы прокинуть через интерфейс (объявляем что будет реализовано, а не как. А в классе потом уже переопределяем) и тут я попал в ловушку. Так как обычные интерфейсы не подходят из-за статика, а статик интерфейс нельзя переопределять. И теперь я в ступоре и не знаю как выйти правильно из ситуации. Однозначно надо рефакторить код в другую сторону, но у меня нет понимания куда именно и как это сделать. Я прям вижу что у меня не объектами идет работа, а функциональщина какая-то, но в силу своих не высоких знаний не могу сам найти правильное решение.


    Ну тут можно создать интерфейс Service, а далее создать имплементацию этого сервисного слоя.
    Далее например, if statement можно упростить путем использования switch. А так кейсы свича можно группировать, то это очень удобно и наверное, более читабельно.

    Было бы неплохо изучить Spring Boot
    Ответ написан
  • Как работать с изображениями в веб-приложениях на Java?

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

    Как хранить изображение? Насколько я знаю, их можно запихивать прямо в PostgreSQL, но я склоняюсь в сторону того, что изображения надо сохранять в ресурсы, а в бд хранить только ссылки.

    Не самая лучшая идея хранить картинки в виде binary в БД. Лучше, как вы отметили в БД хранить ссылку на объект, а ресурс в файловой системе. Можно хранить файлы в распределенных файловых системах (AWS, Google), но вряд ли вы располагаете таким бюджетом.

    Вот, простая реализация хранения картинок в FS.

    Entity
    @Entity
    @Data
    @NoArgsConstructor
    @Table(name = "attachments")
    public class Attachment {
    
      @Id
      @GeneratedValue(strategy = GenerationType.SEQUENCE)
      private Long attachId;
    
      private String attachTitle;
    
      @Column(nullable = false, updatable = false)
      private LocalDate uploadDate;
    
      private String extension;
    
      private String downloadLink;
    
    }


    Repository
    @Repository
    public interface AttachmentRepository extends JpaRepository<Attachment, Long> {}


    Service
    public interface AttachmentService {
    
      /**
       * Загрузить новый файл
       *
       * @param file
       * @param user
       * @throws IOException
       */
      Attachment addAttachment(MultipartFile file, User user) throws IOException;
    
    
      /**
       * Найти Вложение по его ID
       *
       * @param attachId
       * @return
       */
      Attachment findAttachById(Long attachId);	
    
      /**
       * Скачать файл
       *
       * @param uploadYear
       * @param fileName
       * @return
       * @throws MalformedURLException
       */
      Resource loadFileAsResource(String uploadYear, String fileName) throws MalformedURLException;
    
    }


    ServiceImpl
    @Service
    @RequiredArgsConstructor
    public class AttachmentServiceImpl implements AttachmentService {
    
      private final AttachmentRepository attachmentRepository;
      private final AppProperties appProperties;
      private final FileTools fileTools;
    
      /**
       * Загрузить новый файл
       *
       * @param file
       * @param user
       * @throws IOException
       */
      @Override
      public Attachment addAttachment(MultipartFile file, User user) throws IOException {
        // Создаем директорию если ее не существует
        File uploadDir = new File(appProperties.getUploadPath());
        // Если директория uploads не существует, то создаем ее
        if (!uploadDir.exists()) {
          uploadDir.mkdirs();
        }
        String curDate = LocalDateTime.now().toString();
        // Создаем уникальное название для файла и загружаем файл
        String fileName =
            "attach_" + curDate + "_" + file.getOriginalFilename().toLowerCase().replaceAll(" ", "-");
        file.transferTo(new File(uploadDir + "/" + fileName));
        Attachment attachment = Attachment.builder()
            .attachTitle(fileName)
            .uploadDate(LocalDate.now())
            .extension(fileTools.getFileExtension(file.getOriginalFilename()))
            .downloadLink("/attachments/get/" + Year.now() + "/" + fileName)
            .build();
        attachmentRepository.save(attachment);
        return attachment;
      }
    
    
      /**
       * Найти Вложение по его ID
       *
       * @param attachId
       * @return
       */
      @Override
      public Attachment findAttachById(Long attachId) {
        return attachmentRepository
            .findById(attachId)
            .orElseThrow(() -> new AttachmentNotFoundException("Attachment not found!"));
      }
    
    
      /**
       * Скачать файл
       *
       * @param fileName
       * @return
       * @throws MalformedURLException
       */
      @Override
      public Resource loadFileAsResource( String fileName)
          throws MalformedURLException {
        Path fileStorageLocation =
            Paths.get(appProperties.getUploadPath()).toAbsolutePath().normalize();
        Path filePath = fileStorageLocation.resolve(fileName).normalize();
        return new UrlResource(filePath.toUri());
      }
    
    }


    Conroller
    @Controller
    @RequiredArgsConstructor
    @RequestMapping("/attachments")
    public class AttachmentController {
    
      private final AttachmentService attachmentService;
      private final UserService userService;
    
      /**
       * Загрузить новое вложение
       *
       * @param file
       * @return
       * @throws IOException
       */
      @PostMapping(value = "/add", produces = "application/json")
      @ResponseBody
      public ResponseEntity<Map<String, String>> uploadAttachment(
          @RequestPart(value = "file") MultipartFile file)
          throws IOException {
        Attachment attachment = attachmentService.addAttachment(file);
        Map<String, String> attachmentStatus = new HashMap<>();
        attachmentStatus.put("status", "ok");
        attachmentStatus.put("attachId", attachment.getAttachId().toString());
        return ResponseEntity.ok(attachmentStatus);
      }
    
      /**
       * Получить ссылку на скачивание загруженного файла
       *
       * @param filename
       * @param request
       * @return
       * @throws IOException
       */
      @GetMapping("/get/{filename:.+}")
      public ResponseEntity<Resource> serveFile(
           @PathVariable String filename, HttpServletRequest request)
          throws IOException {
        Resource resource = attachmentService.loadFileAsResource(filename);
        String contentType;
        contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
        if (contentType == null) {
          contentType = "application/octet-stream";
        }
        return ResponseEntity.ok()
            .contentType(MediaType.parseMediaType(contentType))
            .header(
                HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=\"" + resource.getFilename() + "\"")
            .body(resource);
      }
    }
    Ответ написан
  • Как сделать то же самое к другой роли пользователя?

    Добрый день!
    Увы, давно не занимаюсь разработкой на Wordpress.
    Замечу, что делать чат на http очень плохая идея. Лучше поднять чат на сокетах или же как вариант подключить сторонний сервис (например, jivochat).
    На ваш вопрос в силу того, что он вырван из контекста смогу ответить общими словами.
    Во-первых, вам нужно проитерировать по списку учеников, а затем выполнить для каждого из них sql запрос в БД.
    Насколько я понимаю у вас используется ACF Repeater.
    if( have_rows('ucitelya', 'user_' . $user->ID) ) {
                            while (have_rows('ucitelya', 'user_' . $user->ID)) {

    Соответственно, вам нужно создать новый repeater для учеников. Т.е. вместо ucitelya передать уже учеников.
    Далее на этом уровне тоже подправить sql запрос, чтобы он делал выборку и возвращал количество непрочитанных для каждого из учеников
    $total = $wpdb->get_row( "
                                          SELECT COUNT(id) as total
                                          FROM  `wp_school_chat`
                                          WHERE service LIKE '".get_sub_field('direction')."' AND sender = '".$user->ID."' AND recipient = '".get_current_user_id()."' AND is_read = 0
                                    ");

    В общем, надо продебажить проект. Посмотреть что возвращает каждый из ваших полей в указанном вами коде, а затем уже добавить новый функционал. Увы, со стороны сложно что-то конкретное ответить
    Ответ написан
  • Картинки на wordpress имеют такие надпись в конце ?v=1610828339?

    Здравствуйте!
    Какой-то плагин оптимизации, кеширования или сжатия изображений добавил версионирование.
    В этом нет никакой ошибки.
    Ответ написан
  • Каким способом лучше извлечь данные из БД?

    azerphoenix
    @azerphoenix Куратор тега Java
    Добрый день, коллега!
    Я бы рекомендовал работать по принципу code first, а не db first. А соответственно, подключить любую ORM библиотеку (Hibernate, MyBatis, EclipseLink) или для android (ormlite, room и др.)
    Уверен, разработка на порядок облегчится.

    Чтобы ответить на перечисленные вами вопросы стоит понять вашу изначальную цель.
    Ответ написан
  • По какому принципу Spring DataJPA обновляет записи в связанных таблицах?

    azerphoenix
    @azerphoenix Куратор тега Java
    Приветствую, коллега!
    Позволь, внести небольшую лепту в ваш код и отметить следующее:
    CrudCourseRepository

    Наверное, указывать Crud в названии не нужно, так как в репозиторий в будущем могут быть добавлены другие методы и соответственно, с точки зрения clean code название не будет корректным.

    Как JpaRepository производит обновление связей в таблице student_courses?

    Как говорится, лучше один раз увидеть, чем сто раз услышать. Так что лучше включить в properties
    spring.jpa.show-sql=true
    spring.jpa.properties.hibernate.format_sql=true


    Предположу, что вы увидите примерно следующее:
    Запрос на SELECT (выборку) из двух таблиц вместе с JOIN, а далее запрос на вставку новой записи (INSERT)

    Насколько я понимаю, если я попытаюсь обновить сущность Student, передав в CrudStudentRepository#save() студента с пустым списком курсов, то в таблице student_courses будут удалены все записи, в которых фигурирует обновляемый студент, но по моему опыту этого не происходит. Как мне тогда удалять/обновлять эти записи?

    Тут пожалуй, вам стоит обратить внимание на CascadeType.

    Например, если в связи OneToMany вы постараетесь сохранить список со стороны самой сущности, то элементы списка будут сохранены, но id у них будет null, так как сама сущность еще не сохранена и ей не присвоен идентификатор. Чтобы избежать этого можно как вариант, указать CascadeType.All или PERSIST & MERGE

    В случае с ManyToMany, думаю, что будет корректным указать тип каскада. Например, CascadeType.PERSIST CascadeType.MERGE

    К слову, есть хороший источник, откуда я также время от времени черпаю информацию. Вот ссылка - link
    Можешь глянуть.
    Ответ написан
  • Каким образом лучше создать администратора в Spring Boot проекте?

    azerphoenix
    @azerphoenix Куратор тега Java
    Приветствую, коллега!
    Да, Spring посложнее, чем Django. Но раз тебе удобно писать именно на нем, то конечно же стоит писать backend на нем.
    И да, если уж делать проект по-хорошему, то тебе нужен Spring Security. Тебе нужно создать роль ADMIN.
    Так как проект простой, то можешь использовать In-Memory Auth.
    Так как ты пишешь REST, то скорее всего тебе нужно будет реализовать jwt auth.
    Чтобы по умолчанию при старте приложения создать пользователя, можешь имплементировать интерфейс CommandLineRunner и в методе run() создать юзеров и сохранить в БД.

    P.S. БД необязательно.
    Ответ написан
  • Возможно ли работать с 3d графикой Java?

    azerphoenix
    @azerphoenix Куратор тега Java
    Приветствую!
    Да, можно.
    Можно сделать, как Василий Банников предлагает через OpenGL.
    А можно использовать игровые движки и фреймворки
    https://www.lwjgl.org/
    https://libgdx.badlogicgames.com/

    Например, библиотека VTM использует вышеперечисленные библиотеки для отрисовки карты в 3d
    https://github.com/opensciencemap/vtm
    Ответ написан
  • Как обработать следующие исключения?

    azerphoenix
    @azerphoenix Куратор тега Java
    В голову сразу приходит несколько вариантов решения задачи:
    1) Использовать Pattern и регулярку, чтобы введенные данные были корректными. Условно говоря пользователь для ФИО может ввести только буквенные символы, а для даты рождения только цифры.
    Пример, реализации подобной задачи можете посмотреть по ссылке:
    https://javatutorialhq.com/java/util/scanner-class...
    Подходит ли вам такое решение?
    Ответ написан
  • Java Spring MVC не видит представления, почему (Inteliji Idea)?

    azerphoenix
    @azerphoenix Куратор тега Java
    Приветствую, коллега!
    Я посмотрел ваш репозиторий и могу предположить следующие причины того, почему вам не удается использовать thymeleaf.
    1) У вас 2 модуля и оба модуля являются war. Соответственно, можно предположить, что вы запускаете первый модуль (firstapp), вместо второго (MVCFirstApp). А шаблонизатор thymeleaf у вас подключен во втором модуле.
    Таким образом вам нужно запустить второй модуль через Tomcat. А также рекомендую прочитать про модули maven, чтобы понять как они устроены и как работают. Например, в родительском pom.xml нужно указать packaging - pom, для модулей, которые являются библиотекой - jar, ну и для основного модуля, который содержит файлы запуска приложения - указать war или jar в зависимости от того, что вам нужно.

    2) Вторая причина того, почему вы не можете открыть страницу может заключаться в контроллере. Возможно, что вы пытаетесь открыть шаблон через базовый URL (/), а метод, для которого назначен шаблон - /hello-world
    Сниппет вашего кода?:
    @Controller
    @RequestMapping("/")
    public class HelloController {
    
        @GetMapping("/hello-world")
        public String sayHello() {
            return "hello_world";
        }
    }


    Таким образом, исходя из текущего проекта, вам достаточно запустить второй модуль через томкат и открыть урл /hello-world, чтобы открыть нужный шаблон
    Ответ написан
  • Почему пишет No suitable driver?

    azerphoenix
    @azerphoenix Куратор тега Java
    Приветствую, коллега!
    Если не ошибаюсь, то это уже чуть ли не 5-й аккаунт, с которого вы задаете однообразные вопросы. Один из ваших аккаунтов уже администрация заблокировала.

    Мои рекомендации на то, чтобы вы изучили основы программирования, ООП, основы Java разработки, видимо, тоже были проигнорированы.

    Поймите меня правильно, сперва стоит изучить основы программирования, а потом уже лезть в android разработку.
    К слову, вот все ваши аккаунты, с которых вы СПАМите QnA.
    https://qna.habr.com/user/Alik_Kolizeev
    https://qna.habr.com/user/Java_Python
    https://qna.habr.com/user/xxxfdd
    https://qna.habr.com/user/new_year2021
    https://qna.habr.com/user/timyr_murmur

    Вот. однотипные вопросы с разных аккаунтов:
    Почему пишет No suitable driver?
    String SQL = "INSERT INTO gps_coordinat" + "(class) " + "VALUES" + "(" +  location.getLatitude() + ")";
                System.out.println("УСПЕХ");


    В чём заключается ошибка?
    String SQL = "INSERT INTO gps_coordinat (class)" + (GPS );


    Хочу зпомнить данные с моего андроид приложение в таблицу Postgresql но выдает ошибку в чём дело?
    String SQL = "INSERT INTO gps_coordinat" + "(class) " + "VALUES" + "(" +  location.getLatitude() + ")";

    Настоятельно рекомендую научится гуглить и читать информацию на русском или английском, прежде чем обращаться на сервис и задавать столь простые однообразные вопросы раз за разом

    Не могу вывести ошибку в своем аднрод приложении почему?
    catch (Exception e){
                System.out.print(e);
                tvLocationGPS.setText(e);
    Ответ написан
  • Хочу зпомнить данные с моего андроид приложение в таблицу Postgresql но выдает ошибку в чём дело?

    azerphoenix
    @azerphoenix Куратор тега Java
    Скажу заранее это плохая идея.
    вам не нужно напрямую обращаться к БД из андроид.
    Для этого пишут бекенд (Rest сервис) и через api обращаются к бд
    Ответ написан
  • Как получать котировки акций на Java?

    azerphoenix
    @azerphoenix Куратор тега Java
    Вот, простой пример совершения http запроса и парсинга данных из xml (DOM Parser) для валют
    https://github.com/azerphoenix/cbar-currency
    Котировки акций по такой же аналогии делаются
    Ответ написан
  • Как настроить WebSecurityConfig правильно?

    azerphoenix
    @azerphoenix Куратор тега Java
    Приветствую!
    1)
    Хочу сделать чтоб вход на страницы админа /adminPageProduct /adminPageUser

    наверное, лучше сделать общий префикс для админ панели, что-то типа /admin/** и на этом уровне ограничивать доступ, чем перечислять каждую ссылку в настройках конфигурации. А урл делать следующей структуры:/admin/products /admin/users. Вам же в любом случае нужно закрыть доступ ко всей админке

    Мне кажется, что проблема у вас может быть тут:
    .antMatchers("/admin*")
    Других явных проблем не вижу, если все остальное настроено корректно
    Ответ написан
  • Как передать значение с андроид приложения на сервер?

    Первый вопрос: как с андроид приложения передать на сервер

    Если у вас появился подобный вопрос, то значит, что ваше приложение является клиент-серверным.
    В качестве клиента выступает - андроид устройство
    В качестве сервера - удаленное серверное ПО.
    Тут важный момент - у вас на данный момент как минимум нет серверной части. Т.е. REST приложение, которое работает на сервере и позволяет обращаться к его эндпоинтам (методам контроллера) для получения или передачи той или иной информации.
    Т.е вам нужно для начала создать это приложение. Если на java, то смотрите в сторону Jakarta EE, Spring, Play. Или любой другой фреймворк, который вам может подойти.
    Второй вопрос на какие сервера вообще можно предать значения?

    Чувствуется, что вы не владеете основами веба, иначе подобный вопрос не звучал бы. Передать значение можно на сервер, которым владеете / арендуете. Это может быть и облачное хранилище - AWS, Google Cloud, Heroku, а может быть какой-нибудь простенький VPS (например, hetzner.com за 3-4 евро в месяц).
    К слову, в качестве сервера, чтобы просто поиграться может выступать и ваш компьютер, который подключен к сети. Достаточно создать rest приложение и сделать его доступным миру. А может быть, вам и не нужен никакой сервер... например, если приложение для личного пользования и вам нужно с телефона просто передать данные, чтобы они оказались на компе, то как вариант можете использовать API Яндекс Диска или Гугл Диска. Закачиваете ваши данные туда, а далее на своем компьютере синхронизируете их.

    В общем, разные цели, разные реализации...
    Ответ написан
  • Остается ли Java все еще актуальной для разработки под Андроид?

    azerphoenix
    @azerphoenix Куратор тега Java
    Хотите стать android разработчиком - изучите kotlin
    Будет огромным плюсом, если вы изучите Java, чтобы например, при изучении какой-либо библиотеки иметь представление о том, что в ней написано.
    Впрочем, вы в дальнейшем сможете переключиться с одного языка на другой, если что-то пойдет не так.

    Можно ли разрабатывать на Java android приложения? Да, можно.
    Ответ написан