乐尚代驾七订单执行二

开始代驾(服务)

司机录入车辆信息后,就开始代驾了。开始代驾后,司机端与乘客端同样要进入司乘同显页面,司乘同显的起始点与终点就是代驾订单的起始点与终点,这里我们不需要提供额外的接口,直接使用“计算最佳驾驶线路”接口即可。

订单在在代驾过程中,我们需要保存驾驶途中的GPS定位,将来我们计算代驾真实里程的时候,就需要用到这些坐标点。那么这些定位点保存在MySQL中可以吗?当然不行,MySQL单表记录超过千万行就开始变慢了。那么保存再哪里呢?保存到MongoDB中。

订单在代驾的过程中,司机端小程序要实时采集录音,把录音和对话文本上传到后端系统,将录音监控保存到Minio,对话文本保存到MongoDB中

  • 更新订单状态:开始代驾
//开始代驾服务
@PostMapping("/startDrive")
public Result<Boolean> startDriver(@RequestBody StartDriveForm startDriveForm) {
    Boolean flag = orderInfoService.startDriver(startDriveForm);
    return Result.ok(flag);
}







//开始代驾服务
@Override
public Boolean startDriver(StartDriveForm startDriveForm) {
    //根据订单id  +  司机id  更新订单状态  和 开始代驾时间
    LambdaQueryWrapper<OrderInfo> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(OrderInfo::getId,startDriveForm.getOrderId());
    wrapper.eq(OrderInfo::getDriverId,startDriveForm.getDriverId());
    
    OrderInfo orderInfo = new OrderInfo();
    orderInfo.setStatus(OrderStatus.START_SERVICE.getStatus());
    orderInfo.setStartServiceTime(new Date());

    int rows = orderInfoMapper.update(orderInfo, wrapper);
    if(rows == 1) {
        return true;
    } else {
        throw new GuiguException(ResultCodeEnum.UPDATE_ERROR);
    }
}







/**
 * 开始代驾服务
 * @param startDriveForm
 * @return
 */
@PostMapping("/order/info/startDrive")
Result<Boolean> startDrive(@RequestBody StartDriveForm startDriveForm);







@Operation(summary = "开始代驾服务")
@GuiguLogin
@PostMapping("/startDrive")
public Result<Boolean> startDrive(@RequestBody StartDriveForm startDriveForm) {
    Long driverId = AuthContextHolder.getUserId();
    startDriveForm.setDriverId(driverId);
    return Result.ok(orderService.startDrive(startDriveForm));
}






@Override
public Boolean startDrive(StartDriveForm startDriveForm) {
    return orderInfoFeignClient.startDrive(startDriveForm).getData();
}

批量保存订单位置信息

  • 司机开始代驾之后,司机端会实时收集司机代驾位置,定时批量上传位置到后台服务
  • 保存到MongoDB里面
//批量保存代驾服务订单位置
@PostMapping("/saveOrderServiceLocation")
public Result<Boolean> saveOrderServiceLocation(@RequestBody List<OrderServiceLocationForm> orderLocationServiceFormList) {
    return Result.ok(locationService.saveOrderServiceLocation(orderLocationServiceFormList));
}







@Override
public Boolean saveOrderServiceLocation(List<OrderServiceLocationForm> orderLocationServiceFormList) {

    List<OrderServiceLocation> list = new ArrayList<>();
    //OrderServiceLocation
    orderLocationServiceFormList.forEach(orderServiceLocationForm->{
        //orderServiceLocationForm -- OrderServiceLocation
        OrderServiceLocation orderServiceLocation = new OrderServiceLocation();
        BeanUtils.copyProperties(orderServiceLocationForm,orderServiceLocation);
        orderServiceLocation.setId(ObjectId.get().toString());
        orderServiceLocation.setCreateTime(new Date());

        list.add(orderServiceLocation);
        //orderServiceLocationRepository.save(orderServiceLocation);
    });
    //批量添加到MongoDB
    orderServiceLocationRepository.saveAll(list);
    return true;
}









