Kaynağa Gözat

Merge remote-tracking branch 'origin/master'

小么熊🐻 3 yıl önce
ebeveyn
işleme
48a107eeb4
80 değiştirilmiş dosya ile 3965 ekleme ve 97 silme
  1. 49 0
      twzd-admin/src/main/java/com/miaxis/app/controller/wx/UserInfoController.java
  2. 226 0
      twzd-admin/src/main/java/com/miaxis/app/controller/wx/WxController.java
  3. 259 0
      twzd-admin/src/main/java/com/miaxis/app/controller/wx/WxNotifyController.java
  4. 74 0
      twzd-admin/src/main/java/com/miaxis/app/controller/wx/WxgzhController.java
  5. 93 0
      twzd-admin/src/main/java/com/miaxis/pc/controller/WxMenuController.java
  6. 12 6
      twzd-admin/src/main/java/com/miaxis/system/controller/system/SysLoginController.java
  7. 70 48
      twzd-admin/src/main/java/com/miaxis/system/controller/test/TestController.java
  8. 31 0
      twzd-admin/src/main/resources/application-dev.yml
  9. 34 1
      twzd-admin/src/main/resources/application-prod.yml
  10. BIN
      twzd-admin/src/main/resources/wechatpay/apiclient_cert.p12
  11. 24 0
      twzd-admin/src/main/resources/wechatpay/apiclient_cert.pem
  12. 28 0
      twzd-admin/src/main/resources/wechatpay/apiclient_key.pem
  13. 55 0
      twzd-common/src/main/java/com/miaxis/common/config/BeanConfig.java
  14. 63 0
      twzd-common/src/main/java/com/miaxis/common/config/CosConfig.java
  15. 37 0
      twzd-common/src/main/java/com/miaxis/common/config/WxVerifierConfig.java
  16. 22 0
      twzd-common/src/main/java/com/miaxis/common/config/WxpayConfig.java
  17. 9 0
      twzd-common/src/main/java/com/miaxis/common/constant/Constants.java
  18. 10 7
      twzd-common/src/main/java/com/miaxis/common/core/domain/entity/UserInfo.java
  19. 3 3
      twzd-common/src/main/java/com/miaxis/common/core/domain/model/LoginUser.java
  20. 18 0
      twzd-common/src/main/java/com/miaxis/common/core/domain/model/WxUserInfo.java
  21. 161 0
      twzd-common/src/main/java/com/miaxis/common/utils/XmlUtil.java
  22. 73 4
      twzd-common/src/main/java/com/miaxis/common/utils/http/HttpUtils.java
  23. 98 0
      twzd-common/src/main/java/com/miaxis/common/utils/wx/MessageUtil.java
  24. 74 0
      twzd-common/src/main/java/com/miaxis/common/utils/wx/SignUtil.java
  25. 1 1
      twzd-generator/src/main/resources/vm/java/controller.java.vm
  26. 11 0
      twzd-service/pom.xml
  27. 1 1
      twzd-service/src/main/java/com/miaxis/feign/dto/WxQrTicket.java
  28. 0 2
      twzd-service/src/main/java/com/miaxis/feign/service/IWxMpService.java
  29. 60 6
      twzd-service/src/main/java/com/miaxis/feign/service/IWxSendService.java
  30. 61 0
      twzd-service/src/main/java/com/miaxis/file/domain/FileInfo.java
  31. 16 0
      twzd-service/src/main/java/com/miaxis/file/mapper/FileInfoMapper.java
  32. 15 0
      twzd-service/src/main/java/com/miaxis/file/service/IFileInfoService.java
  33. 23 0
      twzd-service/src/main/java/com/miaxis/file/service/impl/FileInfoServiceImpl.java
  34. 39 0
      twzd-service/src/main/java/com/miaxis/spread/domain/WxSpreadRelation.java
  35. 13 0
      twzd-service/src/main/java/com/miaxis/spread/mapper/WxSpreadRelationMapper.java
  36. 13 0
      twzd-service/src/main/java/com/miaxis/spread/service/IWxSpreadRelationService.java
  37. 22 0
      twzd-service/src/main/java/com/miaxis/spread/service/impl/WxSpreadRelationServiceImpl.java
  38. 22 0
      twzd-service/src/main/java/com/miaxis/user/mapper/UserInfoMapper.java
  39. 22 0
      twzd-service/src/main/java/com/miaxis/user/service/IUserInfoService.java
  40. 37 0
      twzd-service/src/main/java/com/miaxis/user/service/impl/UserInfoServiceImpl.java
  41. 27 0
      twzd-service/src/main/java/com/miaxis/user/vo/UserVipInfoVO.java
  42. 141 0
      twzd-service/src/main/java/com/miaxis/wx/domain/RefundRecord.java
  43. 69 0
      twzd-service/src/main/java/com/miaxis/wx/domain/WxMenu.java
  44. 166 0
      twzd-service/src/main/java/com/miaxis/wx/domain/WxOrder.java
  45. 47 0
      twzd-service/src/main/java/com/miaxis/wx/domain/WxTicket.java
  46. 10 0
      twzd-service/src/main/java/com/miaxis/wx/dto/AiOrderNotifyDTO.java
  47. 27 0
      twzd-service/src/main/java/com/miaxis/wx/dto/CinemaData.java
  48. 50 0
      twzd-service/src/main/java/com/miaxis/wx/dto/FilmWxpayRefundDTO.java
  49. 46 0
      twzd-service/src/main/java/com/miaxis/wx/dto/PcWxOrderListDTO.java
  50. 70 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxFuluOrderDetailDTO.java
  51. 55 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxFuluOrderNotifyDTO.java
  52. 9 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxNotifyReturnDTO.java
  53. 53 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderCreateDTO.java
  54. 31 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderCreateFuluDTO.java
  55. 28 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderCreatePhoneBillDTO.java
  56. 19 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderDTO.java
  57. 26 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderListDTO.java
  58. 55 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderNotifyDTO.java
  59. 52 0
      twzd-service/src/main/java/com/miaxis/wx/dto/WxpayNotifyDTO.java
  60. 24 0
      twzd-service/src/main/java/com/miaxis/wx/mapper/RefundRecordMapper.java
  61. 23 0
      twzd-service/src/main/java/com/miaxis/wx/mapper/WxMenuMapper.java
  62. 30 0
      twzd-service/src/main/java/com/miaxis/wx/mapper/WxOrderMapper.java
  63. 13 0
      twzd-service/src/main/java/com/miaxis/wx/mapper/WxTicketMapper.java
  64. 28 0
      twzd-service/src/main/java/com/miaxis/wx/service/IRefundRecordService.java
  65. 15 0
      twzd-service/src/main/java/com/miaxis/wx/service/IWxGzhService.java
  66. 48 0
      twzd-service/src/main/java/com/miaxis/wx/service/IWxMenuService.java
  67. 31 0
      twzd-service/src/main/java/com/miaxis/wx/service/IWxMessageEvenService.java
  68. 17 0
      twzd-service/src/main/java/com/miaxis/wx/service/IWxOrderService.java
  69. 13 0
      twzd-service/src/main/java/com/miaxis/wx/service/IWxTicketService.java
  70. 11 0
      twzd-service/src/main/java/com/miaxis/wx/service/WxService.java
  71. 121 0
      twzd-service/src/main/java/com/miaxis/wx/service/impl/RefundRecordServiceImpl.java
  72. 120 15
      twzd-service/src/main/java/com/miaxis/wx/service/impl/WxGzhServiceImpl.java
  73. 197 0
      twzd-service/src/main/java/com/miaxis/wx/service/impl/WxMenuServiceImpl.java
  74. 200 0
      twzd-service/src/main/java/com/miaxis/wx/service/impl/WxMessageEvenServiceImpl.java
  75. 45 0
      twzd-service/src/main/java/com/miaxis/wx/service/impl/WxOrderServiceImpl.java
  76. 22 0
      twzd-service/src/main/java/com/miaxis/wx/service/impl/WxTicketServiceImpl.java
  77. 73 0
      twzd-service/src/main/java/com/miaxis/wx/vo/WxMenuVo.java
  78. 39 0
      twzd-service/src/main/resources/mapper/user/UserInfoMapper.xml
  79. 32 0
      twzd-service/src/main/resources/mapper/wx/WxMenuMapper.xml
  80. 3 3
      twzd-system/src/main/java/com/miaxis/system/dto/system/TokenDTO.java

+ 49 - 0
twzd-admin/src/main/java/com/miaxis/app/controller/wx/UserInfoController.java

@@ -0,0 +1,49 @@
+package com.miaxis.app.controller.wx;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.core.controller.BaseController;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.common.core.domain.entity.UserInfo;
+import com.miaxis.common.utils.SecurityUtils;
+import com.miaxis.user.service.IUserInfoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(Constants.STUDENT_PREFIX+"/user")
+@Api(tags = {"【H5-用户信息】"})
+@Slf4j
+public class UserInfoController extends BaseController {
+
+    @Autowired
+    private IUserInfoService userInfoService;
+
+
+
+    @GetMapping(value = "/info")
+    @ApiOperation("获取用户信息")
+    public Response<UserInfo> getInfo(){
+        String openid = SecurityUtils.getLoginUser().getStudent().getOpenid();
+        return Response.success(userInfoService.getOne(new QueryWrapper<UserInfo>().eq("openid",openid)));
+    }
+
+
+
+
+
+
+
+
+
+
+
+}

+ 226 - 0
twzd-admin/src/main/java/com/miaxis/app/controller/wx/WxController.java

@@ -0,0 +1,226 @@
+package com.miaxis.app.controller.wx;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.miaxis.common.config.WxpayConfig;
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.core.controller.BaseController;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.common.core.domain.entity.SysDictData;
+import com.miaxis.common.core.domain.entity.UserInfo;
+import com.miaxis.common.enums.OrderStatusEnum;
+import com.miaxis.common.exception.CustomException;
+import com.miaxis.common.utils.SecurityUtils;
+import com.miaxis.common.utils.uuid.CommonUtils;
+import com.miaxis.system.service.ISysDictDataService;
+import com.miaxis.wx.domain.WxOrder;
+import com.miaxis.wx.dto.WxOrderDTO;
+import com.miaxis.wx.service.IWxOrderService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.util.EntityUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.util.Base64;
+
+import static com.miaxis.common.utils.OrderCodeFactory.getOrderCode;
+
+/**
+ * 【小程序-微信支付】Controller
+ *
+ * @author miaxis
+ * @date 2021-03-10
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(Constants.STUDENT_PREFIX+"/wx")
+@Api(tags = {"【H5-微信支付】"})
+@Slf4j
+public class WxController extends BaseController {
+
+    @Autowired
+    private HttpClient httpClient;
+
+    @Autowired
+    private WxpayConfig wxpayConfig;
+
+    @Autowired
+    private IWxOrderService wxOrderService;
+
+
+    @Autowired
+    private ISysDictDataService dictDataService;
+
+    @Value("${app.appid}")
+    private String appid;
+    @Value("${wxpay.notifyUrl}")
+    private  String notifyUrl ;
+
+
+
+
+//
+//
+//    @GetMapping("/order/list")
+//    @ApiOperation("查询订单列表")
+//    @ApiImplicitParams({
+//            @ApiImplicitParam(name = "pageNum",value = "当前页码" ,dataType = "int", paramType = "query", required = false),
+//            @ApiImplicitParam(name = "pageSize",value = "每页数据量" , dataType = "int", paramType = "query", required = false),
+//    })
+//    public ResponsePageInfo<WxOrder> list(@ModelAttribute WxOrderListDTO wxOrderListDTO){
+//
+//        String openid = SecurityUtils.getLoginUser().getStudent().getOpenid();
+//        startPage();
+//        wxOrderListDTO.setOpenid(openid);
+//        List<WxOrder> list = wxOrderService.selectOrderList(wxOrderListDTO);
+//        return toResponsePageInfo(list);
+//    }
+
+    /**
+     * 微信支付获取预订单id
+     */
+    @PostMapping(value = "/prepareOrder")
+    @ApiOperation("微信支付下单")
+    public Response<JSONObject> getPrepareOrder(@RequestBody WxOrderDTO wxOrderDTO) throws Exception{
+
+
+        SysDictData sysDictData = dictDataService.selectDictDataById(wxOrderDTO.getDictCode());
+        String[] values = sysDictData.getDictValue().split(",");
+        //创建本地微信订单
+        WxOrder order = createOrder(values);
+        wxOrderService.save(order);
+        return Response.success(placeWxOrder(order, sysDictData.getDictLabel(),notifyUrl));
+
+
+    }
+
+    private WxOrder createOrder(String[] values) {
+        WxOrder order = new WxOrder();
+        UserInfo student = SecurityUtils.getLoginUser().getStudent();
+        String orderCode = getOrderCode(student.getId());
+        order.setOutTradeNo(orderCode);
+        order.setOpenid(student.getOpenid());
+        order.setOrderStatus(OrderStatusEnum.PROCESSING.getCode());
+        Double dprice = Double.valueOf(values[0]);
+        Double v =dprice* 100;
+        order.setTotal(v.intValue());
+        order.setOrderDataJson(values[2]);
+        return order;
+    }
+
+    /**
+     * 微信支付获取预订单id
+     */
+    @PostMapping(value = "/prepareOrder-test")
+    @ApiOperation("微信支付下单-测试")
+    public Response<JSONObject> getPrepareOrderTest() throws Exception{
+
+
+        //创建本地微信订单
+        WxOrder order = new WxOrder();
+        UserInfo student = SecurityUtils.getLoginUser().getStudent();
+        String orderCode = getOrderCode(student.getId());
+        order.setOutTradeNo(orderCode);
+        order.setOpenid(student.getOpenid());
+        order.setGoodsType("1");
+        wxOrderService.createVipOrder(order);
+        //wxOrderService.save(order);
+        return Response.success(placeWxOrder(order, "学车vip充值", "http://jpcj-h5.zzxcx.net.zzxcx.net/prod-api/open-api/wx/notify/wxpay1"));
+
+
+    }
+
+
+    //下单
+    private JSONObject placeWxOrder(WxOrder order, String goodsName, String notifyUrl) throws Exception {
+        HttpPost httpPost = initHttpPost();
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectMapper objectMapper = new ObjectMapper();
+        ObjectNode rootNode = objectMapper.createObjectNode();
+        rootNode.put("mchid",wxpayConfig.getMerchantId())
+                .put("appid", appid)
+                .put("description", goodsName)
+                .put("notify_url", notifyUrl)
+                .put("out_trade_no", order.getOutTradeNo());
+        rootNode.putObject("amount")
+                .put("total", order.getTotal());
+        rootNode.putObject("payer")
+                .put("openid", order.getOpenid());
+        objectMapper.writeValue(bos, rootNode);
+        httpPost.setEntity(new StringEntity(rootNode.toString(), "utf-8"));
+        HttpResponse response = httpClient.execute(httpPost);
+        String bodyAsString = EntityUtils.toString(response.getEntity());
+        if (JSONObject.parseObject(bodyAsString).get("prepay_id") == null){
+            throw new CustomException(JSONObject.parseObject(bodyAsString).get("message").toString());
+        }
+        return getWxParamJson(bodyAsString,order.getOutTradeNo());
+
+    }
+
+    // 生成调用调起微信支付所需参数
+    private JSONObject getWxParamJson(String bodyAsString, String orderCode) throws Exception {
+        String  packageStr = "prepay_id="+JSONObject.parseObject(bodyAsString).get("prepay_id");
+        JSONObject jsonObject = new JSONObject();
+        jsonObject.put("package",packageStr);
+        String nonce_str = RandomStringUtils.randomAlphanumeric(32);
+        jsonObject.put("nonceStr",nonce_str);
+        long timestamp =  System.currentTimeMillis()/1000;
+        jsonObject.put("timeStamp",String.valueOf(timestamp));
+        jsonObject.put("signType","RSA");
+        StringBuffer sb = new StringBuffer();
+        sb.append(appid + "\n");
+        sb.append(timestamp + "\n");
+        sb.append(nonce_str + "\n");
+        sb.append(packageStr+ "\n");
+        System.out.println(sb);
+
+        File file = new ClassPathResource("wechatpay/apiclient_key.pem").getFile();
+        String realPath =file.getAbsolutePath();
+        PrivateKey privateKey = CommonUtils.getPrivateKey(realPath);
+        // 进行签名服务
+        Signature signature = Signature.getInstance("SHA256withRSA");
+        signature.initSign(privateKey);
+        signature.update(sb.toString().getBytes("UTF-8"));
+        byte[] signedData = signature.sign();
+        String base64Str =  Base64.getEncoder().encodeToString(signedData);
+        jsonObject.put("paySign",base64Str);
+        jsonObject.put("appId",appid);
+        return jsonObject;
+    }
+
+    private HttpPost initHttpPost() {
+        HttpPost httpPost = new HttpPost(wxpayConfig.getV3url());
+        httpPost.addHeader("Accept", "application/json");
+        httpPost.addHeader("Content-type","application/json; charset=utf-8");
+        return httpPost;
+    }
+
+
+
+
+
+
+
+
+
+
+
+}

+ 259 - 0
twzd-admin/src/main/java/com/miaxis/app/controller/wx/WxNotifyController.java

