服務端呼叫微信小程式OCR識別介面實現

小隱發表於2019-08-21

一 開發環境

後端語言 java
技術工具框架 springboot

二 實現目的

本demo適用於快速服務端呼叫微信小程式OCR介面實現,以行駛證介面為例

包括

  1. 圖片上傳
  2. 呼叫微信小程式介面實現OCR識別
  3. swagger3 整合呼叫 去除不必要的 - - 簡單實用,詳細檢視openapi文件

三 Demo上線

  1. 搭建我們的基礎環境

目錄結構如下

clipboard.png

  • pom檔案配置
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.7.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.example</groupId>
  <artifactId>demo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>demo</name>
  <description>Demo project for Spring Boot</description>

  <properties>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
      <version>2.1.1.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
      <version>2.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <!-- fastjson -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.59</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>
  • 整合swagger3

官網下載swagger,將dist目錄放入Resource-static下,修改dist為swagger3

開啟目錄下index.html,修改為

 const ui = SwaggerUIBundle({
        url: "swagger.json",
        dom_id: '#swagger-ui',
        deepLinking: true,
        presets: [
          SwaggerUIBundle.presets.apis,
          SwaggerUIStandalonePreset
        ],
        plugins: [
          SwaggerUIBundle.plugins.DownloadUrl
        ],
        layout: "StandaloneLayout"
      })
      // End Swagger UI call region

      window.ui = ui

官網開啟https://petstore.swagger.io/v...,模板json,儲存放到swagger3目錄下,修改內容

{
  "swagger": "2.0",
  "info": {
    "title": "小程式服務端demo",
    "description": "本文件為,小程式服務端介面描述文件swagger頁面",
    "version": "1.0.0"
  },
  "tags": [
    {
      "name": "小程式後端服務",
      "description": "此服務提供小程式訪問後端系統的業務實現."
    }
  ],
  "schemes": [
    "http"
  ],
  "paths": {
    "/api/vehicle/upload-vehicle": {
      "post": {
        "tags": [
          "小程式後端服務"
        ],
        "summary": "行駛證照片上傳介面",
        "description": "行駛證照片上傳介面",
        "operationId": "uploadFile",
        "consumes": [
          "multipart/form-data"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "name": "file",
            "in": "formData",
            "description": "行駛證照片",
            "required": true,
            "type": "file"
          }
        ],
        "responses": {
          "200": {
            "description": "successful operation",
            "schema": {
              "$ref": "#/definitions/RestControllerResult"
            }
          }
        }
      }
    }
  },
  "definitions": {
    "RestControllerResult": {
      "type": "object",
      "properties": {
        "success": {
          "type": "boolean",
          "description": "成功與否",
          "default": false
        },
        "code": {
          "type": "integer",
          "description": "響應碼",
          "format": "int64"
        },
        "infoMsgs": {
          "type": "array",
          "xml": {
            "name": "infoMsgs",
            "wrapped": true
          },
          "items": {
            "type": "string",
            "description": "資訊"
          }
        },
        "warningMsgs": {
          "type": "array",
          "xml": {
            "name": "warningMsgs",
            "wrapped": true
          },
          "items": {
            "type": "string",
            "description": "警告資訊"
          }
        },
        "errorMsg": {
          "type": "string",
          "description": "錯誤資訊"
        },
        "data": {
          "type": "object"
        }
      },
      "xml": {
        "name": "RestControllerResult"
      }
    }
  }
}
  • application啟動類新增Feign呼叫註解
@SpringBootApplication
@EnableFeignClients
public class DemoApplication {

  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }

}
  • 配置全域性檔案 application.yml (properties修改為yml即可)
#服務配置
server:
  port: 8890
  compression:
    enabled: true
  max-http-header-size: 10000000

spring:
  application:
    name: ocr-demo

#外部呼叫
app:
  vehicle: "https://api.weixin.qq.com"

至此,我們的基礎環境細緻的講解完畢,且完整基礎環境搭建完整,騷年們,開始程式碼!!!!

  1. 通用返回dto編寫
package com.example.demo.common.dto;

