java 开发 face++ 人脸特征识别系统

首先要在 face++ 注册一个账号,并且创建一个应用,拿到 api key 和 api secret;

下载 java 接入工具,一个 jar 包:https://github.com/FacePlusPlus/java-sdk

请求返回的数据是 json 格式,需要导入 json 解析包:

commons-beanutils-1.8.3.jar commons-lang-2.5.jar commons-collections-3.2.2.jar ezmorph-1.0.6.jar json-lib-2.3-jdk15.jar

图片上传类:FileUpLoad.java

 1 package com.krry;
 2 
 3 import java.io.File;
 4 import java.io.FileOutputStream;
 5 import java.io.IOException;
 6 import java.io.InputStream;
 7 import java.util.List;
 8 import java.util.UUID;
 9 import javax.servlet.annotation.WebServlet;
10 import javax.servlet.http.HttpServlet;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13 
14 import org.apache.commons.fileupload.FileItem;
15 import org.apache.commons.fileupload.FileItemFactory;
16 import org.apache.commons.fileupload.disk.DiskFileItemFactory;
17 import org.apache.commons.fileupload.servlet.ServletFileUpload;
18 
19 /**
20  *  FileUpLoad
21  * @author krry
22  *
23  */
24 @WebServlet(name="fileUp",urlPatterns={"/show"})
25 public class FileUpLoad extends HttpServlet{
26     
27     private static final long serialVersionUID = 1L;
28 
29     @Override
30     public void service(HttpServletRequest request,HttpServletResponse response) throws IOException{
31         //判断是不是文件上传,根据请求包里面的内容是否为二进制提交的上传的文件 true/false
32         boolean isMultPart = ServletFileUpload.isMultipartContent(request);
33         if(isMultPart){
34             //创建文件上传工厂
35             FileOutputStream out = null;
36             InputStream in = null;
37             try {
38                  FileItemFactory factory = new DiskFileItemFactory();
39                  //创建容器文件类,负责处理上传的文件数据
40                 ServletFileUpload upload = new ServletFileUpload(factory);
41                  //解析上传文件,其实就是解析表单传过来的数据
42                 List<FileItem> fileItems = upload.parseRequest(request);
43                 //只需要拿一张图片
44                 in = fileItems.get(0).getInputStream();
45                 //获取源文件名
46                 String Ofilename = fileItems.get(0).getName();
47                 //拿到后缀名
48                 String ext = Ofilename.substring(Ofilename.indexOf("."), Ofilename.length());
49                 //拿到一个目录,绝对地址
50                 String path =request.getSession().getServletContext().getRealPath("/");
51                 //生成一个唯一的名字
52                 String fileName = UUID.randomUUID().toString() + ext;
53                 //定义上传目录
54                 String dirPath = path+"/upload";
55                 File dirFile = new File(dirPath);
56                 //如果此文件夹不存在
57                 if(!dirFile.exists()){
58                     dirFile.mkdirs();//创建此文件夹
59                 }
60                 //配置文件路径
61                 String filePath = path+"/upload/"+fileName;
62                 //输出流
63                 out = new FileOutputStream(filePath);
64                 //边读取边编写 字节流
65                 byte[] b = new byte[1024];
66                 int length = 0;
67                 while((length = in.read(b)) != -1){  //读到字节数组里面去
68                     out.write(b,0,length);   //从0开始写,写你读了多少
69                 }
70                 //放在request作用域里
71                 request.setAttribute("imgSrc", filePath);
72                 request.setAttribute("imgSrcPage", "upload/"+fileName);
73                 //请求转发,转发到另一个servlet
74                 request.getRequestDispatcher("showImage").forward(request, response);
75             } catch (Exception e) {
76                 
77                 e.printStackTrace();
78             }finally{
79                 out.close();
80                 in.close();
81             }
82         }
83     }
84 
85 }

人脸识别类:Analysis.java

