package com.chuanghai.smartschool.tuitionpayment.controller; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.chuanghai.smartschool.tuitionpayment.common.exception.BizCodeEnume; import com.chuanghai.smartschool.tuitionpayment.common.exception.RRException; import com.chuanghai.smartschool.tuitionpayment.common.utils.CommonResult; import com.chuanghai.smartschool.tuitionpayment.config.WechatConfig; import com.chuanghai.smartschool.tuitionpayment.config.WeixiaoConfig; import com.chuanghai.smartschool.tuitionpayment.entity.PayItem; import com.chuanghai.smartschool.tuitionpayment.entity.PayOrderEntity; import com.chuanghai.smartschool.tuitionpayment.entity.PayableInfoEntity; import com.chuanghai.smartschool.tuitionpayment.entity.PayableInfoWaterEntity; import com.chuanghai.smartschool.tuitionpayment.service.PayItemService; import com.chuanghai.smartschool.tuitionpayment.service.PayOrderService; import com.chuanghai.smartschool.tuitionpayment.service.PayableInfoService; import com.chuanghai.smartschool.tuitionpayment.service.PayableInfoWaterService; import com.chuanghai.smartschool.tuitionpayment.vo.PayableInfoStudentResultVO; import com.chuanghai.smartschool.tuitionpayment.vo.WeixiaoVO; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.poi.ss.formula.functions.T; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 微信相关接口 * * @author codingliang * @email codingliang@gmail.com * @date 2021-08-12 16:04 */ @Controller @RequestMapping("tuitionpayment/wechat") public class WechatController { @Autowired private WechatConfig wechatConfig; @Autowired private WeixiaoConfig weixiaoConfig; /** * 用于记录用户的access_token */ private String accessTokenPublic = ""; /** * 用于记录催缴的次数 计时器 */ private Integer askCount = 0; @Autowired private PayableInfoService payableInfoService; @Autowired private PayableInfoWaterService payableInfoWaterService; @Autowired private PayOrderService payOrderService; @Autowired private FeedbackMsgController feedbackMsgController; @Autowired private PayItemService payItemService; /** * 微信授权回调地址 * * @param code 微信code * @apiNote 用户跳转到微信授权链接上,微信服务器接收用户授权后会携带code回调到该接口上,该接口使用code获取到用户的openId信息。 * 如果openId获取成功,该接口会以 【fontendUrl + 路由地址 + ?openId=wx123456】 的形式跳回到前端应用页面; * 如果openId获取失败,该接口会以 【fontendUrl + /error/?errorMsg=获取用户openId失败】 的形式跳回到前端应用页面。 * 注意: * fontendUrl + 路由地址:前端项目地址+页面路由地址,用于前端页面接收用户的信息或错误信息,该地址需要前端人员与后台开发人员协调好。 */ @GetMapping("pub/auth") public String pubAuth(String code, String state) { // code换取access_token String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + "appid=" + wechatConfig.getAppid() + "&secret=" + wechatConfig.getSecret() + "&code=" + code + "&grant_type=authorization_code"; try { RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); // 解决回参中文乱码 String response = restTemplate.getForObject(url, String.class); ObjectMapper mapper = new ObjectMapper(); JsonNode jsonNode = mapper.readTree(response); String openid = jsonNode.get("openid").asText(); return "redirect:" + wechatConfig.getFontendUrl() + "/#/" + state + "/?openId=" + openid; } catch (Exception e) { return "redirect:" + wechatConfig.getFontendUrl() + "/error/?errorMsg=获取用户openId失败"; } } /** * 微校授权回调地址 * * @param wxcode 微校code * @param state 透传数据 * @return * @apiNote 用户跳转到微校授权链接上,微校服务器接收用户授权后会携带wxcode回调到该接口上,该接口使用wxcode获取到用户的信息。 * 如果用户信息获取成功,该接口会以 【fontendUrl + /?cardNumber=wx123456&name=测试用户】 的形式跳回到前端应用页面; * 如果用户信息获取失败,该接口会以 【fontendUrl + /error/?errorMsg=获取用户信息失败】 的形式跳回到前端应用页面。 * 注意: * fontendUrl + 路由地址:前端项目地址+页面路由地址,用于前端页面接收用户的信息或错误信息,该地址需要前端人员与后台开发人员协调好。 *

*/ @GetMapping("weixiao/auth") public String weixiaoAuth(String wxcode, String state) { String tokenUrl = "https://open.wecard.qq.com/connect/oauth2/token"; Map tokenParams = new HashMap<>(); tokenParams.put("wxcode", wxcode); tokenParams.put("app_key", weixiaoConfig.getAppKey()); tokenParams.put("app_secret", weixiaoConfig.getAppSecret()); tokenParams.put("grant_type", "authorization_code"); tokenParams.put("redirect_uri", state); // 该地址需要与发起授权地址保持一直 try { // wecode换取token RestTemplate client = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity> request = new HttpEntity<>(tokenParams, headers); //ResponseEntity tokenResponse = client.postForEntity(tokenUrl, tokenParams, String.class); ResponseEntity tokenResponse = client.postForEntity(tokenUrl, request, String.class); ObjectMapper mapper = new ObjectMapper(); Map jsonMap = mapper.readValue(tokenResponse.getBody(), new TypeReference>() { }); String accessToken = (String) jsonMap.get("access_token"); // token换取用户信息 String userInfoUrl = "https://open.wecard.qq.com/connect/oauth/get-user-info"; Map userInfoParam = new HashMap<>(); userInfoParam.put("access_token", accessToken); ResponseEntity userInfoResponse = client.postForEntity(userInfoUrl, userInfoParam, String.class); Map userInfoMap = mapper.readValue(userInfoResponse.getBody(), new TypeReference>() { }); String cardNumber = userInfoMap.get("card_number").toString(); String encodeName = URLEncoder.encode(userInfoMap.get("name").toString(), "utf-8"); return "redirect:" + weixiaoConfig.getFontendUrl() + "/#/pages/index/index/?cardNumber=" + cardNumber + "&name=" + encodeName; } catch (Exception e) { e.printStackTrace(); return "redirect:" + weixiaoConfig.getFontendUrl() + "/#/error/"; } } /** * 获取微校的应用有效凭证 7200s有效 两小时内有效 * @return */ @Scheduled(fixedDelay = 7190000) public void getWeiXiaoToken() { try { RestTemplate client = new RestTemplate(); ObjectMapper mapper = new ObjectMapper(); String userInfoUrl = "https://open.wecard.qq.com/cgi-bin/oauth2/token"; Map userInfoParam = new HashMap<>(); userInfoParam.put("app_key", weixiaoConfig.getAppKey()); userInfoParam.put("app_secret", weixiaoConfig.getAppSecret()); userInfoParam.put("grant_type", "client_credentials"); userInfoParam.put("scope", "base"); userInfoParam.put("ocode", "1015730314"); ResponseEntity userInfoResponse = client.postForEntity(userInfoUrl, userInfoParam, String.class); Map userInfoMap = mapper.readValue(userInfoResponse.getBody(), new TypeReference>() { }); accessTokenPublic = userInfoMap.get("access_token").toString(); } catch (Exception e) { e.printStackTrace(); } } /** * 通过学生姓名 身份证查找用户的cardNumber * @param studentName * @param idCard * @return */ @GetMapping("getWeiXiaoToken1") @ResponseBody public String getCardNumber(String studentName, String idCard) { String card_number = ""; try { RestTemplate client = new RestTemplate(); ObjectMapper mapper = new ObjectMapper(); String userInfoUrl ="https://open.wecard.qq.com/cgi-bin/user/search"; Map userInfoParam = new HashMap<>(); userInfoParam.put("access_token", accessTokenPublic); userInfoParam.put("keywords", studentName); ResponseEntity userInfoResponse = client.postForEntity(userInfoUrl, userInfoParam, String.class); JSONObject jsonObj = JSON.parseObject(userInfoResponse.getBody()); JSONArray userlist = jsonObj.getJSONArray("userlist"); Map userInfoMap = mapper.readValue(userlist.get(0).toString(), new TypeReference>() { }); String id_card = ""; if (userInfoMap.get("card_number") != null) { card_number = userInfoMap.get("card_number").toString(); } if (userInfoMap.get("id_card") != null) { id_card = userInfoMap.get("id_card").toString(); } if (idCard.equals(id_card)) { return card_number; } } catch (Exception e) { e.printStackTrace(); } return card_number; } public PayableInfoStudentResultVO queryStudent() { PayableInfoStudentResultVO payableInfoStudentResultVO = new PayableInfoStudentResultVO(); try { // token换取用户信息 RestTemplate client = new RestTemplate(); ObjectMapper mapper = new ObjectMapper(); String userInfoUrl = "https://open.wecard.qq.com/connect/oauth/get-user-info"; Map userInfoParam = new HashMap<>(); userInfoParam.put("access_token", accessTokenPublic); ResponseEntity userInfoResponse = client.postForEntity(userInfoUrl, userInfoParam, String.class); Map userInfoMap = mapper.readValue(userInfoResponse.getBody(), new TypeReference>() { }); String name = userInfoMap.get("name").toString(); String card_number = userInfoMap.get("card_number").toString(); String grade = userInfoMap.get("grade").toString(); grade = grade.substring(2, grade.length()); String clazz = userInfoMap.get("class").toString(); payableInfoStudentResultVO.setIdCard(card_number); payableInfoStudentResultVO.setStudentName(name); payableInfoStudentResultVO.setMajor(grade + clazz); } catch (Exception e) { e.printStackTrace(); } return payableInfoStudentResultVO; } /** * 实现同步下发缴费订单功能 * * @param itemName * @return */ @PostMapping("/oneKey") @ResponseBody public CommonResult oneKey(String itemName) { WeixiaoVO weixiaoVO = new WeixiaoVO(); QueryWrapper wrapper = new QueryWrapper<>(); QueryWrapper water = new QueryWrapper<>(); wrapper.eq("pay_notice_type", "1") .eq("payment_item", itemName); water.eq("pay_notice_type", "1") .eq("payment_item", itemName); List payableInfoEntityList = payableInfoService.list(wrapper); List payableInfoWaterEntityList = payableInfoWaterService.list(water); List cardNumberList = new ArrayList<>(); if (payableInfoEntityList.size() > 0) { payableInfoEntityList.forEach(payableInfoEntity -> { payableInfoEntity.setPayNoticeType("2"); cardNumberList.add(payableInfoEntity.getCardNumber()); payableInfoService.updateById(payableInfoEntity); }); } if (payableInfoWaterEntityList.size() > 0) { payableInfoWaterEntityList.forEach(payableInfoEntityWater -> { payableInfoEntityWater.setPayNoticeType("2"); cardNumberList.add(payableInfoEntityWater.getCardNumber()); payableInfoWaterService.updateById(payableInfoEntityWater); }); } weixiaoVO.setCardNumberList(cardNumberList); weixiaoVO.setTitle(itemName + "缴纳通知"); weixiaoVO.setSender("财务办公室"); weixiaoVO.setContent("同学你好," + itemName + "缴费已经开始,请尽快查看缴费详情完成缴费,谢谢合作!"); JSONObject jsonObject = (JSONObject) JSONObject.toJSON(weixiaoVO); return notice(jsonObject); } /** * 实现催缴下发缴费订单功能 * * @param jsonObject * @return */ @PostMapping("/oneKeyNotice") @ResponseBody public CommonResult oneKeyNotice(@RequestBody JSONObject jsonObject) { String itemName = jsonObject.get("itemName").toString(); JSONArray cardNumberList = jsonObject.getJSONArray("cardNumberList"); if (cardNumberList.size() == 0) { QueryWrapper wrapper = new QueryWrapper<>(); QueryWrapper water = new QueryWrapper<>(); wrapper.in("pay_item_type", "1","3") .eq("payment_item", itemName); water.eq("pay_notice_type", "1") .eq("payment_item", itemName); List payableInfoEntityList = payableInfoService.list(wrapper); List payableInfoWaterEntityList = payableInfoWaterService.list(water); if (payableInfoEntityList.size() > 0) { payableInfoEntityList.forEach(payableInfoEntity -> { cardNumberList.add(payableInfoEntity.getCardNumber()); }); } if (payableInfoWaterEntityList.size() > 0) { payableInfoWaterEntityList.forEach(payableInfoEntityWater -> { cardNumberList.add(payableInfoEntityWater.getCardNumber()); }); } } WeixiaoVO weixiaoVO = new WeixiaoVO(); weixiaoVO.setCardNumberList(cardNumberList); weixiaoVO.setTitle(itemName + "催缴通知"); weixiaoVO.setSender("财务办公室"); weixiaoVO.setContent("同学你好," + itemName + "缴费已经开始,请尽快查看缴费详情完成缴费,谢谢合作!"); JSONObject json = (JSONObject) JSONObject.toJSON(weixiaoVO); return notice(json); } /** * @param jsonObject 封装了发送微校通知的参数信息 * @return */ @PostMapping("weixiao/notice") @ResponseBody public CommonResult notice(@RequestBody JSONObject jsonObject) { WeixiaoVO weixiaoVO = JSONObject.toJavaObject(jsonObject, WeixiaoVO.class); Map param = new HashMap<>(); param.put("title", weixiaoVO.getTitle()); String s = JSON.parseArray(weixiaoVO.getCardNumberList().toString()).toJSONString(); param.put("cards", s); param.put("content", weixiaoVO.getContent()); param.put("sender", weixiaoVO.getSender()); String url = "https://open.wecard.qq.com/cgi-bin/notice/send?access_token=" + accessTokenPublic; try { RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity> request = new HttpEntity<>(param, headers); ResponseEntity responseEntity = restTemplate.postForEntity(url, request, String.class); }catch (Exception e){ throw new RRException(BizCodeEnume.TOKET_INVALID); } return CommonResult.ok(); } /** * 缴费异常订单自动发送微校通知 * itemName 缴费项目 * * @return */ @ResponseBody public CommonResult sendException(String itemName, String orderNo) { QueryWrapper wrapper1 = new QueryWrapper<>(); wrapper1.eq("item_name", itemName); PayItem payItem = payItemService.getOne(wrapper1); //查询微校通知数据 isSend 2 表示开启推送 if (payItem.getItemExcept()) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("status", "1"); wrapper.eq("except_type", "1"); wrapper.eq("pay_item", itemName); wrapper.eq("order_no", orderNo); PayOrderEntity payOrder = payOrderService.getOne(wrapper); List cardNumberList = new ArrayList<>(); WeixiaoVO weixiaoVO = new WeixiaoVO(); if (payOrder != null) { payOrder.setExceptType("2"); String cardNumber = payOrder.getPayerIdentify(); cardNumberList.add(cardNumber); weixiaoVO.setTitle(payOrder.getPayItem() + "缴纳异常通知"); } weixiaoVO.setCardNumberList(cardNumberList); weixiaoVO.setContent("同学你好,你的" + itemName + "缴费订单异常缴费失败,请尽快查看缴费详情,并再次缴费。若为系统原因,请及时反馈!"); weixiaoVO.setSender("财务办公室"); JSONObject jsonObject = (JSONObject) JSONObject.toJSON(weixiaoVO); notice(jsonObject); //更新订单异常推送的状态 payOrderService.updateById(payOrder); } return CommonResult.ok(); } /** * 每天执行一次催缴 下午15点 */ @Scheduled(fixedDelay = 20000) // @Scheduled(cron = "0 0 15 * * ?") public void autoTiming() { List payItemList = payItemService.list(); for (int i = 0; i < payItemList.size(); i++) { PayItem payItem = (PayItem) payItemList.get(i); String itemName = payItem.getItemName(); Boolean itemAsk = payItem.getItemAsk(); Integer itemAskDay = Integer.parseInt(payItem.getItemAskDay()); //获取设置的请求次数 Integer itemAskCount = Integer.parseInt(payItem.getItemAskCount()); //获取本请求成功的次数 Integer count = Integer.parseInt(payItem.getRequestCount()); if (itemAsk) { if ((count < itemAskCount) && (askCount % itemAskDay == 0)) { askPay(itemName); count += 1; payItem.setRequestCount(String.valueOf(count)); payItemService.updateById(payItem); } } } //催缴计数器累加 askCount += 1; } /** * 是否催缴,发送微校通知 * * @return */ public CommonResult askPay(String itemName) { QueryWrapper wrapper1 = new QueryWrapper<>(); wrapper1.eq("item_name", itemName); PayItem payItem = payItemService.getOne(wrapper1); if (!itemName.equals("水费缴纳")) { WeixiaoVO weixiaoVO = new WeixiaoVO(); List cardNumberList = new ArrayList<>(); //查询微校通知数据 isSend 2 表示开启推送 QueryWrapper wapper = new QueryWrapper<>(); wapper.eq("pay_notice_type", "2") .eq("pay_item_type", "1") .eq("payment_item", itemName); List list = payableInfoService.list(wapper); //催缴的人员编号 if (list.size() > 0) { list.forEach(payableInfoEntity -> { String cardNumber = payableInfoEntity.getCardNumber(); cardNumberList.add(cardNumber); weixiaoVO.setTitle(payableInfoEntity.getPaymentItem() + "缴纳通知"); }); } weixiaoVO.setCardNumberList(cardNumberList); weixiaoVO.setContent("同学你好," + itemName + "缴费详情已经下发,请尽快查看缴费项目并完成缴费,谢谢配合!"); weixiaoVO.setSender("财务办公室"); JSONObject jsonObject = (JSONObject) JSONObject.toJSON(weixiaoVO); return notice(jsonObject); } else { WeixiaoVO weixiaoVO = new WeixiaoVO(); List cardNumberList = new ArrayList<>(); //查询微校通知数据 isSend 2 表示开启推送 QueryWrapper wapper1 = new QueryWrapper<>(); wapper1.eq("pay_notice_type", "2") .eq("pay_item_type", "1") .eq("payment_item", itemName); List list1 = payableInfoWaterService.list(wapper1); //催缴的人员编号 if (list1.size() > 0) { list1.forEach(payableInfoEntity -> { String cardNumber = payableInfoEntity.getCardNumber(); cardNumberList.add(cardNumber); weixiaoVO.setTitle(payableInfoEntity.getPaymentItem() + "缴纳通知"); }); weixiaoVO.setCardNumberList(cardNumberList); weixiaoVO.setContent("同学你好," + itemName + "缴费详情已经下发,请尽快查看缴费项目并完成缴费,谢谢配合!"); weixiaoVO.setSender("财务办公室"); JSONObject jsonObject = (JSONObject) JSONObject.toJSON(weixiaoVO); return notice(jsonObject); } } return CommonResult.ok(); } /** * 处理反馈后开启反馈通知功能 * * @param cardNumber 反馈通知对象的微校账号 card_number * @param content 处理内容 * @return */ @GetMapping("/disposeSend") @ResponseBody public CommonResult disposeSend(@RequestParam("cardNumber") String cardNumber, @RequestParam("content") String content, @RequestParam("id") Long id) { List cardNumberList = new ArrayList<>(); cardNumberList.add(cardNumber); WeixiaoVO weixiaoVO = new WeixiaoVO(); weixiaoVO.setTitle("缴费反馈处理通知"); weixiaoVO.setCardNumberList(cardNumberList); weixiaoVO.setContent(content); weixiaoVO.setSender("财务办公室"); JSONObject jsonObject = (JSONObject) JSONObject.toJSON(weixiaoVO); feedbackMsgController.handleFeedbackMsg(id, content); return notice(jsonObject); } }