@@ -0,0 +1,259 @@
+package com.miaxis.app.controller.wx;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.miaxis.common.config.WxpayConfig;
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.core.domain.entity.UserInfo;
+import com.miaxis.common.exception.CustomException;
+import com.miaxis.common.utils.AesUtil;
+import com.miaxis.user.service.IUserInfoService;
+import com.miaxis.wx.domain.RefundRecord;
+import com.miaxis.wx.domain.WxOrder;
+import com.miaxis.wx.dto.WxNotifyReturnDTO;
+import com.miaxis.wx.dto.WxpayNotifyDTO;
+import com.miaxis.wx.service.IRefundRecordService;
+import com.miaxis.wx.service.IWxOrderService;
+import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.Base64Utils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Random;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(Constants.OPEN_PREFIX+"/wx/notify")
+@Api(tags = {"【H5-微信回调】"})
+@Slf4j
+public class WxNotifyController {
+
+
+    @Autowired
+    private WxpayConfig wxpayConfig;
+
+
+    @Autowired
+    private IWxOrderService wxOrderService;
+
+
+    @Autowired
+    private IUserInfoService userInfoService;
+
+    @Autowired
+    private  IRefundRecordService  refundRecordService;
+
+    @Autowired
+    private AutoUpdateCertificatesVerifier verifier;
+
+
+    /**
+     * 微信支付回调接口
+     */
+    @PostMapping(value = "/wxpay")
+    @ApiOperation("微信支付回调")
+    public WxNotifyReturnDTO wxpayNotify(@RequestBody WxpayNotifyDTO wxpayNotifyDTO, HttpServletRequest request) throws GeneralSecurityException, IOException {
+        String bodyString = getBodyString(request);
+        if (!validate(request,bodyString)){
+            throw new CustomException("签名失败");
+        }
+        String resourceString = getSourString(wxpayNotifyDTO);
+        log.info("微信支付回调数据"+resourceString);
+        JSONObject jsonObject = JSONObject.parseObject(resourceString);
+        //将回调数据写入数据库, 并成为会员
+        writeNotifyDataToDb(jsonObject);
+        WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
+        wxNotifyReturnDTO.setCode("SUCCESS");
+        wxNotifyReturnDTO.setMessage("成功");
+        return wxNotifyReturnDTO;
+    }
+
+
+
+    private String getBodyString(HttpServletRequest request) {
+            BufferedReader br = null;
+            StringBuilder sb = new StringBuilder("");
+            try
+            {
+                br = request.getReader();
+                String str;
+                while ((str = br.readLine()) != null)
+                {
+                    sb.append(str);
+                }
+                br.close();
+            }
+            catch (IOException e)
+            {
+                e.printStackTrace();
+            }
+            finally
+            {
+                if (null != br)
+                {
+                    try
+                    {
+                        br.close();
+                    }
+                    catch (IOException e)
+                    {
+                        e.printStackTrace();
+                    }
+                }
+            }
+            return sb.toString();
+
+    }
+
+    private Boolean validate(HttpServletRequest request, String bodyString) throws  NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+        String sign = request.getHeader("Wechatpay-Signature");
+        String timestamp = request.getHeader("Wechatpay-Timestamp");
+        String nonce = request.getHeader("Wechatpay-Nonce");
+
+        StringBuffer sb = new StringBuffer();
+        sb.append(timestamp + "\n");
+        sb.append(nonce + "\n");
+        sb.append(bodyString + "\n");
+        X509Certificate validCertificate = verifier.getValidCertificate();
+        // 进行签名服务
+        Signature signature = Signature.getInstance("SHA256withRSA");
+        // 用微信平台公钥对签名器进行初始化
+        signature.initVerify(validCertificate);
+        // 把我们构造的验签名串更新到签名器中
+        signature.update(sb.toString().getBytes(StandardCharsets.UTF_8));
+        Boolean result = signature.verify(Base64Utils.decodeFromString(sign));
+        log.info("微信支付回调验签:"+result.toString());
+        return result;
+
+    }
+
+
+    /**
+     * 微信退款回调
+     */
+    @PostMapping(value = "/refund")
+    @ApiOperation("微信退款回调")
+    public WxNotifyReturnDTO refundNotify(@RequestBody WxpayNotifyDTO wxpayNotifyDTO, HttpServletRequest request) throws GeneralSecurityException, IOException {
+        String bodyString = getBodyString(request);
+        if (!validate(request,bodyString)){
+            throw new CustomException("签名失败");
+        }
+        String resourceString = getSourString(wxpayNotifyDTO);
+        log.info(resourceString);
+        JSONObject jsonObject = JSONObject.parseObject(resourceString);
+        //将回调数据写入数据库
+        writeRefundNotifyDataToDb(jsonObject);
+
+        WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
+        wxNotifyReturnDTO.setCode("SUCCESS");
+        wxNotifyReturnDTO.setMessage("成功");
+
+        return wxNotifyReturnDTO;
+    }
+
+    private void writeRefundNotifyDataToDb(JSONObject jsonObject) {
+        String refundId = jsonObject.getString("refund_id");
+        RefundRecord refundRecord = refundRecordService.getByRefundId(refundId);
+        if (refundRecord == null) {
+            throw new CustomException("该退款订单不存在");
+        }
+        refundRecord.setTransactionId(jsonObject.getString("transaction_id"));
+        refundRecord.setUserReceivedAccount(jsonObject.getString("user_received_account"));
+        refundRecord.setStatus(jsonObject.getString("refund_status"));
+        refundRecordService.updateById(refundRecord);
+
+
+    }
+
+
+
+
+
+
+    public String writeNotifyDataToDb(JSONObject jsonObject) {
+        String outTradeNo = jsonObject.getString("out_trade_no");
+        WxOrder wxOrder = wxOrderService.getByOutTradeNo(outTradeNo);
+        if (wxOrder == null) {
+            throw new CustomException("该订单不存在");
+        }
+        wxOrder.setTransactionId(jsonObject.getString("transaction_id"));
+        JSONObject amount = jsonObject.getJSONObject("amount");
+        wxOrder.setPayerTotal(amount.getInteger("payer_total"));
+        wxOrder.setTotal(amount.getInteger("total"));
+        wxOrder.setCurrency(amount.getString("currency"));
+        wxOrder.setPayerCurrency(amount.getString("payer_currency"));
+        wxOrder.setTradeState(jsonObject.getString("trade_state"));
+        wxOrder.setBankType(jsonObject.getString("bank_type"));
+        DateTime dateTime  = new DateTime(jsonObject.getString("success_time"));
+        wxOrder.setSuccessTime(dateTime.toDate());
+        wxOrder.setTradeStateDesc(jsonObject.getString("trade_state_desc"));
+        wxOrder.setTradeType(jsonObject.getString("trade_type"));
+        wxOrder.setAttach(jsonObject.getString("attach"));
+        JSONObject sceneInfo = jsonObject.getJSONObject("scene_info");
+        if (sceneInfo != null){
+            wxOrder.setDeviceId(sceneInfo.getString("device_id"));
+        }
+        wxOrderService.updateById(wxOrder);
+
+        //成为会员
+        String data = wxOrder.getOrderDataJson();
+        int days;
+        try{
+            days = Integer.valueOf(data);
+        }catch (Exception e){
+            throw new CustomException("参数值转化异常,请检查数据是否为数值类型");
+        }
+        long timeMillis = days*1440*60*1000l;
+        UserInfo userinfo = userInfoService.getOne(new QueryWrapper<UserInfo>().eq("openid", wxOrder.getOpenid()));
+        Date expireTime = userinfo.getExpireTime();
+        if (expireTime == null && expireTime.getTime()< System.currentTimeMillis()){
+            userinfo.setExpireTime(new Date(System.currentTimeMillis()+timeMillis));
+        }else{
+            userinfo.setExpireTime(new Date(expireTime.getTime()+timeMillis));
+        }
+
+        userInfoService.updateById(userinfo);
+        return outTradeNo;
+
+    }
+
+    private String getSourString(WxpayNotifyDTO wxpayNotifyDTO) throws GeneralSecurityException, IOException {
+        AesUtil aesUtil = new AesUtil(wxpayConfig.getV3key().getBytes());
+        WxpayNotifyDTO.WxpaySource wxpaySource = wxpayNotifyDTO.getResource();
+        return aesUtil.decryptToString(wxpaySource.getAssociated_data().getBytes(), wxpaySource.getNonce().getBytes(), wxpaySource.getCiphertext());
+    }
+
+    private String randomVipcode() {
+        String result = "";
+        Random random = new Random();
+        for(int i =0 ;i <11 ;i ++){
+            result+=random.nextInt(10);
+        }
+        return  result;
+
+
+    }
+
+
+
+
+
+
+
+}

+ 74 - 0
twzd-admin/src/main/java/com/miaxis/app/controller/wx/WxgzhController.java

@@ -0,0 +1,74 @@
+package com.miaxis.app.controller.wx;
+
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.utils.wx.SignUtil;
+import com.miaxis.wx.service.IWxGzhService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 微信公众号相关
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/26 9:28
+ */
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(Constants.OPEN_PREFIX + "/wx/gzh")
+@Api(tags={"wx微信公众号相关"})
+@Slf4j
+public class WxgzhController {
+
+    private final IWxGzhService wxGzhService;
+
+    private final HttpServletRequest request;
+
+    @Value("${cos.bucketName}")
+    private String bucketName;
+    @Value("${cos.path}")
+    private String path;
+    @Value("${cos.preffix}")
+    private String preffix;
+
+
+
+    /**
+     * 处理服务器推送消息
+     * @param request
+     * @param response
+     * @return
+     */
+    @RequestMapping(value = "/notifyMsg",method = { RequestMethod.GET, RequestMethod.POST })
+    @ApiOperation("处理服务器推送消息")
+    public String checkSign(HttpServletRequest request, HttpServletResponse response) {
+        log.info("-----------进入---------");
+        try {
+            String signature = request.getParameter("signature");
+            String timestamp = request.getParameter("timestamp");
+            String nonce = request.getParameter("nonce");
+            String echostr = request.getParameter("echostr");
+            log.info("本身" + signature);
+            if(request.getMethod().equals("GET")){
+                log.info("-----------微信验签---------");
+                return SignUtil.checkSignature(signature, timestamp, nonce) == true ? echostr : null;
+            }else{
+                log.info("-----------推送消息处理---------");
+                return wxGzhService.handlePublicMsg(request);
+            }
+        } catch (Exception e) {
+            log.error("验证公众号token失败", e);
+        }
+        return null;
+    }
+
+
+}

+ 93 - 0
twzd-admin/src/main/java/com/miaxis/pc/controller/WxMenuController.java

@@ -0,0 +1,93 @@
+package com.miaxis.pc.controller;
+
+import com.miaxis.common.annotation.Log;
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.core.controller.BaseController;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.common.core.page.ResponsePageInfo;
+import com.miaxis.common.enums.BusinessTypeEnum;
+import com.miaxis.wx.domain.WxMenu;
+import com.miaxis.wx.service.IWxMenuService;
+import com.miaxis.wx.vo.WxMenuVo;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author wwl
+ * @version 1.0
+ * @date 2021/11/3 9:18
+ */
+@RestController
+@RequestMapping("/pc/menu")
+@Api(tags={"【H5-微信公众号菜单】"})
+@AllArgsConstructor
+public class WxMenuController extends BaseController {
+
+    private final IWxMenuService wxMenuService;
+
+
+    /**
+     * 查询微信公众号菜单列表
+     */
+    @PreAuthorize("@ss.hasPermi('menu:info:list')")
+    @GetMapping("/list")
+    @ApiOperation("查询微信公众号菜单列表")
+    public Response<List<WxMenuVo>> list(){
+        return wxMenuService.selectWxMenuTreeList();
+    }
+
+
+    /**
+     * 获取微信公众号菜单详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('menu:info:query')")
+    @GetMapping(value = "/{id}")
+    @ApiOperation("获取微信公众号菜单详细信息")
+    public Response<WxMenu> getInfo(
+            @ApiParam(name = "id", value = "微信公众号菜单参数", required = true)
+            @PathVariable("id") Long id
+    ){
+        return Response.success(wxMenuService.getById(id));
+    }
+
+    /**
+     * 新增微信公众号菜单
+     */
+    @PreAuthorize("@ss.hasPermi('menu:info:add')")
+    @Log(title = "微信公众号菜单", businessType = BusinessTypeEnum.INSERT)
+    @PostMapping
+    @ApiOperation("新增微信公众号菜单")
+    public Response add(@RequestBody WxMenu wxMenu){
+        return wxMenuService.saveMenu(wxMenu);
+    }
+
+    /**
+     * 修改微信公众号菜单
+     */
+    @PreAuthorize("@ss.hasPermi('menu:info:edit')")
+    @Log(title = "微信公众号菜单", businessType = BusinessTypeEnum.UPDATE)
+    @PutMapping
+    @ApiOperation("修改微信公众号菜单")
+    public Response edit(@RequestBody WxMenu wxMenu){
+        return wxMenuService.updateMenuById(wxMenu);
+    }
+
+    /**
+     * 删除微信公众号菜单
+     */
+    @PreAuthorize("@ss.hasPermi('menu:info:remove')")
+    @Log(title = "微信公众号菜单", businessType = BusinessTypeEnum.DELETE)
+    @DeleteMapping("/{ids}")
+    @ApiOperation("删除微信公众号菜单")
+    public  Response remove(
+            @ApiParam(name = "ids", value = "微信公众号菜单ids参数", required = true)
+            @PathVariable Long[] ids
+    ){
+        return wxMenuService.removeMenuByIds(ids);
+    }
+
+}

+ 12 - 6
twzd-admin/src/main/java/com/miaxis/system/controller/system/SysLoginController.java

@@ -4,9 +4,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.miaxis.common.core.domain.Response;
 import com.miaxis.common.core.domain.entity.SysMenu;
 import com.miaxis.common.core.domain.entity.SysUser;
-import com.miaxis.common.core.domain.model.LoginBody;
-import com.miaxis.common.core.domain.model.LoginBodyNoCode;
-import com.miaxis.common.core.domain.model.LoginUser;
+import com.miaxis.common.core.domain.model.*;
 import com.miaxis.common.enums.StudentLoginTypeEnum;
 import com.miaxis.common.exception.CustomException;
 import com.miaxis.common.utils.SecurityUtils;
@@ -18,7 +16,6 @@ import com.miaxis.system.dto.common.RouterDTO;
 import com.miaxis.system.dto.system.TokenDTO;
 import com.miaxis.system.dto.system.UserInfoDTO;
 import com.miaxis.system.service.ISysMenuService;
-import com.miaxis.common.core.domain.model.WxResult;
 import com.miaxis.wx.service.WxService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -124,10 +121,13 @@ public class SysLoginController
         if (wxResult.getErrcode() != null){
             throw new CustomException("微信授权无效,请重新授权");
         }
+        String userInfoStr = wxService.getUserInfo("zh_CN", wxResult.getAccess_token(), wxResult.getOpenid());
+        WxUserInfo wxUserInfo = JSONObject.parseObject(userInfoStr,WxUserInfo.class);
+
         String token = loginService.login(wxResult.getOpenid(),null, StudentLoginTypeEnum.AUTHORIZATION_CODE_LOGIN.getCode());
         TokenDTO tokenDTO = new TokenDTO();
         tokenDTO.setToken(token);
-        tokenDTO.setWxResult(wxResult);
+        tokenDTO.setWxUserInfo(wxUserInfo);
         return Response.success(tokenDTO) ;
 
 
