开启左侧

JAVA后端上传图片至企微暂时素材

[复制链接]
在线会员 WijgmVR 发表于 2024-2-29 15:27:44 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
1.使用场景

正在使用企业微疑API交心中,常常开辟者需要使用自界说的资本,好比收收当地图片消息,树立通信录自界说头像等。
为了完毕统一资本文献,一次上传能够屡次使用,那里供给了艳材办理交心:以media_id去标记资本文献,完毕文献的上传取下载。
以收收消息为示例:
JAVA后端上传图片至企微临时艳材-1.png


以JSSDK选图片上传为示例:
JAVA后端上传图片至企微临时艳材-2.png


上传的媒介文献限定
统统文献size必需年夜于5个字节
    图片(image):10MB,撑持JPG,PNG格局语音(voice) :2MB,播搁少度没有超越60s,仅撑持AMR格局望频(video) :10MB,撑持MP4格局一般文献(file):20MB
HTTP上传文献办法简析

HTTP是文原和谈,若需要通报两退造文献需要依靠于multipart/form-data格局
1.结构 HTTP恳求包

单个文献的multipart/form-data格局,以下:
  1. --分开符[换止]
  2. Content-Disposition: form-data; name="表单名"; filename="文献名"; filelength=文献实质巨细[换止]
  3. Content-Type: 范例[换止][换止]
  4. 文献的两退造实质[换止]--分开符--
复造代码
Content-Type按照差别文献范例能够树立对于应差别的值,以下表格:
文献范例Content-Type
一般文献application/octet-stream
jpg图片image/jpg
png图片image/png
bmp图片image/bmp
amr音频voice/amr
mp4望频video/mp4
若咱们树立:分开符为acebdf13572468,文献名为wework.txt,文献实质为mytext,因为上传临时艳材请求name牢固为media,那末机关的恳求实质为:
  1. --acebdf13572468
  2. Content-Disposition: form-data; name="media";filename="wework.txt"; filelength=6
  3. Content-Type: application/octet-stream
  4. mytext
  5. --acebdf13572468--
复造代码
2. 树立HTTP头部疑息
  1. POSTURLHTTP/1.1[换止]
  2. Content-Type: multipart/form-data; boundary=分开符[换止]
  3. Content-Length: 恳求体实质巨细[换止][换止]
  4. 第1步机关的恳求体实质
复造代码
假设咱们将第1步组拆的文献实质上传到企业微疑临时艳材,分开符与第1步设定值acebdf13572468,那末便获得以下:
  1. POSThttps://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=accesstoken001&type=file HTTP/1.1
  2. Content-Type: multipart/form-data; boundary=acebdf13572468
  3. Content-Length:168--acebdf13572468
  4. Content-Disposition: form-data; name="media";filename="wework.txt"; filelength=6
  5. Content-Type: application/octet-stream
  6. mytext
  7. --acebdf13572468--
复造代码
上传临时艳材

