вторник, 30 июля 2024 г.

Spring Cloud Gateway

Предположим мы хотим обращаться к нескольким API/нескольким сервисам через одну точку. Для этого мы поднимаем еще один сервис (микросервисная архитектура) и этот сервис будет у нас принимать запросы и перенаправлять их куда надо. Для этого мы создаем приложение Spring Boot и добавляем к нему в зависимости

implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
Далее нам нужно в конфиге прописать маршруты.

spring:
  cloud:
    gateway:
      routes:
        - id: ya
          uri: http://ya.ru
          predicates:
            - Path=/ya/**
          filters:
            - StripPrefix=1
        - id: employees
          uri: http://localhost:8081
          predicates:
            - Path=/employees/**
          filters:
            - StripPrefix=1
Для примера. В результате у нас по адресу localhost:8080/ya будет ya.ru а по адресу localhost:8080/employees будет сервис employees запущенный на 8081 порту (имеется в виду что наш сервис cloud gateway запущен на 8080-м порту). StripPrefix=1 значит убрать первую часть url. Далее все запросы соответствующие предикату перенапрявлются на uri. Мы можем запусть Eureka и разрешать наши сервисы через нее. Для этого нам нужно uri в конфиге маршрутов задавать в таком виде:

	uri: lb://employee-service
Тут указывается название под которым сервис зарегистрирован в Еврике. Так же мы можем посмотреть список зарегестрированных маршрутов через actuator. Для это в конфиг приложения нам надо добавить:

management:
  endpoint:
    gateway:
      enabled=true
  endpoints:
    web:
      exposure:
        include: "*"
И тогда по адресу localhost:8080/actuator/gateway/routes у нас будет информация о маршрутах.

воскресенье, 28 июля 2024 г.

Feign Client и Eureka

Например у нас есть скажем две какие-то сущности в нашей системе, которые хранятся в своих репозитариях и с которыми происходят какие-то процессы. В микросервисной архитектуре мы можем раскидать их два сервиса! Предположим что нам это зачем-то нужно. Например у нас есть два сервиса 1) employee-service который содержит в себе информацию о работниках и 2) organization-service который содержит информацию об организациях. Но у нас в организации есть сотрудники и соответственно второй сервис может получать информацию из первого. Для этого мы можем из второго сервиса вызывать первый например через Spring RestTemplate. Но есть и вариант еще лучше и проще. Это декларативное описание API с помощью Feign.

@FeignClient(name = "employee-service")
public interface EmployeeClient {

	@GetMapping("/organization/{organizationId}")
	List findByOrganization(@PathVariable("organizationId") Long organizationId);
	
}
Вот таким простым образом мы из organization-service можем использовать emplyee-service. Но как organization-service узнает где находится employee-service? Ведь даже если они на одной машине, порты могут быть разные. Или вообще может выбираться рандомный свободный порт. Тут у нас на сцену выходит еще один, третий сервис, ведь у нас же микросервисная архитектура. Это discovery-service, еще одно spring-boot приложение. Создать его проще простого, вот так:

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryApplication {

	public static void main(String[] args) {
		new SpringApplicationBuilder(DiscoveryApplication.class).run(args);
	}

}
. Да для dicsovery-service мы будем использовать Eurekу. Теперь мы можем запусть эвкрику скажем на 8061 порту, потом зайти и глянуть какие же сервисы там зарегистрированы (Instances currently registered with Eureka). Теперь нам нужно чтобы наши сервисы регистрировались в Eureke и тогда они без проблем будут общаться друг с другом даже если будут постоянно перезжать по разным аддресам. Для этого нужно всего лишь добавить евкрика-клиент в зависимости вот так:

implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
. И прописать в конфиги наших сервисов как они будут подключаться к еврике, вот так:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8061/eureka/
  instance:
    instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
.

четверг, 25 июля 2024 г.

Spring Cloud Config

Spring Cloud Config. Вот есть у вас преположим spring сервис. Когда вы его запускаете, он запускается по умолчанию на порту 8080, но вы можете это катомизировать с помошью секции server.port в конфиге. С одной стороны хорошо но с другой стороны каждый раз менять там неудобно особенно если сервер этот нужно запускать в разных местах и конфиг для этих мест должен быть разным. Очевидное решение: каждое из этих мест должно хранить настройки само в себе и ваш сервис при старте должен их подхватывать. Для этого например можно поднять еще один сервис в каждом месте который и будет раздавать этот конфиг. Таким образом мы отделяем изменение конфига от изменения основного сервиса/приложения со всеми вытекающими плюсами. Ну и минус в том что теперь у нас еще по одному сервису/приложению дополнительному которое будет просто раздавать конфиг. Для этого в нашем сервисе-клиенте конфиг сервера в конфиге application.yml прописываем что он ожидает наличия конфиг- сервиса:
 spring:  
  application:  
   name: employee-service  
  config:  
   import: "optional:configserver:http://localhost:8088"  
Здесь optional означает что если сервис конфига он не подхватит то это не повод прекращать работу. Далее таким вот нехитрым способом создаем конфиг-сервис:
 @SpringBootApplication  
 @EnableConfigServer  
 public class ConfigApplication {  
      public static void main(String[] args) {  
           new SpringApplicationBuilder(ConfigApplication.class).run(args);  
      }  
 }  
Сами конфиги собственно у нас хранятся в папке resources/config нашего конфиг сервиса. Поскольку у нас приложение называется employee-service у нас конфиг должен называться employee-service.yml. Там мы добавляем точно так же
 server:  
  port: 8290  
например. Теперь сперва стартанем конфиг-сервис, потом наш employee-service и о чудо, порт теперь у нас 8290 на котором сервис стартует.

понедельник, 5 июня 2017 г.


Privacy policy


​
    We don't receive your phone number, contacts or sms text. All this information never leaks your phone through our application.

    We don't sell any content.

    We don't requier registration.

    Your privacy is not affected in any way.

    We don't require any information and never send it anywhere, application reads phone contacts only to assist you in phone typing.

    We don't show any adds in application.

вторник, 22 июля 2014 г.

Типы приложений вконтакте.

Оказывается есть OpenAPI для сайтов, но не для iframe приложений. Для iframe приложений отдельный раздел документации и OpenAPI для них не подходит. А то можно перепутать и долго удивляться что идет не так.

вторник, 15 июля 2014 г.

Standalone приложения вконтакте. Хранимые процедуры.

Для создания надо код подтверждения на мобильник получить. Потом с помощью этого кода приложение активируется и с помощью get запроса по специально сформированному url получаем еще 2 "секрета" access_token и user_id. Есть там еще такая фишка как хранимые процедуры. Насколько я понял это server side запросы к базе vk. (Для снижения трафика делать обработку данных на сервере). Пишутся они почему то на javascript. Вот например запрос возвращающий фамилии людей разместивших на своих страничках композиции появляющиеся на первых трех строчках в поиске по запросу "Beatles":return API.users.get({"user_ids": API.audio.search({"q":"Beatles", "count":3}).items@.owner_id})@.last_name;

четверг, 1 ноября 2012 г.

Как вернуть строку из unamanaged кода C#.

Предположим есть С++'овская функция возвращающая std::string. Квест : вызвать эту функцию из С# так чтобы это все работало и не падало. Делать так:

const char* __stdcall функцияОберткаС++( ... )
{

    const std::string ret_str = функцияС++API( ... );

    char* pszReturn = NULL;

    // Это заклинание тут необходимо, обычный С++ new не работает (ошибка)
    pszReturn = (char*)::CoTaskMemAlloc( ret_str.length() + 1 );
    strcpy(pszReturn, ret_str.c_str());
    return pszReturn;
}

В C# делаем описываем интерфейс:

[DllImport("библиотека.dll", CharSet = CharSet.None)]
[return: MarshalAs(UnmanagedType.LPStr)]     
public static extern string функцияОберткаС++( ... );

Вот так вроде работает.


четверг, 9 августа 2012 г.

Макрос Q_OBJECT и объявления слотов.

Когда долго не кодишь на Qt забываешь про эти вещи. Вот только что чуть ли не час мучался с сообщением Object::connect: No such slot QDialog::registrationComplete() Object::connect:  (receiver name: 'Dialog'). И все никак не мог понять с чего это слот ищется в QDialog а не в моем унаследованном классе диалога, где он есть. А все дело в том что я забыл написать Q_OBJECT в заголовочном файле класса. И соответственно он и брал QDialog - родительский класс моего класса где макрос Q_OBJECT написан.

среда, 11 апреля 2012 г.

Генерация Java классов из XSD схем с помощью xjc и Maven.

Существуют несколько плагинов для Maven для работы с xjc. После довольно продолжительного гугления выбрал в итоге jaxb2-maven-plugin. Вроде бы все хорошо, нормальный сайт: http://java.net/projects/maven-jaxb2-plugin/pages/Home, развивается, в общем выбрал данный плагин. Оказалось что в моих xsd схемах (которые являются схемами электронной формы налоговой отчетности) в каждом файле есть корневой элемент Файл. Естественно при генерации - коллизия имен, получаются классы с одинакоы именем Файл. Выход - разнести по разным пакетам. У плагинов есть понятие execution, пришлось делать для каждого пакета по экзекьшену. Для каждого экзекьюшена в конфиге указать выходной пакет, <clearOutputDir>false</clearOutputDir> (причем в документации на оф. сайте про данный параметр не написано), да еще и некий <staleFile>, что это такое я в итоге так и не понял, написал просто разные для всех. Вот например такой .pom файл должен получиться:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.rusnalog</groupId>
  <artifactId>rusnaloglib</artifactId>
  <version>0.0.2-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>rusnaloglib</name>
  <url>http://maven.apache.org</url>

  <dependencies>
  <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.0</version>
  <scope>test</scope>
  </dependency>
  <dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.0</version>
</dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.0.3</version>
    </dependency>
  </dependencies>


  <repositories>
<repository>
<id>java.net</id>
<name>java.net Maven Repository</name>
<url>https://maven-repository.dev.java.net/nonav/repository</url>
</repository>
  </repositories>
  <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>jaxb2-maven-plugin</artifactId>
                <version>1.3.1</version>
                <executions>
                    <execution>
                        <id>no_trand</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
                        <phase>
                        generate-sources
                        </phase>
                        <configuration>
                     <packageName>com.rusnaloglib.generated.NO_TRAND</packageName>
                         <schemaDirectory>${basedir}/src/main/xsd/NBO/NO_TRAND</schemaDirectory>
                         <schemaIncludes>
<schemaInclude>*.xsd</schemaInclude>
</schemaIncludes>
<staleFile>${build.directory}/generated-sources/.jaxb-staleFlag-trand</staleFile>
<clearOutputDir>false</clearOutputDir>
                </configuration>
                    </execution>
                    <execution>
                        <id>ndfl2</id>
                        <goals>
                            <goal>xjc</goal>
                        </goals>
<phase>
                        generate-sources
                        </phase>
                     
                        <configuration>
                     <packageName>com.rusnaloglib.generated.NDFL2</packageName>
                    <schemaDirectory>${basedir}/src/main/xsd/NBO/NDFL2</schemaDirectory>
                    <schemaIncludes>
<schemaInclude>*.xsd</schemaInclude>
</schemaIncludes>
<staleFile>${build.directory}/generated-sources/.jaxb-staleFlag-ndfl2</staleFile>
<clearOutputDir>false</clearOutputDir>
                </configuration>
                    </execution>
               </executions>
           </plugin>
       </plugins>
   </build>
</project>

Причем как видно пока для выбора схем указал просто *.xsd,  в дальнейшем надо будет указать файлы либо вовсе убрать эту строку, так как если нужны все файлы в директории то достаточно просто указать директорию (<schemaDirectory>).

пятница, 21 октября 2011 г.

Шифрование публичным ключом.

В данном способе шифрования используются 2 ключа. Публичный ключ передается дешифрующей стороне, а приватный остается у того кто шифрует. Данные ключи к шифру таковы что сообщение зашифрованное пппубличным ключом однозначно расшифровывается с помощью приватного. При этом имея публичный ключ невозможно определить приватный. Таким образом при переписке я беру публичный ключ адресата, шифрую сообщение и посылаю ему. Он делает тоже самое. На практике приходится использовать еще систему подтверждения подлинности публичных ключей. Для этого нужна третья сторона, которой доверяют оба участника переписки.
При это переписка может призводится например следующим образом:
1) Разрешающая сторона выдает всем участникам свой публичный ключ.
2) Я скачиваю запрашиваю сертификат у разрешающей стороны посылая ей свой публичный ключ.
3) Разрешающая сторона изготавливает для меня сертификат следующим образом : делает хеш моего публичного ключа и шифрует его своим приватным ключом и присоединяет это к моему публичному ключу.
4) Мой адресат получает сертификат содержащий мой публичный ключ и его зашифрованный хеш. С помощью публичного ключа разрешающей стороны расшифровывает хеш, делает второй хеш из моего публичного ключа и сравнивает их. Если они совпадают, то оба ключа мои и все ок.
5) Теперь он может зашифровать свое сообщение моим публичным ключом и послать мне, зная что его смогу расшифровать я и никто другой.
Таким образом злоумышленник не знающий приватного ключа сервера не сможет выдать свой публичный ключ за мой.

среда, 7 сентября 2011 г.

Как в QTableView/QTableWidget нарисовать в клетке галочки?

Есть официальный способ. достаточно удобный. Все что Вам нужно - создать класс производный от QStyledItemDelegate переопределив там метод void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index). QPainter - стандартный объект для рисования, из option получаем палитру и прямоугольник рисования (можно будет вызвать painter->translate() чтобы туда перейти и отсчитывать координаты от границ данного прямоугольника при рисовании, в случае с таблицей так и надо сделать) а index - индекс модели (ряд, столбец таблицы) - Вам ведь не во всех клетках нужно галочки рисовать, для остальных просто вызовем метод базового класса.

пятница, 26 августа 2011 г.

Исключения в С++ : по ссылке, копией или по указателю?

Исключение в С++ можно бросить 2-мя способами:
  1. throw MyException();
  2. throw new MyException();
А поймать потом 3-мя:
  1. catch( MyException  ) {}
  2. catch( const MyException& ) {}
  3. catch( MyException* ){}
Ну конечно объект может быть константным а ссылка неконстантной. Ну ладно. Суть в том что 3-ий catch ловит 2-ой throw, а 1-ый и 2-ой ловят 1-ый throw. Из двух последних предпочтительней 2-ой вариант потому что он не делает копии. Ловить надо тоже самое что и бросал иначе не поймаешь. Вариант с броском указателя вызывает проблемы с освобождением памяти которое нужно или не нужно делать в блоке catch в зависимости от того указывает ли указатель на объект размещенный в куче с помощью вызова new или нет. Поэтому самый лучший вариант - ловить по ссылке.


понедельник, 15 августа 2011 г.

Виртуальные функции в Jаva и С++.

То есть конечно же в Java нет никаких виртуальных функций. Все функции (или если следовать ООП терминологии методы) в Java имеют позднее связывание если вы явно не укажите их как final или private. Это значит что вы просто переопределяете их производных классах и получаете тот же эффект который дают виртуальные функции C++. Тот же да не тот. Я пока знаю по крайней один случай при котором виртуальные функции С++ и обычные методы Java дают разный эффект. Это если вы будете вызывать функцию которая переопределена в производном классе в конструкторе или деструкторе базового класса. То есть конечно же делать этого не в коем случае не стоит, в обоих случаях Вас ждут неприятные сюрпризы. Так что же будет происходить? В Java тип объекта во время выполнения известен и будет вызываться метод производного класса при том что инициализация объекта производного класса еще не произведена. При обращении к полям-примитивам они будут иметь значения по умолчанию, а ссылки - null. Вобщем либо неправильное поведение, либо исключение. В С++ виртуальные функции работают как известно даже при отсутствии точной информации о  типе, потому что адреса виртуальных функций находятся  в специальной таблице указатель  на которую хранит в себе объект. При работе конструктора базового класса указатель таблицы виртуальных функций имеет значение свойственное базовому классу и виртуальная функция будет вести себя как будто она виртуальной не является.