/**
 * 开始代驾服务:保存代驾服务订单位置
 * @param orderLocationServiceFormList
 * @return
 */
@PostMapping("/map/location/saveOrderServiceLocation")
Result<Boolean> saveOrderServiceLocation(@RequestBody List<OrderServiceLocationForm> orderLocationServiceFormList);








@Operation(summary = "开始代驾服务:保存代驾服务订单位置")
@PostMapping("/saveOrderServiceLocation")
public Result<Boolean> saveOrderServiceLocation(@RequestBody List<OrderServiceLocationForm> orderLocationServiceFormList) {
    return Result.ok(locationService.saveOrderServiceLocation(orderLocationServiceFormList));
}





@Override
public Boolean saveOrderServiceLocation(List<OrderServiceLocationForm> orderLocationServiceFormList) {
    return locationFeignClient.saveOrderServiceLocation(orderLocationServiceFormList).getData();
}

获取订单最后一个位置

  • 司机开始代驾之后,乘客端获取司机最新动向,就必须获取到司机最后一个位置信息

  • 从MongoDB获取

  • 在地图微服务创建接口

@Operation(summary = "代驾服务:获取订单服务最后一个位置信息")
@GetMapping("/getOrderServiceLastLocation/{orderId}")
public Result<OrderServiceLastLocationVo> getOrderServiceLastLocation(@PathVariable Long orderId) {
    return Result.ok(locationService.getOrderServiceLastLocation(orderId));
}






@Override
public OrderServiceLastLocationVo getOrderServiceLastLocation(Long orderId) {
    //查询MongoDB
    //查询条件 :orderId
    //根据创建时间降序排列
    //最新一条数据
    Query query = new Query();
    query.addCriteria(Criteria.where("orderId").is(orderId));
    query.with(Sort.by(Sort.Order.desc("createTime")));
    query.limit(1);

    OrderServiceLocation orderServiceLocation = 
            mongoTemplate.findOne(query, OrderServiceLocation.class);
    OrderServiceLastLocationVo orderServiceLastLocationVo = new OrderServiceLastLocationVo();
    BeanUtils.copyProperties(orderServiceLocation,orderServiceLastLocationVo);
    return orderServiceLastLocationVo;
}








/**
 * 代驾服务:获取订单服务最后一个位置信息
 * @param orderId
 * @return
 */
@GetMapping("/map/location/getOrderServiceLastLocation/{orderId}")
Result<OrderServiceLastLocationVo> getOrderServiceLastLocation(@PathVariable Long orderId);







@Operation(summary = "代驾服务:获取订单服务最后一个位置信息")
@GuiguLogin
@GetMapping("/getOrderServiceLastLocation/{orderId}")
public Result<OrderServiceLastLocationVo> getOrderServiceLastLocation(@PathVariable Long orderId) {
    return Result.ok(orderService.getOrderServiceLastLocation(orderId));
}







@Override
public OrderServiceLastLocationVo getOrderServiceLastLocation(Long orderId) {
    return locationFeignClient.getOrderServiceLastLocation(orderId).getData();
}

Minio上传接口

司机代驾过程中,司机端小程序实时采集录音,把录音和对话文本上传到后台服务,把录完监控保存Minio

Minio介绍

官网:https://www.minio.org.cn/

MinIO是一个开源的分布式对象存储服务器,支持S3协议并且可以在多节点上实现数据的高可用和容错。它采用Go语言开发,拥有轻量级、高性能、易部署等特点,并且可以自由选择底层存储介质。

MinIO的主要特点包括:

1、高性能:MinIO基于GO语言编写,具有高速、轻量级、高并发等性能特点,还支持多线程和缓存等机制进行优化,可以快速地处理大规模数据。