艳材上传获得media_id,该media_id仅三天内乱有用
media_id正在统一企业内乱使用之间能够同享
**恳求方法:**POST(HTTPS
**恳求地点:**https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
使用multipart/form-data POST上传文献, 文献标记名为"media"
参数分析:
参数必需分析
access_token挪用交心凭据
type媒介文献范例,别离有图片(image)、语音(voice)、望频(video),一般文献(file)
POST的恳求包中,form-data中媒介文献标记,应包罗有 filename、filelength、content-type等疑息
filename标记文献展示的称呼。好比,使用该media_id收消息时,展示的文献名由该字段掌握
恳求示例:
  1. POSThttps://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=accesstoken001&type=file HTTP/1.1
  2. Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
  3. Content-Length:220---------------------------acebdf13572468
  4. Content-Disposition: form-data; name="media";filename="wework.txt"; filelength=6
  5. Content-Type: application/octet-stream
  6. mytext
  7. ---------------------------acebdf13572468--
复造代码
前去数据:
  1. {"errcode":0,"errmsg":"",
  2.    "type":"image","media_id":"1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0","created_at":"1380000000"}
复造代码
参数分析:
参数分析
type媒介文献范例,别离有图片(image)、语音(voice)、望频(video),一般文献(file)
media_id媒介文献上传后获得的唯一标记,3天内乱有用
created_at媒介文献上传时间戳
上传企微临时艳材,对于应企微api文档链交:https://developer.work.weixin.qq.com/document/path/90253
JAVA后端上传图片至企微临时艳材-3.png


2.掌握层交心

掌握层领受方法能够有文献方法领受,也能够前端用图片变换成base64格局字符串方法后端领受。
文献方法领受
  1. @RequestMapping(method =RequestMethod.POST, value ="v1/uploadQwMedia")publicScaResponseParam<JSONObject>uploadQwMedia(String type,String title,int orgId,@RequestParam("file")MultipartFile file){try{if(file ==null){thrownewIllegalArgumentException("不上传图片");}if(StringUtils.isEmpty(type)){thrownewIllegalArgumentException("缺少type参数");}InputStream inputStream = file.getInputStream();FindMediaIdReq req =newFindMediaIdReq();
  2.             req.setTitle(title);//对于应企微api文档中的fileName参数,用于掌握展示的文献称呼
  3.             req.setType(type);//对于应企微api文档中的type参数String mediaId = scaGuideOneCustOneCodeService.uploadQwMedia(orgId, req, inputStream);returnScaResponseParam.OK().fluentSetData(newJSONObject().fluentPut("mediaId", mediaId));}catch(IllegalArgumentException e){
  4.             log.error(e.getMessage(), e);returnScaResponseParam.ERROR(e.getMessage());}catch(Exception e){
  5.             log.error("上传客户博属码到企微临时艳材非常:{}-{}",e.getMessage(), e);returnScaResponseParam.ERROR("上传客户博属码到企微临时艳材非常");}}
复造代码
base64方法领受
  1. @RequestMapping(value ="/base64ImgUpload", method =RequestMethod.POST)publicScaResponseParam<JSONObject>base64ImgUpload(@RequestBodyOneCustOneCodeUploadQwImgRequest request){try{BASE64Decoder decoder =newBASE64Decoder();byte[] bytes = decoder.decodeBuffer(request.getBase64Str());for(int i =0; i < bytes.length;++i){if(bytes[i]<0){
  2.                     bytes[i]+=256;}}int orgId = request.getOrgId();InputStream inputStream =newByteArrayInputStream(bytes);FindMediaIdReq req =newFindMediaIdReq();
  3.             req.setTitle(request.getTitle());//对于应企微api文档中的fileName参数,用于掌握展示的文献称呼
  4.             req.setType(request.getType());//对于应企微api文档中的type参数String mediaId = scaGuideOneCustOneCodeService.uploadQwMedia(orgId, req, inputStream);returnScaResponseParam.OK().fluentSetData(newJSONObject().fluentPut("mediaId", mediaId));}catch(IllegalArgumentException e){
  5.             log.error(e.getMessage(), e);returnScaResponseParam.ERROR(e.getMessage());}catch(Exception e){
  6.             log.error("base64上传客户博属码到企微临时艳材非常:{}-{}",e.getMessage(), e);returnScaResponseParam.ERROR("base64上传客户博属码到企微临时艳材非常");}}
复造代码
恳求参数OneCustOneCodeUploadQwImgRequest类
  1. @Data@SuppressWarnings("all")publicclassOneCustOneCodeUploadQwImgRequest{@ApiModelProperty(value ="文献范例,图片为image", required =true)privateString type;@ApiModelProperty(value ="文献称呼", required =true)privateString title;@ApiModelProperty(value ="图片base64格局字符串", required =true)privateString base64Str;@ApiModelProperty(value ="orgId", required =true)privateint orgId;}
复造代码
4.Service层交心
  1. @OverridepublicStringuploadQwMedia(Integer orgId,FindMediaIdReq reqBean,InputStream inputStream){Map<String,Object> map = qyWeiXinService.uploadMediaForKf(orgId, reqBean, inputStream);String mediaId = map.get("media_id").toString();String createdAt =DateUtil.date2Str(newDate(Long.valueOf(map.get("created_at").toString())*1000));
  2.         log.info("上传企微艳材前去,mediaId:{},createAt:{}", mediaId, createdAt);return mediaId;}
复造代码
qyWeiXinService中的uploadMediaForKf办法
  1. @OverridepublicMap<String,Object>uploadMediaForKf(Integer orgId,FindMediaIdReq reqBean,InputStream inputStream){ScaQyWxBuConfig scaQyWxBuConfig =ScaQyWxBuConfig.getConfigByOrgId(orgId);//获得设置的secret战corpId等疑息if(scaQyWxBuConfig ==null){
  2.             log.error("客服企微参数设置为空, orgId:{}", orgId);thrownewRuntimeException("获得客服企微设置参数失利");}String accessToken =this.getKfAccessToken(scaQyWxBuConfig);//获得accessTokenString title = reqBean.getTitle();//挪用企微api上传图片文献到企微临时艳材returnWinXinMessageUtil.mediaUploadByInputStream(accessToken, inputStream, reqBean.getType(), title);}
复造代码
挪用企微api上传图片文献到企微临时艳材办法,对于应上面的WinXinMessageUtil.mediaUploadByInputStream办法
  1. publicstaticMap<String,Object>mediaUploadByInputStream(String accessToken,InputStream inputStream,String type,String fileName){String upUrl ="https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token="+ accessToken +"&type="+ type;StringBuffer buffer =newStringBuffer();BufferedReader reader =null;try{URL urlObj =newURL(upUrl);HttpURLConnection con =(HttpURLConnection) urlObj.openConnection();
  2.             con.setRequestMethod("POST");// 以Post方法提接表单,默认get方法
  3.             con.setDoInput(true);
  4.             con.setDoOutput(true);
  5.             con.setUseCaches(false);// post方法不克不及使用慢存// 树立恳求头疑息
  6.             con.setRequestProperty("Connection","Keep-Alive");
  7.             con.setRequestProperty("Charset","UTF-8");// 树立鸿沟StringBOUNDARY="----------"+System.currentTimeMillis();
  8.             con.setRequestProperty("Content-Type","multipart/form-data; boundary="+BOUNDARY);// 恳求正文疑息StringBuilder sb =newStringBuilder();
  9.             sb.append("--");//必需 多二讲线
  10.             sb.append(BOUNDARY);
  11.             sb.append("\r\n");
  12.             sb.append("Content-Disposition: form-data;name="media";filename=""+ fileName +""\r\n");
  13.             sb.append("Content-Type:application/octet-stream\r\n\r\n");byte[] head = sb.toString().getBytes("utf-8");//取得 输出流OutputStream out =newDataOutputStream(con.getOutputStream());//输出 表头
  14.             out.write(head);// 把文献已经流文献的方法 拉进到url中DataInputStream in =newDataInputStream(inputStream);int bytes;byte[] bufferOut =newbyte[1024];while((bytes = in.read(bufferOut))!=-1){
  15.                 out.write(bufferOut,0, bytes);}
  16.             in.close();//开头 部门byte[] foot =("\r\n--"+BOUNDARY+"--\r\n").getBytes("utf-8");// 界说最初数据分开线
  17.             out.write(foot);
  18.             out.flush();
  19.             out.close();// 界说BufferedReader输出流去读与URL的照应InputStream conInputStream = con.getInputStream();
  20.             reader =newBufferedReader(newInputStreamReader(conInputStream));String line;while((line = reader.readLine())!=null){
  21.                 buffer.append(line);}String result = buffer.toString();
  22.             log.warn("{}上传临时艳材成果:{}", fileName, result);Map<String,Object> map =JSON.parseObject(result,Map.class);if(!Objects.equals(map.get("errcode"),0)){thrownewIllegalArgumentException("上传临时艳材非常:"+ map.get("errmsg"));}return map;}catch(IOException e){
  23.             log.warn("上传临时艳材{}非常:{}-{}", fileName, e.getMessage(), e);thrownewIllegalArgumentException("上传临时艳材非常", e);}finally{try{if(reader !=null){
  24.                     reader.close();}}catch(IOException e){
  25.                 e.printStackTrace();}}}
