package com.panzhihua.common.utlis; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.panzhihua.common.constants.SecurityConstants; import com.panzhihua.common.controller.BaseController; import com.panzhihua.common.redis.RedisUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.http.entity.ContentType; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.commons.CommonsMultipartFile; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.concurrent.TimeUnit; @Slf4j @Component public class WxXCXTempSend extends BaseController { public static final String APP_ID = "wx118de8a734d269f0"; private static final String APP_SECRET = "0264342daefde5cd70a6adada09ee5b1"; private static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"; private static String APP_IMAGE_URL = "https://www.psciio.com//idcard/8fa82cfba258498eab2fa818220fb592.jpg"; private static String APP_IMAGE_NAME = "5.jpg"; private static String WX_CALL_BACK = "https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token="; //2小时 private static final Long EXPIRE_TIME = 2L; @Resource private RedisTemplate redisTemplate; @Resource private StringRedisTemplate stringRedisTemplate; @Resource private RedisUtils redisUtils; private static WxXCXTempSend wxXCXTempSend; /** * url转变为 MultipartFile对象 * * @param url * @param fileName * @return * @throws Exception */ private static MultipartFile createFileItem(String url, String fileName) throws Exception { FileItem item = null; try { HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); conn.setReadTimeout(30000); conn.setConnectTimeout(30000); // 设置应用程序要从网络连接读取数据 conn.setDoInput(true); conn.setRequestMethod("GET"); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream is = conn.getInputStream(); FileItemFactory factory = new DiskFileItemFactory(16, null); String textFieldName = "uploadfile"; item = factory.createItem(textFieldName, ContentType.APPLICATION_OCTET_STREAM.toString(), false, fileName); OutputStream os = item.getOutputStream(); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = is.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); is.close(); } } catch (IOException e) { throw new RuntimeException("文件下载失败", e); } return new CommonsMultipartFile(item); } /** * 获取小程序token,(ps:0=token获取失败) * * @return */ public String getAccessToken() throws Exception { String accessToken = ""; String appId = this.getAppId(); accessToken = wxXCXTempSend.stringRedisTemplate.boundValueOps("access_token:access_token:" + appId).get(); return accessToken; } public String getAccessToken(String appId) throws Exception { String accessToken = ""; accessToken = wxXCXTempSend.stringRedisTemplate.boundValueOps("access_token:access_token:" + appId).get(); return accessToken; } private String validAccessToken(String accessToken, String appId, String appSecret) throws Exception { if (StrUtil.isEmpty(accessToken)) { //重新获取并设置到缓存 该方法暂时只用在花城 accessToken = getAppAccessToken(appId, appSecret); wxXCXTempSend.stringRedisTemplate.opsForValue().set("access_token:access_token:" + appId, accessToken, EXPIRE_TIME, TimeUnit.HOURS); } else { String accessTokenUrl = WX_CALL_BACK + accessToken; String result = HttpClientUtil.httpGet(accessTokenUrl, null, null); Map resultMap = JSON.parseObject(result, Map.class); //如果Access_token过期也重新获取 if (resultMap.containsKey("errcode")) { accessToken = getAppAccessToken(appId, appSecret); wxXCXTempSend.stringRedisTemplate.opsForValue().set("access_token:access_token:" + appId, accessToken, EXPIRE_TIME, TimeUnit.HOURS); } } return accessToken; } public String getAppAccessToken(String appId, String appSecret) throws Exception { String accessToken = "0"; try { log.info("获取微信token参数:appid=" + appId + ",appSecret=" + appSecret); String accessTokenUrl = ACCESS_TOKEN_URL + "&appid=" + appId + "&secret=" + appSecret; String result = HttpClientUtil.httpGet(accessTokenUrl, null, null); Map resultMap = JSON.parseObject(result, Map.class); StringRedisTemplate redisTemplate = wxXCXTempSend.stringRedisTemplate; if (resultMap.containsKey("access_token")) { accessToken = resultMap.get("access_token").toString(); redisTemplate.opsForValue().set("access_token:access_token:" + appId, accessToken); } HttpServletRequest request = ServletUtils.getRequest(); String requestURI = request.getRequestURI(); //加上时间戳 String datetime = new SimpleDateFormat("yyyyMMdd").format(new Date()); //这里是 Redis key的前缀,如: sys:tabieId:表名 如果不需要去掉表名也可以 String key = MessageFormat.format("{0}:{1}:{2}", "access_token_request_incr",datetime,requestURI); //查询 key 是否存在, 不存在返回 1 ,存在的话则自增加1 redisTemplate.opsForValue().increment(key, 1); } catch (IOException ioe) { log.error("小程序http请求异常"); ioe.printStackTrace(); } return accessToken; } public String getWsAccessToken() throws Exception { String accessToken = "0"; try { // log.info("获取微信token参数:appid=" + APP_ID + ",appSecret=" + APP_SECRET); String accessTokenUrl = ACCESS_TOKEN_URL + "&appid=wx98d62711dfbd8425" + "&secret=97a2a10b990c2774ed279724337b5337"; String result = HttpClientUtil.httpGet(accessTokenUrl, null, null); Map resultMap = JSON.parseObject(result, Map.class); if (resultMap.containsKey("access_token")) { accessToken = resultMap.get("access_token").toString(); } } catch (IOException ioe) { log.error("小程序http请求异常"); ioe.printStackTrace(); } return accessToken; } /** * 获取西区社区通微信token * * @return 西区社区通微信token * @throws Exception 异常 */ public String getXQAppAccessToken() throws Exception { String accessToken = "0"; try { // 此处APP_ID APP_SECRET 在微信小程序后端可见 // String accessTokenUrl = String.format(TEMP_URL, APP_ID, APP_SECRET); String accessTokenUrl = ACCESS_TOKEN_URL + "&appid=" + APP_ID + "&secret=" + APP_SECRET; String result = HttpClientUtil.httpGet(accessTokenUrl, null, null); Map resultMap = JSON.parseObject(result, Map.class); if (resultMap.containsKey("access_token")) { accessToken = resultMap.get("access_token").toString(); } } catch (IOException ioe) { log.error("小程序http请求异常"); ioe.printStackTrace(); } return accessToken; } public String getMediaId(String accessToken) { String mediaId = ""; Boolean aBoolean = redisTemplate.hasKey(SecurityConstants.APPLETS_ACCESS_MEDIA_ID); ValueOperations valueOperations = redisTemplate.opsForValue(); if (aBoolean) { Long expireTime = Long.parseLong(valueOperations.get(SecurityConstants.APPLETS_ACCESS_MEDIA_ID_TIME)); if (expireTime <= System.currentTimeMillis()) { redisTemplate.delete(SecurityConstants.APPLETS_ACCESS_MEDIA_ID);// 如果过期则删除 redisTemplate.delete(SecurityConstants.APPLETS_ACCESS_MEDIA_ID_TIME);// 如果过期则删除 mediaId = getAppMediaId(accessToken); valueOperations.set(SecurityConstants.APPLETS_ACCESS_MEDIA_ID, mediaId); valueOperations.set(SecurityConstants.APPLETS_ACCESS_MEDIA_ID_TIME, System.currentTimeMillis() + 259000000 + ""); } else { mediaId = valueOperations.get(SecurityConstants.APPLETS_ACCESS_MEDIA_ID); } } else { mediaId = getAppMediaId(accessToken); valueOperations.set(SecurityConstants.APPLETS_ACCESS_MEDIA_ID, mediaId); valueOperations.set(SecurityConstants.APPLETS_ACCESS_MEDIA_ID_TIME, System.currentTimeMillis() + 259000000 + ""); } return mediaId; } private String getAppMediaId(String accessToken) { String appMediaId = ""; try { MultipartFile file = createFileItem(APP_IMAGE_URL, APP_IMAGE_NAME); appMediaId = uploadFile(file, accessToken); } catch (Exception e) { log.error("上传临时图片素材失败,错误原因:" + e.getMessage()); } return appMediaId; } /** * 微信小程序临时素材上传 * * @param file * @return * @throws Exception * @author yixiu */ public String uploadFile(MultipartFile file, String access_token) throws Exception { String url = "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=" + access_token + "&type=image"; String result = null; String fileName = file.getOriginalFilename(); URL urlObj = new URL(url); HttpURLConnection con = (HttpURLConnection) urlObj.openConnection(); con.setRequestMethod("POST"); con.setDoInput(true); con.setDoOutput(true); con.setUseCaches(false); // 设置请求头信息 con.setRequestProperty("Connection", "Keep-Alive"); con.setRequestProperty("Charset", "UTF-8"); // 设置边界 String BOUNDARY = "----------" + System.currentTimeMillis(); con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); // 请求正文信息 // 第一部分: StringBuilder sb = new StringBuilder(); sb.append("--"); // 必须多两道线 sb.append(BOUNDARY); sb.append("\r\n"); sb.append("Content-Disposition: form-data;name=\"media\";filename=\"" + fileName + "\"\r\n"); sb.append("Content-Type:application/octet-stream\r\n\r\n"); byte[] head = sb.toString().getBytes(StandardCharsets.UTF_8); // 获得输出流 OutputStream out = new DataOutputStream(con.getOutputStream()); // 输出表头 out.write(head); // 文件正文部分 // 把文件已流文件的方式 推入到url中 DataInputStream in = new DataInputStream(file.getInputStream()); int bytes = 0; byte[] bufferOut = new byte[1024]; while ((bytes = in.read(bufferOut)) != -1) { out.write(bufferOut, 0, bytes); } in.close(); // 结尾部分 byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes(StandardCharsets.UTF_8);// 定义最后数据分隔线 out.write(foot); out.flush(); out.close(); StringBuffer buffer = new StringBuffer(); BufferedReader reader = null; try { // 定义BufferedReader输入流来读取URL的响应 reader = new BufferedReader(new InputStreamReader(con.getInputStream())); String line = null; while ((line = reader.readLine()) != null) { buffer.append(line); } if (result == null) { result = buffer.toString(); } } catch (IOException e) { System.out.println("发送POST请求出现异常! {}"); e.printStackTrace(); throw new IOException("数据读取异常"); } finally { if (reader != null) { reader.close(); } } // 获取到返回HTTP结果 Map map = JSONObject.parseObject(result, Map.class); if (map.containsKey("media_id")) { return map.get("media_id").toString(); } System.out.println("小程序上传临时素材出错,返回信息为: " + result); return null; } @PostConstruct public void init() { wxXCXTempSend = this; wxXCXTempSend.redisTemplate = this.redisTemplate; wxXCXTempSend.stringRedisTemplate = this.stringRedisTemplate; wxXCXTempSend.redisUtils = this.redisUtils; } }