2、可扩展性:MinIO采用分布式存储模式,支持水平扩展,通过增加节点数量来扩展存储容量和性能,支持自动数据迁移和负载均衡。

3、安全性:MinIO提供了多种安全策略,如访问控制列表(ACL)、服务端加密(SSE)、传输层安全性(TLS)等,可以保障数据安全和隐私。

4、兼容性:MinIO兼容AWS S3 API,还支持其他云服务提供商的API,比如GCP、Azure等,可以通过简单的配置实现互操作性。

5、简单易用:MinIO的部署和管理非常简单,只需要运行一个二进制包即可启动服务,同时提供了Web界面和命令行工具等方便的管理工具。

// 创建数据存储目录
mkdir -p ~/minio/data

// 创建minio
docker run \
   -p 9000:9000 \
   -p 9090:9090 \
   --name minio \
   -v ~/minio/data:/data \
   -e "MINIO_ROOT_USER=admin" \
   -e "MINIO_ROOT_PASSWORD=admin123456" \
   -d \
   quay.io/minio/minio server /data --console-address ":9090"
  • 需要在可视化界面,把Summary的Access Policy从private 改为 public
<!-- web-driver模块中加入如下依赖 -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.2</version>
</dependency>




<!-- common-account.yaml -->
minio:
  endpointUrl: http://192.168.6.129:9000
  accessKey: minioadmin
  secreKey: minioadmin
  bucketName: daijia
@Configuration
@ConfigurationProperties(prefix="minio") //读取节点
@Data
public class MinioProperties {

    private String endpointUrl;
    private String accessKey;
    private String secreKey;
    private String bucketName;
}





@Operation(summary = "上传")
@PostMapping("/upload")
public Result<String> upload(@RequestPart("file") MultipartFile file) {
    String url = fileService.upload(file);
    return Result.ok(url);
}







@Override
public String upload(MultipartFile file) {
    try {
        // 创建一个Minio的客户端对象
        MinioClient minioClient = MinioClient.builder()
                .endpoint(minioProperties.getEndpointUrl())
                .credentials(minioProperties.getAccessKey(), minioProperties.getSecreKey())
                .build();

        // 判断桶是否存在
        boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProperties.getBucketName()).build());
        if (!found) {       // 如果不存在,那么此时就创建一个新的桶
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProperties.getBucketName()).build());
        } else {  // 如果存在打印信息
            System.out.println("Bucket 'daijia' already exists.");
        }

        // 设置存储对象名称
        String extFileName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String fileName = new SimpleDateFormat("yyyyMMdd")
                .format(new Date()) + "/" + UUID.randomUUID().toString().replace("-" , "") + "." + extFileName;

        PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                .bucket(minioProperties.getBucketName())
                .stream(file.getInputStream(), file.getSize(), -1)
                .object(fileName)
                .build();
        minioClient.putObject(putObjectArgs) ;

        return minioProperties.getEndpointUrl() + "/" + minioProperties.getBucketName() + "/" + fileName ;

    } catch (Exception e) {
        throw new GuiguException(ResultCodeEnum.DATA_ERROR);
    }
}

保存订单监控记录数据

  • 司机开始代驾之后,整个过程中,记录对话信息,直到代驾结束
  • 在前端小程序,同声传译,把录音转换文本,保存文本内容
@RestController
@RequestMapping("/order/monitor")
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderMonitorController {

    @Autowired
    private OrderMonitorService orderMonitorService;

    @Operation(summary = "保存订单监控记录数据")
    @PostMapping("/saveOrderMonitorRecord")
    public Result<Boolean> saveMonitorRecord(@RequestBody OrderMonitorRecord orderMonitorRecord) {
        return Result.ok(orderMonitorService.saveOrderMonitorRecord(orderMonitorRecord));
    }
}





@Override
public Boolean saveOrderMonitorRecord(OrderMonitorRecord orderMonitorRecord) {
    orderMonitorRecordRepository.save(orderMonitorRecord);
    return true;
}





