Author Archive

Установка PostgreSQL из исходников на Ubuntu 16.04

Склонируйте репозиторий PostgreSQL

git clone https://github.com/postgres/postgres.git

После окончания загрузки файлов перейдите в созданную директорию

cd postgres

Переключитесь на ветку REL_10_STABLE

git checkout REL_10_STABLE

Перед непосредственно сборкой проект нужно установить вспомогательно ПО.

sudo apt-get install libreadline-dev
sudo apt-get install bison
sudo apt-get install flex

Сконфигурируйте проект

./configure

Соберите проект

make

Установить postgres

sudo make install

Переключитесь в режим супер-пользователя:

sudo su

Добавьте нового пользователя postgres:

adduser postgres

Задайте пароль для пользователя postgres:

passwd postgres

Создайте директорию для данных postgres:

mkdir /usr/local/pgsql/data

Поменяйте владельца и группу для директории:

chown postgres:postgres /usr/local/pgsql/data

Далее поменяйте пользователя на postgres:

su - postgres

Проинициализируйте новый кластер баз данных:

/usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data/

Установка Kubuntu c установочной флешки

Делаем на Kubuntu установочную флешку для установки Kubuntu (простите за тавтологию).
Для начала устанавливаем UNetbootin на странице https://unetbootin.github.io/linux_download.html можно его скачать, там же есть инструкция по установке.
Вот так выглядит главное окно программы:

Записываемый на флешку образ можно скачать либо по сети, либо выбрать iso на вашем компьютере.

Первая проблема, которую можно поймать:
/dev/sdb1 не смонтирован

Необходимо сначала примонтировать USB-накопитель /dev/sdb1 к точке монтирования. 
Большинство дистрибутивов делают это автоматически после переподключения USB-накопителя.

По началу я думал, что надо что-то примонтировать или перемонтировать, но оказалось все проще. После того как вы вставите флешку в компьютер / ноутбук, нужно открыть ее содержимое и она примонтируется.

Также, желательно, чтобы в названии флешки были только латинские буквы.

После того, как вы успешно записали флешку, вставили ее компьютер, отключили в BIOS режим UEFI, можете поймать ошибку

(initramfs) Unable to find a medium containing a live file system

Проблема заключается в использовании USB 3.0.
У меня на ноутбуке HP все три USB-порта версии 3.0.
Советуют в BIOS отключить поддержку 3.0 в пользу 2.0.
Но на этом ноуте нет такой опции в BIOS.
А флешка у меня 16 GB USB 3.0.

С флеш-картой USB 2.0 загружался установщик, но где-то посередите он падал с ошибкой.

В конце концов записал ISO на компакт-диск и установил с переносного DVD-ROM.

Target lists can have at most 1664 entries в PostgreSQL

Давно не писал… На прошлой неделе поймал такую ошибку:

ERROR: target lists can have at most 1664 entries

Данная ошибка возникла из-за того, что появилось много зависимостей между сущностями(Entity).
Когда идет запрос данных через Hibernate, то JOIN’ится много таблиц, и общее количество получаемых полей начинает превышать 1664. В нашем случае это было около 1700 полей. Такое разумное ограничение есть у PostgreSQL.
Решить можно такими путями:
1) Переписать запросы, взяв только используемые поля;
2) Сделать некоторые поля Lazy.
Скорее всего, такая проблема и у вас решится вторым путем.

Удаление числа из строки

Иногда мы пользуемся трюком, сохраняя числа (ID из базы данных) в строке через запятую.
Например: «1024,15,8,0,55».
И теперь, допустим, какое-то число из этого списка не нужно, и его необходимо убрать из исходной строки. Как это реализовать?

Первый вариант:
1) разбить строку по запятой
2) отфильтровать удаляемое число
3) собрать строку заново

Второй вариант (допустим, удаляем число 55):
1) вырезать из строки подстроки вида: ,55,
2) удаляем подстроки вида 55, и ,55

Реализация 1-го варианта (Java):

String val = "55";
String collect = Arrays.stream(
        "55,1024,55,15,8,0,55".split(","))
        .filter(v -> !v.equals(val))
        .collect(Collectors.joining(","));