这里返回一个 json 字符串,放到作用域,在前台获取

  1 package com.krry;
  2 
  3 import java.io.ByteArrayOutputStream;
  4 import java.io.DataOutputStream;
  5 import java.io.File;
  6 import java.io.FileInputStream;
  7 import java.io.IOException;
  8 import java.io.InputStream;
  9 import java.net.HttpURLConnection;
 10 import java.net.URL;
 11 import java.net.URLEncoder;
 12 import java.util.ArrayList;
 13 import java.util.Collections;
 14 import java.util.HashMap;
 15 import java.util.Iterator;
 16 import java.util.List;
 17 import java.util.Map;
 18 import java.util.Random;
 19 import java.util.TreeMap;
 20 
 21 import javax.net.ssl.SSLException;
 22 import javax.servlet.annotation.WebServlet;
 23 import javax.servlet.http.HttpServlet;
 24 import javax.servlet.http.HttpServletRequest;
 25 import javax.servlet.http.HttpServletResponse;
 26 
 27 import net.sf.json.JSONArray;
 28 import net.sf.json.JSONObject;
 29 
 30 /**
 31  *  analysis
 32  * @author krry
 33  * String 转json 需要的jar包:版本不能弄错
 34  * commons-beanutils-1.8.3.jar 
 35     commons-lang-2.5.jar
 36     commons-collections-3.2.2.jar
 37     ezmorph-1.0.6.jar 
 38     json-lib-2.3-jdk15.jar 
 39  */
 40 @WebServlet(name="analysis",urlPatterns={"/showImage"})
 41 public class Analysis extends HttpServlet{
 42     
 43     private static final long serialVersionUID = 1L;
 44     
 45     @Override
 46     public void service(HttpServletRequest request,HttpServletResponse response) throws IOException{
 47         
 48         //获取上传的图片地址
 49         String imgPath = request.getAttribute("imgSrc").toString();
 50         File file = new File(imgPath);
 51         byte[] buff = getBytesFromFile(file);
 52         String url = "https://api-cn.faceplusplus.com/facepp/v3/detect";
 53         HashMap<String, String> map = new HashMap<String, String>();
 54         HashMap<String, byte[]> byteMap = new HashMap<String, byte[]>();
 55         map.put("api_key", "15N9eBF_ieE-N2nvI7oK_A9anh2meuUS");
 56         map.put("api_secret", "cBnvsIAo8VaOj53lXCWlpuOSd0NrsFif");
 57         map.put("return_landmark", "1");
 58         map.put("return_attributes", "gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus");
 59         byteMap.put("image_file", buff);
 60         try{
 61             byte[] bacd = post(url, map, byteMap);
 62             String str = new String(bacd);
 63             
 64             JSONObject json = JSONObject.fromObject(str);
 65             JSONArray faces = json.getJSONArray("faces");
 66             
 67             //解析失败
 68             if(str.indexOf("error_message") != -1 || faces.size() == 0){
 69                 request.getSession().setAttribute("error", "解析失败,请重新选择");
 70                 //重定向到首页
 71                 response.sendRedirect("index.jsp");
 72             }else{
 73                 //将人脸信息字符串str信息放到作用域
 74                 request.setAttribute("face", str);
 75                 //请求转发,返回到页面
 76                 request.getRequestDispatcher("showImage.jsp").forward(request, response);
 77             }
 78         }catch (Exception e) {
 79             e.printStackTrace();
 80         }
 81         
 82     }
 83     
 84     
 85     private final static int CONNECT_TIME_OUT = 30000;
 86     private final static int READ_OUT_TIME = 50000;
 87     private static String boundaryString = getBoundary();
 88     
 89     protected static byte[] post(String url, HashMap<String, String> map, HashMap<String, byte[]> fileMap) throws Exception {
 90         HttpURLConnection conne;
 91         URL url1 = new URL(url);
 92         conne = (HttpURLConnection) url1.openConnection();
 93         conne.setDoOutput(true);
 94         conne.setUseCaches(false);
 95         conne.setRequestMethod("POST");
 96         conne.setConnectTimeout(CONNECT_TIME_OUT);
 97         conne.setReadTimeout(READ_OUT_TIME);
 98         conne.setRequestProperty("accept", "*/*");
 99         conne.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
100         conne.setRequestProperty("connection", "Keep-Alive");
101         conne.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1)");
102         DataOutputStream obos = new DataOutputStream(conne.getOutputStream());
103         Iterator iter = map.entrySet().iterator();
104         while(iter.hasNext()){
105             Map.Entry<String, String> entry = (Map.Entry) iter.next();
106             String key = entry.getKey();
107             String value = entry.getValue();
108             obos.writeBytes("--" + boundaryString + "\r\n");
109             obos.writeBytes("Content-Disposition: form-data; name=\"" + key
110                     + "\"\r\n");
111             obos.writeBytes("\r\n");
112             obos.writeBytes(value + "\r\n");
113         }
114         if(fileMap != null && fileMap.size() > 0){
115             Iterator fileIter = fileMap.entrySet().iterator();
116             while(fileIter.hasNext()){
117                 Map.Entry<String, byte[]> fileEntry = (Map.Entry<String, byte[]>) fileIter.next();
118                 obos.writeBytes("--" + boundaryString + "\r\n");
119                 obos.writeBytes("Content-Disposition: form-data; name=\"" + fileEntry.getKey()
120                         + "\"; filename=\"" + encode(" ") + "\"\r\n");
121                 obos.writeBytes("\r\n");
122                 obos.write(fileEntry.getValue());
123                 obos.writeBytes("\r\n");
124             }
125         }
126         obos.writeBytes("--" + boundaryString + "--" + "\r\n");
127         obos.writeBytes("\r\n");
128         obos.flush();
129         obos.close();
130         InputStream ins = null;
131         int code = conne.getResponseCode();
132         try{
133             if(code == 200){
134                 ins = conne.getInputStream();
135             }else{
136                 ins = conne.getErrorStream();
137             }
138         }catch (SSLException e){
139             e.printStackTrace();
140             return new byte[0];
141         }
142         ByteArrayOutputStream baos = new ByteArrayOutputStream();
143         byte[] buff = new byte[4096];
144         int len;
145         while((len = ins.read(buff)) != -1){
146             baos.write(buff, 0, len);
147         }
148         byte[] bytes = baos.toByteArray();
149         ins.close();
150         return bytes;
151     }
152     private static String getBoundary() {
153         StringBuilder sb = new StringBuilder();
154         Random random = new Random();
155         for(int i = 0; i < 32; ++i) {
156             sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".charAt(random.nextInt("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_".length())));
157         }
158         return sb.toString();
159     }
160     private static String encode(String value) throws Exception{
161         return URLEncoder.encode(value, "UTF-8");
162     }
163     
164     public static byte[] getBytesFromFile(File f) {
165         if (f == null) {
166             return null;
167         }
168         try {
169             FileInputStream stream = new FileInputStream(f);
170             ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
171             byte[] b = new byte[1000];
172             int n;
173             while ((n = stream.read(b)) != -1)
174                 out.write(b, 0, n);
175             stream.close();
176             out.close();
177             return out.toByteArray();
178         } catch (IOException e) {
179         }
180         return null;
181     }
182     
183 
184 }