@@ -136,9 +136,15 @@ public class SysLoginController
     @PostMapping("/login/code/test")
     @ApiOperation("用户授权码模式登录--测试")
     public Response<TokenDTO> testloginByAuthorizationCode(String authorizationCode ){
-        String token = loginService.login("oN0Np5sK6JeTRa06hlE4-OkHDlDY",null, StudentLoginTypeEnum.AUTHORIZATION_CODE_LOGIN.getCode());
+        String token = loginService.login("ovKTX5zYvp9OXE43ADwLa1RHna0g",null, StudentLoginTypeEnum.AUTHORIZATION_CODE_LOGIN.getCode());
         TokenDTO tokenDTO = new TokenDTO();
         tokenDTO.setToken(token);
+        WxUserInfo wxUserInfo = new WxUserInfo();
+        wxUserInfo.setOpenid("ovKTX5zYvp9OXE43ADwLa1RHna0g");
+        wxUserInfo.setNickname("Sss");
+        wxUserInfo.setSex("0");
+        wxUserInfo.setHeadimgurl("https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83erGMFzKaOmz6cIaA0J1nicWSlBLdLKY46N5CNCoASiajT7Z3RIfPngPhJsjmqsSjGCFibPU4vCtfz3aw/132");
+        tokenDTO.setWxUserInfo(wxUserInfo);
         return Response.success(tokenDTO) ;
 
 

+ 70 - 48
twzd-admin/src/main/java/com/miaxis/system/controller/test/TestController.java

@@ -1,27 +1,32 @@
 package com.miaxis.system.controller.test;
 
-import cn.hutool.core.io.FileUtil;
 import cn.hutool.extra.qrcode.QrCodeUtil;
-import cn.hutool.extra.qrcode.QrConfig;
-import com.alibaba.fastjson.JSONObject;
-import com.miaxis.common.annotation.Log;
+import com.miaxis.common.constant.Constants;
 import com.miaxis.common.core.domain.Response;
-import com.miaxis.common.enums.BusinessTypeEnum;
-import com.miaxis.feign.dto.WxTicket;
 import com.miaxis.feign.service.IWxMpService;
 import com.miaxis.feign.service.IWxSendService;
 import com.miaxis.wx.service.IWxGzhService;
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.model.ObjectMetadata;
+import com.qcloud.cos.model.PutObjectRequest;
+import com.qcloud.cos.model.PutObjectResult;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
 import lombok.RequiredArgsConstructor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
-import java.net.URLEncoder;
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletRequest;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Calendar;
 
 /**
  * @author wwl
@@ -30,8 +35,8 @@ import java.net.URLEncoder;
  */
 @RestController
 @RequiredArgsConstructor
-@RequestMapping("/wxTest")
-@Api(tags={"测试"})
+@RequestMapping(Constants.OPEN_PREFIX + "/wxTest")
+@Api(tags={"wx测试"})
 public class TestController {
 
     private static final Logger log = LoggerFactory.getLogger(TestController.class);
@@ -45,48 +50,65 @@ public class TestController {
     @Autowired
     IWxMpService wxMpService;
 
+    @Autowired
+    HttpServletRequest request;
+
+    @Autowired
+    private COSClient cosClient;
+
+    @Value("${cos.bucketName}")
+    private String bucketName;
+    @Value("${cos.path}")
+    private String path;
+    @Value("${cos.preffix}")
+    private String preffix;
+
+    @Value("${file.ticketPath}")
+    private String ticketPath;
+
+    @Value("${wxgzh.mediaUpload}")
+    private String materialUrl;
 
-    /**
-     * 生成带参数的二维码
-     */
-    @GetMapping(value = "/generateTicket")
-    @ApiOperation("生成带参数的二维码")
-    public Response generateTicket() throws Exception{
-        String xcxMessageToken = wxGzhService.getGzhToken();
-        WxTicket wxTicket = new WxTicket();
-        wxTicket.setExpire_seconds(3000);
-        wxTicket.setAction_name("QR_SCENE");
-        JSONObject jsonObject1 = new JSONObject();
-        JSONObject jsonObject2 = new JSONObject();
-        jsonObject1.put("scene_id","123");
-        jsonObject2.put("scene",jsonObject1);
-        wxTicket.setAction_info(jsonObject2);
-        String result = wxSendService.generateTicket(xcxMessageToken,wxTicket);
-        System.out.println("生成ticket:" + result);
-        JSONObject jsonStr = JSONObject.parseObject(result);
-
-        QrCodeUtil.generate(
-                jsonStr.getString("url"), //二维码内容
-                QrConfig.create().setImg("C:\\Users\\wwl\\Desktop\\二维码\\微信图片_20211021120216.jpg"),
-                FileUtil.file("C:\\Users\\wwl\\Desktop\\二维码\\logo二维码.jpg")//写出到的文件
-        );
-
-        String decode = QrCodeUtil.decode(FileUtil.file("C:\\Users\\wwl\\Desktop\\二维码\\logo二维码.jpg"));
-        System.out.println("二维码信息:"+ decode);
-        return Response.success();
-    }
 
 
     /**
-     * 测试
+     * cos上传二维码
      */
-    @Log(title = "测试", businessType = BusinessTypeEnum.UPDATE)
-    @PutMapping("/test")
-    @ApiOperation("测试")
-    public void test(Object object){
-        System.out.println("----test-----"+ object);
-        log.info("测试:"+object);
+    @GetMapping(value = "/test01")
+    @ApiOperation("cos上传二维码")
+    public Response test01() throws Exception{
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+        ImageIO.write(QrCodeUtil.generate(
+                "二维码内容", //二维码内容
+                300, 300
+        ), "JPG", os);
+        InputStream inputStream = new ByteArrayInputStream(os.toByteArray());
+
+        ObjectMetadata objectMetadata = new ObjectMetadata();
+        // 从输入流上传必须制定content length, 否则http客户端可能会缓存所有数据,存在内存OOM的情况
+        objectMetadata.setContentLength(os.size());
+
+        // bucket的命名规则为{name}-{appid} ,此处填写的存储桶名称必须为此格式
+        String bucketName = this.bucketName;
+
+        Calendar cal = Calendar.getInstance();
+        int year = cal.get(Calendar.YEAR);
+        int month=cal.get(Calendar.MONTH)+ 1;
+        int day=cal.get(Calendar.DATE);
+
+        //存储的文件名
+        String storagefileName = System.currentTimeMillis() + ".png";
+        // 指定要上传到 COS 上的路径
+        String key = "/"+this.preffix+"/"+ "testTicket"+"/"+year+"/"+month+"/"+day+"/"+storagefileName;
+        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream,objectMetadata);
+        PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
+        String fileUrl=this.path + putObjectRequest.getKey();
+
+        return Response.success(fileUrl);
     }
 
 
+
 }

+ 31 - 0
twzd-admin/src/main/resources/application-dev.yml

@@ -86,4 +86,35 @@ app:
     appSecret: 8604f2a6eb6338cfa64e7df4ec2c08b3
 
 
+# 微信支付
+wxpay:
+    v3url: https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
+    v3urlRefund: https://api.mch.weixin.qq.com/v3/refund/domestic/refunds
+    merchantId: 1615410794
+    serialNumber: 5F85D69504B3B33DAF5A7C5B86A3E93915D3D5B0
+    v3key: 8604f2a6eb6338cfa64e7df4ec2c08b3
+    notifyUrl: http://218.85.55.253:65535/twzd-admin/open-api/wx/notify/wxpay
+    notifyUrlRefund: http://218.85.55.253:65535/twzd-admin/open-api/wx/notify/refund
 
+
+# 腾讯cos
+cos:
+    secretId: AKIDwISNOFsJXYGjy89FJI9UnzuZFgTtRgFe
+    secretKey: IK5af8MJzPoKbdQxDCtKWR5T5PSEkyDB
+    bucket: ap-shanghai
+    bucketName: twzd-1305573081
+    path: https://twzd-1305573081.cos.ap-shanghai.myqcloud.com
+    preffix: twzd-test
+
+
+# 分销二维码生成路径
+file:
+    ticketPath: /data/test/
+
+
+# 公众号上传素材url
+wxgzh:
+    # 上传永久素材
+    materialUrl: https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=
+    # 上传临时素材
+    mediaUpload: https://api.weixin.qq.com/cgi-bin/media/upload?access_token=

+ 34 - 1
twzd-admin/src/main/resources/application-prod.yml

@@ -64,7 +64,7 @@ spring:
         # 密码
         password: miaxis110
         # 连接超时时间
-        timeout: 10s
+        timeout: 10000
         lettuce:
             pool:
                 # 连接池中的最小空闲连接
@@ -82,3 +82,36 @@ spring:
 app:
     appId: wx67ca1b8c9816ef28
     appSecret: 8604f2a6eb6338cfa64e7df4ec2c08b3
+
+# 微信支付
+wxpay:
+    v3url: https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
+    v3urlRefund: https://api.mch.weixin.qq.com/v3/refund/domestic/refunds
+    merchantId: 1615410794
+    serialNumber: 5F85D69504B3B33DAF5A7C5B86A3E93915D3D5B0
+    v3key: 8604f2a6eb6338cfa64e7df4ec2c08b3
+    notifyUrl: http://jpcj-h5.zzxcx.net.zzxcx.net/prod-api/open-api/wx/notify/wxpay
+    notifyUrlRefund: http://jpcj-h5.zzxcx.net.zzxcx.net/prod-api/open-api/wx/notify/refund
+
+
+# 腾讯cos
+cos:
+    secretId: AKIDwISNOFsJXYGjy89FJI9UnzuZFgTtRgFe
+    secretKey: IK5af8MJzPoKbdQxDCtKWR5T5PSEkyDB
+    bucket: ap-shanghai
+    bucketName: twzd-1305573081
+    path: https://twzd-1305573081.cos.ap-shanghai.myqcloud.com
+    preffix: twzd-prod
+
+
+# 带参数的二维码生成路径
+file:
+    ticketPath: /data/test/
+
+
+# 公众号上传素材url
+wxgzh:
+    # 上传永久素材
+    materialUrl: https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=
+    # 上传临时素材
+    mediaUpload: https://api.weixin.qq.com/cgi-bin/media/upload?access_token=

BIN
twzd-admin/src/main/resources/wechatpay/apiclient_cert.p12


+ 24 - 0
twzd-admin/src/main/resources/wechatpay/apiclient_cert.pem

@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID+TCCAuGgAwIBAgIUX4XWlQSzsz2vWnxbhqPpORXT1bAwDQYJKoZIhvcNAQEL
+BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
+FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
+Q0EwHhcNMjExMDIwMDkxOTA2WhcNMjYxMDE5MDkxOTA2WjCBijETMBEGA1UEAwwK
+MTYxNTQxMDc5NDEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTYwNAYDVQQL
+DC3npo/lt57puL/nqIvlpKnlronpqb7pqbblkZjln7norq3mnInpmZDlhazlj7gx
+CzAJBgNVBAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMwRV01WeeQ83V5siu6GFKN7j1yt7DnULtyv9JnbE14z
+WcKCd5L6nyVvWBBtCtjlOjZ9ZXhxS4HUyzy1TDzY/gcVrpLwiV73Mvcjpe643Kax
++tGlfWTcFTEw/eFNzQyj+jaTvYvHqW5iJibNECVbPnkeDiT3M2yB9z6iyIwibKth
+cLXvBqPUkIv/xPRZPjOJvenW64J62whGv8aG/5+dY+lrpKkZlO6P5bEwCZvEd7K5
+F3wf08F8rSE2OTUzzc84I19hNFkKy8iapkw1gKC6y8SLrHvMmiGZhcdo5dG4h5Wr
+vKrkMsXjSq7Zu6RRYDY6d+xr9ZRxWI2iR68A9/fTfsECAwEAAaOBgTB/MAkGA1Ud
+EwQCMAAwCwYDVR0PBAQDAgTwMGUGA1UdHwReMFwwWqBYoFaGVGh0dHA6Ly9ldmNh
+Lml0cnVzLmNvbS5jbi9wdWJsaWMvaXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0
+QjA2QUQzOTc1NDk4NDZDMDFDM0U4RUJEMjANBgkqhkiG9w0BAQsFAAOCAQEAi0Yj
+8PTQOy+kocAvZmWJwZIzvkDSO05nT5HbUhpc83eXBxXLq2PdWlZ0g4dWzoB7eumv
+68nTQ3ohV86vK++J0itaNkXteQVJFSk89OvH7rYfFaUloi6bYFKmuB7Rddu2nkUo
+qMpE6l41MhISe/F7KK1lGP1AgEQIVYcNrMgphlvCTh6KCwRsa2BmdsuG5AeLtnln
+dRuo1Y4dRa/1DyCG8Pi3UsDcCciff6KZXomSoTQy578NV5ApNCAV3v2DPW/8YcWk
+CCon7krnxtJMAeCkZRVzt/HI0HMRzQk6B/oGuBDUlDwdNKnXXyZ36WGelD94WIQ4
+kWNf7oZ4wMDbK0MJ/Q==
+-----END CERTIFICATE-----

+ 28 - 0
twzd-admin/src/main/resources/wechatpay/apiclient_key.pem

@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDMEVdNVnnkPN1e
+bIruhhSje49crew51C7cr/SZ2xNeM1nCgneS+p8lb1gQbQrY5To2fWV4cUuB1Ms8
+tUw82P4HFa6S8Ile9zL3I6XuuNymsfrRpX1k3BUxMP3hTc0Mo/o2k72Lx6luYiYm
+zRAlWz55Hg4k9zNsgfc+osiMImyrYXC17waj1JCL/8T0WT4zib3p1uuCetsIRr/G
+hv+fnWPpa6SpGZTuj+WxMAmbxHeyuRd8H9PBfK0hNjk1M83POCNfYTRZCsvImqZM
+NYCgusvEi6x7zJohmYXHaOXRuIeVq7yq5DLF40qu2bukUWA2Onfsa/WUcViNokev
+APf3037BAgMBAAECggEBAIrAy7yRLQYMgHRgl0LBtizGqd7Zf0J+zHJPzaADfrLR
+dZm0/jrY3/cjMxzQF80MZ71/G8x+NFoN5zbbCwBghrEog+/zT2Rb7rJt8bhUx+ss
+HyAHRzCaGGq/JhDYxrBumoYbhIkTdFfSsqA1VGIiHWNbFUD7OGLyJ7vWEUh/a6ZG
+vt5+qsWLk9ioih06zWeaNXfulovmavZ0vvljhNXj2H83H/E1/3daVrYxuhk63WBm
+x2XJUNL9U8+yqW1WqPRw9u35TV34yoAJSoRbGWcAaJejfrBa6KS815NNJb6dT9Vi
+2cEl6R4YloT3rd/unXTgWMiHVQ+L8StYfB6RellbrDECgYEA6sCKK5h91+5AD39T
++jRt7Rgu7GyW0JI9ev/aT4xdIU2daP0P+YdPzSvvoaje9iknTfLkBJ9mNZDtwUHO
+LWxG5lKYYlXCOlCbVtUSYq8OPthJFo18VOFz7kSigvoS/VGUtTm/QB8soXf8GFf2
+QKdLui9tAFDHUOboXkgR1/Gu6q0CgYEA3onPrmBPYHtYkkJcuoSWsw28hqy0/ZrJ
+yN/Ss2M+zHsefSmPFjGKx5DKZ0bjPTA5Ly2NR78MyzFFSP9XFxOE4wter74i9BTe
+osNhYceWdTIv2vUIHTjOyjKTx1nyeUNAxV0ekce1V4Smql9c9ZybTb9LEb4eD9vw
+EoG8jBNeGuUCgYEA0jZEBDHzTq8cUkRUsNLONOfY7QF4M6EgyMnfdihdJPtZn7As
+4+eVQEa9uOd9cLT9a0G7iaAraIA1Rz9kHyy8eHcx2ayt1oZj8+etJQ1ZFlGbcUSV
+N3UD2TNAy0SgSJMLNRVW+1ZvItBMwIfUDaVBnKHnW8b6FKoRHowu3k6fsakCgYB+
+aXJb78GnYOnTS3c5TI/+blMlfX3igccWIG6kEEBgD6AmITFyvfnDm3Aecpoq6/XP
+4uRaWSB/XCGrccCbDy9xecfztOJOHHzLoIj07ld9g2DD1GUjlF2DZm+j0mh2kcl9
+U4RF81gDuwqhxUIdEzT1WTDfh0u0Xo9lM+VS/L18MQKBgAPHeSoKzFb3bPlAaAN4
+DxyBilpCsq6x0ebXjLj01wqaXT3g2XQqpcgN2QnYQw4pC30lEpP8LhdkEint86Ag
+SwMjtGVUz29fncxcd5tiAVf4+r5azdGcpN0Y0ZC1G20TbMolIyXFet/VbhSYxdop
+I0CuiwRTRJVwH3qRYbkUmM0x
+-----END PRIVATE KEY-----

+ 55 - 0
twzd-common/src/main/java/com/miaxis/common/config/BeanConfig.java

@@ -0,0 +1,55 @@
+package com.miaxis.common.config;
+
+import com.miaxis.common.utils.uuid.CommonUtils;
+import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
+import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
+import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
+import org.apache.http.client.HttpClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.File;
+import java.security.PrivateKey;
+
+
+@Configuration
+public class BeanConfig {
+
+
+    @Autowired
+    private WxpayConfig wxpayConfig;
+    @Autowired
+    private AutoUpdateCertificatesVerifier verifier;
+
+    /**
+     * 腾讯云 COS
+     * @return
+     */
+
+
+
+
+    /**
+     * 微信支付 httpclient 对象
+     * @return
+     * @throws Exception
+     */
+    @Bean
+    public HttpClient wxpayConfigBean() throws Exception{
+        File file = new ClassPathResource("wechatpay/apiclient_key.pem").getFile();
+        String realPath =file.getAbsolutePath();
+        PrivateKey privateKey = CommonUtils.getPrivateKey(realPath);
+        // 初始化httpClient
+        HttpClient httpClient = WechatPayHttpClientBuilder.create()
+                .withMerchant(wxpayConfig.getMerchantId(), wxpayConfig.getSerialNumber(), privateKey)
+                .withValidator(new WechatPay2Validator(verifier)).build();
+        return httpClient;
+
+    }
+
+
+
+
+}

+ 63 - 0
twzd-common/src/main/java/com/miaxis/common/config/CosConfig.java

@@ -0,0 +1,63 @@
+package com.miaxis.common.config;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.http.HttpProtocol;
+import com.qcloud.cos.region.Region;
+import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * cos对象存储
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/25 15:40
+ */
+@Configuration
+public class CosConfig {
+
+    @Value("${cos.secretId}")
+    private String secretId;
+    @Value("${cos.secretKey}")
+    private String secretKey;
+    @Value("${cos.bucket}")
+    private String bucket;
+    @Value("${cos.bucketName}")
+    private String bucketName;
+    @Value("${cos.path}")
+    private String path;
+    @Value("${cos.preffix}")
+    private String preffix;
+
+
+    /**
+     * 腾讯云 COS
+     * @return
+     */
+
+    @Bean
+    public COSClient COSClientconfigBean() {
+        // 1 初始化用户身份信息(secretId, secretKey)。
+        // SECRETID和SECRETKEY请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
+        String secretId = this.secretId;
+        String secretKey = this.secretKey;
+        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
+        // 2 设置 bucket 的地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
+        // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
+        Region region = new Region(this.bucket);
+        ClientConfig clientConfig = new ClientConfig(region);
+        // 这里建议设置使用 https 协议
+        // 从 5.6.54 版本开始,默认使用了 https
+        clientConfig.setHttpProtocol(HttpProtocol.https);
+        // 3 生成 cos 客户端。
+        COSClient cosClient = new COSClient(cred, clientConfig);
+        return cosClient;
+    }
+
+
+}

+ 37 - 0
twzd-common/src/main/java/com/miaxis/common/config/WxVerifierConfig.java

@@ -0,0 +1,37 @@
+package com.miaxis.common.config;
+
+import com.miaxis.common.utils.uuid.CommonUtils;
+import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
+import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
+import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.File;
+import java.security.PrivateKey;
+
+
+@Configuration
+public class WxVerifierConfig {
+
+
+    @Autowired
+    private WxpayConfig wxpayConfig;
+
+    @Bean
+    public AutoUpdateCertificatesVerifier getVerifier() throws Exception{
+        File file = new ClassPathResource("wechatpay/apiclient_key.pem").getFile();
+        String realPath =file.getAbsolutePath();
+        PrivateKey privateKey = CommonUtils.getPrivateKey(realPath);
+        // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
+        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
+                new WechatPay2Credentials(wxpayConfig.getMerchantId(),
+                        new PrivateKeySigner(wxpayConfig.getSerialNumber(), privateKey)),
+                wxpayConfig.getV3key().getBytes("utf-8"));
+        return verifier;
+
+    }
+
+}

+ 22 - 0
twzd-common/src/main/java/com/miaxis/common/config/WxpayConfig.java

@@ -0,0 +1,22 @@
+package com.miaxis.common.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "wxpay")
+public class WxpayConfig {
+
+    private String v3url;
+    //退款
+    private String v3urlRefund;
+    //退款回调
+    private String notifyUrlRefund;
+    //商户id
+    private String merchantId;
+    private String serialNumber;
+    private String v3key;
+
+}

+ 9 - 0
twzd-common/src/main/java/com/miaxis/common/constant/Constants.java

@@ -78,6 +78,15 @@ public class Constants
      */
     public static final String GZH_MESSAGE_TOKEN = "gzh:message:token:";
 
+    /**
+     * 公众号推广码ticket
+     */
+    public static final String GZH_TICKET_KEY = "gzh:ticket:";
+    /**
+     * 公众号推广码素材信息
+     */
+    public static final String GZH_MATERIAL_KEY = "gzh:material:";
+
 
     /**
      * 登录用户 redis key

+ 10 - 7
twzd-common/src/main/java/com/miaxis/common/core/domain/entity/UserInfo.java

@@ -9,8 +9,6 @@ import com.miaxis.common.core.domain.BaseBusinessEntity;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 
 import java.util.Date;
 /**
@@ -72,11 +70,11 @@ public class UserInfo extends BaseBusinessEntity{
     @ApiModelProperty(value = "0 启用 1禁用")
     private Integer status;
 
-    /** 0 否 1是 */
-    @Excel(name = "是否是vip 0 否 1")
-    @TableField("is_vip")
-    @ApiModelProperty(value = "是否是vip 0 否 1是")
-    private Integer isVip;
+//    /** 0 否 1是 */
+//    @Excel(name = "是否是vip 0 否 1")
+//    @TableField("is_vip")
+//    @ApiModelProperty(value = "是否是vip 0 否 1是")
+//    private Integer isVip;
 
 
     /** 驾校班型Id */
@@ -86,5 +84,10 @@ public class UserInfo extends BaseBusinessEntity{
     private String unionId;
 
 
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" )
+    @ApiModelProperty(value = "过期时间")
+    private Date expireTime;
+
+
 
 }

+ 3 - 3
twzd-common/src/main/java/com/miaxis/common/core/domain/model/LoginUser.java

@@ -272,9 +272,9 @@ public class LoginUser implements UserDetails
             List<SimpleGrantedAuthority> roleList = new ArrayList<SimpleGrantedAuthority>();
             roleList.add(new SimpleGrantedAuthority("ROLE_STUDENT"));
             //如果已激活,是vip的话
