依赖
com.aliyun.oss
aliyun-sdk-oss
3.8.1
cn.hutool
hutool-all
5.7.13
controller
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/wx/api/user")
public class QRCodeController {
@Autowired
private OSSUtil ossUtil;
/**
* 生成二维码
*
* @param userId 用户id
* @param path 生成二维码的url
* @return
*/
@PostMapping("/createQRcode")
public String createQRcode(String userId, String path) {
// 获取调用凭证accessToken
String accessToken = AccessToken.getAccessToken();
RestTemplate rest = new RestTemplate();
InputStream inputStream = null;
OutputStream outputStream = null;
String imgUrl = "";
try {
String url = "https://api.weixin.qq.com/cgi-bin/wxaapp/createwxaqrcode?access_token="+accessToken;
log.info("url: "+url);
Map param = new HashMap<>();
param.put("path", path);
// param.put("page", "pages/index/index"); // 路径 如果没有默认跳转到首页面微信小程序发布后才可以使用不能添加参数
param.put("width", 430); //二维码尺寸
param.put("is_hyaline", true); // 是否需要透明底色, is_hyaline 为true时,生成透明底色的小程序码 参数仅对小程序码生效
param.put("auto_color", true); // 自动配置线条颜色,如果颜色依然是黑色,则说明不建议配置主色调 参数仅对小程序码生效
Map line_color = new HashMap<>();
line_color.put("r", 0);
line_color.put("g", 0);
line_color.put("b", 0);
param.put("line_color", line_color);
log.info("调用生成微信URL接口传参:" + param);
MultiValueMap headers = new LinkedMultiValueMap<>();
HttpEntity requestEntity = new HttpEntity(param, headers);
ResponseEntity entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
log.info("调用小程序生成微信永久小程序码URL接口返回结果:" + entity.getBody());
byte[] result = entity.getBody();
log.info(Base64.encodeBase64String(result));
inputStream = new ByteArrayInputStream(result);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
// 最后上传生成的文件名
String finalFileName = System.currentTimeMillis() + "" + new SecureRandom().nextInt(0x0400) + ".jpg";
// oss中的文件夹名
String objectName = sdf.format(new Date()) + "/" + finalFileName;
// 上传oss
ossUtil.uploadFile2OSS(inputStream, objectName);
//获取文件的URl地址
imgUrl = ossUtil.getImgUrl(objectName);
log.info("imgUrl: "+imgUrl);
// // 生成返回的二维码更新到数据库
// WxUser wxUser = new WxUser();
// wxUser.setId(qrCodeVo.getId());
// wxUser.setQRCode(imgUrl);
// wxUserMapper.updateWxUser(wxUser);
} catch (Exception e) {
log.error("调用小程序生成微信永久小程序码URL接口异常",e);
} finally {
if(inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "操作成功";
}
}
TokenBean
@Data
public class TokenBean {
private String token;
private Date date;
}
AccessToken
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class AccessToken {
public static TokenBean tokenBean = new TokenBean();
/**
* 获取微信模板发送所需Token
* 每次获取有效期为2个小时
* @return token
*/
public static String getAccessToken(){
if (tokenBean == null || tokenBean.getDate() == null || tokenBean.getDate().getTime() < new Date().getTime()){
//发送模板请求接口
String result = HttpRequest.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=xxx&secret=xxx")
.header(Header.USER_AGENT, "Mozilla/5.0 (Linux; Android 8.0.0; SM-N9500 Build/R16NW; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.83 Mobile Safari/537.36 T7/10.13 baiduboxapp/10.13.0.11 (Baidu; P1 8.0.0)")//头信息,多个头信息多次调用此方法即可
.timeout(10000)//超时,毫秒
.execute().body();
JSONObject jsonObject = JSONUtil.parseObj(result);
String access_token = (String) jsonObject.get("access_token");
tokenBean.setToken(access_token);
Date date = new Date(new Date().getTime() + 7200 * 1000);
tokenBean.setDate(date);
return access_token;
}else{
return tokenBean.getToken();
}
}
}
OSSUtil
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
@Component
public class OSSUtil {
private static final String endpoint = "oss-cn-shenzhen.aliyuncs.com";
private static final String accessKeyId = "";
private static final String accessKeySecret = "";
private static final String bucketName = "wxcall-xiaobanben";
private static final String FOLDER = "image/";
/**
* 获取oss
*
* @return
*/
public static OSS getOSSClient() {
return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
}
/**
* 上传图片
*
* @param url
* @throws
*/
public void uploadImg2Oss(String url) throws IOException {
File fileOnServer = new File(url);
FileInputStream fin;
try {
fin = new FileInputStream(fileOnServer);
String[] split = url.split("/");
this.uploadFile2OSS(fin, split[split.length - 1]);
} catch (FileNotFoundException e) {
throw new IOException("图片上传失败");
}
}
public String uploadImg2Oss(MultipartFile file) throws IOException {
if (file.getSize() > 5 * 1024 * 1024) {
throw new IOException("上传图片大小不能超过5M!");
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
// 获取文件名
String originalFilename = file.getOriginalFilename();
// 获取文件后缀名
String suffixName = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
// 最后上传生成的文件名
String finalFileName = System.currentTimeMillis() + "" + new SecureRandom().nextInt(0x0400) + suffixName;
// oss中的文件夹名
String objectName = sdf.format(new Date()) + "/" + finalFileName;
// name = DateUtils.dateStr(new Date(), "yyyy/MM/dd") + "/" + System.currentTimeMillis() + substring;
try {
InputStream inputStream = file.getInputStream();
this.uploadFile2OSS(inputStream, objectName);
return objectName;
} catch (Exception e) {
e.printStackTrace();
throw new IOException("图片上传失败");
}
}
/**
* 获得图片路径
*
* @param fileUrl
* @return
*/
public String getImgUrl(String fileUrl) {
System.out.println(fileUrl);
if (!StringUtils.isEmpty(fileUrl)) {
// String[] split = fileUrl.split("/");
return this.getUrl(this.FOLDER + fileUrl);
}
return "";
}
/**
* 上传到OSS服务器 如果同名文件会覆盖服务器上的
*
* @param instream 文件流
* @param fileName 文件名称 包括后缀名
* @return 出错返回"" ,唯一MD5数字签名
*/
public String uploadFile2OSS(InputStream instream, String fileName) {
String ret = "";
try {
OSS ossClient = getOSSClient();
// 创建上传Object的Metadata
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(instream.available());
objectMetadata.setCacheControl("no-cache");
objectMetadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf("."))));
objectMetadata.setHeader("Pragma", "no-cache");
// objectMetadata.setContentDisposition("inline;filename=" + fileName);
// 上传文件
PutObjectResult putResult = ossClient.putObject(bucketName, FOLDER + fileName, instream, objectMetadata);
ret = putResult.getETag();
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
try {
if (instream != null) {
instream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return ret;
}
/**
* 通过文件名判断并获取OSS服务文件上传时文件的contentType
*
* @param filenameExtension 文件名
* @return 文件的contentType
*/
public static final String getContentType(String filenameExtension) {
if (filenameExtension.equalsIgnoreCase(".bmp")) {
return "application/x-bmp";
}
if (filenameExtension.equalsIgnoreCase(".gif")) {
return "image/gif";
}
if (filenameExtension.equalsIgnoreCase(".jpeg") ||
filenameExtension.equalsIgnoreCase(".jpg") ||
filenameExtension.equalsIgnoreCase(".png")) {
return "image/jpg";
}
if (filenameExtension.equalsIgnoreCase(".html")) {
return "text/html";
}
if (filenameExtension.equalsIgnoreCase(".txt")) {
return "text/plain";
}
if (filenameExtension.equalsIgnoreCase(".vsd")) {
return "application/vnd.visio";
}
if (filenameExtension.equalsIgnoreCase(".pptx") ||
filenameExtension.equalsIgnoreCase(".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (filenameExtension.equalsIgnoreCase(".docx") ||
filenameExtension.equalsIgnoreCase(".doc")) {
return "application/msword";
}
if (filenameExtension.equalsIgnoreCase(".xla") ||
filenameExtension.equalsIgnoreCase(".xlc") ||
filenameExtension.equalsIgnoreCase(".xlm") ||
filenameExtension.equalsIgnoreCase(".xls") ||
filenameExtension.equalsIgnoreCase(".xlt") ||
filenameExtension.equalsIgnoreCase(".xlw")) {
return "application/vnd.ms-excel";
}
if (filenameExtension.equalsIgnoreCase(".xlsx")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
if (filenameExtension.equalsIgnoreCase(".xml")) {
return "text/xml";
}
if (filenameExtension.equalsIgnoreCase(".pdf")) {
return "application/pdf";
}
if (filenameExtension.equalsIgnoreCase(".zip")) {
return "application/zip";
}
if (filenameExtension.equalsIgnoreCase(".tar")) {
return "application/x-tar";
}
if (filenameExtension.equalsIgnoreCase(".avi")) {
return "video/avi";
}
if (filenameExtension.equalsIgnoreCase(".mp4")) {
return "video/mpeg4";
}
if (filenameExtension.equalsIgnoreCase(".mp3")) {
return "audio/mp3";
}
if (filenameExtension.equalsIgnoreCase(".mp2")) {
return "audio/mp2";
}
// 默认下载
// return "application/octet-stream";
return "image/jpg";
}
/**
* 获得url链接
*
* @param key
* @return
*/
public String getUrl(String key) {
// 设置URL过期时间为10年 3600l* 1000*24*365*10
OSS ossClient = getOSSClient();
Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
// 生成URL
URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
System.out.println("url: "+url);
if (url != null) {
String host = "https://" + url.getHost() + url.getPath();
System.out.println("host: "+host);
// http://wxcall-xiaobanben.oss-cn-shenzhen.aliyuncs.com/image/20220129/1643469496754508.jpg
return host;
}
return "";
}
/**
* 获取文件夹
*
* @param fileName
* @return
*/
public List fileFolder(String fileName) {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
// 构造ListObjectsRequest请求。
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
// 设置正斜线(/)为文件夹的分隔符。
listObjectsRequest.setDelimiter("/");
// 设置prefix参数来获取fun目录下的所有文件。
if (!StringUtils.isEmpty(fileName)) {
listObjectsRequest.setPrefix(fileName + "/");
}
// 列出文件
ObjectListing listing = ossClient.listObjects(listObjectsRequest);
// 遍历所有commonPrefix
List list = new ArrayList<>();
for (String commonPrefix : listing.getCommonPrefixes()) {
String newCommonPrefix = commonPrefix.substring(0, commonPrefix.length() - 1);
String[] s = newCommonPrefix.split("/");
if (!StringUtils.isEmpty(fileName)) {
list.add(s[s.length - 1]);
} else {
list.add(s[0]);
}
}
// 关闭OSSClient
ossClient.shutdown();
return list;
}
/**
* 列举文件下所有的文件url信息
*/
public ObjectListing listFile2(String fileHost, String nextMarker) {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
// 构造ListObjectsRequest请求。
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
// 设置正斜线(/)为文件夹的分隔符。
listObjectsRequest.setDelimiter("/");
// 列出fun目录下的所有文件和文件夹。
listObjectsRequest.setPrefix(fileHost + "/");
ObjectListing listing = ossClient.listObjects(listObjectsRequest);
// 遍历所有文件。
System.out.println("Objects:");
// objectSummaries的列表中给出的是fun目录下的文件。
for (OSSObjectSummary objectSummary : listing.getObjectSummaries()) {
System.out.println(objectSummary.getKey());
}
// 遍历所有commonPrefix。
System.out.println("\nCommonPrefixes:");
// commonPrefixs列表中显示的是fun目录下的所有子文件夹。由于fun/movie/001.avi和fun/movie/007.avi属于fun文件夹下的movie目录,因此这两个文件未在列表中。
for (String commonPrefix : listing.getCommonPrefixes()) {
System.out.println(commonPrefix);
}
// 关闭OSSClient。
ossClient.shutdown();
return listing;
}
/**
* 列举文件下所有的文件url信息
*/
public List listFile(String fileHost, String nextMarker) {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName);
// 设置prefix参数来获取fun目录下的所有文件。
listObjectsRequest.setPrefix(fileHost + "/");
listObjectsRequest.setMarker(nextMarker);
// 列出文件。
ObjectListing listing = ossClient.listObjects(listObjectsRequest);
// 遍历所有文件。
List list = new ArrayList<>();
for (int i = 0; i < listing.getObjectSummaries().size(); i++) {
String FILE_URL = "http://" + bucketName + "." + endpoint + "/" + listing.getObjectSummaries().get(i).getKey();
list.add(FILE_URL);
}
// 关闭OSSClient。
ossClient.shutdown();
// ObjectListing objectListing = null;
// int total = 0;
// HashMap markerMap = new HashMap<>();
// try {
// ObjectListing objectListing2 = null;
// do {
// String nextMarker2 = objectListing2 != null ? objectListing2.getNextMarker() : null;
// ListObjectsRequest listObjectsRequest2 = new ListObjectsRequest(bucketName).withMarker(nextMarker2).withMaxKeys(100);
// listObjectsRequest2.setPrefix(fileHost + "/");
// objectListing2 = ossClient.listObjects(listObjectsRequest2);
// total += (objectListing2 != null && objectListing2.getObjectSummaries() != null ? objectListing2.getObjectSummaries().size() : 0);
// markerMap.put(markerMap.size() + 1, nextMarker2);
// } while (objectListing2 != null && !StringUtils.isEmpty(objectListing2.getNextMarker()));
//
// ListObjectsRequest listObjectsRequest = new ListObjectsRequest(bucketName).withMarker(nextMarker).withMaxKeys(100);
//
// listObjectsRequest.setPrefix(fileHost + "/");
//
// objectListing = ossClient.listObjects(listObjectsRequest);
// for (int i = 0; i < objectListing.getObjectSummaries().size(); i++) {
// String FILE_URL = "https://" + bucketName + "." + endpoint + "/" + objectListing.getObjectSummaries().get(i).getKey();
// list.add(FILE_URL);
// }
//
// } catch (Exception e) {
//
// } finally {
// // 关闭client
// ossClient.shutdown();
// }
return list;
}
/**
* 删除文件
* objectName key 地址
*
* @param filePath
*/
public Boolean delFile(String filePath) {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
// 删除Object.
boolean exist = ossClient.doesObjectExist(bucketName, filePath);
if (!exist) {
return false;
}
ossClient.deleteObject(bucketName, filePath);
ossClient.shutdown();
return true;
}
/**
* 批量删除
*
* @param keys
*/
public Boolean delFileList(List keys) {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
try {
// 删除文件。
DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keys));
List deletedObjects = deleteObjectsResult.getDeletedObjects();
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
ossClient.shutdown();
}
return true;
}
/**
* 创建文件夹
*
* @param folder
* @return
*/
public String createFolder(String folder) {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
// 文件夹名
final String keySuffixWithSlash = folder;
// 判断文件夹是否存在,不存在则创建
if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) {
// 创建文件夹
ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));
// 得到文件夹名
OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash);
String fileDir = object.getKey();
ossClient.shutdown();
return fileDir;
}
return keySuffixWithSlash;
}
/**
* 通过文件名下载文件
*
* @param objectName 要下载的文件名
* @param localFileName 本地要创建的文件名
*/
public void downloadFile(HttpServletResponse response, String objectName, String localFileName) throws Exception {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
try {
// ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
OSSObject ossObject = ossClient.getObject(bucketName, objectName);
// 读去Object内容 返回
BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
//通知浏览器以附件形式下载
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(objectName, "utf-8"));
//BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(new File("f:\\a.txt")));
byte[] car = new byte[1024];
int L = 0;
while ((L = in.read(car)) != -1) {
out.write(car, 0, L);
}
if (out != null) {
out.flush();
out.close();
}
if (in != null) {
in.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭OSSClient。
ossClient.shutdown();
}
}
public String onlineSee(String key) {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
// 设置URL过期时间为1小时
Date expiration = new Date(new Date().getTime() + 3600 * 1000);
// 临时地址
URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);
// 关闭OSSClient。
ossClient.shutdown();
return url.toString();
}
public Object onlinePreview(String key) {
// 创建OSSClient实例。
OSS ossClient = getOSSClient();
// 设置视频截帧操作。文档页数默认是200,EndPage_-1任意
String style = "imm/previewdoc,EndPage_-1";
String filenameExtension = key.substring(key.lastIndexOf("."));
if (filenameExtension.equalsIgnoreCase(".pdf")) {
style = "imm/previewdoc,EndPage_-1,PdfVector_true";
}
// 指定过期时间为1小时。
Date expiration = new Date(new Date().getTime() + 1000 * 60 * 60);
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET);
req.setExpiration(expiration);
req.setProcess(style);
URL signedUrl = ossClient.generatePresignedUrl(req);
return signedUrl;
}
}
成功生成小程序二维码
微信官方文档.小程序链接:
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.createQRCode.html