← Назад к вопросам

С помощью чего делали интеграции в команде

2.3 Middle🔥 131 комментариев
#REST API и микросервисы#Брокеры сообщений

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Интеграции с внешними системами в команде

Стек технологий для интеграций

В разных проектах мы использовали разные подходы. Расскажу о самых эффективных.

1. REST API + Spring RestTemplate / WebClient

Проект: Платёжная система (интеграция с 5+ платёжными шлюзами)

// Старый подход (Spring 4.x)
@Service
public class StripePaymentService {
    @Autowired
    private RestTemplate restTemplate;
    
    public PaymentResponse processPayment(PaymentRequest request) {
        HttpHeaders headers = new HttpHeaders();
        headers.setBasicAuth("sk_test_xxx", "");
        
        HttpEntity<StripeRequest> entity = new HttpEntity<>(mapRequest(request), headers);
        ResponseEntity<StripeResponse> response = restTemplate.postForEntity(
            "https://api.stripe.com/v1/charges",
            entity,
            StripeResponse.class
        );
        return mapResponse(response.getBody());
    }
}

// Новый подход (Spring 5+, асинхронный)
@Service
public class StripePaymentServiceAsync {
    @Autowired
    private WebClient webClient;
    
    public Mono<PaymentResponse> processPayment(PaymentRequest request) {
        return webClient
            .post()
            .uri("https://api.stripe.com/v1/charges")
            .header("Authorization", "Bearer sk_test_xxx")
            .contentType(MediaType.APPLICATION_JSON)
            .bodyValue(mapRequest(request))
            .retrieve()
            .bodyToMono(StripeResponse.class)
            .map(this::mapResponse);
    }
}

2. Message Brokers: RabbitMQ / Kafka

Проект: Система уведомлений (Email, SMS, Push)

// RabbitMQ
@Configuration
public class RabbitConfig {
    public static final String NOTIFICATION_QUEUE = "notification.queue";
    public static final String NOTIFICATION_EXCHANGE = "notification.exchange";
    
    @Bean
    public Queue notificationQueue() {
        return new Queue(NOTIFICATION_QUEUE, true);
    }
    
    @Bean
    public Exchange notificationExchange() {
        return new DirectExchange(NOTIFICATION_EXCHANGE, true, false);
    }
    
    @Bean
    public Binding binding(Queue queue, Exchange exchange) {
        return BindingBuilder
            .bind(queue)
            .to(exchange)
            .with("notification.*");
    }
}

@Service
public class NotificationPublisher {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void sendNotification(Notification notification) {
        rabbitTemplate.convertAndSend(
            NOTIFICATION_EXCHANGE,
            "notification.email",
            notification
        );
    }
}

@Component
public class NotificationConsumer {
    @RabbitListener(queues = RabbitConfig.NOTIFICATION_QUEUE)
    public void handleNotification(Notification notification) {
        // Отправляем Email/SMS
        mailService.send(notification);
    }
}

// Kafka (более мощный)
@Service
public class KafkaNotificationPublisher {
    @Autowired
    private KafkaTemplate<String, Notification> kafkaTemplate;
    
    public void sendNotification(Notification notification) {
        kafkaTemplate.send("notifications", notification.getId(), notification);
    }
}

@Component
public class KafkaNotificationConsumer {
    @KafkaListener(topics = "notifications", groupId = "notification-group")
    public void listen(Notification notification) {
        mailService.send(notification);
    }
}

3. SOAP (для legacy систем)

Проект: Интеграция с банковской системой (1С)

@Configuration
public class SoapConfig {
    @Bean
    public WebServiceTemplate webServiceTemplate() {
        return new WebServiceTemplate(new HttpComponentsMessageSender());
    }
}

@Service
public class BankIntegrationService {
    @Autowired
    private WebServiceTemplate webServiceTemplate;
    
    private static final String URL = "https://bank.example.com/soap";
    
    public BankAccountResponse getAccountInfo(String accountId) {
        GetAccountRequest request = new GetAccountRequest();
        request.setAccountId(accountId);
        request.setToken("bank_token_xxx");
        
        BankAccountResponse response = (BankAccountResponse) webServiceTemplate
            .marshalSendAndReceive(URL, request);
        
        return response;
    }
}

4. Scheduled Tasks / Polling

Проект: Синхронизация данных с внешним хранилищем

@Component
public class DataSyncScheduler {
    @Autowired
    private ExternalDataService externalService;
    
