前言
在我前面的文章里,其实有一个关于
java代码实现简单的向企业微信发送信息
里面文章,有了如何去配置企业微信的,并且阐述了如何只通过简单的java代码【纯后端】实现发送信息
但是里面并没有涉及到如何去进行 拍照或者选择本地图片进行选择上传到后端。
那么本次将带大家一步步的实现以下内容:
1.配置企业微信服务
2.教大家如何获取企业微信的用户信息
3.教大家如何进行拍照上传图片
4.推送企业微信信息
前置准备
在我本文章,最主要的是通过【应用】进行的,使用场景为将自己制作的vue+springboot项目部署到自建应用上达到访问应用,以获取企业微信用户信息进行处理,并且可以实现上传图片、发送信息等。
需要注意的是: 本次文章不介绍如何将自建的应用部署到企业微信建的应用上,它目前来说是需要检测域名验证,也是比较麻烦的一件事情
另外,本次上传图片,针对PC端、安卓端和IOS端皆有效,已经在本人实际的项目上进行了验证。
我们唯一需要做的准备就一个,那就是新建一个应用,然后获取到三个数据:
corpId: 企业ID
agentId: 应用ID
secret: 应用秘钥
具体如何获取,在我上面提到的文章有具体说明,就不多赘述。
简单来说,如果你是自建的企业,自己建自己获取即可,如果是公司企业,你不是管理员,让是管理员的告诉你对应数据,具体文章有说到。
springboot后端配置
以下皆以我其中一个项目进行说明
企业微信依赖包
我们需要在pom.xml引入企业微信的依赖包
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-cp</artifactId>
<version>4.0.8.B</version>
</dependency>
配置企业微信数据
在application.yml
文件添加企业微信的数据,即
corpId: 企业ID
agentId: 应用ID
secret: 应用秘钥
wechat:
cp:
corpId: 企业ID
secret: 应用秘钥
agentId: 应用ID
需要注意的是,一个springboot项目是可以引入多个应用id配置的,形式如下:
wechat:
cp1:
corpId: 企业ID
secret: 应用秘钥
agentId: 应用ID
cp2:
corpId: 企业ID
secret: 应用秘钥
agentId: 应用ID
需要使用哪个,调用对应的应用即可
config配置
在springboot项目的config配置新建一个文件WxConfig
具体代码如下:
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.impl.WxCpChatServiceImpl;
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
import me.chanjar.weixin.cp.bean.message.WxCpAppChatMessage;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author 相与还
* @dateTime: 2023-01-04
* @description: 企业微信配置
* */
@Configuration
@Getter
public class WxConfig {
@Value("${wechat.cp.secret}")
private String secret;
@Value("${wechat.cp.corpId}")
private String corpId;
@Value("${wechat.cp.agentId}")
private Integer agentId;
@Value("${wechat.cp.redirectUrl}")
private String redirectUrl;
@Value("${wechat.cp.chatId}")
private String chatId;
private static String APP_AGENT_PREFIX = "wx";
@Resource
RedisConfig redisConfig;
public WxCpService getWxCpService() {
WxCpService wxCpService = new WxCpServiceImpl();
WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
config.setAgentId(agentId);
config.setCorpSecret(secret);
config.setCorpId(corpId);
resetTokenAndJsApi(wxCpService, config);
return wxCpService;
}
public void resetTokenAndJsApi(WxCpService wxCpService, WxCpDefaultConfigImpl wxCpDefaultConfig) {
Jedis jedis = redisConfig.getRedisPoolConfig().getResource();
wxCpService.setWxCpConfigStorage(wxCpDefaultConfig);
// String wxAccessToken = "qy2wx"+ this.agentId; 自带的wx
String wxAccessToken = APP_AGENT_PREFIX + this.agentId;
String json = jedis.get(wxAccessToken);
if (!StringUtils.isEmpty(json)) {
wxCpDefaultConfig = JSON.parseObject(json, WxCpDefaultConfigImpl.class);
}
if (wxCpDefaultConfig.isAccessTokenExpired()) {
try {
String accessToken = null;
accessToken = wxCpService.getAccessToken(false);
wxCpDefaultConfig.setAccessToken(accessToken);
} catch (WxErrorException e) {
e.printStackTrace();
}
}
if(wxCpDefaultConfig.isJsapiTicketExpired()){
String jsApi = null;
try {
jsApi = wxCpService.getJsapiTicket();
wxCpDefaultConfig.setJsapiTicket(jsApi);
} catch (WxErrorException e) {
e.printStackTrace();
}
}
jedis.set(wxAccessToken, JSON.toJSONString(wxCpDefaultConfig));
jedis.close();
}
}
注意:为了不使得以上代码在引入到自己的项目的时候报错,需分别引入如下依赖:
<!-- 本项目需要引入redis,尚未验证去除redis的情况,能不能使用该企业微信配置-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
以及在yml文件添加redis配置以及添加redis的配置文件
即,在application.yml
添加如下代码:
redis:
port: 6379
password: redis密码
cluster:
node: redis的ip地址(一般使用公司的服务器的redis的ip,如没有则本机启动redis,使用本机ip)
lettuce:
pool:
min-idle: 0
max-idle: 8
max-active: 20
新建RedisConfig
文件,代码如下:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @dateTime: 2023-01-04
* @description: redis配置
* */
@Configuration
public class RedisConfig {
@Value("${redis.port}")
private Integer port;
@Value("${redis.cluster.node}")
private String url;
@Value("${redis.password}")
private String password;
@Value("${redis.lettuce.pool.max-idle}")
private Integer idle;
@Bean
public JedisPool getRedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(idle);
jedisPoolConfig.setMaxTotal(18);
JedisPool jedisPool = new JedisPool(jedisPoolConfig,url,port,5000,password);
return jedisPool;
}
}
签名算法
企业微信它是使用SHA1算法进行加密签名验证的,所以我们还需要有一个工具类:
新建一个文件ShaUtil
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @Description sha1 加密算法 主要是用生成js-sdk的签名算法
*/
public class ShaUtil {
public static String SHA1(String str) {
try {
MessageDigest digest = java.security.MessageDigest
.getInstance("SHA-1"); //如果是SHA加密只需要将"SHA-1"改成"SHA"即可
digest.update(str.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexStr = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexStr.append(0);
}
hexStr.append(shaHex);
}
return hexStr.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
}
企业微信验证实体
为了能够通过企业微信验证,我们还需要有对应的实体
新建文件WxSignature
import lombok.Data;
/**
* @dateTime: 2021-12-3
* @description; 企业微信实体
* */
@Data
public class WxSignature {
private String jsapiTicket;
//企业微信的corpId
private String corpid;
// 企业微信应用id
private Integer agentId;
// 签名时间戳
private long timestamp;
// 簽名隨機串
private String nonceStr;
// 签名
private String signature;
public String getSignature(String url) {
String res = "jsapi_ticket=" + this.jsapiTicket+"&noncestr="+this.nonceStr+"×tamp="+this.timestamp+"&url="+url;
return res;
}
}
ps:getSignature里面的文本不能变动,否则会验证失败
详情,请参照企业微信api
企业微信签名算法
企业微信controller和service层
那么到这边,我们后端的准备工作基本ok了,接下来,我们需要定义controller层和service层方便我们快速的获取企业微信配置和获取用户信息
首先是controller层
代码如下:
import com.factory.config.WxConfig;
import com.factory.service.WxService;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
import me.chanjar.weixin.cp.api.impl.WxCpOAuth2ServiceImpl;
import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* @dateTime: 2023-01-04
* description: 微信登录
*
* */
@RestController
@RequestMapping("/wx/*")
public class WxController {
@Resource
private WxConfig wxConfig;
@Resource
private WxService wxService;
private WxCpOAuth2Service auth2Service = null;
//获取企业微信用户userId
@GetMapping("/getUserInfo")
public String getUserInfo(@RequestParam("code")String code,@RequestParam("userId") String userId)throws Exception {
WxCpOauth2UserInfo wxCpOauth2UserInfo = null;
if(StringUtils.isEmpty(userId)) {
if(auth2Service == null)
{
auth2Service = new WxCpOAuth2ServiceImpl(wxConfig.getWxCpService());
}
wxCpOauth2UserInfo = auth2Service.getUserInfo(wxConfig.getAgentId(),code);
} else {
return new ResultVo(ResutEnum.OK,userId);
}
String resultUserId = wxCpOauth2UserInfo.getUserId();
return resultUserId;
}
// 获取微信sdk
@GetMapping("/getWxJsSdkConfig")
public WxSignature getWxJsSdkConfig(@RequestParam("url")String url)throws Exception {
return wxService.getWxJsSdkConfig(wxConfig,url);
}
}
service层
代码如下:
mport org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.UUID;
/**
* @dateTime: 2023-01-04
* @description: 微信service
* */
@Service
public class WxService {
public WxSignature getWxJsSdkConfig(WxConfig wxConfig,String url) throws Exception{
WxSignature wxSignature = new WxSignature();
wxSignature.setCorpid(wxConfig.getCorpId());
wxSignature.setJsapiTicket(wxConfig.getWxCpService().getJsapiTicket());
wxSignature.setTimestamp(LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
wxSignature.setAgentId(wxConfig.getAgentId());
wxSignature.setNonceStr(UUID.randomUUID().toString());
wxSignature.setSignature(ShaUtil.SHA1(wxSignature.getSignature(url)));
System.out.println(wxSignature.toString());
return wxSignature;
}
}
ps:需要注意的是,可能我和你们前面建的文件位置不一样,如果你们引入我的位置,可能会报错,我这边就不做引入文件(WxConfig,WxSignature文件),你们根据代码提示引入即可
vue前端配置
后端写完了,那么我们前端就比较简单了,只需要调用axios获取对应数据即可。
不过有一点需要注意,如果需要获取企业微信的用户信息,必须得通过企业微信应用,访问自己的自建应用才能够拿到,所以在开发阶段,一般情况,是查找人员的企业微信userId信息,直接写死数据。等待开发完成再把写死的数据移除,部署之后获取访问人员的企业微信用户信息。
企业微信依赖
vue项目也是需要安装依赖
使用
npm install weixin-js-sdk
然后在main.js引入,引入代码在后面发出来
axios配置
那么为了让大家看明白如何在前端使用,我依照自己的习惯,获取和编写axios的配置
第一步,安装axios依赖
npm install axios
第二步:在main.js引入axios
import axios from 'axios'
Vue.prototype.$axios = axios
第三步:编写工具类
新建request.js
代码如下:
import axios from 'axios'
// 创建axios实例
// eslint-disable-next-line no-unused-vars
const service = axios.create({
baseURL: '/', // api的base_Url
timeout: 50000 // 请求超时时间
});
// 请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
return config
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error)
}
)
// 响应拦截器
axios.interceptors.response.use(
function (config) {
// 对响应数据做点什么
return config
},
function (error) {
// 对响应错误做点什么
return Promise.reject(error)
}
)
export default service
第四步:编写api类进行获取调用后端接口
新建axiosApi.js
代码如下:
import service from '../utils/request'
// get请求实例
export function getAxios (param1,param2) {
return service.get('/test/getAxios', {
headers: { 'Content-Type': 'application/json' },
params: {
param1: param1,
param2: param2,
}
})
}
// post请求实例,参数为对象
export function postAxios(obj) {
return service.post('/test/postAxios', JSON.stringify(obj), {
headers: { 'Content-Type': 'application/json' }
})
}
// 获取userId信息
export function getUserIdInfo (code, userId) {
return service.get('/wx/getUserInfo', {
headers: { 'Content-Type': 'application/json' },
params: {
code: code,
userId: userId
}
})
}
// 获取企业微信的配置信息
export function getWxJsSdkConfig () {
// 通过截取地址栏获取url
const url = window.location.href.split('#')[0]
return service.get('/wx/getWxJsSdkConfig', {
headers: { 'Content-Type': 'application/json' },
params: {
url: url
}
})
}
如果通过正式部署到应用后,它的地址栏的形式一般为:
http://xxx.com:9010/?code=XhjaBDulcPFJSK5Kq3VNCnRgT-CwJKQilQbsuNLtdso&state=#/XXX`
即域名+端口+生成的code和跳转的路径组成
以上获取配置和用户信息根据地址栏信息获取
main.js
一般情况,我都是定义一个根变量去接收获取的企业微信userId,
并且在main.js下进行获取企业微信配置。
主要是因为,如果在每个页面都获取一遍的话,再加上很多人访问,它是很容易会有限制获取的。
于是,在main.js下我们的代码如下:
import Vue from 'vue'
import App from './App'
import wx from 'weixin-js-sdk'
import axios from 'axios'
// 根据自己的axios的get和post文件修改位置
import { getWxJsSdkConfig } from "../src/axiosApi"
Vue.prototype.$axios = axios
Vue.prototype.$wx = wx
new Vue({
el: '#app',
router,
render: h => h(App),
data: function () {
return {
userId: '', // 获取登录的用户userid
}
},
mounted () {
// 调用后端接口获取企业微信配置
this.registerWxApi();
},
methods: {
async registerWxApi () {
await getWxJsSdkConfig().then(res => {
console.log("企业微信后端配置数据:",res);
this.$wx.config({
beta: true,
debug: false,
appId: res.data.corpid,
timestamp: res.data.timestamp,
nonceStr: res.data.nonceStr,
signature: res.data.signature,
jsApiList: ['chooseImage','getLocalImageData']
// jsApiList 这边我只引入了两个,是关于调用企业微信接口进行拍照获取图片的
})
})
},
},
}).$mount('#app')
ps:这边res获取到的数据,请根据自己项目决定是res.data还是res.data.data或者其他内容
App.vue -获取企业微信用户信息
在该页面获取企业微信userId,注意必须先得获取到企业微信配置后才能获取用户信息
App.vue的代码如下:
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
// 根据自己的axios的get和post文件修改位置
import { getUserIdInfo } from '../src/axiosApi'
export default {
name: 'App',
mounted () {
this.solveUserIdNull ();
},
data() {
return {
userId: '',
}
},
methods: {
// 解决userId为空
solveUserIdNull () {
this.getUserId().then(res => {
this.userId = res
sessionStorage.setItem('userId', this.userId)
})
},
async getUserId () {
const reg = new RegExp('(^|&)code=([^&]*)(&|$)')
const code = window.location.search.substring(1).match(reg)[2];
await getUserIdInfo(code, this.$root.userId).then(res => {
this.userId = res.data.data
this.$root.userId = this.userId
})
return this.userId
},
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>
router需要安装vue-router才能使用
使用
npm install vue-router
同时,我有使用
sessionStorage.setItem('userId', this.userId)
this.$root.userId = this.userId
意味着,你可以使用session.getItem('userId')
或者this.$root.userId
获得企业微信用户信息
企业微信拍照
那么接下来,就是教大家如何使用企业微信的拍照接口进行拍照了。
首先的话,它获取的数据为base64,因此,这边我只教到如何获取base64,至于你需要传给后端,或者需要做什么就不多写了,根据自己的需求来即可
在你需要拍照功能的vue文件编写如下代码:
<template>
<div>
<button type="primary" @click.native="chooseImage">上传图片</button>
</div>
</template>
<script>
export default {
name: 'xxx',
data () {
return {
base64: "", // 接收单张图片base64数据
}
},
methods: {
chooseImage () {
// 必须定义变量接收this,否则无法赋值
const _this = this
_this.$wx.chooseImage({
count: 1, // 默认9 ,一次可选择的图片数量
sourceType: ['camera', 'album'], // 可以指定来源是相册还是相机,默认二者都有
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
isShowProgressTips: 1,
success: (res => {
_this.$wx.getLocalImgData({
localId: res.localIds[0].toString(),
success: (data => {
const local = data.localData
_this.base64= local
}),
fail: (err => {
console.log(err);
})
})
console.log("选择图片成功!");
}),
fail: (err => {
console.log(err);
})
})
},
}
}
</script>
以上为上传单张图片的方法
如果需要上传多张图片,参照如下代码:
<template>
<div>
<button type="primary" @click.native="chooseImage">上传图片</button>
</div>
</template>
<script>
export default {
name: 'xxx',
data () {
return {
baseImg: [], // 接收多张图片base64数据
weixinCount: 0, // 统计一次微信上传图片数量
}
},
methods: {
chooseImage () {
// 必须定义变量接收this,否则无法赋值
const that = this
that.$wx.chooseImage({
count: 9,
sizeType: ['original','compressed'],
sourceType: ['album', 'camera'],
defaultCameraMode: "normal",
success: function (res) {
that.localIds = res.localIds;
// 获取图片名称
let picName = [];
picName = res.localIds;
picName.forEach(item => {
console.log("图片数据:",item);
console.log("图片名称",item.substring(item.lastIndexOf("/")+1));
// 获取图片名称
that.baseImg.push({
imgBase64 : "",
imgName: item.substring(item.lastIndexOf("/")+1),
});
})
that.updateBase64Data(that.localIds.shift());
console.log(that.baseImg,"base64");
},
fail: function (res) {
console.log("选择图片失败:",res);
}
});
},
updateBase64Data (localId) {
// ios端上传图片会有问题,需要加base64的图片头部
const that = this
that.$wx.getLocalImgData({
localId: localId,
success: function (res) {
let localData = res.localData
let prefix = 'base64,';
let index = localData.indexOf(prefix)
let actData = localData
// 设置参数,展示添加头部data:image/jpeg:base64
if (index > -1) {
actData = localData.substring(index+7)
}
console.log("lo", localData.substring(index+7).length);
// baseImg是在data里定义的一个base64数组
that.baseImg[that.weixinCount].imgBase64 = "data:image/jpeg;base64,"+actData;
that.weixinCount = that.weixinCount +1;
if (that.localIds.length > 0) {
that.updateBase64Data(that.localIds.shift())
}
},
fail: function (res) {
console.log("获取图片数据失败:",res);
}
})
},
}
}
</script>
以上代码主要需要注意这么几点:
调用企业微信接口,访问内部,如果不用变量接收是拿不到值进行赋值的
ios端获取的图片是有问题的,可以根据判断base64是否有base64的图片头文件进行判断
其他如果获取图片不清楚的,可以console打印数据进行查看
发送企业微信信息
发送企业微信信息,是在后端进行,一般我会封装一个方法,需要使用的时候调用该方法即可。
新建WxSendMessageConfig
代码如下:
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpMessageService;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.impl.WxCpMessageServiceImpl;
import me.chanjar.weixin.cp.bean.message.WxCpMessage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
@Configuration
public class WxSendAppConfig {
@Resource
private WxConfig wxConfig;
/**
* @Param WxUserId 企业微信用户userId
* @Description 发送普通文本信息
*/
public void WxMessage1(String WxUserId) {
// 开启微信服务
WxCpService wxCpService = wxConfig.getWxCpService();
WxCpMessageService wxCpMessageService = new WxCpMessageServiceImpl(wxCpService);
// 开启微信消息服务
WxCpMessage wxCpMessage = new WxCpMessage();
String msg = "测试文本";
// 设置发送用户
wxCpMessage.setToUser(WxUserId);
// 设置发送主体
wxCpMessage.setContent(msg);
// 设置发送信息类型 text为普通文本
wxCpMessage.setMsgType("text");
try {
wxCpMessageService.send(wxCpMessage);
}catch(Exception e) {
System.out.println("发送企业微信信息失败:"+e);
}
}
/**
* @Param WxUserId 企业微信用户userId
* @Description 发送卡片文本信息
*/
public void WxMessage2(String WxUserId) {
// 开启微信服务
WxCpService wxCpService = wxConfig.getWxCpService();
WxCpMessageService wxCpMessageService = new WxCpMessageServiceImpl(wxCpService);
// 开启微信消息服务
WxCpMessage wxCpMessage = new WxCpMessage();
wxCpMessage.setToUser(WxUserId);
wxCpMessage.setMsgType("textcard");
wxCpMessage.setTitle("文本标题");
wxCpMessage.setDescription("文本主体");
wxCpMessage.setBtnTxt("按钮名称");
wxCpMessage.setUrl("点击按钮跳转url");
try {
wxCpMessageService.send(wxCpMessage);
}catch(Exception e) {
System.out.println("发送企业微信信息失败:"+e);
}
}
}
更多发送信息类型参考企业微信API
企业微信发送信息api
结语
以上就是关于企业微信配置企业微信服务获取服务的逻辑和过程,如有问题可相互讨论,另有新内容将在该文章更新。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/101111.html