解析 json 字符串,先转换成 json 格式,json 数组,一个个获取人脸属性

  1 <%@page import="net.sf.json.JSONObject"%>
  2 <%@page import="net.sf.json.JSONArray"%>
  3 <%@ page language="java" import="java.io.File" pageEncoding="utf-8"%>
  4 <%@page import="java.math.BigDecimal"%>
  5 <%@ page import="java.util.*" %>
  6 <%
  7 
  8     String path = request.getContextPath();
  9     int port = request.getServerPort();
 10     String basePath = null; 
 11     if(port==80){
 12         basePath = request.getScheme()+"://"+request.getServerName()+path;
 13     }else{
 14         basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
 15     }
 16     pageContext.setAttribute("basePath", basePath);
 17     
 18     
 19     Object str = request.getAttribute("face");
 20     JSONObject json = JSONObject.fromObject(str);
 21     JSONArray faces = json.getJSONArray("faces");
 22     StringBuffer strBuff = new StringBuffer();
 23     //识别出人脸的个数
 24     int length = faces.size();
 25     
 26     //识别出多少个人脸,就是循环多少次
 27     for(int i = 0;i < length;i++){
 28     
 29         JSONObject face = faces.getJSONObject(i);  //拿到第i+1个人脸部信息
 30         JSONObject attribute = face.getJSONObject("attributes");//拿到脸部属性
 31         
 32         //年龄
 33         JSONObject age = attribute.getJSONObject("age");
 34         int ageValue = age.getInt("value");
 35         
 36         //性别
 37         JSONObject gender = attribute.getJSONObject("gender");
 38         String sex = gender.getString("value");
 39         if(sex.equals("Male")) sex = "男";
 40         else sex = "女";
 41         
 42         //人种
 43         JSONObject ethnicity = attribute.getJSONObject("ethnicity");
 44         String races = ethnicity.getString("value");
 45         if(races.equals("Asian")) races = "亚洲人";
 46         else if(races.equals("White")) races = "白人";
 47         else races = "黑人";
 48         
 49         //微笑程度
 50         JSONObject smile = attribute.getJSONObject("smile");
 51         String smileRange = String.format("%.2f",smile.getDouble("value"));
 52         
 53         //表情
 54         JSONObject emotion = attribute.getJSONObject("emotion");
 55         Map<String,Double> mapp = new TreeMap<String,Double>();
 56         //装配表情信息到map
 57         double sadness = emotion.getDouble("sadness");
 58         mapp.put("伤心", sadness);
 59         double neutral = emotion.getDouble("neutral");
 60         mapp.put("平静", neutral);
 61         double disgust = emotion.getDouble("disgust");
 62         mapp.put("厌恶", disgust);
 63         double anger = emotion.getDouble("anger");
 64         mapp.put("愤怒", anger);
 65         double happiness = emotion.getDouble("happiness");
 66         mapp.put("高兴", happiness);
 67         double surprise = emotion.getDouble("surprise");
 68         mapp.put("惊讶", surprise);
 69         double fear = emotion.getDouble("fear");
 70         mapp.put("恐惧", fear);
 71         
 72         //利用list取最大值
 73         List<Double> listmap = new ArrayList<Double>();
 74         for(String key:mapp.keySet()){
 75             listmap.add(mapp.get(key));
 76         }
 77         //取到最大值
 78         double valueMax = Collections.max(listmap);
 79         //根据map的value获取map的key  
 80         String emotionMax = "";  
 81         for (Map.Entry<String, Double> entry : mapp.entrySet()) {  
 82             if(valueMax == entry.getValue()){  
 83                 emotionMax = entry.getKey();  
 84             }
 85         }
 86         
 87         //颜值分数
 88         JSONObject beauty = attribute.getJSONObject("beauty");
 89         String beautys = "";
 90         if(sex.equals("男")) beautys = String.format("%.2f",beauty.getDouble("male_score"));
 91         else beautys = String.format("%.2f",beauty.getDouble("female_score"));
 92         
 93         //面部状态
 94         JSONObject skinstatus = attribute.getJSONObject("skinstatus");
 95         Map<String,String> mapSkin = new TreeMap<String,String>();
 96         //装配信息到map
 97         double health = skinstatus.getDouble("health");
 98         mapSkin.put("健康指数", String.format("%.2f",health));
 99         double stain = skinstatus.getDouble("stain");
100         mapSkin.put("色斑指数", String.format("%.2f",stain));
101         double acne = skinstatus.getDouble("acne");
102         mapSkin.put("青春痘指数", String.format("%.2f",acne));
103         double dark_circle = skinstatus.getDouble("dark_circle");
104         mapSkin.put("黑眼圈指数", String.format("%.2f",dark_circle));
105         
106         strBuff.append("<br>");
107         strBuff.append("<span>年龄:").append(ageValue).append("岁</span>");
108         strBuff.append("<span>性别:").append(sex).append("</span>");
109         strBuff.append("<br>").append("<br>");
110         strBuff.append("<span>人种:").append(races+"</span>");
111         strBuff.append("<span>微笑程度:").append(smileRange+"%</span>");
112         strBuff.append("<br>").append("<br>");
113         strBuff.append("<span>表情:").append(emotionMax+"</span>");
114         strBuff.append("<span>颜值分数:").append(beautys+"</span>");
115         strBuff.append("<br>").append("<br>");
116         int counts = 0;
117         for(String key:mapSkin.keySet()){
118             counts++;
119             strBuff.append("<span>"+key+":").append(mapSkin.get(key)+"</span>");
120             if(counts % 2 == 0) strBuff.append("<br>").append("<br>");
121         }
122              
123         strBuff.append("<br>");
124              
125     }
126       
127       
128 
129 %>
130 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
131 <html>
132   <head>
133     
134     <title> Java开发人脸特征识别系统  --krry</title>
135     
136     <meta http-equiv="pragma" content="no-cache">
137     <meta http-equiv="cache-control" content="no-cache">
138     <meta http-equiv="expires" content="0">    
139     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
140     <meta http-equiv="description" content="This is my page">
141 
142     <style type="text/css">
143          *{padding:0px;margin:0px;}
144          body{background: #FFF;background:url("images/78788.jpg");background-size:cover;}
145          .a_btn{text-decoration:none;font-family:"幼圆";background:#fff;transition:.6s;color:#f60;cursor:pointer;width:100px;height:40px;border-radius:10px;display: inline-block;text-align:center;line-height:40px;}
146         .aa{position: absolute;left: 48px;top: 31px;}
147         .a_btn:hover{background:red;color:#fff;transition:.6s;}
148          .clear{clear:both;}
149          .title{margin-top: 25px;font-size:48px;font-family:"幼圆";color: #ff7272;text-shadow: 1px 1px 3px #ff3737;text-align:center;line-height:45px;}
150          .content{margin:0 auto;width:900px;}
151           .content .img{float:left;margin-top:30px;}
152           .content .img img{border-radius:10px;}
153          .content .describe{margin-top:30px;width:500px;color:#000;font-family:"幼圆";font-size:18px;float:right;}
154          .content .describe span{width: 190px;display: inline-block;}
155     </style>
156 
157   </head>
158   
159   <body>
160           <div class="aa"><a class="a_btn" href="${basePath}">返回</a></div>
161           <div class="title">人脸识别结果</div>
162           <div class="content">
163             <div class = "img">
164                <img style="float:left" width="350" src="${imgSrcPage}" />
165             </div>
166             <div style="float:right" class="describe"><%=strBuff.toString() %></div>
167             <div class="clear"></div>
168         </div>
169   </body>
170 </html>

首页:

 1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
 2 
 3 <%
 4 
 5     Object ermsg = request.getSession().getAttribute("error");
 6     StringBuffer strBuff = new StringBuffer();
 7     if(ermsg != null){
 8         //清除作用域
 9         request.getSession().removeAttribute("error");
10         strBuff.append("loading('"+ermsg+"',4)");
11     }
12 %>
13 
14 <!doctype html>
15 <html>
16     <head>
17        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
18        <meta name="keywords" content="关键词,关键词">
19        <meta name="description" content="">
20        <link rel="stylesheet" type="text/css" href="css/sg.css" />
21        <link rel="stylesheet" type="text/css" href="css/sg/css/animate.css" />
22        <link rel="stylesheet" type="text/css" href="css/sg/css/sg.css" />
23        
24        <title> Java开发人脸特征识别系统  --krry</title>
25        <style type="text/css">
26            *{padding:0px;margin:0px;}
27            body{background:url("images/5.jpg");background-size:cover;font-size:18px;font-family:"微软雅黑";color:#666;}
28            img{border:none;}
29            h1{font-size:24px;}
30            .title{margin-top: 30px;font-size:48px;font-family:"幼圆";color: #ff7272;text-shadow: 1px 1px 3px #ff3737;text-align:center;line-height:45px;}
31            .box{margin:100px auto;text-align:center;}
32            .box .b_btn{width:100px;height:40px;background:#fff;transition:.6s;font-size:16px;font-family:"微软雅黑";display:block;margin:54px auto;text-align:center;
33                        cursor:pointer;line-height:40px;text-decoration:none;color:#F60;border:1px;border-radius:12px}
34               .box .b_btn:hover{background:red;color:#fff;transition:.6s;}
35               .busbu{top:0;background:rgba(0, 0, 0, 0.2);display:none;width:100%;height:100%;position:absolute;z-index:1000;}
36        </style>
37     </head>
38 
39 <body>
40    <!--action  提交的路径  method:post(打包传输) get(明文传输) enctype(采用二进制)-->
41    <form action="show" method="post" enctype="multipart/form-data">
42    <div class="box">
43        <div class="title">人脸特征识别系统 --krry</div>
44        <input type="file" id="fileChoice" accept="image/jpeg,image/png" style="display:none" name="files"/>
45        <a class="b_btn" href="javascript:void(0);" onclick="choice()">选择照片</a>
46        <input type="button" value="提交解析" class="b_btn" id="but"/>
47        <input type="submit" class="sub_btn" style="display:none;"/> 
48    </div>
49    </form>
50    <div class="busbu"></div>
51      <script src="js/jquery-1.11.3.min.js"></script>
52     <script src="js/sg.js"></script>
53     <script src="js/sgutil.js"></script>
54     <script type="text/javascript" src="css/sg/tz_util.js"></script>
55     <script type="text/javascript" src="css/sg/sg.js"></script>
56     <script type="text/javascript">
57     <%=strBuff.toString() %>
58     //选择照片
59     function choice(){
60        //js 弱类型  快速定位
61        var choose = document.getElementById("fileChoice");
62        choose.click();
63     }
64     $("#but").click(function(){
65         if($("#fileChoice").val()){//如果选择了照片
66             $(".sub_btn").click();
67             $(".busbu").show();
68             loading("正在解析",900);//再展示
69         }else{
70             $.tmDialog.alert({open:"top",content:"请先选择一张照片",title:"Krry温馨提醒"});
71         }
72     });
73       
74 </script>
75 </body>
76 
77 </html>

需要注意的点,json 字符串的转换和解析,获取 json 中人脸属性的方法 

git:https://github.com/Krryxa/face

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据结构与算法

洛谷P2925 [USACO08DEC]干草出售Hay For Sale

题目描述 Farmer John suffered a terrible loss when giant Australian cockroaches ate ...

30240
来自专栏mathor

Hanoi(汉诺塔)

13620
来自专栏Java成神之路

Java企业微信开发_02_通讯录同步

       登录企业微信—>管理工具—>通讯录同步助手—>开启“API接口同步”  ; 开启后,即可看到通讯录密钥,也可设置通讯录API的权限:读取或者编辑通...

96420
来自专栏大内老A

ASP.NET MVC的Model元数据与Model模板:将”ListControl”引入ASP.NET MVC

我们不仅可以创建相应的模板来根据Model元数据控制种类型的数据在UI界面上的呈现方法,还可以通过一些扩展来控制Model元数据本身。在某些情况下通过这两者的结...

37460
来自专栏Java与Android技术栈

当RxJava遇到AOP

公司打算开发一款全新的To C产品,因此我开始做一些搭建框架的事儿以及POC。新的产品能够使用一些比较新的技术,在新产品中我大量使用了Rx。这就导致了原先的AO...

10020
来自专栏木宛城主

PowerShell 获取Site Collection下被签出的文件

由于权限的设置,当文件被签出时导致别人不可见了,这对校验文件个数的人来说着实是件烦恼的事。幸好利用PowerShell,可以获取Site Collection下...

20670
来自专栏个人分享

Hive metastore源码阅读(一)

  不要问我为什么,因为爱,哈哈哈哈。。。进入正题,最近做项目顺带学习了下hive metastore的源码,进行下知识总结。

31810
来自专栏小樱的经验随笔

HDU 2438 Turn the corner(三分查找)

托一个学弟的福,学了一下他的最简便三分写法,然后找了一道三分的题验证了下,AC了一题,写法确实方便,还是我太弱了,漫漫AC路!各路大神,以后你们有啥好的简便写法...

30150
来自专栏一个会写诗的程序员的博客

【Kotlin 反应式编程】第1讲 你好,Reactive Programming

【Kotlin 反应式编程】第1讲 你好,Reactive Programming

9220
来自专栏Spark生态圈

[Spark SQL] 源码解析之Optimizer

optimizer 以及之后的模块都只会在触发了action操作后才会执行。优化器是用来将Resolved LogicalPlan转化为optimized Lo...

11120

扫码关注云+社区

领取腾讯云代金券