    @Autowired
    private LocalDataRepository localRepository;
    
    // Каждые 5 минут
    @Scheduled(fixedRate = 300000)
    public void syncData() {
        List<ExternalData> external = externalService.fetchAll();
        external.forEach(item -> {
            LocalData local = localRepository.findById(item.getId()).orElse(new LocalData());
            local.update(item);
            localRepository.save(local);
        });
        logger.info("Data sync completed: {} items", external.size());
    }
}

5. Webhooks (для real-time интеграций)

Проект: Платёжная система слушает события от Stripe

// У нас (эндпоинт для входящих webhook'ов)
@RestController
@RequestMapping("/webhooks")
public class StripeWebhookController {
    @Autowired
    private PaymentWebhookService webhookService;
    
    @PostMapping("/stripe")
    public ResponseEntity<Void> handleStripeEvent(@RequestBody String payload,
                                                   @RequestHeader("Stripe-Signature") String signature) {
        // Проверяем подпись
        if (!verifySignature(payload, signature)) {
            return ResponseEntity.badRequest().build();
        }
        
        Event event = Gson.fromJson(payload, Event.class);
        webhookService.processEvent(event);
        
        return ResponseEntity.ok().build();
    }
    
    private boolean verifySignature(String payload, String signature) {
        String secret = "whsec_xxx";
        // HMAC-SHA256 verification
        return true;
    }
}

// Обработка событий
@Service
public class PaymentWebhookService {
    @Transactional
    public void processEvent(Event event) {
        switch (event.getType()) {
            case "charge.succeeded":
                handleChargeSucceeded((ChargeData) event.getData());
                break;
            case "charge.failed":
                handleChargeFailed((ChargeData) event.getData());
                break;
        }
    }
    
    private void handleChargeSucceeded(ChargeData data) {
        Payment payment = paymentRepository.findById(data.getMetadata("order_id")).orElseThrow();
        payment.setStatus(PaymentStatus.COMPLETED);
        paymentRepository.save(payment);
        // Отправляем email клиенту
    }
}

6. GraphQL

Проект: API для мобильного приложения

@Component
public class OrderQueryResolver implements GraphQLQueryResolver {
    @Autowired
    private OrderService orderService;
    
    public Order order(String id) {
        return orderService.findById(id);
    }
    
    public List<Order> orders(int limit, int offset) {
        return orderService.findAll(limit, offset);
    }
}

@Component
public class OrderMutationResolver implements GraphQLMutationResolver {
    @Autowired
    private OrderService orderService;
    
    public Order createOrder(CreateOrderInput input) {
        return orderService.create(input);
    }
}

7. WebSockets (для real-time)

Проект: Live чат / мониторинг

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic", "/queue");
        config.setApplicationDestinationPrefixes("/app");
    }
    
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
    }
}

@Controller
public class ChatController {
    @MessageMapping("/chat.sendMessage")
    @SendTo("/topic/public")
    public ChatMessage sendMessage(@Payload ChatMessage message) {
        return message;
    }
}

Best Practices интеграций в команде

1. Retry логика

@Service
public class ResilientPaymentService {
    @Retryable(value = {IOException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))
    public PaymentResponse process(PaymentRequest request) throws IOException {
        return restClient.post(request);
    }
}

2. Circuit Breaker

@Service
@CircuitBreaker(name = "paymentService", fallbackMethod = "fallback")
public Mono<PaymentResponse> processPayment(PaymentRequest request) {
    return externalPaymentAPI.process(request);
}

public Mono<PaymentResponse> fallback(PaymentRequest request, Exception ex) {
    // Вернуть дефолтный ответ или сохранить в очередь
    return Mono.just(PaymentResponse.PENDING);
}

3. Логирование и мониторинг

@Aspect
@Component
public class IntegrationLogging {
    @Around("@annotation(IntegrationPoint)")
    public Object log(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long duration = System.currentTimeMillis() - start;
        
        logger.info("Integration [{}] completed in {}ms", 
            pjp.getSignature().getName(), duration);
        return result;
    }
}

Мой выбор в новых проектах

  • Синхронные REST API → WebClient
  • Асинхронные события → Kafka
  • Real-time → WebSockets
  • Legacy → SOAP (но стараемся мигрировать)
  • Надёжность → Circuit Breaker + Retry
С помощью чего делали интеграции в команде | PrepBro