企业微信开发总结-获取通讯录
最近遇到个项目需求,需要能够获取到用户企业的通讯录,同步到我们系统中,这样就不用重复输入一批企业人员了。一开始想的很简单,实际研究下来发现企业微信比个人微信对接起来复杂多了, 也许是微信平台考虑到企业数据的安全性,特意设计的很复杂吧。话不多说,直奔主题。
PS: 本项目代码是基于java语言springboot框架开发的,使用工具是IDEA, jdk1.8。如果看官您采用的是其他语言,那只能参考下本文的思路了。
一、 前期企业微信准备

  1. 先注册个企业微信,这个按照官方指引来就行了。进入服务商平台-服务商信息-基本信息,查看corpId, 保存备用。 同时需要设置IP白名单。不然后面的API接口调用会失败哦。

  2. 进入应用管理,选择应用类型。 我这里做的是H5网页,所以选择网页应用。创建一个。注意应用类型,有普通应用和通讯录应用两种。 这里有个坑,普通应用的说明里也可以访问通讯录,但是他没有说无法获取到人员手机号码和姓名,只有人员的id,部门什么的。 这个和我的需求显然是不匹配的。 自己也是踏过这个坑,后面发现调用获取人员详情接口时,没有手机号码返回,一查看接口说明才发现这个问题。 所以新手就不用再犯同样的错误了,节约时间。创建完查看应用详情。

SuiteID和Secret需要记录下来,这是第三方应用获取授权企业信息时需要的参数。
可信域名要填写我们应用的域名,如果没有需要去申请。建议配置https。还有安装完成回调域名,业务设置URL都写好。
接下来还有回调配置

数据回调URL是用于企业微信的通信消息的,比如谁发信息给谁了,会推送到这个地址。我们这里虽然不需要,但还是写个接口响应一下吧,不然会无法进行安装测试。
指令回调URL是非业务的交互指令通知,比如企业对我们的应用完成授权的时候,而这个正是我们需要的。我们需要在这里取到企业的临时授权码,用来换取永久授权码,进而取到企业的AccessToken, 获取通讯录数据。其实拿到永久授权码的数据返回中也有AccessToken,可以直接用。 存储永久授权码是为了以后再调取企业接口,直接使用永久授权去换取AccessToken。
Token自己填写或者自动生成,EncodingAESKey也是。这两个是用于验证和微信平台的数据交互的安全性。
接口得先写好,调通后这里的回调填写保存才能成功。所以下面开始撸代码。
二、 业务代码
application.properties中配置相关参数

suitId=这里是应用的suiteID
suitSecret=这里是应用的Secret
#平台作为服务商的参数
corpId=服务商corpId
token=应用回调token
encodingAesKey=应用回调encodingAESKey

创建表wx_corp_info,用于存储授权企业的信息。用的是mysql数据库。

然后mybatis-plus逆向生成相关的代码
编写主类
WeiXinCorpController