-            if (this.getStudent().getIsVip() == 1){
-                roleList.add(new SimpleGrantedAuthority("ROLE_VIP"));
-            }
+//            if (this.getStudent().getIsVip() == 1){
+//                roleList.add(new SimpleGrantedAuthority("ROLE_VIP"));
+//            }
             return roleList;
         }else {
             return null;

+ 18 - 0
twzd-common/src/main/java/com/miaxis/common/core/domain/model/WxUserInfo.java

@@ -0,0 +1,18 @@
+package com.miaxis.common.core.domain.model;
+
+
+import lombok.Data;
+
+@Data
+public class WxUserInfo {
+     String openid;
+     String nickname;
+     String sex;
+     String province;
+     String city;
+     String country;
+     String headimgurl;
+     String[] privilege;
+     String unionid;
+
+}

+ 161 - 0
twzd-common/src/main/java/com/miaxis/common/utils/XmlUtil.java

@@ -0,0 +1,161 @@
+package com.miaxis.common.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * xml util
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/26 14:55
+ */
+public class XmlUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(XmlUtil.class);
+
+    /**
+     * 将Map转换为XML格式的字符串
+     *
+     * @param data Map类型数据
+     * @return XML格式的字符串
+     * @throws Exception
+     */
+    public static String mapToXml(Map<String, String> data) throws Exception {
+        log.info("----mapToXml-----"+data);
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
+        org.w3c.dom.Document document = documentBuilder.newDocument();
+        org.w3c.dom.Element root = document.createElement("xml");
+        document.appendChild(root);
+        for (String key: data.keySet()) {
+            String value = data.get(key);
+            if (value == null) {
+                value = "";
+            }
+            value = value.trim();
+            org.w3c.dom.Element filed = document.createElement(key);
+            filed.appendChild(document.createTextNode(value));
+            root.appendChild(filed);
+        }
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer transformer = tf.newTransformer();
+        DOMSource source = new DOMSource(document);
+        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+        StringWriter writer = new StringWriter();
+        StreamResult result = new StreamResult(writer);
+        transformer.transform(source, result);
+        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
+        try {
+            writer.close();
+        } catch (Exception ex) {
+
+        }
+        log.info("----mapToXml-return-----"+output);
+        return output;
+    }
+
+
+    /**
+     * 微信回复图片 map转换xml
+     * @param data
+     * @return
+     * @throws Exception
+     */
+    public static String mapToXmlSpecial(Map<String, String> data) throws Exception {
+        log.info("----mapToXml-----"+data);
+        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
+        org.w3c.dom.Document document = documentBuilder.newDocument();
+        org.w3c.dom.Element root = document.createElement("xml");
+        document.appendChild(root);
+
+        org.w3c.dom.Element toUserName = document.createElement("ToUserName");
+        toUserName.setTextContent(data.get("ToUserName"));
+        root.appendChild(toUserName);
+        org.w3c.dom.Element fromUserName = document.createElement("FromUserName");
+        fromUserName.setTextContent(data.get("FromUserName"));
+        root.appendChild(fromUserName);
+        org.w3c.dom.Element createTime = document.createElement("CreateTime");
+        createTime.setTextContent(data.get("CreateTime"));
+        root.appendChild(createTime);
+        org.w3c.dom.Element msgType = document.createElement("MsgType");
+        msgType.setTextContent(data.get("MsgType"));
+        root.appendChild(msgType);
+        org.w3c.dom.Element image = document.createElement("Image");
+        root.appendChild(image);
+        org.w3c.dom.Element mediaId = document.createElement("MediaId");
+        mediaId.setTextContent(data.get("MediaId"));
+        image.appendChild(mediaId);
+
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer transformer = tf.newTransformer();
+        DOMSource source = new DOMSource(document);
+        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+        StringWriter writer = new StringWriter();
+        StreamResult result = new StreamResult(writer);
+        transformer.transform(source, result);
+        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
+        try {
+            writer.close();
+        } catch (Exception ex) {
+
+        }
+        log.info("----mapToXml-return-----"+output);
+        return output;
+    }
+
+
+    /**
+     * XML格式字符串转换为Map
+     *
+     * @param strXML XML字符串
+     * @return XML数据转换后的Map
+     * @throws Exception
+     */
+    public static Map<String, String> xmlToMap(String strXML) throws Exception {
+        log.info("4....");
+        try {
+            Map<String, String> data = new HashMap<>();
+            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+            InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
+            org.w3c.dom.Document doc = documentBuilder.parse(stream);
+            doc.getDocumentElement().normalize();
+            NodeList nodeList = doc.getDocumentElement().getChildNodes();
+            for (int idx = 0; idx < nodeList.getLength(); ++idx) {
+                Node node = nodeList.item(idx);
+                if (node.getNodeType() == Node.ELEMENT_NODE) {
+                    org.w3c.dom.Element element = (org.w3c.dom.Element) node;
+                    data.put(element.getNodeName(), element.getTextContent());
+                }
+            }
+            try {
+                stream.close();
+            } catch (Exception ex) {
+                // do nothing
+            }
+            return data;
+        } catch (Exception ex) {
+            throw ex;
+        }
+    }
+
+
+}

+ 73 - 4
twzd-common/src/main/java/com/miaxis/common/utils/http/HttpUtils.java

@@ -6,10 +6,7 @@ import org.slf4j.LoggerFactory;
 
 import javax.net.ssl.*;
 import java.io.*;
-import java.net.ConnectException;
-import java.net.SocketTimeoutException;
-import java.net.URL;
-import java.net.URLConnection;
+import java.net.*;
 import java.security.cert.X509Certificate;
 
 /**
@@ -251,4 +248,76 @@ public class HttpUtils
             return true;
         }
     }
+
+    public static  String connectHttpsByPost(String path, File file) throws Exception{
+        URL urlObj = new URL(path);
+        //连接
+        HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
+        String result = null;
+        con.setDoInput(true);
+        con.setDoOutput(true);
+        con.setUseCaches(false); // post方式不能使用缓存
+
+        // 设置请求头信息
+        con.setRequestProperty("Connection", "Keep-Alive");
+        con.setRequestProperty("Charset", "UTF-8");
+        // 设置边界
+        String BOUNDARY = "----------" + System.currentTimeMillis();
+        con.setRequestProperty("Content-Type",
+                "multipart/form-data; boundary="
+                        + BOUNDARY);
+
+        // 请求正文信息
+        // 第一部分:
+        StringBuilder sb = new StringBuilder();
+        sb.append("--"); // 必须多两道线
+        sb.append(BOUNDARY);
+        sb.append("\r\n");
+        sb.append("Content-Disposition: form-data;name=\"media\";filelength=\"" + file.length() + "\";filename=\""
+                + file.getName() + "\"\r\n");
+        sb.append("Content-Type:application/octet-stream\r\n\r\n");
+        byte[] head = sb.toString().getBytes("utf-8");
+        // 获得输出流
+        OutputStream out = new DataOutputStream(con.getOutputStream());
+        // 输出表头
+        out.write(head);
+
+        // 文件正文部分
+        // 把文件已流文件的方式 推入到url中
+        DataInputStream in = new DataInputStream(new FileInputStream(file));
+        int bytes = 0;
+        byte[] bufferOut = new byte[1024];
+        while ((bytes = in.read(bufferOut)) != -1) {
+            out.write(bufferOut, 0, bytes);
+        }
+        in.close();
+        // 结尾部分
+        byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
+        out.write(foot);
+        out.flush();
+        out.close();
+        StringBuffer buffer = new StringBuffer();
+        BufferedReader reader = null;
+        try {
+            // 定义BufferedReader输入流来读取URL的响应
+            reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
+            String line = null;
+            while ((line = reader.readLine()) != null) {
+                buffer.append(line);
+            }
+            if (result == null) {
+                result = buffer.toString();
+            }
+        } catch (IOException e) {
+            System.out.println("发送POST请求出现异常!" + e);
+            e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                reader.close();
+            }
+        }
+        return result;
+    }
+
+
 }

+ 98 - 0
twzd-common/src/main/java/com/miaxis/common/utils/wx/MessageUtil.java

@@ -0,0 +1,98 @@
+package com.miaxis.common.utils.wx;
+
+import com.miaxis.common.utils.XmlUtil;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 微信消息工具
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/25 13:19
+ */
+public class MessageUtil {
+
+    public static final String MESSAGE_TEXT="text";//文本消息
+    public static final String MESSAGE_IMAGE="image";//图片消息
+    public static final String MESSAGE_VOICE="voice";//语音消息
+    public static final String MESSAGE_VIDEO="video";//视频消息
+    public static final String MESSAGE_LOCATION="LOCATION";//地理位置消息
+    public static final String MESSAGE_EVENT="event";//事件消息
+    public static final String MESSAGE_SUBSCRIBE="subscribe";//关注
+    public static final String MESSAGE_UNSUBSCRIBE="unsubscribe";//取消关注
+    public static final String MESSAGE_SCAN="SCAN";//已关注扫码消息
+    public static final String MESSAGE_CLICK="CLICK";//点击菜单拉取消息
+    public static final String MESSAGE_VIEW="VIEW";//点击菜单跳转链接消息
+    public static final String MESSAGE_VIEW_MINIPROGRAM="view_miniprogram";//点击菜单跳转小程序的消息
+
+
+
+    /**
+     * 回复文本消息
+     * @param fromUserName
+     * @param toUserName
+     * @param content 回复的消息内容(换行:在content中能够换行,微信客户端就支持换行显示)
+     * @return
+     */
+    public static String initText(String fromUserName, String toUserName, String content) throws Exception{
+        // 返回消息时ToUserName的值与FromUserName的互换
+        Map<String, String> returnMap = new HashMap<>();
+        returnMap.put("ToUserName", fromUserName);
+        returnMap.put("FromUserName", toUserName);
+        returnMap.put("CreateTime", new Date().getTime()+"");
+        returnMap.put("MsgType", "text");
+        returnMap.put("Content", content);
+        return XmlUtil.mapToXml(returnMap);
+    }
+
+
+    /**
+     * 回复图片消息
+     * @param fromUserName
+     * @param toUserName
+     * @param mediaId 通过素材管理中的接口上传多媒体文件,得到的id。
+     * @return
+     */
+    public static String initImage(String fromUserName, String toUserName, String mediaId) throws Exception{
+        // 返回消息时ToUserName的值与FromUserName的互换
+        Map<String, String> returnMap = new HashMap<>();
+        returnMap.put("ToUserName", fromUserName);
+        returnMap.put("FromUserName", toUserName);
+        returnMap.put("CreateTime", new Date().getTime()+"");
+        returnMap.put("MsgType", "image");
+        returnMap.put("MediaId", mediaId);
+        return XmlUtil.mapToXmlSpecial(returnMap);
+    }
+
+
+    /**
+     * 回复图文消息
+     * @param fromUserName 开发者微信号
+     * @param toUserName 接收方帐号(收到的OpenID)
+     * @param articles 图文消息信息,注意,如果图文数超过限制,则将只发限制内的条数
+     * @param title 图文消息标题
+     * @param description 图文消息描述
+     * @param picUrl 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200
+     * @param url 点击图文消息跳转链接
+     * @return
+     */
+    public static String initNews(String fromUserName, String toUserName, String articles, String title, String description, String picUrl, String url)  throws Exception{
+        // 返回消息时ToUserName的值与FromUserName的互换
+        Map<String, String> returnMap = new HashMap<>();
+        returnMap.put("ToUserName", fromUserName);
+        returnMap.put("FromUserName", toUserName);
+        returnMap.put("CreateTime", new Date().getTime()+"");
+        returnMap.put("MsgType", "news");
+        returnMap.put("ArticleCount", "1");
+        returnMap.put("Content", articles);
+        returnMap.put("Title", title);
+        returnMap.put("Description", description);
+        returnMap.put("PicUrl", picUrl);
+        returnMap.put("Url", url);
+        return XmlUtil.mapToXml(returnMap);
+    }
+
+
+}

+ 74 - 0
twzd-common/src/main/java/com/miaxis/common/utils/wx/SignUtil.java

@@ -0,0 +1,74 @@
+package com.miaxis.common.utils.wx;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+/**
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/21 16:20
+ */
+public class SignUtil {
+
+    private static String token = "twzd";// 与微信公众号上的token一致,是服务器令牌(token),这里写什么。服务器就填什么
+
+    /**
+     * 校验签名
+     *
+     * @param signature 签名
+     * @param timestamp 时间戳
+     * @param nonce     随机数
+     * @return 布尔值
+     */
+    public static boolean checkSignature(String signature, String timestamp, String nonce) {
+        String checktext = null;
+        if (null != signature) {
+            //对ToKen,timestamp,nonce 按字典排序
+            String[] paramArr = new String[]{token, timestamp, nonce};
+            Arrays.sort(paramArr);
+            //将排序后的结果拼成一个字符串
+            String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);
+            try {
+                MessageDigest md = MessageDigest.getInstance("SHA-1");
+                //对接后的字符串进行sha1加密
+                byte[] digest = md.digest(content.toString().getBytes());
+                checktext = byteToStr(digest);
+            } catch (NoSuchAlgorithmException e) {
+                e.printStackTrace();
+            }
+        }
+        //将加密后的字符串与signature进行对比
+        return checktext != null ? checktext.equals(signature.toUpperCase()) : false;
+    }
+
+    /**
+     * 将字节数组转化我16进制字符串
+     *
+     * @param byteArrays 字符数组
+     * @return 字符串
+     */
+    private static String byteToStr(byte[] byteArrays) {
+        String str = "";
+        for (int i = 0; i < byteArrays.length; i++) {
+            str += byteToHexStr(byteArrays[i]);
+        }
+        return str;
+    }
+
+    /**
+     * 将字节转化为十六进制字符串
+     *
+     * @param myByte 字节
+     * @return 字符串
+     */
+    private static String byteToHexStr(byte myByte) {
+        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+        char[] tampArr = new char[2];
+        tampArr[0] = Digit[(myByte >>> 4) & 0X0F];
+        tampArr[1] = Digit[myByte & 0X0F];
+        String str = new String(tampArr);
+        return str;
+    }
+
+}

+ 1 - 1
twzd-generator/src/main/resources/vm/java/controller.java.vm

@@ -35,7 +35,7 @@ import com.miaxis.common.core.page.ResponsePageInfo;
  */
 @RestController
 @RequestMapping("/${moduleName}/${businessName}")
-@Api(tags={"【小程序-${functionName}】"})
+@Api(tags={"【H5-${functionName}】"})
 public class ${ClassName}Controller extends BaseController{
     @Autowired
     private I${ClassName}Service ${className}Service;

+ 11 - 0
twzd-service/pom.xml

@@ -49,6 +49,17 @@
             <version>0.2.1</version>
         </dependency>
 
+        <!--谷歌二维码生成-->
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+        </dependency>
+
+        <!--hutool工具包-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
 
     </dependencies>
 

+ 1 - 1
twzd-service/src/main/java/com/miaxis/feign/dto/WxTicket.java → twzd-service/src/main/java/com/miaxis/feign/dto/WxQrTicket.java

@@ -8,7 +8,7 @@ import lombok.Data;
  * @date 2021/10/20 15:08
  */
 @Data
-public class WxTicket {
+public class WxQrTicket {
 
     private Integer expire_seconds;  //该二维码有效时间,以秒为单位。 最大不超过2592000(即30天),此字段如果不填,则默认有效期为60秒。
     private String action_name;  //二维码类型,QR_SCENE为临时的整型参数值,QR_STR_SCENE为临时的字符串参数值,QR_LIMIT_SCENE为永久的整型参数值,QR_LIMIT_STR_SCENE为永久的字符串参数值

+ 0 - 2
twzd-service/src/main/java/com/miaxis/feign/service/IWxMpService.java

@@ -5,8 +5,6 @@ import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
-import javax.servlet.annotation.HandlesTypes;
-
 /**
  * @author wwl
  * @version 1.0

+ 60 - 6
twzd-service/src/main/java/com/miaxis/feign/service/IWxSendService.java

@@ -1,11 +1,15 @@
 package com.miaxis.feign.service;
 
+import com.alibaba.fastjson.JSONObject;
 import com.miaxis.common.config.FeignConfig;
-import com.miaxis.feign.dto.WxTicket;
+import com.miaxis.feign.dto.WxQrTicket;
+import feign.Headers;
+
+import feign.Param;
+import feign.form.FormData;
 import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.*;
+
 
 /**
  * 微信公众号接口
@@ -35,11 +39,61 @@ public interface IWxSendService {
      * 生成带参数二维码接口
      *      -文档链接:https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html
      * @param accessToken
-     * @param wxTicket:二维码参数
+     * @param wxQrTicket:二维码参数
      * @return
      */
     @PostMapping(value = "/qrcode/create")
-    String generateTicket(@RequestParam("access_token")String accessToken, WxTicket wxTicket);
+    String generateTicket(@RequestParam("access_token")String accessToken, WxQrTicket wxQrTicket);
+
+
+    /**
+     * 创建菜单接口
+     *      -文档链接:https://developers.weixin.qq.com/doc/offiaccount/Custom_Menus/Creating_Custom-Defined_Menu.html
+     * @param accessToken
+     * @param jsonObject json
+     * @return
+     */
+    @PostMapping(value = "/menu/create")
+    @ResponseBody
+    String createMenu(@RequestParam("access_token")String accessToken, JSONObject jsonObject);
+
+
+    /**
+     * 新增永久图文素材
+     *      -文档链接:https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Adding_Permanent_Assets.html
+     * @param accessToken
+     * @param jsonObject json
+     * @return
+     */
+    @PostMapping(value = "/material/add_news")
+    @ResponseBody
+    String materialAddNews(@RequestParam("access_token")String accessToken, JSONObject jsonObject);
+
+
+    /**
+     * 新增其他类型永久素材
+     *      -文档链接:https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Adding_Permanent_Assets.html
+     * @param accessToken
+     * @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
+     * @param media form-data中媒体文件标识,有filename、filelength、content-type等信息
+     * @return
+     */
+    @PostMapping(value = "/material/add_material")
+    @Headers("Content-Type: multipart/form-data")
+    String materialAddByType(@RequestParam("access_token")String accessToken, @RequestParam("type")String type, @Param("photo") FormData media);
+
+
+    /**
+     * 获取用户信息
+     * @param token 调用接口凭证
+     * @param openid 普通用户的标识,对当前公众号唯一
+     * @param lang 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语
+     * @return
+     */
+    @GetMapping(value = "/user/info")
+    String userInfo(@RequestParam("access_token") String token,
+                    @RequestParam("openid") String openid,
+                    @RequestParam("lang") String lang);
 
 
 }

+ 61 - 0
twzd-service/src/main/java/com/miaxis/file/domain/FileInfo.java

@@ -0,0 +1,61 @@
+package com.miaxis.file.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.miaxis.common.annotation.Excel;
+import com.miaxis.common.core.domain.BaseBusinessEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 文件对象 file_info
+ *
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/28 14:30
+ */
+@Data
+@TableName("file_info")
+@ApiModel(value = "FileInfo", description = "文件对象 file_info")
+public class FileInfo extends BaseBusinessEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 自增id */
+    @TableId(value = "file_id")
+    @ApiModelProperty(value = "自增id")
+    private Long fileId;
+
+    /** 顺序 */
+    @Excel(name = "顺序")
+    @TableField("seq")
+    @ApiModelProperty(value = "顺序")
+    private Long seq;
+
+    /** 文件业务类型 */
+    @Excel(name = "文件业务类型")
+    @TableField("file_type")
+    @ApiModelProperty(value = "文件业务类型")
+    private String fileType;
+
+    /** 备注 */
+    @Excel(name = "备注")
+    @TableField("remark")
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    /** 文件url(访问地址) */
+    @Excel(name = "文件url(访问地址)")
+    @TableField("file_url")
+    @ApiModelProperty(value = "文件url(访问地址)")
+    private String fileUrl;
+
+    /** 文件路径 */
+    @Excel(name = "文件路径")
+    @TableField("file_path")
+    @ApiModelProperty(value = "文件路径")
+    private String filePath;
+
+
+}

+ 16 - 0
twzd-service/src/main/java/com/miaxis/file/mapper/FileInfoMapper.java

@@ -0,0 +1,16 @@
+package com.miaxis.file.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.file.domain.FileInfo;
+
+
+/**
+ * 文件Mapper接口
+ *
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/28 14:36
+ */
+public interface FileInfoMapper extends BaseMapper<FileInfo> {
+
+}

+ 15 - 0
twzd-service/src/main/java/com/miaxis/file/service/IFileInfoService.java

@@ -0,0 +1,15 @@
+package com.miaxis.file.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.file.domain.FileInfo;
+
+/**
+ * 文件Service接口
+ *
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/28 14:33
+ */
+public interface IFileInfoService extends IService<FileInfo>{
+
+}

+ 23 - 0
twzd-service/src/main/java/com/miaxis/file/service/impl/FileInfoServiceImpl.java

@@ -0,0 +1,23 @@
+package com.miaxis.file.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.miaxis.file.domain.FileInfo;
+import com.miaxis.file.mapper.FileInfoMapper;
+import com.miaxis.file.service.IFileInfoService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 文件Service业务层处理
+ *
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/28 14:35
+ */
+@Service
+@RequiredArgsConstructor
+public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements IFileInfoService {
+
+    private final  FileInfoMapper fileInfoMapper;
+
+}

+ 39 - 0
twzd-service/src/main/java/com/miaxis/spread/domain/WxSpreadRelation.java

@@ -0,0 +1,39 @@
+package com.miaxis.spread.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.miaxis.common.core.domain.BaseBusinessEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * wx推广关系对象 wx_spread_relation
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/29 9:39
+ */
+@Data
+@TableName("wx_spread_relation")
+@ApiModel(value = "WxSpreadRelation", description = "wx推广关系对象 wx_spread_relation")
+public class WxSpreadRelation extends BaseBusinessEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 主键 */
+    @TableId(value = "id")
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    @TableField("openid")
+    @ApiModelProperty(value = "用户唯一标识")
+    private String openid;
+
+    @TableField("parent_openid")
+    @ApiModelProperty(value = "用户唯一标识(父级)")
+    private String parentOpenid;
+
+    @TableField("status")
+    @ApiModelProperty(value = "状态  0:有效(默认)、1:失效 (伪删除)")
+    private String status;
+}