/**
 * 保存订单监控记录数据
 * @param orderMonitorRecord
 * @return
 */
@PostMapping("/order/monitor/saveOrderMonitorRecord")
Result<Boolean> saveMonitorRecord(@RequestBody OrderMonitorRecord orderMonitorRecord);






@Autowired
private MonitorService monitorService;

@Operation(summary = "上传录音")
@PostMapping("/upload")
public Result<Boolean> upload(@RequestParam("file") MultipartFile file,
                              OrderMonitorForm orderMonitorForm) {

    return Result.ok(monitorService.upload(file, orderMonitorForm));
}









@Override
public Boolean upload(MultipartFile file, OrderMonitorForm orderMonitorForm) {
    //上传文件
    String url = fileService.upload(file);

    OrderMonitorRecord orderMonitorRecord = new OrderMonitorRecord();
    orderMonitorRecord.setOrderId(orderMonitorForm.getOrderId());
    orderMonitorRecord.setFileUrl(url);
    orderMonitorRecord.setContent(orderMonitorForm.getContent());
    orderMonitorFeignClient.saveMonitorRecord(orderMonitorRecord);

    return true;
}

订单监控审核

需求描述

  • 我们之前功能里面很多地方使用腾讯云COS服务,比如司机认证上传图片,包含身份证、驾驶证等图片。因为上传这些图片,目前无法保证图片是否违规。如果使用人工审核,速度太慢。使用腾讯云数据万象实现自动审核

开通数据万象服务

  • 官方网址:https://cloud.tencent.com/product/ci
    在这里插入图片描述

腾讯云COS图片审核

@Service
public class CiServiceImpl implements CiService {

    @Autowired
    private TencentCloudProperties tencentCloudProperties;

    //图片审核
    @Override
    public Boolean imageAuditing(String path) {

        //1.创建任务请求对象
        ImageAuditingRequest request = new ImageAuditingRequest();
        //2.添加请求参数 参数详情请见 API 接口文档
        //2.1设置请求 bucket
        request.setBucketName(tencentCloudProperties.getBucketPrivate());
        //2.2设置审核策略 不传则为默认策略(预设)
        //request.setBizType("");
        //2.3设置 bucket 中的图片位置
        request.setObjectKey(path);
        //3.调用接口,获取任务响应对象
        COSClient client = this.getCosClient();
        ImageAuditingResponse response = client.imageAuditing(request);
        client.shutdown();
        //用于返回该审核场景的审核结果,返回值:0:正常。1:确认为当前场景的违规内容。2:疑似为当前场景的违规内容。
        if (!response.getPornInfo().getHitFlag().equals("0")
                || !response.getAdsInfo().getHitFlag().equals("0")
                || !response.getTerroristInfo().getHitFlag().equals("0")
                || !response.getPoliticsInfo().getHitFlag().equals("0")
        ) {
            return false;
        }
        return true;
    }

    public COSClient getCosClient() {
        String secretId = tencentCloudProperties.getSecretId();
        String secretKey = tencentCloudProperties.getSecretKey();
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
        // 2 设置 bucket 的地域, COS 地域
        Region region = new Region(tencentCloudProperties.getRegion());
        ClientConfig clientConfig = new ClientConfig(region);
        // 这里建议设置使用 https 协议
        clientConfig.setHttpProtocol(HttpProtocol.https);
        // 3 生成 cos 客户端。
        COSClient cosClient = new COSClient(cred, clientConfig);
        return cosClient;
    }
}

腾讯云COS图片增加审核
在这里插入图片描述

//图片审核
Boolean imageAuditing = ciService.imageAuditing(uploadPath);
if(!imageAuditing) {
    //删除违规图片
    cosClient.deleteObject(tencentCloudProperties.getBucketPrivate(),uploadPath);
    throw new GuiguException(ResultCodeEnum.IMAGE_AUDITION_FAIL);
}

封装文本审核接口