import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * 通用介面返回結果.
 *
 * @author : 小隱
 * @since : 2019/8/21 9:44
 */
public class RestControllerResult<T> implements Serializable {

  private static final long serialVersionUID = -3698136820012767666L;
  private Boolean success;
  private Integer code;
  private List<String> infoMsgs = new LinkedList<>();
  private List<String> warningMsgs = new LinkedList<>();
  private String errorMsg;
  private T data;

  public RestControllerResult() {
  }

  public RestControllerResult(T t) {
    this.data = t;
  }

  public Boolean getSuccess() {
    return this.success;
  }

  public void setSuccess(Boolean success) {
    this.success = success;
  }

  public Integer getCode() {
    return this.code;
  }

  public void setCode(int code) {
    this.code = code;
  }

  public List<String> getInfoMsgs() {
    return this.infoMsgs;
  }

  public void setInfoMsgs(List<String> infoMsgs) {
    this.infoMsgs = infoMsgs;
  }

  public List<String> getWarningMsgs() {
    return this.warningMsgs;
  }

  public void setWarningMsgs(List<String> warningMsgs) {
    this.warningMsgs = warningMsgs;
  }

  public String getErrorMsg() {
    return this.errorMsg;
  }

  public void setErrorMsg(String errorMsg) {
    this.errorMsg = errorMsg;
  }

  public T getData() {
    return this.data;
  }

  public void setData(T data) {
    this.data = data;
  }

  public static <T> RestControllerResult<T> success(T data) {
    RestControllerResult result = new RestControllerResult(data);
    result.setSuccess(true);
    return result;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    } else if (o != null && this.getClass() == o.getClass()) {
      RestControllerResult<?> that = (RestControllerResult) o;
      return this.code.equals(that.code) && Objects.equals(this.success, that.success) && Objects
          .equals(this.infoMsgs, that.infoMsgs) && Objects
          .equals(this.warningMsgs, that.warningMsgs) && Objects
          .equals(this.errorMsg, that.errorMsg) && Objects.equals(this.data, that.data);
    } else {
      return false;
    }
  }

  @Override
  public int hashCode() {
    return Objects.hash(
        new Object[]{this.success, this.code, this.infoMsgs, this.warningMsgs, this.errorMsg,
            this.data});
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder("RestControllerResult{");
    sb.append("success=").append(this.success);
    sb.append(", code=").append(this.code);
    sb.append(", infoMsgs=").append(this.infoMsgs);
    sb.append(", warningMsgs=").append(this.warningMsgs);
    sb.append(", errorMsg='").append(this.errorMsg).append('\'');
    sb.append(", data=").append(this.data);
    sb.append('}');
    return sb.toString();
  }
}
  1. controller層編寫(分為api-controller)

api

package com.example.demo.api;

import com.example.demo.common.dto.RestControllerResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * 小程式請求後端系統Api.
 *
 * @author : 小隱
 * @since : 2019/8/15 15:37
 */
@RestController
@RequestMapping("/api/vehicle")
public interface AppVehicleMiniApi {

  /**
   * 上傳行駛證照片.
   *
   * @param img 圖片
   * @return result
   */
  @PostMapping("upload-vehicle")
  RestControllerResult uploadVehicle(@RequestParam("file") MultipartFile img);

}

controller

package com.example.demo.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.api.AppVehicleMiniApi;
import com.example.demo.common.dto.RestControllerResult;
import com.example.demo.service.AppVehicleService;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 1. 小程式請求後端系統完成功能Controller.
 2.  3. @author : 小隱
 4. @since : 2019/8/21
 */
@RestController
public class AppVehicleMiniApiController implements AppVehicleMiniApi {

  private static final Logger logger = LoggerFactory.getLogger(AppVehicleMiniApiController.class);
  private static final String IMG_EMPTY = "上傳照片為空";

  @Resource
  private AppVehicleService appVehicleService;