复造代码
获得token的办法,对于应上面的getKfAccessToken办法
那里先从redis慢存获得,获得没有到再挪用企微api交心获得,能够按照理论情况截至通融。
  1. privateStringgetKfAccessToken(ScaQyWxBuConfig scaQyWxBuConfig){String corpId = scaQyWxBuConfig.getCorpId();//从设置中获得的corpIdString secret = scaQyWxBuConfig.getSecretKf();//从设置中获得的secretif(StringUtils.isEmpty(corpId)||StringUtils.isEmpty(secret)){returnnull;}String key ="HYP_GUIDE_"+ corpId +"AccessToken"+ secret;//劣先从redis慢存中获得String accessToken = jedisCluster.get(key);if(StringUtils.isEmpty(accessToken)){//慢存中获得没有到再挪用企微api交心获得accessTokentry{
  2.             accessToken =WinXinMessageUtil.getAccessToken(corpId, secret);
  3.             jedisCluster.set(key, accessToken);
  4.             jedisCluster.expire(key,7000);//树立过时时间}catch(Exception e){
  5.             log.error(e.getMessage());}}return accessToken;}
复造代码
3.挪用企微api交心获得accessToken疑息,

对于应上面的WinXinMessageUtil.getAccessToken
  1. publicstaticStringgetAccessToken(StringCorpID,StringSecret)throwsException{String access_token ="";CloseableHttpClient httpclient =HttpClients.createDefault();try{HttpGet httpGet =newHttpGet("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid="+CorpID+"&corpsecret="+Secret);CloseableHttpResponse response1 = httpclient.execute(httpGet);JSONObject resultJsonObject;try{HttpEntity httpEntity = response1.getEntity();if(httpEntity !=null){try{BufferedReader bufferedReader =newBufferedReader(newInputStreamReader(httpEntity.getContent(),"UTF-8"),8*1024);StringBuilder entityStringBuilder =newStringBuilder();String line;while((line = bufferedReader.readLine())!=null){
  2.                         entityStringBuilder.append(line);}//使用 从HttpEntity中获得的String天生JsonObject
  3.                     resultJsonObject =newJSONObject(entityStringBuilder.toString().trim());
  4.                     access_token = resultJsonObject.get("access_token")+"";}catch(Exception e){
  5.                     log.warn("获得企微token非常:{}-{}", e.getMessage(), e);}}}finally{
  6.             response1.close();}}finally{
  7.         httpclient.close();}return access_token;}
复造代码
您需要登录后才可以回帖 登录 | 立即注册 qq_login

本版积分规则

发布主题
阅读排行更多+
用专业创造成效
400-778-7781
周一至周五 9:00-18:00
意见反馈:server@mailiao.group
紧急联系:181-67184787
ftqrcode

扫一扫关注我们

Powered by 职贝云数A新零售门户 X3.5© 2004-2025 职贝云数 Inc.( 蜀ICP备2024104722号 )