Задать вопрос
  • С# NPOI Word .docx Чтение Запись Редактирование?

    newross
    @newross
    Product owner
    Разбирался с NPOI по этой документации https://github.com/nissl-lab/npoi/wiki/Getting-Sta...
    Мой код тебе не поможет, могу дать пару советов:
    - не генерируй весь документ с нуля, используй шаблоны. Оставь в шаблоне плейсхолдеры типа {CustomerName} и заменяй их на нужный тебе текст
    - при копировании параграфов, строк в таблице и т.п. у NPOI течет память. Чтобы избежать этого, надо писать свои костыли
    Ответ написан
    1 комментарий
  • Парсинг (скрапинг) получение информации с сайтов, авторизация, инструменты, примеры?

    azerphoenix
    @azerphoenix Куратор тега Spring
    Java Software Engineer
    Здравствуйте!
    Начнем с простого, когда контент сайта загружается без фреймворков. Соответственно, нет никаких аяксов, не нужно никуда скроллить, чтобы получить следующую страницу или кликать на кнопки и т.д. для получения материалов. Т.е. вам достаточно отправить GET запрос на некий сайт и получить данные.
    В этом случае для парсинга будет достаточно библиотеки jsoup. Либо для своей кастомной реализации используйте DOM & SAX Parser.

    Теперь, чуть усложним задачу сайт точно также формируется без фреймворков, но для получения доступа к информации нужна авторизация. Если тут используется какая-то простая авторизация, то достаточно будет единожды получить кукисы и при каждом запросе указывать на сервер. Также не забывайте про referrer & User-agent.

    Теперь, еще усложним задачу - контент формируется динамически (посредством js-фреймворков или аякс запроса и т.д.). В этом случае jsoup не поможет, так как для загрузки контента вам нужно прокликать на кнопку (Загрузить еще) или проскроллить вниз, чтобы тригернуть загрузку контента и т.д. Т.е. вам нужна некая интерактивность. Для этого стоит посмотреть в сторону Selenium + (любой браузер). В качестве браузера можно использовать - firefox, chromium и др. Для быстродействия желательно использовать headless браузеры.

    Усложняем задачу дальше. Понадобилось авторизоваться и решить некую капчу. В часности рекапчу. Тут скажу заранее, что я сам когда-то давно искал возможные пути обхода и самое простое решение - использовать платный сервис.
    Ссылка на сайт - https://anti-captcha.com/
    После ввода имени пользователя и пароля селениум триггерит клик на капче, а дальше данные пересылаем на сервер и получаем решение капчи.

    Усложним задачу еще больше - различные honeypot. Тут как говорится кто на что горазд. Все зависит от конкретного сайта и конкретной реализации (софта) honeypot. Некоторые могут заблокировать по ip, если запрос был произведен на несуществующий урл. Например, на сайте всего 100 страниц, а вы запросили 101 страницу и попались в ловушку. Или например, вы заполнили невидимое input поле, которое в норме пользователь не видит и соответственно, не заполняет.

    Идем дальше - если вам нужна некая интерактивность (т.е. пользователь сайта должен иметь возможность самостоятельно парсить сайт), то вам нужна клиентская часть написанная на javascript. Подобные онлайн-сервисы имеются. Наберите в гугл web scraping online и увидите различные сервисы. Как правило, они предлагают установить некое расширение, при клике на котором он получает доступ к элементам DOM, а далее уже можно при помощи селекторов (id, xpath, class ) определить что нужно спарсить. Определить тип навигации / пагинации (например, пагинация при помощи нумерации страниц или пагинация при помощи кнопки Далее и др.). Тут могут свои подводные камни. Например, некоторые сайты при достижении максимальной страницы могут выдавать ошибку (404), некоторые не выдают ошибку и лишь показывают контент заново. Иногда нужно проверять страницу на наличие пустоты на странице (на отсутствие элементов по селектору). Иногда нужно проверять страницу на наличие ошибки 404 и т.д. В общем, это уже работа фронтэндера.

    Некоторые динамически формируемые страницы могут подгружать контент при помощи json или xml. Соответственно, для парсинга некоторых сайтов можно обойтись без использования selenium. А лишь запросить материалы по их внутреннему API, а затем при помощи gson или jackson спарсить их.

    Одним из универсальных инструментов парсинга, с которым мне приходилось сталкиваться была программа Visual Web Ripper. Стоит примерно 250-300 долларов. Программа подгружает контент сайта внутри себя через IE (может уже и обновили этот момент). А далее уже можно задавать условия парсинга и экспортировать данные.
    Ответ написан
    Комментировать
  • Как напимер работать с api вконтакте или другими сервисами использующими Basik Autentification?

    azerphoenix
    @azerphoenix Куратор тега Java
    Java Software Engineer
    Здравствуйте!
    Для работы с API других сайтов вы можете использовать RestTemplate.
    В статье описано, как с ним работать. Как слать POST GET и др. запросы. Как получать ответы и как этот ответ разобрать в pojo
    https://www.baeldung.com/rest-template

    Вот, например, реализованный метод для получения статуса сервиса hotelbeds
    public HttpStatus getStatus() {
            RestTemplate restTemplate = new RestTemplate();
            HttpEntity httpEntity = new HttpEntity(hotelbedsAuth.hotelsAuth());
            ResponseEntity<String> response = restTemplate.exchange(
                    hotelbedsProperties.getHotelBaseUrl()+"/status", HttpMethod.GET, httpEntity, String.class);
            return response.getStatusCode();
    }

    В общем, прочитайте про RestTemplate.

    Once the bearer token expires, you will have to use Basic Authorization again to obtain a new bearer token.

    Тут вы можете использовать CRON или аннотацию @Scheduled, чтобы по крону в заданный интервал времени запускать метод по обновлению токена

    https://www.baeldung.com/spring-scheduled-tasks
    Ответ написан
    1 комментарий
  • SQL запрос выборка из 2х таблиц?

    ThunderCat
    @ThunderCat Куратор тега MySQL
    {PHP, MySql, HTML, JS, CSS} developer
    Во первых - всегда форматируйте код, и вам легче, и ошибок меньше, и людям приятно смотреть...
    SELECT id name // выполнится, но не так как задумано, не хватает запятых
    FROM table1 
    LEFT JOIN b as // здесь все совсем плохо
    (  
               SELECT worker_id date value //тут уже даже не выполнится
               FROM table2 
               WHERE data = 'интересующая дата'  //date же!
    ) 
    ON table1.id = b.worker_id //могло бы даже работать, но выше куча ошибок
    WHERE date = 'null' // так работать не будет. date IS NULL будет, но у вас вроде нужно value проверять?

    Кроме прочего - тут должен был быть просто джоин 2 таблиц, без всяких танцев, ну и дата судя по всему должна быть в интервале, а не одно число, хотя тут уже не совсем ясно что там вообще и как хранится. Так же имена полей надо обрамлять `обратными кавычками`
    Ответ написан
    2 комментария
  • Почему не подгружаются зависимости Entity?

    @D3lphi
    Добавьте mappedBy="managers" к аннотации OneToMany.
    Ответ написан
    Комментировать
  • Как заинжектить репозиторий в другом классе?

    Maksclub
    @Maksclub
    maksfedorov.ru
    TelegramController ts = new TelegramController();

    но обратил внимание что не инжектится репозиторий, точнее при отладке его значение равно Null

    Конечно не инжектятся, вы же их в конструктор объекта, который руками создаете, не добавляете!
    Autowiring -- инструмент DI-контейнера, то есть если контроллер создается из контейнера, то он получит все зависимости. В Spring все вращается вокруг контейнера зависимостей, вы в таком случае создаете сервис, указываете зависимости, а уже контейнер собирает ваш сервис.

    Но в данном случае вы контроллер руками создали, значит все зависимсоти будьте добры ручкам и обеспечьте объекту. НО! Использовать контроллеры как сервисы изнутри других контроллеров (и любых других слоев приложения, а не фреймворка) не верно и очень путает, за все время видел тольк один такой случай для горячей подмены на время переезда.

    Если хотите переиспользовать логику:
    Логика должна быть не в другом контроллере, а в некотором сервисе (объекте), который бы вы вызывали из двух (и более) контроллеров. Тогда все бы легко и ПОНЯТНО работало бы и инжектилось.
    Ответ написан
    9 комментариев
  • Как правильно сделать авторизацию пользователя на servlet+jsp?

    @Evgeny_13
    1. Написать сервлет, который будет проверять на эдентичность userName и password, например из базы, и писать роль.
    2. Написать фильтр, который будет получать роль авторизировавшегося пользователя и запрещать переход на какие-либо страницы, делать какие-либо действия.
    3. Сделать jsp-страницу, которая будет использовать сервлет и отправлять данные!

    P.S. Не забудь зарегистрировать сервлет и фильтр в web.xml.

    1. b18b5f93b4eb4a0e988cd1e1190c139b.png
    2. a9a8d900d25348edbb04a6670f7dfbd2.png
    3. 2207cda414044a729399b22bef125fe1.png
    Ответ написан
    Комментировать
  • Передать значение в модальное окно bootstrap?

    alex-1917
    @alex-1917
    Если ответ помог, отметь решением
    shop24club.ru/api/modal1.php

    <script>
    	$('#modal_purchase_question').on('show.bs.modal', function (event) {
    		var button = $(event.relatedTarget);
    		var recipient = button.data('whatever');
    		var recipient_two = button.parents('.card').find('h3').text();
    		var modal = $(this);
    		modal.find('.modal-title').text('Заголовок: ' + recipient_two + ', дата-аттрибут: ' + recipient);
    	})
    </script>


    Гуглить вот так: bootstrap modal events
    )))
    Ответ написан
    4 комментария
  • Контрольная сумма С#?

    @none7
    Для первого набора байт подходит такой простой код:
    static byte[] crc(byte[] data) {
        ushort sum = 0;
        foreach (byte b in data)
            sum += b;
        return new byte[] {(byte)(sum & 255), (byte)(sum >> 8)};
    }

    Те есть сумма всех байтов сообщения включая код операции и длину сообщения, но без чексуммы. То есть в документации косяк чексумма считается с 0 по 4+n без -1, n длина данных для команды. Но там ведь сказано, что чексумма это «сумма байтов пакета».

    А вот собственно и полный тест:
    static ushort crc(byte[] data, ushort sum = 0) {
        foreach (byte b in data) sum += b;
        return sum;
    }
    static void Main(string[] args)
    {
        // пакеты без чексумм
        byte[] mass1 = new byte[] { 75, 0, 25, 0, 3, 48, 117, 0, 126, 37, 0, 188, 138, 169, 53, 66, 15, 52, 115, 203, 112, 103, 220, 16, 92, 237, 76, 80, 254};
        byte[] mass2 = new byte[] { 75, 0, 25, 0, 3, 64, 156, 0, 126, 37, 0, 188, 138, 169, 245, 165, 14, 52, 115, 203, 96, 64, 220, 16, 92, 237, 76, 80, 254};
        byte[] mass3 = new byte[] { 75, 0, 25, 0, 3, 80, 195, 0, 126, 37, 0, 88, 138, 169, 181, 9, 14, 52, 115, 203, 120, 60, 220, 32, 131, 237, 236, 214, 255};
        byte[] mass4 = new byte[] { 75, 0, 25, 0, 3, 112, 17, 1, 126, 37, 0, 88, 138, 169, 181, 9, 14, 52, 115, 203, 120, 60, 220, 32, 131, 237, 236, 214, 255};
        byte[] mass5 = new byte[] { 75, 0, 25, 0, 3, 60, 134, 1, 126, 37, 0, 88, 138, 169, 181, 9, 14, 52, 115, 203, 120, 60, 220, 32, 131, 237, 236, 214, 255};
    
        foreach(var mass in new byte[][] {mass1, mass2, mass3, mass4, mass5}) {
            bool first = true;
            Console.Write("{");
            foreach (var b in mass)  {
                if (!first) Console.Write(", ");
                else first = false;
    
                Console.Write(b);
            }
            var sum = BitConverter.GetBytes(crc(mass));
            // вывод чексуммы
            Console.WriteLine(", {0}, {1}}}", sum[0], sum[1]);
        }
    }
    Ответ написан
    2 комментария
  • C# com-порт получение информации, обработка старт-бита, стоп-бита?

    @vitvov
    Если я правильно понял ваш вопрос, то ваше устройство шлёт постоянно данные и вам нужно только читать.
    Все что вам нужно, это создать подключение к порту и подписаться на событие обновления. При возникновении события вы получите массив данных с порта, этот массив вы сохраняете в буфер или разбираете на лету (как вам удобнее). Напишу для вас маленький пример:
    //  Наследуем наш клас от SerialPort для более красивого кода
    public class MySerialPort : SerialPort
    {
            private const int DataSize = 54;    //  я так и не понял, какой размер данных нужен. Укажите правильное число в байтах
            private readonly byte[] _bufer = new byte[DataSize];
            private int _stepIndex;
            private bool _startRead;
    
            public MySerialPort(string port)
                : base()
            {
                //  все папаметры вы должны указать в соответствии с вашим устройством
                //base.PortName = COM1;
                base.BaudRate = 115200;
                base.DataBits = 8;
                base.StopBits = StopBits.Two;
                base.Parity = Parity.None;
                base.ReadTimeout = 1000;
    
                //  тут подписываемся на событие прихода данных в порт
                //  для вашей задачи это должно подойт идеально
                base.DataReceived += SerialPort_DataReceived;
            }
    
            //  открываем порт передав туда имя
            public void Open(string portName)
            {
                if (base.IsOpen)
                {
                    base.Close();
                }
                base.PortName = portName;
                base.Open();
            }
    
            //  эта функция вызвется каждый раз, когда в порт чтото будет передано от вашего устройства
            void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                var port = (SerialPort)sender;
                try
                {
                    //  узнаем сколько байт пришло
                    int buferSize = port.BytesToRead;
                    for (int i = 0; i < buferSize; ++i)
                    {
                        //  читаем по одному байту
                        byte bt = (byte)port.ReadByte();
                        //  если встретили начало кадра (0xFF) - начинаем запись в _bufer
                        if (0xFF == bt)
                        {
                            _stepIndex = 0;
                            _startRead = true;
                            //  раскоментировать если надо сохранять этот байт
                            //_bufer[_stepIndex] = bt;
                            //++_stepIndex;
                        }
                        //  дописываем в буфер все остальное
                        if (_startRead)
                        {
                            _bufer[_stepIndex] = bt;
                            ++_stepIndex;
                        }
                        //  когда буфер наполнлся данными
                        if (_stepIndex == DataSize && _startRead)
                        {
                            //  по идее тут должны быть все ваши данные.
    
                            //  .. что то делаем ...
                            //  var item = _bufer[7];
    
                            _startRead = false;
                        }
                    }
                }
                catch {}
            }
    }

    использовать это нужно так:
    var port = new MySerialPort();
    port.Open("COM5");

    Это код прототипа, всего лишь техника работы которая может помочь вам.
    Ответ написан
    2 комментария
  • C# com-порт получение информации, обработка старт-бита, стоп-бита?

    @Emil2014
    Я писал на С#,делал на BackgroungWorker. Грубо вырезанный кусок кода....
    private void TransferWorker_DoWork(object sender, DoWorkEventArgs e)
            {
                // переменная для снятия из очереди
                Packet pkt;
                // массив для передачи
                byte[] wr_buf = new byte[6];
                // массив для приема
                byte[] rd_buf = new byte[6];
                // цикл до отмены работы или опустошения очереди запросов
                /// TODO теперь не выходит по завершению очереди - уменьшить на переключение контекста задач
                while ((_TransferWorker.CancellationPending == false))// && (_toTransfer.Count != 0))
                {
    
    
    case Mode_transfer.Read_ADC:// Чтение данных
                                Массив data = pkt.obj as Массив;
                                // читаем АЦП
                                wr_buf[0] = Convert.ToByte('A');
                                wr_buf[1] = (byte)0;
                                // Пишем отправляеммый пакет
                                _Serial.Write(wr_buf, 0, 2);
                                // ждем пока весь пакет уйдет или запросят отбой
                                while ((_TransferWorker.CancellationPending == false) && (_Serial.BytesToWrite != 0)) ;
                                // попытка поймать заголовок
                                try
                                {
                                    int dummy = 0, lenghtReadingPacket;
                                    bool end = false;
                                    int counter =0;
                                    while (end != true){
                                        dummy = _Serial.BytesToRead;
                                        if (dummy <= 3)
                                        {
                                            System.Threading.Thread.Sleep(1);
                                            if (counter++ > _Serial.ReadTimeout)
                                            {
                                                _dataLostArgs.ErrorPreambulaLen++;
                                                throw new TimeoutException("Preambula not full!");
                                            }
                                        }
                                        else end = true;
                                    }
                                    dummy = _Serial.Read(rd_buf, 0, 3);
                                    var dummy2 = dummy;
                                    if ((dummy != 3))
                                    {
                                        _dataLostArgs.ErrorPreambulaLen++;
                                        throw new TimeoutException("Preambula not full!");
                                    }
                                    if (rd_buf[(int)ADC_Packet.Name] != 'D'){
                                        _dataLostArgs.PreambulaLost ++;   
                                        throw new TimeoutException("Data preambula lost!");
                                    }
                                    // длина пакета в словах
                                    lenghtReadingPacket = rd_buf[(int)ADC_Packet.LenghtOfPacket];
                                    byte[] rd_buf_ADC = new byte[lenghtReadingPacket * 2 + 1];
                                    end = false;
                                    counter = 0;
                                    while (end != true){
                                        dummy = _Serial.BytesToRead;
                                        if (dummy < (lenghtReadingPacket * 2 + 1))
                                        {
                                            System.Threading.Thread.Sleep(1);
                                            if (counter++ > _Serial.ReadTimeout + 100)
                                            {
                                                var dummy3 = _Serial.Read(rd_buf_ADC, 0, lenghtReadingPacket * 2 + 1);
                                                _dataLostArgs.PoorPacket++;
                                                throw new TimeoutException();
                                            }
                                        }
                                        else end = true;
                                    }
    
                                    dummy = _Serial.Read(rd_buf_ADC, 0, lenghtReadingPacket * 2 + 1);
                                    if (dummy == (lenghtReadingPacket * 2 + 1))
                                        for (Int32 i = 0; i < lenghtReadingPacket * 2 ; i += 2)
                                        {
                                            int a = rd_buf_ADC[i];
                                            int b = rd_buf_ADC[i + 1];
                                            if (a != 0 || b != 0) data.Add(rd_buf_ADC[i] * 256 + rd_buf_ADC[i + 1]);
                                        }
                                    else {
                                        _dataLostArgs.PoorPacket++;
                                        throw new TimeoutException("Not all bytes received!");
                                    }
                                }
                                catch (TimeoutException)
                                {
                                    /// TODO ПОдумать при зависании считывания АЦП 
                                    OnADCDataLost(this, _dataLostArgs);
                                }
                                finally
                                {
                                    // Чистим за собой
                                    _Serial.DiscardInBuffer();
                                    _Serial.DiscardOutBuffer();
                                }
                                break;

    Работало на пределе из-за скорости 510416 Бод на RS485. Код довольно грязный... Но смысл был в том что, первое чтение возвращало не весь пакет. Надо ВСЕГДА проверять возвращаемые значения функций чтения. И что-то делать если пакет приходит не весь и кусками. И с задержкой, ставить timeout Exception что бы не провалится в Read навсегда.
    Ответ написан
    1 комментарий
  • C# com-порт получение информации, обработка старт-бита, стоп-бита?

    gbg
    @gbg Куратор тега Программирование
    Любые ответы на любые вопросы
    Первое. Отделить мух от котлет. Есть физическая часть протокола - это скорость в бодах, стартовые - стоповые биты и четность. Этим занимается железо порта и на высокий уровень это не пролезает. От программиста требуется задать эти параметры при открытии порта -
    new SerialPort(selectedItem.ToString(), 9600, Parity.None, 416, StopBits.One);

    9600 - скорость, Parity.None - четность, StopBits.One - количество стоповых бит.
    Вот тут все нужно выставить по спецификации.
    Контроллер UART сам будет ждать стартовый бит, считать бит четности и так далее. Если честность не сойдется, программа получит ошибку чтения. Служебные биты (старт, стоп, четность) программисту не передаются.

    Теперь о шине RS485. Это полудуплексный интерфейс - одновременно можно либо передавать, либо слушать. Если ваша задача состоит только в том, чтобы слушать, у вас почти нет проблем.

    Вам нужно верно настроить порт, открыть его и читать как обычный файл. Временную буферизацию вам обеспечит ОС - то, что приходит в порт сначала попадает в небольшой буфер, а только после этого идет в приложение, поэтому с чтением особо спешить не стоит, но и растягивать удовольствие не желательно.

    Увы, на C# я не пишу (и считаю, что общаться со внешними устройствами лучше на C++, дабы приход дворника (сборщика мусора) не обломал весь недо-рилтайм), поэтому мои примеры кода вам просто так не подойдут.

    Идея такая - читаем из порта все, что в нем есть и складываем к себе в буфер. Это в идеале можно делать в отдельном потоке.
    Затем буфер нужно обработать. Это можно сделать тремя способами - регулярным выражением, конечным автоматом и "в лоб".

    Начните с написания программы, которая просто читает поток и выводит его на монитор в hex.
    Ответ написан
    1 комментарий
  • С# Массив получить из функции?

    opium
    @opium
    Просто люблю качественно работать
    Уберите преобразование ToString()
    var  UserNotMemberGroup=ServerApiParsXml.UserNotMemberGroupp(result.SelectSingleNode("response"));
    Ответ написан
    4 комментария