  @Override
  public RestControllerResult uploadVehicle(MultipartFile img) {
    logger.info("=======>行駛證上傳<=======");
    RestControllerResult resultsDtoRestControllerResult = new RestControllerResult<>();
    if (img.isEmpty()) {
      logger.error(IMG_EMPTY);
      resultsDtoRestControllerResult.setSuccess(false);
      resultsDtoRestControllerResult.setCode(400);
      resultsDtoRestControllerResult.setErrorMsg(IMG_EMPTY);
      return resultsDtoRestControllerResult;
    }
    System.out.println(JSONObject.toJSONString(appVehicleService.ocrVehilce(img)));
    resultsDtoRestControllerResult.setSuccess(true);
    resultsDtoRestControllerResult.setCode(200);
    resultsDtoRestControllerResult.setData(appVehicleService.ocrVehilce(img));
    return resultsDtoRestControllerResult;
  }
}
  1. service實現
package com.example.demo.service;

import org.springframework.web.multipart.MultipartFile;

/**
 * 行駛證圖片上傳服務介面.
 *
 * @author : 小隱
 * @since : 2019/8/19 15:50
 */
public interface AppVehicleService {

  /**
   * 識別行駛證.
   *
   * @param img 上傳圖片
   * @return 識別結果
   */
  Object ocrVehilce(MultipartFile img);

}
package com.example.demo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.feign.AppVehicleFeign;
import com.example.demo.service.AppVehicleService;
import java.util.Map;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

/**
 * 行駛證照片服務.
 *
 * @author : 小隱
 * @since : 2019/8/19 18:11
 */
@Service
public class AppVehicleServiceImpl implements AppVehicleService {

  private static final Logger logger = LoggerFactory.getLogger(AppVehicleServiceImpl.class);

  @Resource
  private AppVehicleFeign appVehicleFeign;

  @Override
  public Object ocrVehilce(MultipartFile img) {
    Object value = appVehicleFeign.getWeiXinToken();
    String s = JSONObject.toJSONString(value);
    Map<String, Object> map = (Map<String, Object>)JSONObject.parse(s);
    Object token = "";
    if (map.get("access_token") != null) {
      logger.info("最終token為" + map.get("access_token"));
      token = map.get("access_token");
    } else {
      //返回失敗結果
      logger.error("微信介面服務獲取token發生錯誤,錯誤程式碼 " + map.get("errcode"));
      logger.error("微信介面服務獲取token發生錯誤,錯誤資訊 " + map.get("errmsg"));
    }
    return appVehicleFeign.ocrVehicle(img,token.toString());
  }
}
  1. 重點戲:Feign呼叫實現
package com.example.demo.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;

/**
 * 行駛證處理feign.
 *
 * @author : 小隱
 * @since : 2019/8/20 17:03
 */
@FeignClient(value = "vehicle", fallbackFactory = AppVehicleFeignFactory.class, url = "${app.vehicle}")
public interface AppVehicleFeign {

  /**
   * 獲取微信token.
   *
   * @return token
   */
  @GetMapping("/cgi-bin/token?grant_type=client_credential&appid=[小程式開發id]&secret=[微信金鑰]")
  Object getWeiXinToken();

  /**
   * 識別行駛證.
   *
   * @param img 照片
   * @param token token
   * @return 識別結果
   */
  @PostMapping(value = "/cv/ocr/driving?type=photo&access_token={token}",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  Object ocrVehicle(@RequestPart(value = "file") MultipartFile img,
      @PathVariable(name = "token") String token);

}
package com.example.demo.feign;

import feign.hystrix.FallbackFactory;

/**
 * 行駛證feign工廠.
 *
 * @author : 小隱
 * @since : 2019/8/20 17:10
 */
public class AppVehicleFeignFactory implements FallbackFactory<AppVehicleFeign> {

  @Override
  public AppVehicleFeign create(Throwable throwable) {
    return null;
  }
}

終於可以愉快地測試了!!!!!

啟動應用,訪問地址 http://localhost:8890/swagger3/index.html

clipboard.png

乾淨、簡潔、明瞭

點選上傳介面,try it out,選擇行駛證照片,執行

clipboard.png

老夫手把手教學結束了!!!!

原創不易,小隱出品,轉載,請註明作者、出處,謝謝大家不吝賜教!!!!!

微訊號huc_lele,歡迎來擾!

相關文章