package xxx;import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.util.StringUtil;
import com.hssx.cloudmodel.constant.Constant;
import com.hssx.cloudmodel.entity.SysParam;
import com.hssx.cloudmodel.entity.User;
import com.hssx.cloudmodel.entity.WxCorpInfo;
import com.hssx.cloudmodel.mapper.SysParamMapper;
import com.hssx.cloudmodel.mapper.UserMapper;
import com.hssx.cloudmodel.mapper.WxCorpInfoMapper;
import com.hssx.cloudmodel.util.HttpRespMsg;
import com.hssx.cloudmodel.util.JsapiTicketUtil;
import com.hssx.cloudmodel.util.Sha1Util;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.json.XML;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.SortedMap;
import java.util.TreeMap;@RestController
@RequestMapping("/wxcorp")
@Slf4j
public class WeiXinCorpController {public static final String GET_SUITE_ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/get_suite_token";public static final String GET_PREAUTH_CODE_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/get_pre_auth_code?suite_access_token=SUITE_ACCESS_TOKEN";//获取企业永久授权码public static final String GET_CORP_PERMANENT_CODE_URL = "https://qyapi.weixin.qq.com/cgi-bin/service/get_permanent_code?suite_access_token=SUITE_ACCESS_TOKEN";//获取成员详情public static final String GET_USER_INFO_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&userid=USERID";//获取部门列表public static final String GET_DEPARTMENT_URL = "https://qyapi.weixin.qq.com/cgi-bin/department/list?access_token=ACCESS_TOKEN&id=";//获取部门成员详情public static final String GET_DEPARTMENT_USER_DETAIL_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/list?access_token=ACCESS_TOKEN&department_id=DEPARTMENT_ID&fetch_child=1";public static final String AUTH_CALLBACK_URL = "http://ymhh.yunsu.cn/wxcorp/authcallback";@Value("${suitId}")private String suitId;@Value("${suitSecret}")private String suitSecret;@Value("${token}")private String token;@Value("${encodingAesKey}")private String encodingAesKey;@Value("${corpId}")private String corpId;@AutowiredRestTemplate restTemplate;public static String SUITE_ACCESS_TOKEN = null;public static long suiteTokenExpireTime = 0L;public static String PRE_AUTH_CODE = null;public static long expireTime = 0L;@ResourceSysParamMapper sysParamMapper;@ResourceWxCorpInfoMapper wxCorpInfoMapper;@ResourceUserMapper userMapper;@ApiOperation(value = "企业微信数据回调", notes = "企业微信数据回调")@RequestMapping(value = "/dataCallback/{corpId}", method = RequestMethod.GET)@ResponseBodypublic String dataCallback(@PathVariable String corpId, String msg_signature, String timestamp, String nonce, String echostr) {System.out.println("========dataCallback========="+corpId);try {String sVerifyMsgSig = msg_signature;String sVerifyTimeStamp = timestamp;String sVerifyNonce = nonce;String sVerifyEchoStr = echostr;WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, corpId);String sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,sVerifyNonce, sVerifyEchoStr);//需要返回的明文System.out.println("verifyurl echostr: " + sEchoStr);return sEchoStr;// 验证URL成功,将sEchoStr返回// HttpUtils.SetResponse(sEchoStr);}  catch (AesException e) {e.printStackTrace();}return "success";}@ApiOperation(value = "企业微信数据回调", notes = "企业微信数据回调")@RequestMapping(value = "/dataCallback/{corpId}", method = RequestMethod.POST)@ResponseBodypublic String dataCallbackPost(@PathVariable String corpId, @RequestBody String requestBody, String msg_signature, String timestamp, String nonce) {log.info("========dataCallback========="+corpId);// String sReqMsgSig = HttpUtils.ParseUrl("msg_signature");String sReqMsgSig = msg_signature;// String sReqTimeStamp = HttpUtils.ParseUrl("timestamp");String sReqTimeStamp = timestamp;// String sReqNonce = HttpUtils.ParseUrl("nonce");String sReqNonce = nonce;// post请求的密文数据// sReqData = HttpUtils.PostData();
//        String sReqData = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";log.info("===========dataCallback POST=============" + msg_signature);log.info("===========corpId=====suitId========" + suitId);try {WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, suitId);String sMsg = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, requestBody);log.info("解密后===msg: " + sMsg);} catch (Exception e) {// TODO// 解密失败,失败原因请查看异常e.printStackTrace();}return "success";}@ApiOperation(value = "企业微信指令回调", notes = "企业微信指令回调, 处理回调验证")@RequestMapping(value = "/cmdCallback", method = RequestMethod.GET)@ResponseBodypublic String cmdCallbackGet(String msg_signature, String timestamp, String nonce, String echostr) {try {log.info("===========cmdCallback GET=============" + msg_signature);String sVerifyMsgSig = msg_signature;String sVerifyTimeStamp = timestamp;String sVerifyNonce = nonce;String sVerifyEchoStr = echostr;WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, corpId);String sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp,sVerifyNonce, sVerifyEchoStr);//需要返回的明文log.info("verifyurl echostr: " + sEchoStr);return sEchoStr;// 验证URL成功,将sEchoStr返回// HttpUtils.SetResponse(sEchoStr);}  catch (AesException e) {e.printStackTrace();}return "success";}@ApiOperation(value = "企业微信指令回调", notes = "企业微信指令回调, 处理消息体")@RequestMapping(value = "/cmdCallback", method = RequestMethod.POST)@ResponseBodypublic String cmdCallbackPost(@RequestBody(required = false) String requestBody, String msg_signature, String timestamp, String nonce) {// String sReqMsgSig = HttpUtils.ParseUrl("msg_signature");String sReqMsgSig = msg_signature;// String sReqTimeStamp = HttpUtils.ParseUrl("timestamp");String sReqTimeStamp = timestamp;// String sReqNonce = HttpUtils.ParseUrl("nonce");String sReqNonce = nonce;// post请求的密文数据// sReqData = HttpUtils.PostData();
//        String sReqData = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";log.info("===========企业微信指令回调 POST=============" + msg_signature);log.info("===========corpId=====suitId========" + suitId);try {WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(token, encodingAesKey, suitId);String sMsg = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, requestBody);log.info("解密后===msg: " + sMsg);// TODO: 解析出明文xml标签的内容进行处理org.json.JSONObject jsonObject = XML.toJSONObject(sMsg);log.info("json=="+jsonObject.toString());jsonObject = jsonObject.getJSONObject("xml");if (jsonObject.has("AuthCode")) {//企业授权通知String authCode = jsonObject.getString("AuthCode");handleCorpAuth(authCode);} else if (jsonObject.has("SuiteTicket")) {//ticket推送String ticket = jsonObject.getString("SuiteTicket");String timeStamp = jsonObject.getLong("TimeStamp")+"";log.info("ticket=="+ticket);//存储SysParam param = sysParamMapper.selectOne(new QueryWrapper<SysParam>().eq("param_code", "suite_ticket"));if (param == null) {param = new SysParam();param.setParamCode("suite_ticket");param.setParamName(ticket);param.setRemark(timeStamp);sysParamMapper.insert(param);} else {param.setParamName(ticket);param.setRemark(timeStamp);sysParamMapper.updateById(param);}}} catch (Exception e) {// TODO// 解密失败,失败原因请查看异常e.printStackTrace();}return "success";}@ApiOperation(value = "企业授权微信应用", notes = "企业授权微信应用")@RequestMapping("/getAuthPage")@ResponseBodypublic HttpRespMsg getAuthPage() {HttpRespMsg msg = new HttpRespMsg();String preAuthCode = getAuthCode();String url = "https://open.work.weixin.qq.com/3rdapp/install?suite_id=SUITE_ID&pre_auth_code=PRE_AUTH_CODE&redirect_uri=REDIRECT_URI&state=STATE";url = url.replace("SUITE_ID", suitId).replace("PRE_AUTH_CODE", preAuthCode).replace("REDIRECT_URI", URLEncoder.encode(AUTH_CALLBACK_URL));msg.data = url;return msg;}@ApiOperation(value = "企业授权后回调地址")@RequestMapping("/authcallback")@ResponseBodypublic HttpRespMsg authcallback(String auth_code, Integer expires_in, String state) {HttpRespMsg msg = new HttpRespMsg();log.info("authcallback收到: auth_code="+auth_code+", expires_in="+ expires_in+",state= "+state);handleCorpAuth(auth_code);return msg;}private void handleCorpAuth(String authCode) {String suitAccessToken = getSuiteAccessToken();String url = GET_CORP_PERMANENT_CODE_URL.replace("SUITE_ACCESS_TOKEN", suitAccessToken);//失效了,需要重新获取HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);JSONObject reqParam = new JSONObject();reqParam.put("auth_code",  authCode);HttpEntity<String> requestEntity = new HttpEntity<String>(reqParam.toJSONString(), headers);ResponseEntity<String> responseEntity = this.restTemplate.exchange(url,HttpMethod.POST, requestEntity, String.class);if (responseEntity.getStatusCode() == HttpStatus.OK) {String resp = responseEntity.getBody();log.info(resp);JSONObject obj = JSONObject.parseObject(resp);if (obj.getIntValue("errcode") == 0) {JSONObject corpInfo = obj.getJSONObject("auth_corp_info");String corpId = corpInfo.getString("corpid");WxCorpInfo data = wxCorpInfoMapper.selectById(corpId);if (data == null) {//不存在的情况下,需要生成企业信息data = new WxCorpInfo();log.info("================create corp=========");data.setCorpid(corpId);String permanentCode = obj.getString("permanent_code");String curCorpAccessToken = obj.getString("access_token");LocalDateTime time = LocalDateTime.now();time = time.plusSeconds(obj.getLong("expires_in"));data.setAccessToken(curCorpAccessToken);data.setCorpFullName(corpInfo.getString("corp_full_name"));data.setCorpIndustry(corpInfo.getString("corp_industry"));data.setCorpName(corpInfo.getString("corp_name"));data.setCorpScale(corpInfo.getString("corp_scale"));data.setCorpSubIndustry(corpInfo.getString("corp_sub_industry"));data.setExpireTime(time);data.setLocation(corpInfo.getString("location"));data.setPermanentCode(permanentCode);//取到当前授权人,按照授权人与企业进行匹配JSONObject authUserInfo = obj.getJSONObject("auth_user_info");data.setAuthUsername(authUserInfo.getString("name"));String userId = authUserInfo.getString("userid");//授权人的useridJSONObject userDetail = getUserInfo(curCorpAccessToken, userId);//按姓名和手机号进行匹配log.info("===userDetail==" + userDetail.toJSONString());User user = userMapper.selectOne(new QueryWrapper<User>().eq("account", userDetail.getString("mobile")).eq("username", userDetail.getString("name")));if (user != null) {//找到了匹配的企业data.setCompanyId(user.getCompanyId());}wxCorpInfoMapper.insert(data);//获取部门JSONObject deptObj = getDepartments(curCorpAccessToken);JSONArray deptObjJSONArray = deptObj.getJSONArray("department");for (int i=0;i<deptObjJSONArray.size(); i++) {int deptId = deptObjJSONArray.getJSONObject(i).getIntValue("id");JSONArray userList = getDeptUserDetail(curCorpAccessToken, deptId);for (int m=0;m<userList.size(); m++) {JSONObject item = userList.getJSONObject(m);log.info("userid="+item.getString("userid")+", name=" + item.getString("name")+", mobile="+item.getString("mobile"));//不存在的人员, 进行插入User employee = new User();employee.setUsername(item.getString("name"));employee.setAccount(item.getString("mobile"));int count = userMapper.selectCount(new QueryWrapper<User>().eq("account", employee.getAccount()).eq("company_id", data.getCompanyId()));if (count == 0) {//手机号不存在的,添加if (data.getCompanyId() != null) {employee.setCompanyId(data.getCompanyId());userMapper.insert(employee);}}}}}}}}private JSONArray getDeptUserDetail(String accessToken, int deptId) {String url = GET_DEPARTMENT_USER_DETAIL_URL.replace("ACCESS_TOKEN", accessToken).replace("DEPARTMENT_ID", ""+deptId);String result = restTemplate.getForObject(url, String.class);JSONObject obj = JSONObject.parseObject(result);JSONArray userlist = obj.getJSONArray("userlist");return userlist;}private JSONObject getDepartments(String accessToken) {String url = GET_DEPARTMENT_URL.replace("ACCESS_TOKEN", accessToken);String result = restTemplate.getForObject(url, String.class);JSONObject obj = JSONObject.parseObject(result);return obj;}private JSONObject getUserInfo(String accessToken, String userId) {String url = GET_USER_INFO_URL.replace("ACCESS_TOKEN", accessToken).replace("USERID", userId);String result = restTemplate.getForObject(url, String.class);JSONObject obj = JSONObject.parseObject(result);return obj;}//获取预授权码private String getAuthCode() {if (PRE_AUTH_CODE == null || expireTime < System.currentTimeMillis()) {//失效了,需要重新获取String resp = restTemplate.getForObject(GET_PREAUTH_CODE_URL.replaceAll("SUITE_ACCESS_TOKEN", getSuiteAccessToken()), String.class);log.info(resp);JSONObject obj = JSONObject.parseObject(resp);if (obj.getIntValue("errcode") == 0) {PRE_AUTH_CODE = obj.getString("pre_auth_code");expireTime = System.currentTimeMillis() + obj.getIntValue("expires_in")*1000;}}return PRE_AUTH_CODE;}//获取第三方应用临时凭证private String getSuiteAccessToken() {if (SUITE_ACCESS_TOKEN == null || suiteTokenExpireTime < System.currentTimeMillis()) {//失效了,需要重新获取HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);JSONObject reqParam = new JSONObject();reqParam.put("suite_id",  suitId);reqParam.put("suite_secret", suitSecret);SysParam param = sysParamMapper.selectOne(new QueryWrapper<SysParam>().eq("param_code", "suite_ticket"));if (param != null) {reqParam.put("suite_ticket",param.getParamName());}HttpEntity<String> requestEntity = new HttpEntity<String>(reqParam.toJSONString(), headers);ResponseEntity<String> responseEntity = this.restTemplate.exchange(GET_SUITE_ACCESS_TOKEN_URL,HttpMethod.POST, requestEntity, String.class);if (responseEntity.getStatusCode() == HttpStatus.OK) {String resp = responseEntity.getBody();log.info(resp);JSONObject obj = JSONObject.parseObject(resp);if (obj.getIntValue("errcode") == 0) {SUITE_ACCESS_TOKEN = obj.getString("suite_access_token");suiteTokenExpireTime = System.currentTimeMillis() + obj.getIntValue("expires_in")*1000;}}}return SUITE_ACCESS_TOKEN;}
}

