JAVA 기반 대리운전 미니프로그램 아키텍처와 uniapp 실전 코드

시스템 구성 개요

대리운전 서비스는 사용자 앱과 관리 백엔드로 구성되며, 프론트엔드는 uniapp 기반의 크로스플랫폼 앱을, 서버는 JAVA 생태계로 구축한다.

앱 핵심 기능

  • 계정 체계: SMS 인증, 위채 오픈ID 연동
  • GIS 기능: 실시간 위치 수집, 목적지 검색
  • 예약 흐름: 요청 → 배차 → 완료 정산
  • 결제 연동: 위채/알리페이 결제
  • 만족도 평가: 별점 및 코멘트

서버 기술 스택

구성 요소적용 기술
API 계층Spring Boot 3.x
영속 계층MySQL + MyBatis
캐시/세션Redis Cluster
실시간 통신WebSocket / SSE
외부 연동지도 SDK, 결제 게이트웨이

핵심 모듈 구현

경로 탐색 서비스

@Service
public class NavigationService {
    
    private final MapPort mapAdapter;
    
    public NavigationService(MapPort mapAdapter) {
        this.mapAdapter = mapAdapter;
    }
    
    public PathResult findOptimalPath(Coordinate from, Coordinate to) {
        return mapAdapter.computeRoute(from, to, RouteStrategy.FASTEST);
    }
}

주문 상태 실시간 전파

@Component
public class OrderEventBroadcaster {
    
    @Autowired
    private SimpMessagingTemplate messagingTemplate;
    
    public void notifyDriverAssigned(Long orderNo, DriverInfo driver) {
        messagingTemplate.convertAndSend(
            "/topic/order/" + orderNo,
            new DispatchEvent(driver.getName(), driver.getPlateNumber())
        );
    }
}

uniapp 프론트엔드 코드

위치 권한 획득 및 좌표 변환

async function fetchCurrentPosition() {
  try {
    const pos = await uni.getLocation({
      type: 'gcj02',
      altitude: false,
      geocode: true
    });
    
    return {
      lat: pos.latitude,
      lng: pos.longitude,
      addr: pos.address ?? ''
    };
  } catch (err) {
    console.error('위치 획득 실패:', err);
    throw new PositionError('GPS 신호를 확인해주세요');
  }
}

주문 생성 및 폴링 로직

class OrderRepository {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
  }
  
  async submit(dto) {
    const { data } = await uni.request({
      url: `${this.baseUrl}/v1/rides`,
      method: 'POST',
      header: { 'Content-Type': 'application/json' },
      data: JSON.stringify({
        pickup: dto.origin,
        dropoff: dto.destination,
        vehicleType: dto.carClass
      })
    });
    return data.rideId;
  }
  
  subscribeStatus(rideId, callback) {
    const socket = uni.connectSocket({
      url: `wss://ws.example.com/rides/${rideId}`
    });
    
    socket.onMessage((evt) => {
      const payload = JSON.parse(evt.data);
      callback(payload.status, payload.eta);
    });
    
    return () => socket.close();
  }
}

Spring Boot 컨트롤러

@RestController
@RequiredArgsConstructor
@RequestMapping("/v1/rides")
public class RideCommandController {
    
    private final RideApplicationService rideService;
    
    @PostMapping
    public ResponseEntity<RideCreatedResponse> requestRide(
            @RequestBody @Valid RideRequest command,
            @AuthenticationPrincipal UserPrincipal user) {
        
        var rideId = rideService.placeOrder(user.getId(), command);
        return ResponseEntity.status(HttpStatus.CREATED)
            .body(new RideCreatedResponse(rideId));
    }
    
    @PatchMapping("/{rideId}/cancel")
    public ResponseEntity<Void> cancelRide(
            @PathVariable UUID rideId,
            @RequestParam CancellationReason cause) {
        
        rideService.revoke(rideId, cause);
        return ResponseEntity.noContent().build();
    }
}

오픈소스 활용 팁

  • UI 프레임워크: uview-plus 또는 uni-ui 활용
  • 지도 SDK: amap-uniapp 플러그인으로 네이티브 지도 임베드
  • 백엔드 참고: jeecg-boot, ruoyi 등의 권한/CRUD 모듈 활용

운영 고려사항

  • 지도 API는 월별 호출량에 따른 상용 라이선스 필수
  • 결제 모듈은 ICP 등록 및 기업 인증 완료 후 개통 가능
  • WebSocket 연결은 재접속 로직과 하트비트 필수
  • 기사 전용 앱은 별도 빌드 타겟으로 분리 권장

태그: Spring Boot UniApp websocket Redis MyBatis

7월 24일 03:31에 게시됨