见企业微信官方网站:https://developer.work.weixin.qq.com/document/path/90513
// 引用企业微信sdk
<script src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
或vue命令行
npm install weixin-js-sdk
import 'wx' from 'weixin-js-sdk'
// axios
或vue命令行:npm i axios vue-axios
import _axios from 'axios'
<template>
<div class="hello">
<button @click="toScan()">toScan</button>
</div>
</template>
<script>
/* eslint-disable */
// eslint-disable-next-line
import wx from "weixin-js-sdk"
import _axios from 'axios'
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome',
data:{
appId:'',
timestamp:'',
nonceStr:'',
signature:'',
}
}
},
methods:{
async getParams(){
let that = this;
_axios.get("http://ip:8080/wx/getToken")
.then(
function (response) {
that.data = response.data.data;
that.scanCode();
}
)
.catch(function (error) { // 请求失败处理
console.log(error);
});
},
async toScan(){
let that = this;
await that.getParams();
},
async scanCode(){
let that = this;
try{
//动态获取当前页面的url地址
//将url作为参数传入接口,将接口数据解构出来用data对象接受
if(that.data.appId.length === 0) return;
//可以将接口中数据打印出来看
wx.config({
beta: true,// 必须这么写,否则wx.invoke调用形式的jsapi会有问题
debug: true, // 在测试没问题之后,关闭debug模式,防止弹窗
appId: that.data.appId, // 必填,企业微信的corpID
timestamp: that.data.timestamp, // 必填,生成签名的时间戳
nonceStr: that.data.nonceStr, // 必填,生成签名的随机串
signature: that.data.signature,// 必填,签名,见 附录-JS-SDK使用权限签名算法
jsApiList: ["scanQRCode"] // 必填,需要使用的JS接口列表,凡是要调用的接口都需要传进来
})
}catch(error){
console.log(error)
}
wx.ready(function () {
/*alert('ready');*/
// 调用企业微信扫一扫接口
wx.scanQRCode({
desc: "scanQRCode desc",
needResult: 1, // 默认为0,扫描结果由企业微信处理,1则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是条形码(一维码),默认二者都有
success: function(res) {
// 回调
const resultIsbn = res.resultStr;//当needResult为1时返回处理结果
that.$router.push({ path: '/book-info', query: { isbn: resultIsbn } })//带扫码结果跳转到自己的页面
},
error: function(res) {
if (res.errMsg.indexOf('function_not_exist') > 0) {
alert('版本过低请升级')
}
}
})
})
wx.error(function(res){
//config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
let result = res.resultStr// eslint-disable-line no-unused-vars
console.log("ready失败!")
})
}
}
}
</script>
import com.alibaba.fastjson.JSONObject;
import com.MyCache;
import com.common.ServerResponse;
import com.HttpClientHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/wx")
@Slf4j
public class WxController {
private static String CORPID = "********";
private static String CORPSECRET = "********";
private static String GET_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
private static String NONCESTR = "********";
private static String CURR_URL = "********";
@RequestMapping("/getToken")
@ResponseBody
public ServerResponse getTokenInfo(){
try{
String tokenStr = getToken();
log.info(tokenStr);
String ticket = getTickets(tokenStr);
String timeStamp = String.valueOf(System.currentTimeMillis()/1000);
String signature = getSignature(NONCESTR,ticket,timeStamp,CURR_URL);
Map<String,String> data = new HashMap<>();
data.put("appId",CORPID);
data.put("timestamp",timeStamp);
data.put("nonceStr",NONCESTR);
data.put("signature",signature);
return ServerResponse.createBySuccess(data);
}catch (Exception e){
log.error(e.toString());
return ServerResponse.createByErrorMessage(e.toString());
}
}
// 获取秘钥
private String getSignature(String noncestr, String ticket, String timeStamp, String currUrl) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("jsapi_ticket=").append(ticket)
.append("&noncestr=").append(noncestr)
.append("×tamp=").append(timeStamp)
.append("&url=").append(currUrl);
return getSha1(stringBuilder.toString());
}
// 获取token
public String getToken(){
String tokenCache = MyCache.get("wxToken",String.class);
if(!StringUtils.isEmpty(tokenCache)){
return tokenCache;
}
JSONObject param = new JSONObject();
param.put("corpid",CORPID);
param.put("corpsecret",CORPSECRET);
String resultStr = HttpClientHelper.httpGet(GET_TOKEN_URL,param);
System.out.println(resultStr);
JSONObject result = JSONObject.parseObject(resultStr);
String errcode = result.getString("errcode");
String token = "";
if("0".equals(errcode)){
token = result.getString("access_token");
MyCache.put("wxToken",token,7200*1000L);
}
return token;
}
// 根据token 获取tickets
public String getTickets(String token){
String ticketCache = MyCache.get("apiTicket",String.class);
if(!StringUtils.isEmpty(ticketCache)){
return ticketCache;
}
JSONObject param = new JSONObject();
param.put("access_token",token);
String resultStr = HttpClientHelper.httpGet("https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket",param);
System.out.println(resultStr);
JSONObject result = JSONObject.parseObject(resultStr);
String errcode = result.getString("errcode");
String ticket = "";
if("0".equals(errcode)){
ticket = result.getString("ticket");
MyCache.put("apiTicket",ticket,7200*1000L);
}
return ticket;
}
// sha1加密
public static String getSha1(String str) {
char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
try {
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(str.getBytes("UTF-8"));
byte[] md = mdTemp.digest();
int j = md.length;
char buf[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
buf[k++] = hexDigits[byte0 & 0xf];
}
return new String(buf);
} catch (Exception e) {
return null;
}
}
}
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.List;
/**
* HTTP工具类,参数统一用JSONObject对象进行传递
* 需要注意的是,如果参数对顺序有要求,如有签名校验时
* 在构建JSONObject对象时需要指定ordered = true
* 创建为LinkedHashMap
*/
@SuppressWarnings("all")
public class HttpClientHelper {
public static String httpGet(String url) {
return httpGet(url, null, null);
}
public static String httpGet(String url, JSONObject params) {
return httpGet(url, params, null);
}
public static String httpGet(String url, JSONObject params, Header header) {
String result = "";
if (StringUtils.isEmpty(url)) return result;
if (params != null && !params.isEmpty()) url = convertGetParams(url, params);
HttpGet httpGet = new HttpGet(url);
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
httpGet.setConfig(getHttpConfig());
httpGet.setHeader(header);
try {
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity, Consts.UTF_8);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接,释放资源
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
private static String convertGetParams(String url, JSONObject params) {
StringBuffer sb = url.contains("?") ? new StringBuffer(url) : new StringBuffer(url + "?");
params.forEach((k, v) -> sb.append(k).append("=").append(v).append("&"));
return sb.substring(0, sb.length() - 1);
}
public static String httpPost(String url, JSONObject params) {
return httpPost(url, params, null, ContentType.APPLICATION_JSON);
}
public static String httpPost(String url, JSONObject params, Header header) {
return httpPost(url, params, header, ContentType.APPLICATION_JSON);
}
public static String httpPost(String url, JSONObject params, Header header, ContentType contentType) {
String result = "";
if (StringUtils.isEmpty(url)) return result;
//创建默认的httpClient实例
CloseableHttpClient httpClient = HttpClients.createDefault();
//创建httpPost
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader(header);
httpPost.setConfig(getHttpConfig());
StringEntity request;
try {
if (ContentType.APPLICATION_FORM_URLENCODED == contentType) {
List<BasicNameValuePair> pairs = Lists.newArrayList();
params.forEach((key, value) -> pairs.add(new BasicNameValuePair(key, String.valueOf(value))));
request = new UrlEncodedFormEntity(pairs, Consts.UTF_8);
} else {
request = new StringEntity(String.valueOf(params), ContentType.APPLICATION_JSON);
}
httpPost.setEntity(request);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity, Consts.UTF_8);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接,释放资源
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
private static RequestConfig getHttpConfig() {
return RequestConfig.custom()
.setConnectTimeout(10000)//一、连接超时:connectionTimeout-->指的是连接一个url的连接等待时间
.setSocketTimeout(10000)// 二、读取数据超时:SocketTimeout-->指的是连接上一个url,获取response的返回等待时间
.setConnectionRequestTimeout(10000)
.build();
}
}
import org.springframework.util.StringUtils;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Description: 缓存工具类
* 1.部分方法未验证,如有问题请自行修改
* 2.其他方法请自行添加
*/
public class MyCache {
/**
* 屏蔽工具类的无参构造 避免工具类被实例化
*/
private MyCache(){}
/**
* 缓存留存期 30min 1H 24H
*/
public static final long CACHE_HOLD_TIME_30M = 30 * 60 * 1000L;
public static final long CACHE_HOLD_TIME_1H = 2 * CACHE_HOLD_TIME_30M;
public static final long CACHE_HOLD_TIME_24H = 24 * CACHE_HOLD_TIME_1H;
public static final long CACHE_HOLD_TIME_FOREVER = -1L;
/**
* 缓存容量、最少使用容量
*/
private static final int CACHE_MAX_CAP = 1000;
private static final int CLEAN_LRU_CAP = 800;
/**
* 缓存当前大小
*/
private static AtomicInteger CACHE_CURRENT_SIZE = new AtomicInteger(0);
/**
* 缓存对象
*/
private static final Map<String,Node> CACHE_MAP = new ConcurrentHashMap<>(CACHE_MAX_CAP);
/**
* 最少使用记录
*/
private static final List<String> LRU_LIST = new LinkedList<>();
/**
* 自动清理标志位
*/
private static volatile boolean CLEAN_RUN_FLAG = false;
/**
* 默认30MIN
* @param key
* @param val
*/
public static void put(String key,Object val){
put(key,val,CACHE_HOLD_TIME_30M);
}
/**
* 添加永久缓存
* @param key
* @param val
*/
public static void putForever(String key,Object val){
put(key,val,CACHE_HOLD_TIME_FOREVER);
}
/**
* 添加缓存
* @param key
* @param val
* @param ttlTime
*/
public static void put(String key,Object val,long ttlTime){
if (!StringUtils.hasLength(key) || null == val){
return;
}
checkSize();
updateCacheLru(key);
CACHE_MAP.put(key,new Node(val,ttlTime));
}
/**
* 获取缓存信息
* @param key
* @param clazz
* @param
* @return
*/
public static <T> T get(String key,Class<T> clazz){
if (!StringUtils.hasLength(key) || !CACHE_MAP.containsKey(key)){
return null;
}
updateCacheLru(key);
return (T) CACHE_MAP.get(key).getVal();
}
/**
* 更新最近使用位置
* @param key
*/
private static void updateCacheLru(String key){
synchronized (LRU_LIST){
LRU_LIST.remove(key);
LRU_LIST.add(0,key);
}
}
/**
* 删除,成功则容量-1
* @param key
*/
private static boolean remove(String key){
Node node = CACHE_MAP.remove(key);
if (null!=node){
CACHE_CURRENT_SIZE.getAndDecrement();
return true;
}
return false;
}
/**
* 检查是否超过容量,先清理过期,在清理最少使用
*/
private static void checkSize(){
if (CACHE_CURRENT_SIZE.intValue() > CACHE_MAX_CAP){
deleteTimeOut();
}
if (CACHE_CURRENT_SIZE.intValue() > CLEAN_LRU_CAP){
deleteLru();
}
}
/**
* 删除最久未使用,尾部删除
* 永久缓存不会被清除
*/
private static void deleteLru(){
synchronized (LRU_LIST){
while (LRU_LIST.size() > CLEAN_LRU_CAP){
int lastIndex = LRU_LIST.size() - 1;
String key = LRU_LIST.get(lastIndex);
if (!CACHE_MAP.get(key).isForever() && remove(key)){
LRU_LIST.remove(lastIndex);
}
}
}
}
/**
* 删除过期
*/
private static void deleteTimeOut(){
List<String> del = new LinkedList<>();
for (Map.Entry<String,Node> entry:CACHE_MAP.entrySet()){
if (entry.getValue().isExpired()){
del.add(entry.getKey());
}
}
for (String k:del){
remove(k);
}
}
/**
* 缓存是否已存在,过期则删除返回False
* @param key
* @return
*/
public static boolean contains(String key){
if (CACHE_MAP.containsKey(key)){
if (!CACHE_MAP.get(key).isExpired()){
return true;
}
if (remove(key)){
return false;
}
return true;
}
return false;
}
/**
* 清空缓存
*/
public static void clear(){
CACHE_MAP.clear();
CACHE_CURRENT_SIZE.set(0);
LRU_LIST.clear();
}
/**
* 重置自动清理标志
* @param flag
*/
public static void setCleanRunFlag(boolean flag){
CLEAN_RUN_FLAG = flag;
}
/**
* 自动清理过期缓存
*/
private static void startAutoClean(){
if (!CLEAN_RUN_FLAG){
setCleanRunFlag(true);
ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1);
scheduledExecutor.scheduleAtFixedRate(()->{
try {
MyCache.setCleanRunFlag(true);
while (CLEAN_RUN_FLAG){
MyCache.deleteTimeOut();
}
} catch (Exception e) {
e.printStackTrace();
}
},10,MyCache.CACHE_HOLD_TIME_1H, TimeUnit.SECONDS);
}
}
/**
* 缓存对象类
*/
public static class Node{
/**
* 缓存值
*/
private Object val;
/**
* 过期时间
*/
private long ttlTime;
public Node(Object val,long ttlTime){
this.val = val;
if (ttlTime<0){
this.ttlTime = ttlTime;
}else{
this.ttlTime = System.currentTimeMillis() + ttlTime;
}
}
public Object getVal(){
return this.val;
}
public boolean isExpired(){
if (this.ttlTime<0){
return false;
}
return System.currentTimeMillis() > this.ttlTime;
}
public boolean isForever(){
if (this.ttlTime<0){
return true;
}
return false;
}
}
}
import java.io.Serializable;
public class ServerResponse<T> implements Serializable
{
private int status;
private String msg;
private T data;
private ServerResponse(final int status) {
this.status = status;
}
private ServerResponse(final int status, final T data) {
this.status = status;
this.data = data;
}
private ServerResponse(final int status, final String msg, final T data) {
this.status = status;
this.msg = msg;
this.data = data;
}
private ServerResponse(final int status, final String msg) {
this.status = status;
this.msg = msg;
}
public boolean isSuccess() {
return this.status == ResponseCode.SUCCESS.getCode();
}
public int getStatus() {
return this.status;
}
public T getData() {
return this.data;
}
public String getMsg() {
return this.msg;
}
public static <T> ServerResponse<T> createBySuccess() {
return new ServerResponse<T>(ResponseCode.SUCCESS.getCode());
}
public static <T> ServerResponse<T> createBySuccessMessage(final String msg) {
return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), msg);
}
public static <T> ServerResponse<T> createBySuccess(final T data) {
return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), data);
}
public static <T> ServerResponse<T> createBySuccess(final String msg, final T data) {
return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(), msg, data);
}
public static <T> ServerResponse<T> createByError() {
return new ServerResponse<T>(ResponseCode.ERROR.getCode(), ResponseCode.ERROR.getDesc());
}
public static <T> ServerResponse<T> createByErrorMessage(final String errorMessage) {
return new ServerResponse<T>(ResponseCode.ERROR.getCode(), errorMessage);
}
public static <T> ServerResponse<T> createByErrorCodeMessage(final int errorCode, final String errorMessage) {
return new ServerResponse<T>(errorCode, errorMessage);
}
}
public enum ResponseCode {
SUCCESS(0, "SUCCESS"),
ERROR(1, "ERROR"),
NEED_LOGIN(10, "NEED_LOGIN"),
ILLEGAL_ARGUMENT(2, "ILLEGAL_ARGUMENT");
private final int code;
private final String desc;
private ResponseCode(final int code, final String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return this.code;
}
public String getDesc() {
return this.desc;
}
}