需要指导和代码的话,请联系qq:373132975

企业微信开发总结-获取通讯录相关推荐

  1. 企业微信开发:获取 access_token(二)

    前言   简单的用白话了解一下企业微信的作用,企业微信是腾讯微信团队为企业打造的专业办公管理工具.大致和钉钉差不多,适用于政府.企业等各类组织的一个产品,可以有效的帮您管理员工.个人感觉企业微信开发要 ...

  2. asp.net企业微信开发之同步通讯录

    参考腾讯提供的企业微信api,得知企业微信在同步通讯录时需要先将部门和人员按照规定格式上传,然后再根据上传后返回的media_id执行部门或者人员的覆盖操作. 话不多说,直接上菜. 同步程序 publ ...

  3. 企业微信开发--网页授权(获取code)

    在企业微信中,我们可以开发企业应用.使用企业应用,我们可以访问到外部网站.那么外部网站如何获取到企业微信共享用户id呢?企业微信提供了OAuth的授权登录方式,可以让网页和企业微信共享用户ID,从而免 ...

  4. 服务器端缓存企业微信,企业微信开发

    企业微信开发又以下三类,可以根据需要查看相应的文档 企业内部应用开发:开发内部使用应用,开发个性化办公应用 第三方应用开发:开发出来的应用可供其他企业使用 第三方应用开发.png 智慧硬件开发 企业内 ...

  5. 企业微信开发第三方应用开发视频教程,ToB Dev李月喜全网首发

    csdn程序员学院<企业微信三方应用开发>视频课程,全网企业微信三方应用开发教程首发, https://edu.csdn.net/course/detail/30582  即将完结欢迎试看 ...

  6. 前端企业微信开发内嵌H5记录

    前端企业微信开发内嵌H5记录(Vue) 文章目录 前端企业微信开发内嵌H5记录(Vue) 一.引入相应JS-SDK 1.JS-SDK 二.授权(网页授权) 1.构造网页授权链接 2.发起授权 3.注入 ...

  7. 企业微信开发H5页面授权 使用接口的问题

    企业微信 h5踩坑指南 企业微信开发H5页面授权 使用接口的问题 开发企业微信的时候 h5页面需要获取登录用户的信息,这个时候就需要jsdk里面的 [开发文档] (https://work.weixi ...

  8. Java企业微信开发-企业微信所有类型消息推送封装

    企业微信开发第一步获取AccessToken,企业微信的AccessToken和公众号的不一样,企业微信所有接口调用只需要一个AccessToken,而公众号授权和jssdk是分开的 一.获取企业微信 ...

  9. 微信及企业微信内嵌浏览器内核信息及H5跑分数据-企业微信开发

    加我微信li570467731,拉你进二百多人企业微信开发同行群(文末有二维码). 企业微信开发三部曲: <企业微信应用开发概述篇(免费)>已完结: <企业微信开发第三方应用开发篇& ...

最新文章

  1. mybaits的模糊查询_mybatis模糊查询防止SQL注入(很详细)
  2. Handler研究2-AsyncTask,AsyncQueryHandler分析
  3. python not not()
  4. android bitmap 占用内存大小,drawable与bitmap内存占用大小
  5. 北京有一个“牧人”合唱团
  6. Java_基础—List的三个子类的特点
  7. cocos2d-x-lua基础系列教程四(lua多继承)
  8. 三星关闭在华最后一家电脑厂 约850名员工受影响
  9. python找零钱英镑_[求教!!]怎么用python编写一个找零钱的程序??
  10. 两个offer如何做选择?年薪20万vs年薪15万
  11. request python菜鸟教程_Python之学习菜鸟教程踩的坑
  12. vue-better-scroll引用报错[BScroll warn]: Can not resolve the wrapper DOM.
  13. ifix如何设画面大小_组态软件实用技术教程第3章iFIX画面设计.ppt
  14. SPSS个案处理插件v1.0 用SPSS构造Bootstrap样本
  15. ssh 所选的用户密钥未在远程主机上注册
  16. 升级Win10注意事项个人总结
  17. 肇庆学院计算机基础学分,肇庆学院学分制学籍管理实施细则试行-肇庆学院教务处.DOC...
  18. word2016 上次启动时失败以安全模式能够解决该问题【office专业版】
  19. 使用MATLAB实现对信号的EMD分解
  20. y=asin(wx+φ)的对称中心_函数y=Asin(wx+φ)的性质.ppt

热门文章

  1. gmail 邮箱找回方法
  2. 洛谷 P5734 【深基6.例6】文字处理软件
  3. python娱乐 -- 源码实现 叮当猫小猪佩奇羊吃草 动画
  4. 不在沉默中爆发就在沉默中死亡,处于沉寂状态的 Emotet 僵尸网络是怎样卷土重来的?(一)
  5. HDMI系列之一:基于Nios II的HDMI显示图片
  6. win10 强制删除文件夹
  7. java lucene词干提取_词形变换和词干提取工具(英文)
  8. 2020-07-13 html的p标签嵌套img + css的3大特性 + JS的客户端服务端时间不对称 + http与https切换时共用cookie和localStorage
  9. 大家可以自己做网站,简单又省钱
  10. 战队口号霸气押韵8字_夺冠时隔8天,詹姆斯深夜晒照,5字发文太霸气,球迷膜拜...