+ 13 - 0
twzd-service/src/main/java/com/miaxis/spread/mapper/WxSpreadRelationMapper.java

@@ -0,0 +1,13 @@
+package com.miaxis.spread.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.spread.domain.WxSpreadRelation;
+
+/**
+ * wx推广关系Mapper接口
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/29 9:41
+ */
+public interface WxSpreadRelationMapper extends BaseMapper<WxSpreadRelation> {
+}

+ 13 - 0
twzd-service/src/main/java/com/miaxis/spread/service/IWxSpreadRelationService.java

@@ -0,0 +1,13 @@
+package com.miaxis.spread.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.spread.domain.WxSpreadRelation;
+
+/**
+ * wx推广关系Service接口
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/29 9:42
+ */
+public interface IWxSpreadRelationService extends IService<WxSpreadRelation> {
+}

+ 22 - 0
twzd-service/src/main/java/com/miaxis/spread/service/impl/WxSpreadRelationServiceImpl.java

@@ -0,0 +1,22 @@
+package com.miaxis.spread.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.miaxis.spread.domain.WxSpreadRelation;
+import com.miaxis.spread.mapper.WxSpreadRelationMapper;
+import com.miaxis.spread.service.IWxSpreadRelationService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * wx推广关系Service业务层处理
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/29 9:42
+ */
+@Service
+@AllArgsConstructor
+public class WxSpreadRelationServiceImpl extends ServiceImpl<WxSpreadRelationMapper, WxSpreadRelation> implements IWxSpreadRelationService {
+
+    private final WxSpreadRelationMapper wxSpreadRelationMapper;
+
+}

+ 22 - 0
twzd-service/src/main/java/com/miaxis/user/mapper/UserInfoMapper.java

@@ -0,0 +1,22 @@
+package com.miaxis.user.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.common.core.domain.entity.UserInfo;
+
+/**
+ * 用户Mapper接口
+ *
+ * @author miaxis
+ * @date 2021-08-18
+ */
+public interface UserInfoMapper extends BaseMapper<UserInfo> {
+    /**
+     * 查询用户列表
+     *
+     * @param userInfo 用户
+     * @return 用户集合
+     */
+    public List<UserInfo> selectUserInfoList(UserInfo userInfo);
+
+}

+ 22 - 0
twzd-service/src/main/java/com/miaxis/user/service/IUserInfoService.java

@@ -0,0 +1,22 @@
+package com.miaxis.user.service;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.common.core.domain.entity.UserInfo;
+
+/**
+ * 用户Service接口
+ *
+ * @author miaxis
+ * @date 2021-08-18
+ */
+public interface IUserInfoService extends IService<UserInfo>{
+    /**
+     * 查询用户列表
+     *
+     * @param userInfo 用户
+     * @return 用户集合
+     */
+    public List<UserInfo> selectUserInfoList(UserInfo userInfo);
+}

+ 37 - 0
twzd-service/src/main/java/com/miaxis/user/service/impl/UserInfoServiceImpl.java

@@ -0,0 +1,37 @@
+package com.miaxis.user.service.impl;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.miaxis.common.core.domain.entity.UserInfo;
+import com.miaxis.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.apache.commons.lang3.StringUtils;
+import com.miaxis.user.mapper.UserInfoMapper;
+
+import com.miaxis.user.service.IUserInfoService;
+
+/**
+ * 用户Service业务层处理
+ *
+ * @author miaxis
+ * @date 2021-08-18
+ */
+@Service
+public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements IUserInfoService {
+    @Autowired
+    private UserInfoMapper userInfoMapper;
+
+    /**
+     * 查询用户列表
+     *
+     * @param userInfo 用户
+     * @return 用户
+     */
+    @Override
+    public List<UserInfo> selectUserInfoList(UserInfo userInfo){
+        return userInfoMapper.selectUserInfoList(userInfo);
+    }
+}

+ 27 - 0
twzd-service/src/main/java/com/miaxis/user/vo/UserVipInfoVO.java

@@ -0,0 +1,27 @@
+package com.miaxis.user.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+
+@Data
+public class UserVipInfoVO {
+
+
+
+    /** 微信openid */
+    @ApiModelProperty(value = "微信openid")
+    private String openid;
+
+    /** 0 否 1是 */
+
+    @ApiModelProperty(value = "是否是vip 0 否 1是")
+    private Integer isVip;
+
+
+
+    @ApiModelProperty(value = "签名")
+    private String sign;
+
+
+}

+ 141 - 0
twzd-service/src/main/java/com/miaxis/wx/domain/RefundRecord.java

@@ -0,0 +1,141 @@
+package com.miaxis.wx.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.miaxis.common.annotation.Excel;
+import com.miaxis.common.core.domain.BaseBusinessEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 微信退款记录对象 refund_record
+ *
+ * @author miaxis
+ * @date 2021-05-18
+ */
+@Data
+@TableName("refund_record")
+@ApiModel(value = "RefundRecord", description = "微信退款记录对象 refund_record")
+public class RefundRecord extends BaseBusinessEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 记录id */
+    @TableId(value = "id")
+    @ApiModelProperty(value = "记录id")
+    private Long id;
+
+    /** 微信支付退款号 */
+    @Excel(name = "微信支付退款号")
+    @TableField("refund_id")
+    @ApiModelProperty(value = "微信支付退款号")
+    private String refundId;
+
+    /** 退款单号 */
+    @Excel(name = "退款单号")
+    @TableField("out_refund_no")
+    @ApiModelProperty(value = "退款单号")
+    private String outRefundNo;
+
+    /** 微信支付订单号 */
+    @Excel(name = "微信支付订单号")
+    @TableField("transaction_id")
+    @ApiModelProperty(value = "微信支付订单号")
+    private String transactionId;
+
+    /** 商户订单号 */
+    @Excel(name = "商户订单号")
+    @TableField("out_trade_no")
+    @ApiModelProperty(value = "商户订单号")
+    private String outTradeNo;
+
+    /** 枚举值:
+ORIGINAL:原路退款
+BALANCE:退回到余额
+OTHER_BALANCE:原账户异常退到其他余额账户
+OTHER_BANKCARD:原银行卡异常退到其他银行卡
+示例值:ORIGINAL */
+    @Excel(name = "枚举值: ORIGINAL:原路退款 BALANCE:退回到余额 OTHER_BALANCE:原账户异常退到其他余额账户 OTHER_BANKCARD:原银行卡异常退到其他银行卡 示例值:ORIGINAL")
+    @TableField("channel")
+    @ApiModelProperty(value = "枚举值: ORIGINAL:原路退款 BALANCE:退回到余额 OTHER_BALANCE:原账户异常退到其他余额账户 OTHER_BANKCARD:原银行卡异常退到其他银行卡 示例值:ORIGINAL")
+    private String channel;
+
+    /** 退款入账账户 */
+    @Excel(name = "退款入账账户")
+    @TableField("user_received_account")
+    @ApiModelProperty(value = "退款入账账户")
+    private String userReceivedAccount;
+
+    /** 退款成功时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "退款成功时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @TableField("success_time")
+    @ApiModelProperty(value = "退款成功时间")
+    private Date successTime;
+
+    /** 退款状态枚举值:SUCCESS:退款成功CLOSED:退款关闭PROCESSING:退款处理中ABNORMAL:退款异常 */
+    @Excel(name = "退款状态 枚举值: SUCCESS:退款成功 CLOSED:退款关闭 PROCESSING:退款处理中 ABNORMAL:退款异常")
+    @TableField("status")
+    @ApiModelProperty(value = "退款状态 枚举值: SUCCESS:退款成功 CLOSED:退款关闭 PROCESSING:退款处理中 ABNORMAL:退款异常")
+    private String status;
+
+    /** 资金账户 */
+    @Excel(name = "资金账户")
+    @TableField("funds_account")
+    @ApiModelProperty(value = "资金账户")
+    private String fundsAccount;
+
+    /** 订单总金额,单位为分。
+示例值:100 */
+    @Excel(name = "订单总金额,单位为分。 示例值:100")
+    @TableField("total")
+    @ApiModelProperty(value = "订单总金额,单位为分。 示例值:100")
+    private Integer total;
+
+    /** 退款标价金额,单位为分 */
+    @Excel(name = "退款标价金额,单位为分")
+    @TableField("refund")
+    @ApiModelProperty(value = "退款标价金额,单位为分")
+    private Integer refund;
+
+    /** 现金支付金额 */
+    @Excel(name = "现金支付金额")
+    @TableField("payer_total")
+    @ApiModelProperty(value = "现金支付金额")
+    private Integer payerTotal;
+
+    /** 退款给用户的金额,不包含所有优惠券金额 */
+    @Excel(name = "退款给用户的金额,不包含所有优惠券金额")
+    @TableField("payer_refund")
+    @ApiModelProperty(value = "退款给用户的金额,不包含所有优惠券金额")
+    private Integer payerRefund;
+
+    /** 去掉非充值代金券退款金额后的退款金额 */
+    @Excel(name = "去掉非充值代金券退款金额后的退款金额")
+    @TableField("settlement_refund")
+    @ApiModelProperty(value = "去掉非充值代金券退款金额后的退款金额")
+    private Integer settlementRefund;
+
+    /** 应结订单金额=订单金额-免充值代金券金额 */
+    @Excel(name = "应结订单金额=订单金额-免充值代金券金额")
+    @TableField("settlement_total")
+    @ApiModelProperty(value = "应结订单金额=订单金额-免充值代金券金额")
+    private Integer settlementTotal;
+
+    /** 优惠退款金额&lt;=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见 */
+    @Excel(name = "优惠退款金额&lt;=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见")
+    @TableField("discount_refund")
+    @ApiModelProperty(value = "优惠退款金额&lt;=退款金额,退款金额-代金券或立减优惠退款金额为现金,说明详见")
+    private Integer discountRefund;
+
+    /** 符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。 */
+    @Excel(name = "符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。")
+    @TableField("currency")
+    @ApiModelProperty(value = "符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。")
+    private String currency;
+
+}

+ 69 - 0
twzd-service/src/main/java/com/miaxis/wx/domain/WxMenu.java

@@ -0,0 +1,69 @@
+package com.miaxis.wx.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.miaxis.common.core.domain.BaseBusinessEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 微信公众号菜单对象 wx_menu
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/26 10:06
+ */
+@Data
+@TableName("wx_menu")
+@ApiModel(value = "WxMenu", description = "微信公众号菜单对象 wx_menu")
+public class WxMenu extends BaseBusinessEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 主键 */
+    @TableId(value = "id")
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    @TableField("parent_id")
+    @ApiModelProperty(value = "父节点")
+    private Integer parentId;
+
+    @TableField("type")
+    @ApiModelProperty(value = "菜单的响应动作类型,view表示网页类型,click表示点击类型,miniprogram表示小程序类型")
+    private String type;
+
+    @TableField("menu_name")
+    @ApiModelProperty(value = "菜单标题")
+    private String menuName;
+
+    @TableField("click_key")
+    @ApiModelProperty(value = "click等点击类型必须,菜单KEY值,用于消息接口推送,不超过128字节")
+    private String clickKey;
+
+    @TableField("url")
+    @ApiModelProperty(value = "view、miniprogram类型必须,网页 链接,用户点击菜单可打开链接,不超过1024字节。 type为miniprogram时,不支持小程序的老版本客户端将打开本url。")
+    private String url;
+
+    @TableField("media_id")
+    @ApiModelProperty(value = "media_id类型和view_limited类型必须,调用新增永久素材接口返回的合法media_id")
+    private String mediaId;
+
+    @TableField("appid")
+    @ApiModelProperty(value = "miniprogram类型必须,小程序的appid(仅认证公众号可配置)")
+    private String appid;
+
+    @TableField("page_path")
+    @ApiModelProperty(value = "miniprogram类型必须,小程序的页面路径")
+    private String pagePath;
+
+    @TableField("article_id")
+    @ApiModelProperty(value = "发布后获得的合法 article_id")
+    private String articleId;
+
+    @TableField("sort")
+    @ApiModelProperty(value = "排序")
+    private Integer sort;
+
+}

+ 166 - 0
twzd-service/src/main/java/com/miaxis/wx/domain/WxOrder.java

@@ -0,0 +1,166 @@
+package com.miaxis.wx.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.miaxis.common.annotation.Excel;
+import com.miaxis.common.core.domain.BaseBusinessEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 电影订单对象 film_order
+ *
+ * @author miaxis
+ * @date 2021-05-07
+ */
+@Data
+@TableName("wx_order")
+@ApiModel(value = "WxOrder", description = "微信订单对象 wx_order")
+public class WxOrder extends BaseBusinessEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** id */
+    @TableId(value = "id")
+    @ApiModelProperty(value = "id")
+    private Long id;
+
+    /** 商户订单号 */
+    @Excel(name = "商户订单号")
+    @TableField("out_trade_no")
+    @ApiModelProperty(value = "商户订单号")
+    private String outTradeNo;
+
+    /** 退款单号 */
+    @Excel(name = "退款单号")
+    @TableField("out_refund_no")
+    @ApiModelProperty(value = "退款单号")
+    private String outRefundNo;
+
+    /** 退款原因 */
+    @Excel(name = "退款原因")
+    @TableField("refund_reason")
+    @ApiModelProperty(value = "退款原因")
+    private String refundReason;
+
+
+    /** 微信支付系统生成的订单号 */
+    @Excel(name = "微信支付系统生成的订单号")
+    @TableField("transaction_id")
+    @ApiModelProperty(value = "微信支付系统生成的订单号")
+    private String transactionId;
+
+    /** 交易类型,枚举值 */
+    @Excel(name = "交易类型,枚举值")
+    @TableField("trade_type")
+    @ApiModelProperty(value = "交易类型,枚举值")
+    private String tradeType;
+
+    /** 交易状态,枚举值:
+        SUCCESS:支付成功
+        REFUND:转入退款
+        NOTPAY:未支付
+        CLOSED:已关闭
+        REVOKED:已撤销(付款码支付)
+        USERPAYING:用户支付中(付款码支付)
+        PAYERROR:支付失败(其他原因,如银行返回失败)
+        ACCEPT:已接收,等待扣款 */
+    @TableField("trade_state")
+    @ApiModelProperty(value = "交易状态,枚举值: SUCCESS:支付成功 REFUND:转入退款 NOTPAY:" +
+            "未支付 CLOSED:已关闭 REVOKED:已撤销(付款码支付) " +
+            "USERPAYING:用户支付中(付款码支付) PAYERROR:支付失败(其他原因,如银行返回失败) ACCEPT:已接收,等待扣款")
+    private String tradeState;
+    /** 交易状态描述 */
+    @Excel(name = "交易状态描述")
+    @TableField("trade_state_desc")
+    @ApiModelProperty(value = "交易状态描述")
+    private String tradeStateDesc;
+
+    /** 银行类型 */
+    @Excel(name = "银行类型")
+    @TableField("bank_type")
+    @ApiModelProperty(value = "银行类型")
+    private String bankType;
+
+    /** 附加数据 */
+    @Excel(name = "附加数据")
+    @TableField("attach")
+    @ApiModelProperty(value = "附加数据")
+    private String attach;
+
+    /** 支付完成时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "支付完成时间", width = 30, dateFormat = "yyyy-MM-dd")
+    @TableField("success_time")
+    @ApiModelProperty(value = "支付完成时间")
+    private Date successTime;
+
+    /** 用户在直连商户appid下的唯一标识 */
+    @Excel(name = "用户在直连商户appid下的唯一标识")
+    @TableField("openid")
+    @ApiModelProperty(value = "用户在直连商户appid下的唯一标识")
+    private String openid;
+
+    /** 商品名称 */
+    @Excel(name = "商品类型")
+    @TableField("goods_type")
+    @ApiModelProperty(value = "商品类型,具体查看字典定义.")
+    private String goodsType;
+
+    /** 商品名称 */
+    @Excel(name = "商品图片地址")
+    @TableField("goods_picture_url")
+    @ApiModelProperty(value = "商品图片地址")
+    private String goodsPictureUrl;
+
+    /** 订单总金额,单位为分。 */
+    @Excel(name = "订单总金额,单位为分。")
+    @TableField("total")
+    @ApiModelProperty(value = "订单总金额,单位为分。")
+    private Integer total;
+
+    /** 用户支付金额,单位为分。 */
+    @Excel(name = "用户支付金额,单位为分。")
+    @TableField("payer_total")
+    @ApiModelProperty(value = "用户支付金额,单位为分。")
+    private Integer payerTotal;
+
+    /** CNY:人民币,境内商户号仅支持人民币。 */
+    @Excel(name = "CNY:人民币,境内商户号仅支持人民币。")
+    @TableField("currency")
+    @ApiModelProperty(value = "CNY:人民币,境内商户号仅支持人民币。")
+    private String currency;
+
+    /** 用户支付币种 */
+    @Excel(name = "用户支付币种")
+    @TableField("payer_currency")
+    @ApiModelProperty(value = "用户支付币种")
+    private String payerCurrency;
+
+    /** 商户端设备号 */
+    @Excel(name = "商户端设备号")
+    @TableField("device_id")
+    @ApiModelProperty(value = "商户端设备号")
+    private String deviceId;
+
+
+    /** 商户端设备号 */
+    @Excel(name = "订单数据详情")
+    @TableField("order_data_json")
+    @ApiModelProperty(value = "订单数据详情")
+    private String orderDataJson;
+
+    /** 订单状态 */
+    @Excel(name = "订单数据详情")
+    @TableField("order_status")
+    @ApiModelProperty(value = "订单状态: 1 -进行中 2-购买成功 3-购买失败")
+    private String orderStatus;
+
+
+
+
+}