司机微服务接口

@Tag(name = "腾讯云CI审核接口管理")
@RestController
@RequestMapping(value="/cos")
@SuppressWarnings({"unchecked", "rawtypes"})
public class CiController {

    @Autowired
    private CiService ciService;

    @Operation(summary = "文本审核")
    @PostMapping("/textAuditing")
    public Result<TextAuditingVo> textAuditing(@RequestBody String content) {
        return Result.ok(ciService.textAuditing(content));
    }

}








@Override
public TextAuditingVo textAuditing(String content) {
    if(!StringUtils.hasText(content)) {
        TextAuditingVo textAuditingVo = new TextAuditingVo();
        textAuditingVo.setResult("0");
        return textAuditingVo;
    }

    COSClient cosClient = this.getCosClient();

    //1.创建任务请求对象
    TextAuditingRequest request = new TextAuditingRequest();
    //2.添加请求参数 参数详情请见 API 接口文档
    request.setBucketName(tencentCloudProperties.getBucketPrivate());
    //2.1.1设置请求内容,文本内容的Base64编码
    byte[] encoder = org.apache.commons.codec.binary.Base64.encodeBase64(content.getBytes());
    String contentBase64 = new String(encoder);
    request.getInput().setContent(contentBase64);
    request.getConf().setDetectType("all");

    //3.调用接口,获取任务响应对象
    TextAuditingResponse response = cosClient.createAuditingTextJobs(request);
    AuditingJobsDetail detail = response.getJobsDetail();
    TextAuditingVo textAuditingVo = new TextAuditingVo();
    if ("Success".equals(detail.getState())) {
        //检测结果: 0(审核正常),1 (判定为违规敏感文件),2(疑似敏感,建议人工复核)。
        String result = detail.getResult();

        //违规关键词
        StringBuffer keywords = new StringBuffer();
        List<SectionInfo> sectionInfoList = detail.getSectionList();
        for (SectionInfo info : sectionInfoList) {

            String pornInfoKeyword = info.getPornInfo().getKeywords();
            String illegalInfoKeyword = info.getIllegalInfo().getKeywords();
            String abuseInfoKeyword = info.getAbuseInfo().getKeywords();

            if (pornInfoKeyword.length() > 0) {
                keywords.append(pornInfoKeyword).append(",");
            }
            if (illegalInfoKeyword.length() > 0) {
                keywords.append(illegalInfoKeyword).append(",");
            }
            if (abuseInfoKeyword.length() > 0) {
                keywords.append(abuseInfoKeyword).append(",");
            }
        }
        textAuditingVo.setResult(result);
        textAuditingVo.setKeywords(keywords.toString());
    }
    return textAuditingVo;
}






/**
 * 文本审核
 * @param content
 * @return
 */
@PostMapping("/ci/textAuditing")
Result<TextAuditingVo> textAuditing(@RequestBody String content);

订单监控接口完善

在这里插入图片描述

@Override
public Boolean upload(MultipartFile file, OrderMonitorForm orderMonitorForm) {
    //上传文件
    String url = fileService.upload(file);

    OrderMonitorRecord orderMonitorRecord = new OrderMonitorRecord();
    orderMonitorRecord.setOrderId(orderMonitorForm.getOrderId());
    orderMonitorRecord.setFileUrl(url);
    orderMonitorRecord.setContent(orderMonitorForm.getContent());
    //增加文本审核
    TextAuditingVo textAuditingVo = 
            ciFeignClient.textAuditing(orderMonitorForm.getContent()).getData();
    orderMonitorRecord.setResult(textAuditingVo.getResult());
    orderMonitorRecord.setKeywords(textAuditingVo.getKeywords());
    
    orderMonitorFeignClient.saveMonitorRecord(orderMonitorRecord);
    return true;
}

李国华知道自己被判定是安全的,第一次感谢岁月。

房思琪的初恋乐园
林奕含

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值