System.out.println(collect);//1024,15,8,0

Реализация 2-го варианта (Java):

int del = 55;
String result = "55,1024,55,15,8,0,55"
        .replaceAll("," + del + ",", ",")
        .replaceAll(",?" + del + ",?", "");
System.out.println(result);//1024,15,8,0

Некоторые вещи про закачку файлов

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

  • Можно загружать файлы не только в виде байт, но и формате base64.
  • Файл загружается на веб-сервер и сохраняется как временный файл
  • При передаче файла на сервер используется кодирование multipart/form-data
  • Из временного файла можно получить оригинальное название файла, байты файла, тип содержимого(ContentType), размер.
  • На основе байтов можно рассчитать хэш. Например, алгоритмом MD5, SHA-1 или SHA-256.
  • Хэш файла может пригодиться при отдаче файла, чтобы проверить целостность.
  • При отдаче файла следует указать HTTP-заголовок Content-Disposition. Параметр inline сообщает браузеру, что файл можно открыть непосредственно в браузере, если конечно позволяет тип файла. Параметр attachment сообщает, что файл должен скачиваться. Также в Content-Disposition передается наименование файла, которое лучше кодировать с помощью URL Encoding.
  • Если в браузере вы хотите отобрать процесс загрузки файла, например, в процентах, то проще всего это сделать через javascript, который может отслеживать кол-во отправленных байтов.

Бинарный алгоритм вычисления НОД

Наибольшим общим делителем (НОД) для двух целых чисел называется наибольший из их общих делителей.
Например: для чисел 8 и 12 наибольший общий делитель равен 4.

Ранее мы уже рассматривали нахождение НОД с помощью Алгоритма Евклида:

long gcd(long a,long b){
	return b == 0 ? a : gcd(b,a % b);		
}

Сейчас рассмотрим Бинарный алгоритм Евклида, который быстрее обычного алгоритма Евклида.
Бинарный алгоритм основан на следующих свойствах НОД:

НОД(2m, 2n) = 2 НОД(m, n),
НОД(2m, 2n+1) = НОД(m, 2n+1),
НОД(-m, n) = НОД(m, n)

Теперь реализуем этот алгоритм на Java:

static int gcd(int m, int n){
    if(m == 0) return n;
    if(n == 0) return m;
    if(n == m) return n;
    if(m == 1) return 1;
    if(n == 1) return 1;
    boolean em = (m & 1) == 0;
    boolean en = (n & 1) == 0;
    if(em && en) return gcd(m >> 1, n >> 1) << 1;
    if(em) return gcd(m >> 1, n);
    if(en) return gcd(m, n >> 1);
    if(n > m) return gcd((n - m) >> 1, m);
    return gcd((m - n) >> 1, n);
}

Для ускорения деления на два используется сдвиг битов на позицию вправо(>> 1), для умножения на два используется сдвиг на позицию влево (<< 1). Проверка четности числа осуществляется проверкой последнего бита числа (m & 1), если выражение равно 0, то число четно, иначе нечетно.

Как из Java обратиться к сервису по протоколу HTTPS

Это юбилейная 100-я статья!!!

Уже не знаю в какой раз приходится обращаться к сервису по протоколу HTTPS, и каждый раз уходит время, чтобы воспроизвести шаги. Сегодня решил все-таки написать шпаргалку и больше не тратить время на такую проблему.

Для начала открываем сайт в браузере:

В адресной строке браузера рядом с текстом https:// есть иконка, нажав на которую появится возможность просмотреть / скачать / экспортировать сертификат.
Нужно экспортировать сертификат в файл test.crt

Файл будет иметь примерно такое содержание:

-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIUGyZeQnd4LMFso5FQwrzjHmrNWVswDQYJKoZIhvcNAQEF
utCwINC/0L7QtNC70LjQvdC90L7RgdGC0Lgg0YHQtdGA0LLQtdGA0LAwMgYDVR0f
KqOTBEhH50jwo6WaQIUrD54ElD5gVO3VIT+eAMZm0HzXF+NKpkNaiR1b
-----END CERTIFICATE-----

Далее необходимо выполнить следующую команду:

sudo keytool -import -alias yourname -file test.crt
 -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

-alias — произвольное уникальное название
-file — путь к файлу
-keystore — путь к хранилищу сертификатов Java
$JAVA_HOME — путь к домашней директории Java, которую вы используете для запуска вашего приложения
-storepass — пароль к хранилищу, по умолчанию changeit

Получение содержимого текстового файла (Spring Boot)

Вот уже несколько месяцев последние два проекта делаю с использованием Spring Boot.
Бывает так, что нужно интегрироваться с внешней системой, но эта система не готова по каким-то причинам, а нужно показать свой функционал, в этом случае пишем заглушку. Т.к. в моем случае внешний сервис давал данные в формате JSON, я решил положить пример ответа сервиса в ресурсы (resource) по пути files/cities.json.

Далее встал вопрос как его вытянуть. Погуглил, в итоге собрал такую функцию (сперва получаем контекст приложения, из которого получаем ресурс):

private static String getFileContent(String filePath) throws IOException {
    ApplicationContext appContext =
        new ClassPathXmlApplicationContext(new String[] {});
 
    Resource resource = appContext.getResource(filePath);
 
    StringBuilder sb = new StringBuilder();
    BufferedReader br = null;
    try{
        br = new BufferedReader(
            new InputStreamReader(resource.getInputStream(), "UTF-8"));
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
    }finally {
        if(br != null) try {
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return sb.toString();
}

Пример вызова функции:

try {
    String text = getFileContent("files/cities.json");
} catch (IOException e) {
    e.printStackTrace();
}

Я использовал чтение файла для временной заглушки, но можно использовать и для других целей.
p.s. Обратите внимание, что в функции указана кодировка UTF-8. Можно её не указывать, тогда возьмется кодировка системы. Кодировку можно указать и при запуске приложения:

java -Dfile.encoding=UTF8

Совет: лучше в функции явно прописать UTF-8, если, конечно, она вам нужна.

Замер времени (Java)

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

long start = System.currentTimeMillis();
//тут замеряемый код
System.out.println(System.currentTimeMillis() - start);

Но такой подход быстро надоедает. Я выделил замер времени в отдельный класс TimeMeter, теперь можно удобно останавливать несколько раз таймер и измерять время, если нужно измерить промежуточные значения. Можно также использовать несколько экземпляров таймера.
Реализация:

public class TimeMeter {
    private long start;
	private long stop;
 
    public TimeMeter(){
        start = now();
    }
 
    public void stop(){
        stop = now();
    }
 
    @Override
    public String toString() {
        return getDuration() + " msec";
    }
 
    public long getDuration(){
        return (stop == 0 ? now() : stop) - start;
    }
 
    private long now(){
        return System.currentTimeMillis();
    }
}

Самый простой вариант использования:

TimeMeter timeMeter = new TimeMeter();
//тут замеряемый код
System.out.println(timeMeter);

Таймер с несколькими остановками и замерами времени:

TimeMeter timeMeter = new TimeMeter();
//тут замеряемый код 1
timeMeter.stop();
System.out.println(timeMeter);
//тут замеряемый код 2
timeMeter.stop();
System.out.println(timeMeter);

Глобальный и внутренние таймеры:

TimeMeter totalTimeMeter = new TimeMeter();
for (int i = 0; i < 100; i++) {
    TimeMeter timeMeter = new TimeMeter();
    //тут замеряемый код
    System.out.println("time " + i + ": " + timeMeter);
}
System.out.println("total time: " + totalTimeMeter);

p.s. Можете придумать и сделать свою версию, здесь простор для творчества.

$(…).size is not a function

Второй раз за последние месяцы прикручиваю тему Metronic и ловлю такую ошибку:

$(...).size is not a function

В первый раз я потратил достаточно времени, чтобы понять в чем причина, а во второй раз было дело техники.

Всё дело в том, что Metronic использует 1-ю версию jQuery (v1.12.4), а в проекте bower брал последную 3-ю версию jQuery (v3.1.0).
В 3-ей версии почему-то убрали эту функцию.

Все решается использованием 1-й версии jQuery. В bower.json я исправил версию так:

"jquery": "1.12.4"