+ 47 - 0
twzd-service/src/main/java/com/miaxis/wx/domain/WxTicket.java

@@ -0,0 +1,47 @@
+package com.miaxis.wx.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.miaxis.common.core.domain.BaseBusinessEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 微信推广二维码对象 wx_ticket
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/28 16:22
+ */
+@Data
+@TableName("wx_ticket")
+@ApiModel(value = "WxQrTicket", description = "微信推广二维码对象 wx_ticket")
+public class WxTicket extends BaseBusinessEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 主键 */
+    @TableId(value = "id")
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    @TableField("openid")
+    @ApiModelProperty(value = "用户唯一标识(微信)")
+    private String openid;
+
+    @TableField("ticket")
+    @ApiModelProperty(value = "获取的二维码ticket")
+    private String ticket;
+
+    @TableField("ticket_file_id")
+    @ApiModelProperty(value = "永久二维码图片id(关联file_info文件表)")
+    private Long ticketFileId;
+
+    @TableField("media_id")
+    @ApiModelProperty(value = "微信永久素材media_id(可根据接口获取图片、视频、语音等)")
+    private String mediaId;
+
+    @TableField("status")
+    @ApiModelProperty(value = "状态  0:有效(默认)、1:失效 (伪删除)")
+    private String status;
+}

+ 10 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/AiOrderNotifyDTO.java

@@ -0,0 +1,10 @@
+package com.miaxis.wx.dto;
+
+public class AiOrderNotifyDTO {
+
+    String time;
+    String appid;
+    String request;
+    String response;
+
+}

+ 27 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/CinemaData.java

@@ -0,0 +1,27 @@
+package com.miaxis.wx.dto;
+
+
+import lombok.Data;
+
+
+/**
+ * 排期数据
+ */
+@Data
+public class CinemaData {
+    Integer netPrice;
+    String planType;
+    String showTime;
+    String language;
+    Integer duration;
+    String showId;
+    String stopSellTime;
+    Integer cinemaId;
+    String cinemaName;
+    Integer filmId;
+    String scheduleArea;
+    String filmName;
+    String hallName;
+    String showVersionType;
+
+}

+ 50 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/FilmWxpayRefundDTO.java

@@ -0,0 +1,50 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 微信支付退款 dto
+ */
+@Data
+public class FilmWxpayRefundDTO {
+    private static final long serialVersionUID = 1L;
+
+
+    @ApiModelProperty(value = "商户订单号")
+    private String out_trade_no;
+
+    @ApiModelProperty(value = "商户系统内部的退款单号")
+    private String out_refund_no;
+
+
+    @ApiModelProperty(value = "原因")
+    private String reason;
+
+
+    @ApiModelProperty(value = "是否允许调座,1-允许,0-不允许")
+    private WxpaySource resource;
+
+    @ApiModelProperty(value = "回调摘要")
+    private String summary;
+
+
+    @Data
+    public class WxpaySource{
+        @ApiModelProperty(value = "对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM")
+        private String algorithm;
+        @ApiModelProperty(value = "Base64编码后的开启/停用结果数据密文")
+        private String ciphertext;
+        @ApiModelProperty(value = "附加数据")
+        private String associated_data;
+        @ApiModelProperty(value = "原始回调类型,为transaction")
+        private String original_type;
+        @ApiModelProperty(value = "加密使用的随机串")
+        private String nonce;
+
+
+    }
+
+
+
+}

+ 46 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/PcWxOrderListDTO.java

@@ -0,0 +1,46 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class PcWxOrderListDTO {
+    private static final long serialVersionUID = 1L;
+
+
+
+    @ApiModelProperty(value = "商户订单号")
+    private String  outTradeNo;
+
+    @ApiModelProperty(value = "开始时间,格式yyyyMMdd")
+//    @JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
+    private String startTime;
+
+
+    @ApiModelProperty(value = "结束时间,格式yyyyMMdd")
+//    @JsonFormat(pattern="yyyyMMdd",timezone = "GMT+8")
+    private String endTime;
+
+
+    @ApiModelProperty(value = "商品类型")
+    private String  goodsType;
+
+
+//
+//    @ApiModelProperty(value = "支付状态: 交易状态,枚举值:\n" +
+//            "SUCCESS:支付成功\n" +
+//            "REFUND:转入退款\n" +
+//            "NOTPAY:未支付\n" +
+//            "CLOSED:已关闭\n" +
+//            "REVOKED:已撤销(付款码支付)\n" +
+//            "USERPAYING:用户支付中(付款码支付)\n" +
+//            "PAYERROR:支付失败(其他原因,如银行返回失败)\n" +
+//            "ACCEPT:已接收,等待扣款")
+//    private String  tradeState;
+
+    @ApiModelProperty(value = "订单状态: 1 -进行中 2-购买成功 3-购买失败")
+    private String  orderStatus;
+
+
+
+}

+ 70 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxFuluOrderDetailDTO.java

@@ -0,0 +1,70 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 福禄订单详情
+ */
+@Data
+public class WxFuluOrderDetailDTO {
+    private static final long serialVersionUID = 1L;
+
+
+
+    @ApiModelProperty(value = "福禄开放平台订单号")
+    private String order_id;
+
+    @ApiModelProperty(value = "合作商家订单号")
+    private String customer_order_no;
+
+    @ApiModelProperty(value = "充值描述")
+    private String recharge_description;
+
+    @ApiModelProperty(value = "运营商流水号")
+    private String operator_serial_number;
+
+
+    @ApiModelProperty(value = "商品Id")
+    private String product_id;
+
+    @ApiModelProperty(value = "商品名称")
+    private String product_name;
+
+    @ApiModelProperty(value = "创建时间,格式为:yyyy-MM-dd HH:mm:ss")
+    private String create_time;
+
+    @ApiModelProperty(value = "交易完成时间,格式为:yyyy-MM-dd HH:mm:ss")
+    private String charge_finish_time;
+
+
+    @ApiModelProperty(value = "充值账号")
+    private String charge_account;
+
+
+
+    @ApiModelProperty(value = "购买数量")
+    private Integer buy_num;
+
+    @ApiModelProperty(value = "订单类型:1-话费 2-流量 3-卡密 4-直充")
+    private Integer order_type;
+
+    @ApiModelProperty(value = "交易单价")
+    private Double order_price;
+
+
+    @ApiModelProperty(value = "订单状态: (success:成功,processing:处理中,failed:失败,untreated:未处理)")
+    private String order_status;
+
+    @ApiModelProperty(value = "签名")
+    private String sign;
+
+
+
+
+
+
+
+
+
+}

+ 55 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxFuluOrderNotifyDTO.java

@@ -0,0 +1,55 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 微信支付回调 dto
+ */
+@Data
+public class WxFuluOrderNotifyDTO {
+    private static final long serialVersionUID = 1L;
+
+
+
+    @ApiModelProperty(value = "福禄开放平台订单号")
+    private String order_id;
+
+
+    @ApiModelProperty(value = "交易完成时间,格式为:yyyy-MM-dd HH:mm:ss")
+    private String charge_finish_time;
+
+
+    @ApiModelProperty(value = "合作商家订单号")
+    private String customer_order_no;
+
+    @ApiModelProperty(value = "订单状态")
+    private String order_status;
+
+
+    @ApiModelProperty(value = "充值描述")
+    private String recharge_description;
+
+
+    @ApiModelProperty(value = "商品Id")
+    private String product_id;
+
+    @ApiModelProperty(value = "购买数量")
+    private String buy_num;
+
+    @ApiModelProperty(value = "运营商流水号")
+    private String operator_serial_number;
+
+
+    @ApiModelProperty(value = "签名")
+    private String sign;
+
+
+
+
+
+
+
+
+
+}

+ 9 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxNotifyReturnDTO.java

@@ -0,0 +1,9 @@
+package com.miaxis.wx.dto;
+
+import lombok.Data;
+
+@Data
+public class WxNotifyReturnDTO {
+    String code;
+    String message;
+}

+ 53 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderCreateDTO.java

@@ -0,0 +1,53 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class WxOrderCreateDTO {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "购票类型: 1-竞价购票 2-秒出票" ,required=true,allowableValues ="1,2")
+    private int ticketType;
+
+    @ApiModelProperty(value = "总金额, 单位分")
+    private int total;
+
+    @ApiModelProperty(value = "排期的showId,由影院接口得来")
+    private String showId;
+
+    /** 商品名称 */
+//    @ApiModelProperty(value = "商品类型")
+//    private String goodsType;
+
+    /** 商品名称 */
+    @ApiModelProperty(value = "商品图片地址")
+    private String goodsPictureUrl;
+
+    @ApiModelProperty(value = "影院id")
+    private String cinemaId;
+
+    @ApiModelProperty(value = "用户所选的座位,例:1排1座,1排2座 以英文的逗号 “ , “隔开。 如果座位是情侣座,请传入 : 1排1座(情侣座),1排2座(情侣座)")
+    private String seat;
+
+    @ApiModelProperty(value = "商家订单id")
+    private String thirdOrderId;
+
+    @ApiModelProperty(value = "预留的手机号")
+    private String reservedPhone;
+
+
+    @ApiModelProperty(value = "是否允许调座,1-允许,0-不允许")
+    private Integer acceptChangeSeat;
+
+    @ApiModelProperty(value = "座位接口的seatId字段, 如果有多个,则以竖线分割")
+    private String seatId;
+
+
+    @ApiModelProperty(value = "座位接口的seatNo字段,如果有多个,则以竖线分割")
+    private String seatNo;
+
+
+
+
+}

+ 31 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderCreateFuluDTO.java

@@ -0,0 +1,31 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class WxOrderCreateFuluDTO {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "商品编号")
+    private Integer product_id;
+
+    @ApiModelProperty(value = "外部订单号",hidden = true)
+    private String customer_order_no;
+
+    @ApiModelProperty(value = "充值账号")
+    private String charge_account;
+
+    /** 商品名称 */
+    @ApiModelProperty(value = "购买数量")
+    private Integer buy_num;
+
+    @ApiModelProperty(value = "商品图片地址")
+    private String goodsPictureUrl;
+
+
+
+
+
+
+}

+ 28 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderCreatePhoneBillDTO.java

@@ -0,0 +1,28 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class WxOrderCreatePhoneBillDTO {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "天猫订单号")
+    private String tmallNo;
+
+    @ApiModelProperty(value = "充值号码")
+    private String rechargePhoneNo;
+
+    @ApiModelProperty(value = "运营商:1-移动 2-联通 3-电信")
+    private Integer operators;
+
+
+    @ApiModelProperty(value = "商品图片地址")
+    private String goodsPictureUrl;
+
+
+
+
+
+
+}

+ 19 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderDTO.java

@@ -0,0 +1,19 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class WxOrderDTO {
+    private static final long serialVersionUID = 1L;
+
+
+
+    @ApiModelProperty(value = "商品字典编码",required = true)
+    private Long dictCode;
+
+
+
+
+
+}

+ 26 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderListDTO.java

@@ -0,0 +1,26 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class WxOrderListDTO {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "近几天的天数")
+    private Integer days;
+
+
+    @ApiModelProperty(value = "openid",hidden = true)
+    private String  openid;
+
+    @ApiModelProperty(value = "商品类型",hidden = true)
+    private String  goodsType;
+
+
+    @ApiModelProperty(value = "订单状态: 1 -进行中 2-购买成功 3-购买失败")
+    private String  orderStatus;
+
+
+
+}

+ 55 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxOrderNotifyDTO.java

@@ -0,0 +1,55 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 微信支付回调 dto
+ */
+@Data
+public class WxOrderNotifyDTO {
+    private static final long serialVersionUID = 1L;
+
+
+
+    @ApiModelProperty(value = "时间戳")
+    private String time;
+
+
+    @ApiModelProperty(value = "订单状态发生变更时的事件如: ORDER_CLOSE")
+    private String eventName;
+
+
+    @ApiModelProperty(value = "接入方下单时的订单号")
+    private String thirdOrderId;
+
+    @ApiModelProperty(value = "回调地址,各个场景发生时,将通过此地址通知接入方")
+    private String notifyUrl;
+
+
+
+
+    @ApiModelProperty(value = "api下单成本价(竞价结束回调通知返回:WAIT_TICKET场景)")
+    private String orderPrice;
+
+
+    @ApiModelProperty(value = "如果事件为订单关闭 ORDER_CLOSE 则有此字段")
+    private String closeCause;
+
+    @ApiModelProperty(value = "实际出票座位,仅供参考,可能与票不一样,也可能为空,一般当实际座位与下单座位不一样时会有")
+    private String realSeat;
+
+
+
+    @ApiModelProperty(value = "取票码字符串如: “[\\”123123\\”,\\”4564357\\”]” 直接用json解析可得到数组,如取票失败则用使用原始截图")
+    private String ticketCode;
+
+    @ApiModelProperty(value = "取票码原始截图如: “[\\”http:\\\\/\\\\/shoutudyp.oss-cn-shenzhen.aliyuncs.com\\\\/b768007aa9071eba3e3018a27dcc47c0.png\\”,\\”http:\\\\/\\\\/shoutudyp.oss-cn-shenzhen.aliyuncs.com\\\\/f9774915e35fae41ae96ebf288477394.jpg\\”]” 直接用json解析可得到数组")
+    private String ticketImage;
+
+
+
+
+
+
+}

+ 52 - 0
twzd-service/src/main/java/com/miaxis/wx/dto/WxpayNotifyDTO.java

@@ -0,0 +1,52 @@
+package com.miaxis.wx.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 微信支付回调 dto
+ */
+@Data
+public class WxpayNotifyDTO {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "通知的唯一ID")
+    private String id;
+
+    @ApiModelProperty(value = "创建的时间,rfc3339标准格式")
+    private String create_time;
+
+    @ApiModelProperty(value = "通知的类型,支付成功通知的类型为TRANSACTION.SUCCESS")
+    private String event_type;
+
+
+    @ApiModelProperty(value = "通知的资源数据类型")
+    private String resource_type;
+
+
+    @ApiModelProperty(value = "数据资源")
+    private WxpaySource resource;
+
+    @ApiModelProperty(value = "回调摘要")
+    private String summary;
+
+
+    @Data
+    public class WxpaySource{
+        @ApiModelProperty(value = "对开启结果数据进行加密的加密算法,目前只支持AEAD_AES_256_GCM")
+        private String algorithm;
+        @ApiModelProperty(value = "Base64编码后的开启/停用结果数据密文")
+        private String ciphertext;
+        @ApiModelProperty(value = "附加数据")
+        private String associated_data;
+        @ApiModelProperty(value = "原始回调类型,为transaction")
+        private String original_type;
+        @ApiModelProperty(value = "加密使用的随机串")
+        private String nonce;
+
+
+    }
+
+
+
+}

+ 24 - 0
twzd-service/src/main/java/com/miaxis/wx/mapper/RefundRecordMapper.java

@@ -0,0 +1,24 @@
+package com.miaxis.wx.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.wx.domain.RefundRecord;
+
+import java.util.List;
+
+/**
+ * 微信退款记录Mapper接口
+ *
+ * @author miaxis
+ * @date 2021-05-18
+ */
+public interface RefundRecordMapper extends BaseMapper<RefundRecord> {
+    /**
+     * 查询微信退款记录列表
+     *
+     * @param refundRecord 微信退款记录
+     * @return 微信退款记录集合
+     */
+    public List<RefundRecord> selectRefundRecordList(RefundRecord refundRecord);
+
+    RefundRecord getByRefundId(String refundId);
+}

+ 23 - 0
twzd-service/src/main/java/com/miaxis/wx/mapper/WxMenuMapper.java

@@ -0,0 +1,23 @@
+package com.miaxis.wx.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.wx.domain.WxMenu;
+import com.miaxis.wx.vo.WxMenuVo;
+
+import java.util.List;
+
+/**
+ * 微信公众号菜单Mapper接口
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/26 10:12
+ */
+public interface WxMenuMapper extends BaseMapper<WxMenu> {
+
+    /**
+     * 查询微信公众号菜单列表
+     * @return 微信公众号菜单集合
+     */
+    List<WxMenuVo> selectWxMenuList();
+
+}

+ 30 - 0
twzd-service/src/main/java/com/miaxis/wx/mapper/WxOrderMapper.java

@@ -0,0 +1,30 @@
+package com.miaxis.wx.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.wx.domain.WxOrder;
+import com.miaxis.wx.dto.PcWxOrderListDTO;
+import com.miaxis.wx.dto.WxOrderListDTO;
+
+import java.util.List;
+
+/**
+ * 电影订单Mapper接口
+ *
+ * @author miaxis
+ * @date 2021-05-07
+ */
+public interface WxOrderMapper extends BaseMapper<WxOrder> {
+    /**
+     * 查询电影订单列表
+     *
+     * @param wxOrder 电影订单
+     * @return 电影订单集合
+     */
+    public List<WxOrder> selectWxOrderList(WxOrder wxOrder);
+
+    WxOrder getByOutTradeNo(String outTradeNo);
+
+    List<WxOrder> selectOrderList(WxOrderListDTO wxOrderListDTO);
+
+    List<WxOrder> selectPcOrderList(PcWxOrderListDTO pcWxOrderListDTO);
+}

+ 13 - 0
twzd-service/src/main/java/com/miaxis/wx/mapper/WxTicketMapper.java

@@ -0,0 +1,13 @@
+package com.miaxis.wx.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.miaxis.wx.domain.WxTicket;
+
+/**
+ * 微信推广二维码Mapper接口
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/28 16:31
+ */
+public interface WxTicketMapper extends BaseMapper<WxTicket> {
+}

