阿里云营业执照识别API

最近有由于需要,我开始接触阿里云的云市场的印刷文字识别-营业执照识别这里我加上了官网的申请说明,只要你有阿里云账号就可以用,前500次是免费的,API说明很简陋,只能做个简单参考。

一、API介绍


JAVA示例:

 public static void main(String[] args) {String host = "https://dm-58.data.aliyun.com";String path = "/rest/160601/ocr/ocr_business_license.json";String method = "POST";String appcode = "你自己的AppCode";Map<String, String> headers = new HashMap<String, String>();//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105headers.put("Authorization", "APPCODE " + appcode);//根据API的要求,定义相对应的Content-Typeheaders.put("Content-Type", "application/json; charset=UTF-8");Map<String, String> querys = new HashMap<String, String>();String bodys = "{\"image\":\"对图片内容进行Base64编码\"}";try {/*** 重要提示如下:* HttpUtils请从* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java* 下载** 相应的依赖请参照* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml*/HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);System.out.println(response.toString());//获取response的body//System.out.println(EntityUtils.toString(response.getEntity()));} catch (Exception e) {e.printStackTrace();}}

返回码:

{"config_str" : "null\n", #配置字符串信息"angle" : float, #输入图片的角度(顺时针旋转),[0, 90, 180,270]"reg_num" : string, #注册号,没有识别出来时返回"FailInRecognition""name" : string, #公司名称,没有识别出来时返回"FailInRecognition""type" : string, #公司类型,没有识别出来时返回"FailInRecognition""person" : string, #公司法人,没有识别出来时返回"FailInRecognition""establish_date": string, #公司注册日期(例:证件上为"2014年04月16日",算法返回"20140416")"valid_period": string, #公司营业期限终止日期(例:证件上为"2014年04月16日至2034年04月15日",算法返回"20340415")#当前算法将日期格式统一为输出为"年月日"(如"20391130"),并将"长期"表示为"29991231",若证件上没有营业期限,则默认其为"长期",返回"29991231"。"address" : string, #公司地址,没有识别出来时返回"FailInRecognition""capital" : string, #注册资本,没有识别出来时返回"FailInRecognition""business": string, #经营范围,没有识别出来时返回"FailInRecognition""emblem" : string, #国徽位置[top,left,height,width],没有识别出来时返回"FailInDetection""title" : string, #标题位置[top,left,height,width],没有识别出来时返回"FailInDetection""stamp" : string, #印章位置[top,left,height,width],没有识别出来时返回"FailInDetection""qrcode" : string, #二维码位置[top,left,height,width],没有识别出来时返回"FailInDetection""success" : bool, #识别成功与否 true/false"request_id": string
}

购买后,在云市场列表里展示,你可要点击进去查看AppCode等其主要信息(接口调用里需要AppCode)

简单的API介绍,但挺有效了的,唯一不好的就是没有错误返回码的描述,需要自己测试。

二、代码开发

闲话少说,上代码:

  1. AliyunImageRecognitionUtil :阿里云图像识别工具类
package com.casic.cloud.qcy.util;import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.web.multipart.commons.CommonsMultipartFile;import com.alibaba.fastjson.JSONObject;
import com.casic.cloud.qcy.constant.Constants;import sun.misc.BASE64Encoder;/** * @ClassName: AliyunImageRecognitionUtil * @Description: 阿里云图像识别工具类* @author: tianpengw* @date 2019年3月21日 上午8:49:08 *  */
public class AliyunImageRecognitionUtil {private static String businessLicenceHost = PropertiesUtil.getProperties("businessLicenceHost");private static String businessLicencePath = PropertiesUtil.getProperties("businessLicencePath");private static String method = "POST";private static String appCode = PropertiesUtil.getProperties("appCode");/*** * @Description: 根据文件全路径识别* @author: tianpengw* @param imgPath* @return*/public static Map<String,Object> bussinessLicenceRecognition(String imgPath){Map<String,Object> resultMap = new HashMap<String,Object>();Map<String, String> headers = new HashMap<String, String>();//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105headers.put("Authorization", "APPCODE " + appCode);headers.put("Content-Type", "application/json; charset=UTF-8");Map<String, String> querys = new HashMap<String, String>();String bodys = "{\"image\":\""+imageToBase64Str(imgPath)+"\"}";try {/*** 重要提示如下:* HttpUtils请从* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java* 下载** 相应的依赖请参照* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml*/HttpResponse response = AliyunHttpUtils.doPost(businessLicenceHost, businessLicencePath, method, headers, querys, bodys);String resStr = EntityUtils.toString(response.getEntity());System.out.println(resStr);resultMap = JSONObject.parseObject(resStr, Map.class);//获取response的body} catch (Exception e) {e.printStackTrace();}return resultMap;}/*** * @Description: 根据InputStream识别* @author: tianpengw* @param imgPath* @return*/public static Map<String,Object> bussinessLicenceRecognition(InputStream inputStream){Map<String,Object> resultMap = new HashMap<String,Object>();Map<String, String> headers = new HashMap<String, String>();//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105headers.put("Authorization", "APPCODE " + appCode);headers.put("Content-Type", "application/json; charset=UTF-8");Map<String, String> querys = new HashMap<String, String>();// 加密BASE64Encoder encoder = new BASE64Encoder();byte[] data = null;try {data = new byte[inputStream.available()];inputStream.read(data);inputStream.close();} catch (IOException e) {e.printStackTrace();}String bodys = "{\"image\":\""+encoder.encode(data)+"\"}";try {/*** 重要提示如下:* HttpUtils请从* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java* 下载** 相应的依赖请参照* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml*/HttpResponse response = AliyunHttpUtils.doPost(businessLicenceHost, businessLicencePath, method, headers, querys, bodys);String resStr = EntityUtils.toString(response.getEntity());System.out.println(resStr);resultMap = JSONObject.parseObject(resStr, Map.class);resultMap.put("errCode", Constants.RESULT_SUCCESS);//获取response的body} catch (Exception e) {e.printStackTrace();resultMap.put("errCode", Constants.RESULT_FAIL);}return resultMap;}/*** * @Description: 根据byte[]识别* @author: tianpengw* @param imgPath* @return*/public static Map<String,Object> bussinessLicenceRecognition( byte[] data){Map<String,Object> resultMap = new HashMap<String,Object>();Map<String, String> headers = new HashMap<String, String>();//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105headers.put("Authorization", "APPCODE " + appCode);headers.put("Content-Type", "application/json; charset=UTF-8");Map<String, String> querys = new HashMap<String, String>();// 加密BASE64Encoder encoder = new BASE64Encoder();String bodys = "{\"image\":\""+encoder.encode(data)+"\"}";try {/*** 重要提示如下:* HttpUtils请从* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java* 下载** 相应的依赖请参照* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml*/HttpResponse response = AliyunHttpUtils.doPost(businessLicenceHost, businessLicencePath, method, headers, querys, bodys);String resStr = EntityUtils.toString(response.getEntity());System.out.println(resStr);resultMap = JSONObject.parseObject(resStr, Map.class);resultMap.put("errCode", Constants.RESULT_SUCCESS);//获取response的body} catch (Exception e) {e.printStackTrace();resultMap.put("errCode", Constants.RESULT_FAIL);}return resultMap;}/*** 图片转base64字符串* @param imgFile 图片路径* @return*/public static String imageToBase64Str(String imgFile) {InputStream inputStream = null;byte[] data = null;try {inputStream = new FileInputStream(imgFile);data = new byte[inputStream.available()];inputStream.read(data);inputStream.close();} catch (IOException e) {e.printStackTrace();}// 加密BASE64Encoder encoder = new BASE64Encoder();return encoder.encode(data);}public static void main(String[] args) {String imgPath = "d:/yyzznew1.jpg";Map<String,Object> map = AliyunImageRecognitionUtil.bussinessLicenceRecognition(imgPath);System.out.println(map.get("person"));System.out.println(map.get("reg_num"));}
}
  1. AliyunHttpUtils :阿里云httpUtils
package com.casic.cloud.qcy.util;import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;/** * @ClassName: AliyunHttpUtils * @Description: * @author: tianpengw* @date 2019年3月21日 上午8:44:51 *  */
public class AliyunHttpUtils {/*** get* * @param host* @param path* @param method* @param headers* @param querys* @return* @throws Exception*/public static HttpResponse doGet(String host, String path, String method, Map<String, String> headers, Map<String, String> querys)throws Exception {       HttpClient httpClient = wrapClient(host);HttpGet request = new HttpGet(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}return httpClient.execute(request);}/*** post form* * @param host* @param path* @param method* @param headers* @param querys* @param bodys* @return* @throws Exception*/public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, Map<String, String> bodys)throws Exception {        HttpClient httpClient = wrapClient(host);HttpPost request = new HttpPost(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (bodys != null) {List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();for (String key : bodys.keySet()) {nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));}UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");request.setEntity(formEntity);}return httpClient.execute(request);}  /*** Post String* * @param host* @param path* @param method* @param headers* @param querys* @param body* @return* @throws Exception*/public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, String body)throws Exception {     HttpClient httpClient = wrapClient(host);HttpPost request = new HttpPost(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (StringUtils.isNotBlank(body)) {request.setEntity(new StringEntity(body, "utf-8"));}return httpClient.execute(request);}/*** Post stream* * @param host* @param path* @param method* @param headers* @param querys* @param body* @return* @throws Exception*/public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, byte[] body)throws Exception {        HttpClient httpClient = wrapClient(host);HttpPost request = new HttpPost(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (body != null) {request.setEntity(new ByteArrayEntity(body));}return httpClient.execute(request);}/*** Put String* @param host* @param path* @param method* @param headers* @param querys* @param body* @return* @throws Exception*/public static HttpResponse doPut(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, String body)throws Exception {       HttpClient httpClient = wrapClient(host);HttpPut request = new HttpPut(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (StringUtils.isNotBlank(body)) {request.setEntity(new StringEntity(body, "utf-8"));}return httpClient.execute(request);}/*** Put stream* @param host* @param path* @param method* @param headers* @param querys* @param body* @return* @throws Exception*/public static HttpResponse doPut(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, byte[] body)throws Exception {      HttpClient httpClient = wrapClient(host);HttpPut request = new HttpPut(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (body != null) {request.setEntity(new ByteArrayEntity(body));}return httpClient.execute(request);}/*** Delete*  * @param host* @param path* @param method* @param headers* @param querys* @return* @throws Exception*/public static HttpResponse doDelete(String host, String path, String method, Map<String, String> headers, Map<String, String> querys)throws Exception {      HttpClient httpClient = wrapClient(host);HttpDelete request = new HttpDelete(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}return httpClient.execute(request);}private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {StringBuilder sbUrl = new StringBuilder();sbUrl.append(host);if (!StringUtils.isBlank(path)) {sbUrl.append(path);}if (null != querys) {StringBuilder sbQuery = new StringBuilder();for (Map.Entry<String, String> query : querys.entrySet()) {if (0 < sbQuery.length()) {sbQuery.append("&");}if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {sbQuery.append(query.getValue());}if (!StringUtils.isBlank(query.getKey())) {sbQuery.append(query.getKey());if (!StringUtils.isBlank(query.getValue())) {sbQuery.append("=");sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));}                    }}if (0 < sbQuery.length()) {sbUrl.append("?").append(sbQuery);}}return sbUrl.toString();}private static HttpClient wrapClient(String host) {HttpClient httpClient = new DefaultHttpClient();if (host.startsWith("https://")) {sslClient(httpClient);}return httpClient;}private static void sslClient(HttpClient httpClient) {try {SSLContext ctx = SSLContext.getInstance("TLS");X509TrustManager tm = new X509TrustManager() {public X509Certificate[] getAcceptedIssuers() {return null;}public void checkClientTrusted(X509Certificate[] xcs, String str) {}public void checkServerTrusted(X509Certificate[] xcs, String str) {}};ctx.init(null, new TrustManager[] { tm }, null);SSLSocketFactory ssf = new SSLSocketFactory(ctx);ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);ClientConnectionManager ccm = httpClient.getConnectionManager();SchemeRegistry registry = ccm.getSchemeRegistry();registry.register(new Scheme("https", 443, ssf));} catch (KeyManagementException ex) {throw new RuntimeException(ex);} catch (NoSuchAlgorithmException ex) {throw new RuntimeException(ex);}}
}
  1. PropertiesUtil :读取配置文件工具
package com.casic.cloud.qcy.util;import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;/** * @ClassName: PropertiesUtil * @Description: * @author tianpengw* @date 2018年6月27日 下午3:09:08 *  */
public class PropertiesUtil {private static Logger log = LogManager.getLogger(PropertiesUtil.class);private static Properties prop;static{try{if(null == prop){prop = new Properties();}InputStream fis = null;fis =  ClassLoaderUtils.getResourceAsStream("common.properties", PropertiesUtil.class);if(fis!=null){prop.load(fis);// 将属性文件流装载到Properties对象中   fis.close();// 关闭流   }}catch (Exception e) {log.error("读取配置文件出错:" + e );}}/*** * @Description: 根据key获取配置的值* @author tianpengw * @param key* @return*/public static String getProperties(String key){if(key==null) return null;return prop.getProperty(key);}/*** * @Description: * @author tianpengw * @param proper 读取配置的文件名称* @param key* @return*/public static String getPropertie(String resourceName,String key){InputStream fis =  ClassLoaderUtils.getResourceAsStream(resourceName, PropertiesUtil.class);if(fis!=null){try {prop.load(fis);fis.close();// 关闭流   } catch (IOException e) {e.printStackTrace();}   }if(key==null) return null;return prop.getProperty(key);}/*** * @Description: 根据key获取配置的值,若没有,则取传过来的默认的值* @author tianpengw * @param key* @param defaultValue 默认值* @return*/public static String getProperties(String key,String defaultValue){if(key==null) return null;return prop.getProperty(key, defaultValue);}
}
  1. 配置文件common.properties(放在 src/main/resources下)
#aliyun business licence recognition
businessLicenceHost = https://dm-58.data.aliyun.com
businessLicencePath = /rest/160601/ocr/ocr_business_license.json
appCode = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

三、测试结果

  1. 成功的结果:
  2. 失败结果,当处理非营业执照的图片时将会返回“invalid business licence”结果,我这么没有进行判断处理直接按照正确的json解析,所以报错,此处你们可以按照自己需求选择处理逻辑。从这返回结果也看的出该接口做的不合理,返回内容不统一,导致接口使用者,必须知晓各种情况才能做有效的处理,如果此处能返回json串,给错误码那对于调用者来说就方便多了。

四、后记

  1. 此API适合一般的营业执照和新的三证合一的营业执照,但是字段获取的含义不同,此处需要注意;
  2. 由于API并未列出错误码,在未知的错误情况还包含识别次数不够的时候是报错还是有错误提示(由于条件限制,此情况无法验证);
  3. 工具是死的,人是活的,开发需要考虑尽可能多的情况,来保证代码的完善。

至此,工具介绍完毕,欢迎交流。

阿里云-印刷文字识别-营业执照识别相关推荐

  1. 阿里云OCR-身份证/营业执照识别

    在进行具体的服务调用之前,请参见以下步骤,完成准备工作: 创建阿里云AccessKeyId和AccessKeySecret.具体请参见创建AccessKey. 安装Java依赖.具体请参见安装Java ...

  2. 【阿里云高校计划】身份证识别系统搭建 day2 【抛砖引玉】

    身份证识别系统搭建 [阿里云高校计划]身份证识别系统搭建 day2 [抛砖引玉] 身份证识别系统搭建 一.项目简介 二.获取视觉智能开放平台提供的SDK 三.项目实现 (一)前端index.html ...

  3. python 验证码识别 阿里云_python3调用阿里云图像识别OCR-实现验证码识别

    python3 调用阿里云图像识别OCR-验证码识别 前言 使用别人的接口,是需要在别人的平台上创建应用的. 所以,我们要先去 购买地址:(放心,免费的.) https://market.aliyun ...

  4. 9月27日云栖精选夜读:阿里云首推免费人脸识别SDK 让每个APP轻松拥有短视频AR特效...

    摘要: 早在今年五月,阿里云已经推出了短视频解决方案.近日,阿里云再次率先颠覆行业,在业内首推免费的人脸识别SDK,结合其原有的短视频能力,大大降低了人脸识别+AR特效+短视频的入行门槛. 早在今年五 ...

  5. 9月27日云栖精选夜读:阿里云首推免费人脸识别SDK 让每个APP轻松拥有短视频AR特效

    想不想知道是什么 早在今年五月,阿里云已经推出了短视频解决方案.近日,阿里云再次率先颠覆行业,在业内首推免费的人脸识别SDK,结合其原有的短视频能力,大大降低了人脸识别+AR特效+短视频的入行门槛. ...

  6. ORC工具(使用阿里云统一文字识别接口实现)

    废话不多,直接上代码. public class Text {/*** 使用AK&SK初始化账号Client** @param accessKeyId 阿里云的accessKeyId* @pa ...

  7. 【探花交友】阿里云OSS、百度人脸识别

    文章目录 1.完善用户信息 1.1.阿里云OSS 1.2.百度人脸识别 1.完善用户信息 用户在首次登录时需要完善个人信息,包括性别.昵称.生日.城市.头像等.其中,头像数据需要做图片上传,这里采用阿 ...

  8. 阿里云servless实现身份证智能识别Demo

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 前言 servless实现身份证智能识别. 提示:以下是本篇文章正文内容,下面案例可供参考 一.如何快速实现阿里云Servless实现 ...

  9. 阿里云智能文字转语音源码

    介绍: 去阿里云免费开通服务,获取appkey,accessKeyId,accessKeySecret 在源码里替换下就可以使用了. 创建项目获取Appkey 创建获取accessKeyId和acce ...

最新文章

  1. Lombok 的爱恨情仇
  2. 更换group.id时kafka从哪开始消费
  3. Windows Server 2012 R2 VDI系列(一)—环境简介
  4. 给Source Insight做个外挂系列之一--发现Source Insight
  5. 类的无参方法和Doc注释
  6. 可提高效率的网页设计PS插件
  7. win10护眼模式_电脑技巧|Win10系统如何设置护眼模式?
  8. 推荐一款Linux服务器连接工具FinalShell
  9. POJ1061 青蛙的约会(扩展欧几里得)题解
  10. mysql数据库任务驱动式教程课后答案_MySQL数据库任务驱动式教程
  11. Flutter 开发环境搭建Unable to ‘pub upgrade‘ flutter tool. Retrying in five seconds...
  12. 洛谷 P4392 Sound 静音问题
  13. 计算机组成原理第五版(白中英)第三章多层次存储器 习题
  14. 最常用的9款免费开源游戏引擎
  15. 停车还能360全方位影像_辅助停车,新手司机就选360全景吧!
  16. python中的关系运算符可以连续室友_在Python中,关系运算符可以连续使用,例如135等价于13 and 35。...
  17. wpf开源ui引用步骤_计划成功的开源聚会的3个步骤
  18. 使用cpolar配置内网访问(内网穿透)教程(超详细,简单)
  19. 数独 ( 二 ) ——生成数独终局
  20. 【负荷预测、电价预测】基于神经网络的负荷预测和价格预测(Matlab代码实现)

热门文章

  1. Mysql Order By 与 Group By
  2. “百度杯”CTF比赛 2017 二月场 wp
  3. OpenStack高级控制服务之使用编配服务(Heat)实现自动化部署云主机
  4. 删除非空目录linux_如何在Linux中删除空的非空目录
  5. 一篇文章讲清什么是NVMe
  6. 153870-20-3,S-acetyl-PEG3-alcohol羟基可以反应进一步衍生化合物
  7. 全新的 Uber 应用设计
  8. 中学计算机课教具,中学教师20余载自制教具 “变废为宝”让课堂易懂
  9. 【JavaSE】十二生肖带你走进枚举类
  10. Nginx目录结构、编译参数、状态码概述