+ 28 - 0
twzd-service/src/main/java/com/miaxis/wx/service/IRefundRecordService.java

@@ -0,0 +1,28 @@
+package com.miaxis.wx.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.wx.domain.RefundRecord;
+import com.miaxis.wx.domain.WxOrder;
+import com.miaxis.wx.dto.WxNotifyReturnDTO;
+
+import java.util.List;
+
+/**
+ * 微信退款记录Service接口
+ *
+ * @author miaxis
+ * @date 2021-05-18
+ */
+public interface IRefundRecordService extends IService<RefundRecord>{
+    /**
+     * 查询微信退款记录列表
+     *
+     * @param refundRecord 微信退款记录
+     * @return 微信退款记录集合
+     */
+    public List<RefundRecord> selectRefundRecordList(RefundRecord refundRecord);
+
+    RefundRecord getByRefundId(String refundId);
+
+    WxNotifyReturnDTO refund(WxOrder wxOrder, String refundCode, String failCause) throws Exception;
+}

+ 15 - 0
twzd-service/src/main/java/com/miaxis/wx/service/IWxGzhService.java

@@ -1,6 +1,11 @@
 package com.miaxis.wx.service;
 
+import com.alibaba.fastjson.JSONObject;
+
+import javax.servlet.http.HttpServletRequest;
+
 /**
+ * 微信公众号服务
  * @author wwl
  * @version 1.0
  * @date 2021/10/20 14:56
@@ -12,4 +17,14 @@ public interface IWxGzhService {
      * @return
      */
     String getGzhToken();
+
+
+    /**
+     * 微信推送消息处理
+     */
+    String handlePublicMsg(HttpServletRequest request);
+
+
+
+
 }

+ 48 - 0
twzd-service/src/main/java/com/miaxis/wx/service/IWxMenuService.java

@@ -0,0 +1,48 @@
+package com.miaxis.wx.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.wx.domain.WxMenu;
+import com.miaxis.wx.vo.WxMenuVo;
+
+import java.util.List;
+
+/**
+ * 微信公众号菜单Service接口
+ * @author wwl
+ * @version 1.0
+ * @date 2021/11/3 9:23
+ */
+public interface IWxMenuService extends IService<WxMenu> {
+
+    /**
+     * 查询微信公众号菜单列表
+     *
+     * @return 微信公众号菜单集合
+     */
+    Response<List<WxMenuVo>> selectWxMenuTreeList();
+
+    /**
+     * 新增微信公众号菜单
+     * @param wxMenu
+     * @return
+     */
+    Response saveMenu(WxMenu wxMenu);
+
+
+    /**
+     * 修改微信公众号菜单
+     * @param wxMenu
+     * @return
+     */
+    Response updateMenuById(WxMenu wxMenu);
+
+    /**
+     * 删除微信公众号菜单
+     * @param ids
+     * @return
+     */
+    Response removeMenuByIds(Long[] ids);
+}

+ 31 - 0
twzd-service/src/main/java/com/miaxis/wx/service/IWxMessageEvenService.java

@@ -0,0 +1,31 @@
+package com.miaxis.wx.service;
+
+/**
+ * 微信消息事件处理
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/27 14:33
+ */
+public interface IWxMessageEvenService {
+
+    //关注事件
+//    String subscribeEvent();
+
+    /**
+     * 扫码关注事件
+     * @param fromUserName 发送方帐号(一个OpenID)
+     * @param ticket 二维码的ticket
+     * @return
+     */
+    String scanSubscribeEvent(String fromUserName,String ticket);
+
+    /**
+     * click获取分销二维码事件
+     * @param fromUserName 发送方帐号(一个OpenID)
+     * @param token 凭证
+     * @return
+     */
+    String gainTicketEvent(String fromUserName,String token);
+
+
+}

+ 17 - 0
twzd-service/src/main/java/com/miaxis/wx/service/IWxOrderService.java

@@ -0,0 +1,17 @@
+package com.miaxis.wx.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.wx.domain.WxOrder;
+
+/**
+ */
+public interface IWxOrderService extends IService<WxOrder>{
+
+
+
+    void createVipOrder(WxOrder order);
+
+    WxOrder getByOutTradeNo(String outTradeNo);
+
+
+}

+ 13 - 0
twzd-service/src/main/java/com/miaxis/wx/service/IWxTicketService.java

@@ -0,0 +1,13 @@
+package com.miaxis.wx.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.miaxis.wx.domain.WxTicket;
+
+/**
+ * 微信推广二维码Service接口
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/28 16:24
+ */
+public interface IWxTicketService extends IService<WxTicket> {
+}

+ 11 - 0
twzd-service/src/main/java/com/miaxis/wx/service/WxService.java

@@ -30,4 +30,15 @@ public interface WxService {
             @RequestParam("code") String code,
             @RequestParam("grant_type") String grantType);
 
+
+    /**
+     * 获取用户信息
+     */
+    @GetMapping(value = "/sns/userinfo")
+    String getUserInfo(
+            @RequestParam("lang") String lang,
+            @RequestParam("access_token") String accessToken,
+            @RequestParam("openid") String openid
+    );
+
 }

+ 121 - 0
twzd-service/src/main/java/com/miaxis/wx/service/impl/RefundRecordServiceImpl.java

@@ -0,0 +1,121 @@
+package com.miaxis.wx.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.miaxis.common.config.WxpayConfig;
+import com.miaxis.common.exception.CustomException;
+import com.miaxis.wx.domain.RefundRecord;
+import com.miaxis.wx.domain.WxOrder;
+import com.miaxis.wx.dto.WxNotifyReturnDTO;
+import com.miaxis.wx.mapper.RefundRecordMapper;
+import com.miaxis.wx.service.IRefundRecordService;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.util.EntityUtils;
+import org.joda.time.DateTime;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 微信退款记录Service业务层处理
+ *
+ * @author miaxis
+ * @date 2021-05-18
+ */
+@Service
+public class RefundRecordServiceImpl extends ServiceImpl<RefundRecordMapper, RefundRecord> implements IRefundRecordService {
+    @Resource
+    private RefundRecordMapper refundRecordMapper;
+
+    @Autowired
+    private HttpClient httpClient;
+
+
+    @Autowired
+    private WxpayConfig wxpayConfig;
+    /**
+     * 查询微信退款记录列表
+     *
+     * @param refundRecord 微信退款记录
+     * @return 微信退款记录
+     */
+    @Override
+    public List<RefundRecord> selectRefundRecordList(RefundRecord refundRecord){
+        return refundRecordMapper.selectRefundRecordList(refundRecord);
+    }
+
+    @Override
+    public WxNotifyReturnDTO refund(WxOrder wxOrder, String refundCode,String failCause) throws Exception{
+        if (failCause.length()>80){
+            failCause = "购买失败,详情请在小程序查看";
+        }
+        HttpPost httpPost = new HttpPost(wxpayConfig.getV3urlRefund());
+        httpPost.addHeader("Accept", "application/json");
+        httpPost.addHeader("Content-type","application/json; charset=utf-8");
+        ObjectMapper objectMapper = new ObjectMapper();
+        ObjectNode rootNode = objectMapper.createObjectNode();
+        rootNode.put("out_trade_no", wxOrder.getOutTradeNo())
+                .put("out_refund_no", refundCode)
+                .put("reason", failCause)
+                .put("notify_url",wxpayConfig.getNotifyUrlRefund());
+        rootNode.putObject("amount")
+                .put("refund", wxOrder.getTotal())
+                .put("total", wxOrder.getTotal())
+                .put("currency", wxOrder.getCurrency());
+
+//        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+//        objectMapper.writeValue(bos, rootNode);
+        httpPost.setEntity(new StringEntity(rootNode.toString(), "utf-8"));
+        HttpResponse response = httpClient.execute(httpPost);
+        // 返回数据:
+        String bodyAsString = EntityUtils.toString(response.getEntity());
+        if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
+            //  保存退款数据到数据库
+            RefundRecord refundRecord = new RefundRecord();
+            JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
+            refundRecord.setRefundId(jsonObject.getString("refund_id"));
+            refundRecord.setOutRefundNo(jsonObject.getString("out_refund_no"));
+            refundRecord.setTransactionId(jsonObject.getString("transaction_id"));
+            refundRecord.setOutTradeNo(jsonObject.getString("out_trade_no"));
+            refundRecord.setChannel(jsonObject.getString("channel"));
+            refundRecord.setUserReceivedAccount(jsonObject.getString("user_received_account"));
+            if (jsonObject.getString("success_time")!=null){
+                refundRecord.setSuccessTime(new DateTime(jsonObject.getString("success_time")).toDate());
+            }
+            refundRecord.setCreateTime(new DateTime(jsonObject.getString("create_time")).toDate());
+            refundRecord.setStatus(jsonObject.getString("status"));
+            refundRecord.setFundsAccount(jsonObject.getString("funds_account"));
+            JSONObject amount = jsonObject.getJSONObject("amount");
+            refundRecord.setTotal(amount.getInteger("total"));
+            refundRecord.setRefund(amount.getInteger("refund"));
+            refundRecord.setPayerTotal(amount.getInteger("payer_total"));
+            refundRecord.setPayerRefund(amount.getInteger("payer_refund"));
+            refundRecord.setSettlementRefund(amount.getInteger("settlement_refund"));
+            refundRecord.setSettlementTotal(amount.getInteger("settlement_total"));
+            refundRecord.setDiscountRefund(amount.getInteger("discount_refund"));
+            refundRecord.setCurrency(amount.getString("currency"));
+            this.save(refundRecord);
+
+            WxNotifyReturnDTO wxNotifyReturnDTO = new WxNotifyReturnDTO();
+            wxNotifyReturnDTO.setCode("SUCCESS");
+            wxNotifyReturnDTO.setMessage("成功");
+            return wxNotifyReturnDTO;
+        }else{
+            throw new CustomException(bodyAsString);
+        }
+
+    }
+
+    @Override
+    public RefundRecord getByRefundId(String refundId) {
+        return refundRecordMapper.getByRefundId(refundId);
+    }
+}

+ 120 - 15
twzd-service/src/main/java/com/miaxis/wx/service/impl/WxGzhServiceImpl.java

@@ -1,15 +1,23 @@
 package com.miaxis.wx.service.impl;
 
+import cn.hutool.json.XML;
 import com.alibaba.fastjson.JSONObject;
 import com.miaxis.common.constant.Constants;
-import com.miaxis.common.core.redis.RedisCache;
+import com.miaxis.common.utils.StringUtils;
+import com.miaxis.common.utils.wx.MessageUtil;
 import com.miaxis.feign.service.IWxSendService;
+import com.miaxis.wx.mapper.WxMenuMapper;
 import com.miaxis.wx.service.IWxGzhService;
+import com.miaxis.wx.service.IWxMessageEvenService;
+import com.qcloud.cos.COSClient;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -20,14 +28,18 @@ import java.util.concurrent.TimeUnit;
  */
 @Service
 @Slf4j
+@RequiredArgsConstructor
 public class WxGzhServiceImpl implements IWxGzhService {
 
+    private final RedisTemplate redisTemplate;
 
-    @Resource
-    private RedisCache redisCache;
+    private final IWxSendService wxSendService;
 
-    @Resource
-    private IWxSendService wxSendService;
+    private final WxMenuMapper wxMenuMapper;
+
+    private final COSClient cosClient;
+
+    private final IWxMessageEvenService wxMessageEvenService;
 
     @Value("${app.appid}")
     private String appid;
@@ -36,20 +48,113 @@ public class WxGzhServiceImpl implements IWxGzhService {
     private String secret;
 
 
+    /**
+     * 获取微信公众号token
+     * @return
+     */
     @Override
     public String getGzhToken() {
-        Object cacheObject = redisCache.getCacheObject(Constants.GZH_MESSAGE_TOKEN);
-        //如果过期,重新获取并保存到redis
-        if (cacheObject == null){
+        String token = "";
+        Integer expiresIn;
+        if (redisTemplate.hasKey(Constants.GZH_MESSAGE_TOKEN)){
+            token = (String)redisTemplate.opsForValue().get(Constants.GZH_MESSAGE_TOKEN);
+        }
+        if (StringUtils.isEmpty(token)){
             String result = wxSendService.getAccessToken("client_credential",appid,secret);
             JSONObject json = JSONObject.parseObject(result);
-            String token = json.getString("access_token");
-            int expiresIn = json.getIntValue("expires_in");
-            redisCache.setCacheObject(Constants.GZH_MESSAGE_TOKEN,token,expiresIn, TimeUnit.SECONDS);
-            return token;
-        }else {
-            return String.valueOf(cacheObject);
+            token = json.getString("access_token");
+            expiresIn = json.getIntValue("expires_in");
+            if (expiresIn <= 0){
+                expiresIn = 7000;
+            }
+
+            redisTemplate.opsForValue().set(Constants.GZH_MESSAGE_TOKEN,token,expiresIn, TimeUnit.SECONDS);
         }
 
+        return token;
+    }
+
+
+
+    /**
+     * 微信推送消息处理
+     * @param request
+     * @return
+     */
+    @Override
+    public String handlePublicMsg(HttpServletRequest request) {
+        try {
+            log.info("1....");
+            cn.hutool.json.JSONObject decryptMap = XML.toJSONObject(IOUtils.toString(request.getInputStream()));
+            cn.hutool.json.JSONObject jsonObjectData = decryptMap.getJSONObject("xml");
+            log.info("2-----jsonObjectData------"+jsonObjectData);
+
+            //开发者微信号
+            String toUserName = jsonObjectData.getStr("ToUserName");
+            //发送方帐号(一个OpenID)
+            String fromUserName = jsonObjectData.getStr("FromUserName");
+            // 区分消息类型
+            String msgType = jsonObjectData.getStr("MsgType");
+
+            // 普通消息
+            if (MessageUtil.MESSAGE_TEXT.equals(msgType)) { // 文本消息
+                log.info("2.1...");
+                String content = jsonObjectData.getStr("Content");
+                if (content.startsWith("你好")){
+                    return MessageUtil.initText(fromUserName, toUserName, "你好啊");
+                }else if (content.startsWith("傻逼")){
+                    return MessageUtil.initText(fromUserName, toUserName, "你才是煞笔");
+                }else {
+                    return MessageUtil.initText(fromUserName, toUserName, "文本消息-默认回复信息");
+                }
+
+            } else if (MessageUtil.MESSAGE_IMAGE.equals(msgType)) { // 图片消息
+                log.info("2.2...");
+                return MessageUtil.initText(fromUserName, toUserName, "抱歉,暂时无法识别图片信息!");
+            }else if (MessageUtil.MESSAGE_EVENT.equals(msgType)) { // 事件消息
+                log.info("3....");
+                // 区分事件推送
+                String event = jsonObjectData.getStr("Event");
+                if (MessageUtil.MESSAGE_SUBSCRIBE.equals(event)) { // 关注事件 或 扫描二维码关注事件
+                    log.info("3.1...");
+                    //存在Ticket为扫码关注
+                    if (org.apache.commons.lang3.StringUtils.isNotEmpty(jsonObjectData.getStr("Ticket"))){
+                        log.info("3.1.2..");
+                        //根据Ticket  推送绑定信息到上级用户
+                        String subscribeEvent = wxMessageEvenService.scanSubscribeEvent(fromUserName, jsonObjectData.getStr("Ticket"));
+                        return MessageUtil.initText(fromUserName,toUserName,subscribeEvent);
+
+                    }else {
+                        return MessageUtil.initText(fromUserName, toUserName, "关注事件");
+                    }
+
+                }  else if (MessageUtil.MESSAGE_UNSUBSCRIBE.equals(event)) { // 取消订阅事件
+                    // todo 处理取消订阅事件
+
+                } else if (MessageUtil.MESSAGE_SCAN.equals(event)) { // 已关注扫描二维码事件
+                    log.info("3.2...");
+                    return MessageUtil.initText(fromUserName, toUserName, "已关注扫描二维码事件");
+                    
+                } else if (MessageUtil.MESSAGE_LOCATION.equals(event)) { // 上报地理位置事件
+                    // todo 处理上报地理位置事件
+
+                } else if (MessageUtil.MESSAGE_CLICK.equals(event)) { // 点击菜单拉取消息时的事件推送事件
+                    log.info("3.3.....click:" + jsonObjectData.get("EventKey"));
+                    //判断事件KEY值,与自定义菜单接口中KEY值对应
+                    if ("generateTicket".equals(jsonObjectData.get("EventKey"))){ //获取分销二维码
+                        String mediaId = wxMessageEvenService.gainTicketEvent(fromUserName, this.getGzhToken());
+                        return MessageUtil.initImage(fromUserName,toUserName,mediaId);
+                    }
+
+                } else if (MessageUtil.MESSAGE_VIEW.equals(event)) { // 点击菜单跳转链接时的事件推送
+                    // todo 处理点击菜单跳转链接时的事件推送
+                }
+            }
+        } catch (Exception e) {
+            log.error("处理微信公众号请求信息,失败", e);
+        }
+        return null;
     }
+
+
 }

+ 197 - 0
twzd-service/src/main/java/com/miaxis/wx/service/impl/WxMenuServiceImpl.java

@@ -0,0 +1,197 @@
+package com.miaxis.wx.service.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.miaxis.common.core.domain.Response;
+import com.miaxis.common.exception.CustomException;
+import com.miaxis.common.sign.VerifyUtil;
+import com.miaxis.feign.service.IWxSendService;
+import com.miaxis.wx.domain.WxMenu;
+import com.miaxis.wx.mapper.WxMenuMapper;
+import com.miaxis.wx.service.IWxGzhService;
+import com.miaxis.wx.service.IWxMenuService;
+import com.miaxis.wx.vo.WxMenuVo;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * 微信公众号菜单Service业务层处理
+ * @author wwl
+ * @version 1.0
+ * @date 2021/11/3 9:24
+ */
+@Service
+@AllArgsConstructor
+@Slf4j
+public class WxMenuServiceImpl extends ServiceImpl<WxMenuMapper, WxMenu> implements IWxMenuService {
+
+    private final WxMenuMapper wxMenuMapper;
+
+    private final IWxGzhService wxGzhService;
+
+    private final IWxSendService wxSendService;
+
+    /**
+     * 查询微信公众号菜单列表
+     *
+     * @return 微信公众号菜单
+     */
+    @Override
+    public Response<List<WxMenuVo>> selectWxMenuTreeList(){
+        List<WxMenuVo> menuList = wxMenuMapper.selectWxMenuList();
+        return Response.success(builTree(menuList));
+    }
+
+    //建立树形结构
+    public List<WxMenuVo> builTree(List<WxMenuVo> menuList){
+        List<WxMenuVo> infoVos =new ArrayList<>();
+        //获取根节点
+        List<WxMenuVo> rootMenuLists =new  ArrayList<>();
+        for(WxMenuVo menuVo : menuList) {
+            if(menuVo.getParentId().toString().equals("0")) {
+                rootMenuLists.add(menuVo);
+            }
+        }
+        for(WxMenuVo wxMenuVo : rootMenuLists) {
+            wxMenuVo=getTree(wxMenuVo,menuList);
+            infoVos.add(wxMenuVo);
+        }
+        return infoVos;
+    }
+    //递归,建立子树形结构
+    private WxMenuVo getTree(WxMenuVo wxMenuVo,List<WxMenuVo> menuList){
+        List<WxMenuVo> infoVos = new ArrayList<>();
+        for (WxMenuVo menuVo : menuList) {
+            if (menuVo.getParentId().toString().equals(wxMenuVo.getId().toString())){
+                infoVos.add(getTree(menuVo,menuList));
+            }
+        }
+        wxMenuVo.setChildren(infoVos);
+        return wxMenuVo;
+    }
+
+
+    /**
+     * 新增微信公众号菜单
+     * @param wxMenu
+     * @return
+     */
+    @Override
+    public Response saveMenu(WxMenu wxMenu) {
+        try {
+            wxMenuMapper.insert(wxMenu);
+            sendMenu();
+            return Response.success();
+        }catch (Exception e){
+            throw new CustomException("系统异常");
+        }
+    }
+
+    /**
+     * 修改微信公众号菜单
+     * @param wxMenu
+     * @return
+     */
+    @Override
+    public Response updateMenuById(WxMenu wxMenu) {
+        try {
+            wxMenuMapper.updateById(wxMenu);
+            sendMenu();
+            return Response.success();
+        }catch (Exception e){
+            throw new CustomException("系统异常");
+        }
+    }
+
+    /**
+     * 删除微信公众号菜单
+     * @param ids
+     * @return
+     */
+    @Override
+    public Response removeMenuByIds(Long[] ids) {
+        try {
+            this.removeByIds(Arrays.asList(ids));
+            sendMenu();
+            return Response.success();
+        }catch (Exception e){
+            throw new CustomException("系统异常");
+        }
+    }
+
+
+    /**
+     * 发送菜单至微信
+     * @return
+     */
+    private String sendMenu(){
+        JSONObject wxMenuJson = getWxMenuJson();
+        String token = wxGzhService.getGzhToken();
+        String result = wxSendService.createMenu(token,wxMenuJson);
+        log.info("-----sendMenu-----"+ result);
+        return result;
+    }
+
+
+    /**
+     * 查询微信菜单数据
+     * @return
+     */
+    private JSONObject getWxMenuJson() {
+
+        JSONObject menuJson = new JSONObject();
+        //获取父类
+        List<WxMenu> menuList = wxMenuMapper.selectByMap(new HashMap<String,Object>(){{
+            put("parent_id",0);
+        }});
+        JSONArray button=new JSONArray();
+        for(WxMenu menu : menuList){
+            if(!VerifyUtil.verifyString(menu.getType())){
+                JSONObject childButton = new JSONObject();
+                childButton.put("name", menu.getMenuName());
+                //父类
+                JSONArray sub_button = new JSONArray();
+                List<WxMenu> childMenuList = wxMenuMapper.selectList(new QueryWrapper<WxMenu>().eq("parent_id", menu.getId()).orderByAsc("sort"));
+
+                for (WxMenu childMenu : childMenuList) {
+                    sub_button.add(getChildMenuJson(childMenu));
+                }
+                childButton.put("sub_button", sub_button);
+                button.add(childButton);
+            }else{
+                button.add(getChildMenuJson(menu));
+            }
+        }
+
+        menuJson.put("button", button);
+        return menuJson;
+    }
+
+
+    private JSONObject getChildMenuJson(WxMenu menu){
+        JSONObject menuJson = new JSONObject();
+        menuJson.put("type", menu.getType());
+        menuJson.put("name", menu.getMenuName());
+        if(menu.getType().equals("view")){
+            menuJson.put("url", menu.getUrl());
+        }else if(menu.getType().equals("click")){
+            menuJson.put("key", menu.getClickKey());
+        }else if(menu.getType().equals("miniprogram")){
+            menuJson.put("url", menu.getUrl());
+            menuJson.put("key", menu.getClickKey());
+            menuJson.put("appid", menu.getAppid());
+            menuJson.put("pagepath", menu.getPagePath());
+        }
+        return menuJson;
+    }
+
+
+}

+ 200 - 0
twzd-service/src/main/java/com/miaxis/wx/service/impl/WxMessageEvenServiceImpl.java

@@ -0,0 +1,200 @@
+package com.miaxis.wx.service.impl;
+
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.img.ImgUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import cn.hutool.extra.qrcode.QrConfig;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.miaxis.common.constant.Constants;
+import com.miaxis.common.utils.http.HttpUtils;
+import com.miaxis.feign.dto.WxQrTicket;
+import com.miaxis.feign.service.IWxSendService;
+import com.miaxis.spread.domain.WxSpreadRelation;
+import com.miaxis.spread.service.IWxSpreadRelationService;
+import com.miaxis.wx.service.IWxMessageEvenService;
+import com.miaxis.wx.service.IWxTicketService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.awt.*;
+import java.io.File;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/27 14:35
+ */
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class WxMessageEvenServiceImpl implements IWxMessageEvenService {
+
+    private final RedisTemplate redisTemplate;
+
+    private final IWxSendService wxSendService;
+
+    private final IWxTicketService wxTicketService;
+
+    private final IWxSpreadRelationService wxSpreadRelationService;
+
+    @Value("${file.ticketPath}")
+    private String ticketPath;
+
+    @Value("${wxgzh.mediaUpload}")
+    private String mediaUpload;
+
+    @Value("${cos.bucketName}")
+    private String bucketName;
+
+    @Value("${cos.path}")
+    private String path;
+
+    @Value("${cos.preffix}")
+    private String preffix;
+
+
+    /**
+     * 扫码关注事件
+     * @param fromUserName 发送方帐号(一个OpenID)
+     * @param ticket 二维码的ticket
+     * @return
+     */
+    @Override
+    public String scanSubscribeEvent(String fromUserName, String ticket) {
+
+        String message = "";
+        //判断是否存在父级推广关系
+        List<WxSpreadRelation> spreadRelations = wxSpreadRelationService.list(new QueryWrapper<WxSpreadRelation>().eq("openid", fromUserName));
+        if (spreadRelations.isEmpty()){
+            String openid = (String) redisTemplate.opsForValue().get(Constants.GZH_TICKET_KEY + ticket);
+            //保存推广关系表
+            WxSpreadRelation wxSpreadRelation = new WxSpreadRelation();
+            wxSpreadRelation.setOpenid(fromUserName);
+            wxSpreadRelation.setParentOpenid(openid);
+            wxSpreadRelationService.save(wxSpreadRelation);
+            message = "已成功绑定推广关系!";
+        }else {
+            message = "已存在推广关系!";
+        }
+        return message;
+    }
+
+
+    /**
+     * click获取推广二维码事件
+     * @param fromUserName 发送方帐号(一个OpenID)
+     * @param token 凭证
+     * @return
+     */
+    @Override
+    public String gainTicketEvent(String fromUserName,String token) {
+
+        // 根据fromUserName查询缓存 判断用户推广码是否过期
+        if (redisTemplate.hasKey(Constants.GZH_MATERIAL_KEY + fromUserName)){
+            String mediaId = (String) redisTemplate.opsForValue().get(Constants.GZH_MATERIAL_KEY + fromUserName);
+            return mediaId;
+        }
+
+        //生成带参数二维码ticket(永久)
+        WxQrTicket wxQrTicket = new WxQrTicket();
+        wxQrTicket.setExpire_seconds(259200);//3天
+        wxQrTicket.setAction_name("QR_SCENE");//临时
+        JSONObject jsonObject1 = new JSONObject();
+        JSONObject jsonObject2 = new JSONObject();
+        jsonObject1.put("scene_id","123");
+        jsonObject2.put("scene",jsonObject1);
+        wxQrTicket.setAction_info(jsonObject2);
+        String wxTicketResult = wxSendService.generateTicket(token, wxQrTicket);
+        JSONObject jsonStr = JSONObject.parseObject(wxTicketResult);
+        log.info("---------ticket-------" + jsonStr);
+
+        //获取用户信息
+        String userInfoResult = wxSendService.userInfo(token, fromUserName, "zh_CN");
+        JSONObject userInfo = JSONObject.parseObject(userInfoResult);
+        log.info("---------userInfo-------" + userInfo);
+
+        //根据ticket生成二维码图片存储
+        File ticketFile = QrCodeUtil.generate(
+                jsonStr.getString("url"), //二维码内容
+                QrConfig.create().setImg(ticketPath + "logo.jpg"), //附带logo
+                FileUtil.file(ticketPath + fromUserName + ".jpg")//写出到的文件
+        );
+
+        ImgUtil.pressImage(
+                FileUtil.file(ticketPath+"jinpai.jpg"),
+                FileUtil.file(ticketPath+fromUserName+"_img.jpg"),
+                ImgUtil.read(FileUtil.file(ticketPath+fromUserName+".jpg")), //水印图片
+                0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
+                -360, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
+                1.0f
+        );
+
+        DateTime date = DateUtil.date();
+        Date newDate = DateUtil.offsetDay(date, 3);
+        String dateStr = DateUtil.format(newDate, "yyyy-MM-dd");
+        log.info(dateStr);
+
+        String text = userInfo.getString("nickname")+"  此二维码有效期至:"+dateStr;
+        ImgUtil.pressText(
+                FileUtil.file(ticketPath+fromUserName+"_img.jpg"),
+                FileUtil.file(ticketPath+fromUserName+"_text.jpg"),
+                text, Color.red, //文字
+                new Font("黑体", Font.BOLD, 30), //字体
+                0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
+                400, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
+                0.8f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
+        );
+
+
+        try {
+            File textFile = new File(ticketPath + fromUserName+"_text.jpg");
+            //上传素材
+            String path = mediaUpload + token + "&type=image";
+            String result = HttpUtils.connectHttpsByPost(path,textFile);
+            result = result.replaceAll("[\\\\]", "");
+            JSONObject resultJSON = JSONObject.parseObject(result);
+            log.info("------result:" + resultJSON);
+
+            //缓存用户推广码相关信息
+            redisTemplate.opsForValue().set(Constants.GZH_TICKET_KEY+jsonStr.getString("ticket"),fromUserName,259200, TimeUnit.SECONDS);
+            redisTemplate.opsForValue().set(Constants.GZH_MATERIAL_KEY+fromUserName,resultJSON.getString("media_id"),259200, TimeUnit.SECONDS);
+
+            //删除服务器文件
+            File imgFile = new File(ticketPath + fromUserName+"_img.jpg");
+            if (ticketFile.exists() && imgFile.exists() && textFile.exists()) {
+                if (ticketFile.delete()) {
+                    log.info("删除:" + ticketFile.getName() + "成功!");
+                } else {
+                    log.info("删除:" + ticketFile.getName() + "失败!");
+                }
+                if (imgFile.delete()) {
+                    log.info("删除:" + imgFile.getName() + "成功!");
+                } else {
+                    log.info("删除:" + imgFile.getName() + "失败!");
+                }
+                if (textFile.delete()) {
+                    log.info("删除:" + textFile.getName() + "成功!");
+                } else {
+                    log.info("删除:" + textFile.getName() + "失败!");
+                }
+            }
+
+            return resultJSON.getString("media_id");
+        } catch (Exception e) {
+            log.info("-----异常------click获取推广二维码事件");
+        }
+        return null;
+    }
+
+
+}

+ 45 - 0
twzd-service/src/main/java/com/miaxis/wx/service/impl/WxOrderServiceImpl.java

@@ -0,0 +1,45 @@
+package com.miaxis.wx.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.miaxis.system.service.ISysConfigService;
+import com.miaxis.wx.domain.WxOrder;
+import com.miaxis.wx.mapper.WxOrderMapper;
+import com.miaxis.wx.service.IWxOrderService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 电影订单Service业务层处理
+ *
+ * @author miaxis
+ * @date 2021-05-07
+ */
+@Service
+@Slf4j
+public class WxOrderServiceImpl extends ServiceImpl<WxOrderMapper, WxOrder> implements IWxOrderService {
+    @Resource
+    private WxOrderMapper wxOrderMapper;
+
+
+    @Autowired
+    private ISysConfigService configService;
+
+
+
+    @Override
+    public void createVipOrder(WxOrder wxOrder) {
+        String price = configService.selectConfigByKey("vip_price");
+        Double dprice = Double.valueOf(price);
+        Double v =dprice* 100;
+        wxOrder.setTotal(v.intValue());
+
+
+    }
+    @Override
+    public WxOrder getByOutTradeNo(String outTradeNo) {
+        return wxOrderMapper.getByOutTradeNo(outTradeNo);
+    }
+}

+ 22 - 0
twzd-service/src/main/java/com/miaxis/wx/service/impl/WxTicketServiceImpl.java

@@ -0,0 +1,22 @@
+package com.miaxis.wx.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.miaxis.wx.domain.WxTicket;
+import com.miaxis.wx.mapper.WxTicketMapper;
+import com.miaxis.wx.service.IWxTicketService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 微信推广二维码Service业务层处理
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/28 16:30
+ */
+@Service
+@RequiredArgsConstructor
+public class WxTicketServiceImpl extends ServiceImpl<WxTicketMapper, WxTicket> implements IWxTicketService {
+
+    private final WxTicketMapper wxTicketMapper;
+
+}

+ 73 - 0
twzd-service/src/main/java/com/miaxis/wx/vo/WxMenuVo.java

@@ -0,0 +1,73 @@
+package com.miaxis.wx.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.miaxis.common.core.domain.BaseBusinessEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 微信公众号菜单返回参 WxMenuVo
+ * @author wwl
+ * @version 1.0
+ * @date 2021/10/26 10:06
+ */
+@Data
+@ApiModel(value = "WxMenuVo", description = "微信公众号菜单对象 WxMenuVo")
+public class WxMenuVo {
+
+    private static final long serialVersionUID = 1L;
+
+    /** 主键 */
+    @TableId(value = "id")
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    @TableField("parent_id")
+    @ApiModelProperty(value = "父节点")
+    private Integer parentId;
+
+    @TableField("type")
+    @ApiModelProperty(value = "菜单的响应动作类型,view表示网页类型,click表示点击类型,miniprogram表示小程序类型")
+    private String type;
+
+    @TableField("menu_name")
+    @ApiModelProperty(value = "菜单标题")
+    private String menuName;
+
+    @TableField("click_key")
+    @ApiModelProperty(value = "click等点击类型必须,菜单KEY值,用于消息接口推送,不超过128字节")
+    private String clickKey;
+
+    @TableField("url")
+    @ApiModelProperty(value = "view、miniprogram类型必须,网页 链接,用户点击菜单可打开链接,不超过1024字节。 type为miniprogram时,不支持小程序的老版本客户端将打开本url。")
+    private String url;
+
+    @TableField("media_id")
+    @ApiModelProperty(value = "media_id类型和view_limited类型必须,调用新增永久素材接口返回的合法media_id")
+    private String mediaId;
+
+    @TableField("appid")
+    @ApiModelProperty(value = "miniprogram类型必须,小程序的appid(仅认证公众号可配置)")
+    private String appid;
+
+    @TableField("page_path")
+    @ApiModelProperty(value = "miniprogram类型必须,小程序的页面路径")
+    private String pagePath;
+
+    @TableField("article_id")
+    @ApiModelProperty(value = "发布后获得的合法 article_id")
+    private String articleId;
+
+    @TableField("sort")
+    @ApiModelProperty(value = "排序")
+    private Integer sort;
+
+    @ApiModelProperty(value = "子节点分类")
+    private List<WxMenuVo> children;
+
+}

+ 39 - 0
twzd-service/src/main/resources/mapper/user/UserInfoMapper.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.miaxis.user.mapper.UserInfoMapper">
+
+    <resultMap type="UserInfo" id="UserInfoResult">
+        <result property="id"    column="id"    />
+        <result property="phone"    column="phone"    />
+        <result property="wechar"    column="wechar"    />
+        <result property="headImage"    column="head_image"    />
+        <result property="nickName"    column="nick_name"    />
+        <result property="openid"    column="openid"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="status"    column="status"    />
+        <result property="isVip"    column="is_vip"    />
+        <result property="unionId"    column="union_id"    />
+    </resultMap>
+
+    <sql id="selectUserInfoVo">
+        select * from user_info
+    </sql>
+
+    <select id="selectUserInfoList" parameterType="UserInfo" resultMap="UserInfoResult">
+        <include refid="selectUserInfoVo"/>
+        <where>
+            <if test="phone != null  and phone != ''"> and phone = #{phone}</if>
+            <if test="wechar != null  and wechar != ''"> and wechar = #{wechar}</if>
+            <if test="headImage != null  and headImage != ''"> and head_image = #{headImage}</if>
+            <if test="nickName != null  and nickName != ''"> and nick_name like concat('%', #{nickName}, '%')</if>
+            <if test="openid != null  and openid != ''"> and openid = #{openid}</if>
+            <if test="status != null "> and status = #{status}</if>
+            <if test="isVip != null "> and is_vip = #{isVip}</if>
+            <if test="unionId != null  and unionId != ''"> and union_id = #{unionId}</if>
+        </where>
+    </select>
+
+</mapper>

+ 32 - 0
twzd-service/src/main/resources/mapper/wx/WxMenuMapper.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.miaxis.wx.mapper.WxMenuMapper">
+
+    <resultMap type="WxMenu" id="WxMenuResult">
+        <result property="id"    column="id"    />
+        <result property="parentId"    column="parent_id"    />
+        <result property="type"    column="type"    />
+        <result property="menuName"    column="menu_name"    />
+        <result property="clickKey"    column="click_key"    />
+        <result property="url"    column="url"    />
+        <result property="mediaId"    column="media_id"    />
+        <result property="appid"    column="appid"    />
+        <result property="pagePath"    column="page_path"    />
+        <result property="articleId"    column="article_id"    />
+        <result property="sort"    column="sort"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectWxMenuVo">
+        select * from wx_menu
+    </sql>
+
+    <select id="selectWxMenuList" resultType="com.miaxis.wx.vo.WxMenuVo">
+        <include refid="selectWxMenuVo"/>
+        ORDER BY sort
+    </select>
+
+</mapper>

+ 3 - 3
twzd-system/src/main/java/com/miaxis/system/dto/system/TokenDTO.java

@@ -1,6 +1,6 @@
 package com.miaxis.system.dto.system;
 
-import com.miaxis.common.core.domain.model.WxResult;
+import com.miaxis.common.core.domain.model.WxUserInfo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -17,6 +17,6 @@ public class TokenDTO {
     private static final long serialVersionUID = 1L;
     @ApiModelProperty(value = "令牌")
     private String token;
-    @ApiModelProperty(value = "微信返回数据")
-    private WxResult wxResult;
+    @ApiModelProperty(value = "微信返回用户数据")
+    private WxUserInfo wxUserInfo;
 }