Browse Source

e码头公众号目录改造

zhushouping 1 year ago
parent
commit
731e03f1cd
20 changed files with 604 additions and 18 deletions
  1. 19 0
      sql/E码头目录改造sql.sql
  2. 11 1
      src/main/java/com/ematou/wxservice/api/WeChatApi.java
  3. 90 0
      src/main/java/com/ematou/wxservice/api/WeChatApiRestTemplate.java
  4. 9 0
      src/main/java/com/ematou/wxservice/common/constant/WeChatConstant.java
  5. 27 0
      src/main/java/com/ematou/wxservice/common/xml/builder/ImageBuilder.java
  6. 117 0
      src/main/java/com/ematou/wxservice/entity/pojo/Material.java
  7. 28 0
      src/main/java/com/ematou/wxservice/mapper/MaterialMapper.java
  8. 25 0
      src/main/java/com/ematou/wxservice/mp/handler/WeChatImageMessageHandler.java
  9. 1 1
      src/main/java/com/ematou/wxservice/mp/handler/WeChatSubscribeEventHandler.java
  10. 22 0
      src/main/java/com/ematou/wxservice/mp/menu/MediaButton.java
  11. 24 6
      src/main/java/com/ematou/wxservice/mp/menu/MenuButtonManager.java
  12. 26 0
      src/main/java/com/ematou/wxservice/mp/message/WeChatMpXmlOutImageMessage.java
  13. 2 0
      src/main/java/com/ematou/wxservice/mp/message/WeChatMpXmlOutMessage.java
  14. 3 1
      src/main/java/com/ematou/wxservice/mp/router/WeChatMessageHandlerRouter.java
  15. 33 0
      src/main/java/com/ematou/wxservice/service/MaterialService.java
  16. 1 5
      src/main/java/com/ematou/wxservice/service/UserInfoService.java
  17. 77 4
      src/main/java/com/ematou/wxservice/service/WeChatService.java
  18. 89 0
      src/main/resources/mybatis/MaterialMapper.xml
  19. BIN
      src/main/resources/static/images/after-sale-service.png
  20. BIN
      src/main/resources/static/images/business-cooperation.png

+ 19 - 0
sql/E码头目录改造sql.sql

@@ -0,0 +1,19 @@
+
+-- 素材
+create table wx_service.mp_material
+(
+    id                           int UNSIGNED         auto_increment comment '主键ID',
+    media_id                     varchar(255)         comment '上传公众号返回的ID',
+    file_name                    varchar(255)         comment '文件名',
+    file_size                    BIGINT(20)           comment '文件大小',
+    file_path                    varchar(255)         comment '文件目录',
+    file_type                    varchar(127)         comment '文件类型',
+    creator_id                   bigint               comment '创建人',
+    create_time                  varchar(22)          comment '创建时间',
+    moder_id                     bigint               comment '修改人',
+    mod_time                     varchar(22)          comment '修改时间',
+    tstm                         timestamp on update CURRENT_TIMESTAMP    comment '时间戳',
+    constraint material_pk  primary key (id),
+    constraint material_pk  unique (file_name)
+)
+    ENGINE=INNODB DEFAULT CHARSET=utf8 comment '公众号永久素材';

+ 11 - 1
src/main/java/com/ematou/wxservice/api/WeChatApi.java

@@ -52,7 +52,17 @@ public enum WeChatApi {
      * 发送模板消息,请求体参考:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html
      * 发送成功和失败都有事件的推送
      */
-    SEND_TEMPLATE_MSG("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s", "POST");
+    SEND_TEMPLATE_MSG("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s", "POST"),
+
+    /**
+     * 上传素材
+     */
+    MEDIA_UPLOAD("https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=%s&type=image", "POST"),
+    /**
+     * 查看素材
+     */
+    MEDIA_GET("https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=%s", "POST");
+
 
 
     private String url;

+ 90 - 0
src/main/java/com/ematou/wxservice/api/WeChatApiRestTemplate.java

@@ -12,6 +12,10 @@ import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
 import org.springframework.web.client.RestTemplate;
 
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.util.Arrays;
 
 /**
@@ -121,4 +125,90 @@ public class WeChatApiRestTemplate {
         return res;
     }
 
+    /**
+     * 上传永久素材
+     * @author zhushouping
+     * @since 1.0.0
+     * @date 2023/8/15
+     * @return
+     */
+    public String postByStream(String url, File file){
+
+        BufferedReader reader = null;
+        String result = null;
+        try {
+            URL urlObj = new URL(url);
+            //连接
+            HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
+            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输入流来读取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 (MalformedURLException e) {
+            logger.error("请求微信API失败,请求方法:POST\nurl:\n" + url + "\n请求文件:" + file.getName() + "\n异常信息:" + e.getMessage());
+            throw new RuntimeException("请求微信API失败,请求方法:POST\nurl:\n" + url + "\n请求文件:" + file.getName() + "\n异常信息:" + e.getMessage());
+        } catch (UnsupportedEncodingException e) {
+            logger.error("请求微信API失败,请求方法:POST\nurl:\n" + url + "\n请求文件:" + file.getName() + "\n异常信息:" + e.getMessage());
+            throw new RuntimeException("请求微信API失败,请求方法:POST\nurl:\n" + url + "\n请求文件:" + file.getName() + "\n异常信息:" + e.getMessage());
+        } catch (IOException e) {
+            logger.error("请求微信API失败,请求方法:POST\nurl:\n" + url + "\n请求文件:" + file.getName() + "\n异常信息:" + e.getMessage());
+            throw new RuntimeException("请求微信API失败,请求方法:POST\nurl:\n" + url + "\n请求文件:" + file.getName() + "\n异常信息:" + e.getMessage());
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+        return result;
+    }
+
 }

+ 9 - 0
src/main/java/com/ematou/wxservice/common/constant/WeChatConstant.java

@@ -34,6 +34,11 @@ public class WeChatConstant {
         public static final String SCANCODE_PUSH_BUTTON = "scancode_push_button";      // 扫码取件
         public static final String MY_HISTORY_RECORD = "my_history_button";     // 取件历史
         public static final String POLICY_SUPPORT = "policy_support_button";    // 政策支持
+
+        public static final String BUSINESS_COOPERATION = "business_cooperation_btn";    // 商务合作
+        public static final String AFTER_SALE_SERVICE = "after_sale_service_btn";    // 商务合作
+
+
     }
 
     /**
@@ -67,6 +72,10 @@ public class WeChatConstant {
         public static final String LOCATION = "LOCATION";
         public static final String CLICK = "CLICK";
         public static final String VIEW = "VIEW";
+        /**
+         * 下发消息
+         */
+        public static final String MEDIA_ID = "media_id";
         public static final String MINIPROGRAM = "miniprogram";
         public static final String MASS_SEND_JOB_FINISH = "MASSSENDJOBFINISH";
         /**

+ 27 - 0
src/main/java/com/ematou/wxservice/common/xml/builder/ImageBuilder.java

@@ -0,0 +1,27 @@
+package com.ematou.wxservice.common.xml.builder;
+
+import com.ematou.wxservice.mp.message.WeChatMpXmlOutImageMessage;
+
+/**
+ * 构建图片下发消息
+ * @author lhm
+ * @version 1.0
+ * 2021-05-11 15:03
+ */
+public class ImageBuilder extends BaseBuilder<ImageBuilder, WeChatMpXmlOutImageMessage> {
+
+    private String mediaId;;
+
+    public ImageBuilder mediaId(String mediaId) {
+        this.mediaId = mediaId;
+        return this;
+    }
+
+    @Override
+    public WeChatMpXmlOutImageMessage build() {
+        WeChatMpXmlOutImageMessage weChatMpXmlOutImageMessage = new WeChatMpXmlOutImageMessage();
+        setCommon(weChatMpXmlOutImageMessage);
+        weChatMpXmlOutImageMessage.setMediaId(this.mediaId);
+        return weChatMpXmlOutImageMessage;
+    }
+}

+ 117 - 0
src/main/java/com/ematou/wxservice/entity/pojo/Material.java

@@ -0,0 +1,117 @@
+package com.ematou.wxservice.entity.pojo;
+
+import java.sql.Timestamp;
+
+/**
+ * 公众号需要的素材
+ *
+ * @author zhushouping
+ * @since 1.0.0
+ * @date 2023/8/15
+ */
+public class Material {
+
+    private Integer id; //本地存储的唯一ID
+
+    private String mediaId; //上传公众号返回的ID
+
+    private String fileName; // 文件名
+    private Long fileSize; // 文件大小
+    private String filePath; // 文件目录
+
+    private String fileType; //文件类型
+
+    private Integer creatorId;
+    private String createTime;
+    private Integer moderId;
+    private String modTime;
+    private Timestamp tmst;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getMediaId() {
+        return mediaId;
+    }
+
+    public void setMediaId(String mediaId) {
+        this.mediaId = mediaId;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+
+    public Long getFileSize() {
+        return fileSize;
+    }
+
+    public void setFileSize(Long fileSize) {
+        this.fileSize = fileSize;
+    }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+
+    public String getFileType() {
+        return fileType;
+    }
+
+    public void setFileType(String fileType) {
+        this.fileType = fileType;
+    }
+
+    public Integer getCreatorId() {
+        return creatorId;
+    }
+
+    public void setCreatorId(Integer creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public String getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
+
+    public Integer getModerId() {
+        return moderId;
+    }
+
+    public void setModerId(Integer moderId) {
+        this.moderId = moderId;
+    }
+
+    public String getModTime() {
+        return modTime;
+    }
+
+    public void setModTime(String modTime) {
+        this.modTime = modTime;
+    }
+
+    public Timestamp getTmst() {
+        return tmst;
+    }
+
+    public void setTmst(Timestamp tmst) {
+        this.tmst = tmst;
+    }
+}

+ 28 - 0
src/main/java/com/ematou/wxservice/mapper/MaterialMapper.java

@@ -0,0 +1,28 @@
+package com.ematou.wxservice.mapper;
+
+import com.ematou.wxservice.entity.pojo.Material;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 公众号素材数据操作
+ *
+ * @author zhushouping
+ * @since 1.0.0
+ * @date 2023/8/15
+ */
+@Mapper
+@Repository
+public interface MaterialMapper {
+
+    int insertMaterial(@Param("material") Material material);
+
+    int updateMaterial(@Param("material") Material material);
+
+    Material queryMaterialByFileName(@Param("fileName") String fileName);
+
+    Material queryMaterialByMediaId(@Param("mediaId") String mediaId);
+
+    int deleteMaterialByMediaId(@Param("mediaId") String mediaId);
+}

+ 25 - 0
src/main/java/com/ematou/wxservice/mp/handler/WeChatImageMessageHandler.java

@@ -0,0 +1,25 @@
+package com.ematou.wxservice.mp.handler;
+
+import com.ematou.wxservice.mp.message.WeChatMessage;
+import com.ematou.wxservice.mp.message.WeChatMpXmlOutImageMessage;
+import com.ematou.wxservice.mp.message.WeChatMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WeChatImageMessageHandler implements WeChatMessageHandler {
+
+    @Override
+    public WeChatMpXmlOutMessage handlerMessage(WeChatMessage weChatMessage) {
+
+
+            WeChatMpXmlOutImageMessage m = WeChatMpXmlOutMessage.IMAGE()
+                                                        .mediaId(weChatMessage.getMediaId())
+                                                        .fromUser(weChatMessage.getToUser())
+                                                        .toUser(weChatMessage.getFromUser())
+                                                        .build();
+            return m;
+
+
+    }
+
+}

+ 1 - 1
src/main/java/com/ematou/wxservice/mp/handler/WeChatSubscribeEventHandler.java

@@ -25,7 +25,7 @@ public class WeChatSubscribeEventHandler implements WeChatMessageHandler {
 
         WeChatMpXmlOutNewsMessage.Item item = new WeChatMpXmlOutNewsMessage.Item();
         item.setTitle("欢迎关注【e码头】");
-        item.setDescription(">>>点击绑定手机号,立即取件!");
+        item.setDescription("e码头致力于打造中国领先的消费品线下跨境零售创新平台,自建及帮助进口跨境品牌商家搭建线下跨境零售业务网点。\n>>>门店购买的订单,点击绑定手机号,立即取件!");
         item.setPicUrl("https://wxservice.fu-qing.com/images/emtnew.png");
         item.setUrl("https://wxservice.fu-qing.com/view/binding?openid="+weChatMessage.getFromUser());
         return WeChatMpXmlOutMessage.NEWS().addArticle(item).toUser(weChatMessage.getFromUser()).fromUser(weChatMessage.getToUser()).build();

+ 22 - 0
src/main/java/com/ematou/wxservice/mp/menu/MediaButton.java

@@ -0,0 +1,22 @@
+package com.ematou.wxservice.mp.menu;
+
+public class MediaButton extends ClickButton{
+
+    private String media_id;
+
+    public String getMedia_id() {
+        return media_id;
+    }
+
+    public void setMedia_id(String media_id) {
+        this.media_id = media_id;
+    }
+
+    public MediaButton(String name, String type, String key, String media_id) {
+        super(name, type, key);
+        this.media_id = media_id;
+    }
+
+    public MediaButton() {
+    }
+}

+ 24 - 6
src/main/java/com/ematou/wxservice/mp/menu/MenuButtonManager.java

@@ -11,12 +11,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
-import org.springframework.web.client.RestTemplate;
 
 import javax.annotation.PostConstruct;
 import java.util.*;
@@ -75,7 +71,7 @@ public class MenuButtonManager {
             map.put("button", Arrays.asList(companyMenuButton, goodsMenuButton, takeParcelMenuButton));
 
         } else if (WeChatAccount.QH_E_MA_TO.getItem().equals(wechat)) {
-            ClickButton myCodeBtn = new ClickButton("我的取件码", WeChatConstant.EventType.CLICK.toLowerCase(), WeChatConstant.CustomEventKey.MY_TAKE_PARCEL_CODE);
+            /*ClickButton myCodeBtn = new ClickButton("我的取件码", WeChatConstant.EventType.CLICK.toLowerCase(), WeChatConstant.CustomEventKey.MY_TAKE_PARCEL_CODE);
             ClickButton scanPush = new ClickButton("扫码取件", WeChatConstant.EventType.SCANCODE_PUSH.toLowerCase(), WeChatConstant.CustomEventKey.SCANCODE_PUSH_BUTTON);
             //ClickButton myHistoryBtn = new ClickButton("取件历史", WeChatConstant.EventType.CLICK.toLowerCase(), WeChatConstant.CustomEventKey.MY_HISTORY_RECORD);
             //ViewButton addressEntryBtn = new ViewButton("收货地址管理", WeChatConstant.EventType.VIEW.toLowerCase(), "http://kmall-test.ds-bay.com:8080/qrcode/verification.html");
@@ -98,8 +94,30 @@ public class MenuButtonManager {
             goodsMenuButton.setSub_button(Arrays.asList(supplier, showGoods, showNews));
 
 
-            map.put("button", Arrays.asList(companyMenuButton, goodsMenuButton, takeParcelMenuButton));
+            map.put("button", Arrays.asList(companyMenuButton, goodsMenuButton, takeParcelMenuButton));*/
+            //品牌信息、官方商城、扫码取件
+            MenuButton brandMenuButton = new MenuButton("品牌信息");
+            //品牌介绍、品牌动态、商务合作
+            ViewButton brandInfoBtn = new ViewButton("品牌介绍", WeChatConstant.EventType.VIEW.toLowerCase(), "https://mp.weixin.qq.com/s/wydyGIDHneGS86uv2adfBA?scene=18#wechat_redirect");
+            ViewButton brandDynamicBtn = new ViewButton("品牌动态", WeChatConstant.EventType.VIEW.toLowerCase(), "https://mp.weixin.qq.com/s/exx2UWlbdXGxhtZpA5ZujQ?scene=18#wechat_redirect");
+            String businessMediaId = weChatService.mediaUpload(WeChatConstant.CustomEventKey.BUSINESS_COOPERATION);
+            //String businessMediaId = "cvw1kfvywUWCq28CBDTqMoTYizso3Zg1eT7QS8ORRqMv5y_hs99WG8x-beJb4y0r";
+            MediaButton businessBtn = new MediaButton("商务合作", WeChatConstant.EventType.MEDIA_ID.toLowerCase(), WeChatConstant.CustomEventKey.BUSINESS_COOPERATION, businessMediaId);
+            brandMenuButton.setSub_button(Arrays.asList(brandInfoBtn, brandDynamicBtn, businessBtn));
+
+            MenuButton mallMenuButton = new MenuButton("官方商城");
+            //跨境e购、售后服务
+            MiniProgramButton miniProgramButton = new MiniProgramButton("跨境e购",WeChatConstant.EventType.MINIPROGRAM.toLowerCase(),"http://mp.weixin.qq.com","wx1f09731935da5dd7","/pages/index/index");
+            String afterServiceMediaId = weChatService.mediaUpload(WeChatConstant.CustomEventKey.AFTER_SALE_SERVICE);
+            //String afterServiceMediaId = "cvw1kfvywUWCq28CBDTqMrMkllh2LYLVmneULJEOJGF6XNdjAsoX83F9jb4tP9pkr";
+            MediaButton afterServiceBtn = new MediaButton("售后服务", WeChatConstant.EventType.MEDIA_ID.toLowerCase(), WeChatConstant.CustomEventKey.AFTER_SALE_SERVICE, afterServiceMediaId);
+            mallMenuButton.setSub_button(Arrays.asList(miniProgramButton, afterServiceBtn));
+
+            MenuButton scanMenuButton = new MenuButton("扫码取件");
+            ClickButton scanPush = new ClickButton("扫码取件", WeChatConstant.EventType.SCANCODE_PUSH.toLowerCase(), WeChatConstant.CustomEventKey.SCANCODE_PUSH_BUTTON);
+            scanMenuButton.setSub_button(Arrays.asList(scanPush)); // myCodeBtn  我的取件码菜单屏蔽
 
+            map.put("button", Arrays.asList(brandMenuButton, mallMenuButton, scanMenuButton));
 
         }
 

+ 26 - 0
src/main/java/com/ematou/wxservice/mp/message/WeChatMpXmlOutImageMessage.java

@@ -0,0 +1,26 @@
+package com.ematou.wxservice.mp.message;
+
+import com.ematou.wxservice.common.constant.WeChatConstant;
+import com.ematou.wxservice.common.xml.converter.XStreamCDataConverter;
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+import com.thoughtworks.xstream.annotations.XStreamConverter;
+
+@XStreamAlias("xml")
+public class WeChatMpXmlOutImageMessage extends WeChatMpXmlOutMessage {
+
+    @XStreamAlias("MediaId")
+    @XStreamConverter(value = XStreamCDataConverter.class)
+    private String mediaId;
+
+    public WeChatMpXmlOutImageMessage(){
+        this.msgType = WeChatConstant.XmlMsgType.IMAGE;
+    }
+
+    public String getMediaId() {
+        return mediaId;
+    }
+
+    public void setMediaId(String mediaId) {
+        this.mediaId = mediaId;
+    }
+}

+ 2 - 0
src/main/java/com/ematou/wxservice/mp/message/WeChatMpXmlOutMessage.java

@@ -1,6 +1,7 @@
 package com.ematou.wxservice.mp.message;
 
 import com.ematou.wxservice.common.utils.XStreamTransformer;
+import com.ematou.wxservice.common.xml.builder.ImageBuilder;
 import com.ematou.wxservice.common.xml.builder.NewsBuilder;
 import com.ematou.wxservice.common.xml.builder.TextBuilder;
 import com.ematou.wxservice.common.xml.converter.XStreamCDataConverter;
@@ -46,6 +47,7 @@ public abstract class WeChatMpXmlOutMessage implements Serializable {
     }
 
     public static NewsBuilder NEWS() { return new NewsBuilder(); }
+    public static ImageBuilder IMAGE() { return new ImageBuilder(); }
 
     public String toXml() {
         return XStreamTransformer.toXml((Class<WeChatMpXmlOutMessage>) this.getClass(), this);

+ 3 - 1
src/main/java/com/ematou/wxservice/mp/router/WeChatMessageHandlerRouter.java

@@ -30,7 +30,8 @@ public class WeChatMessageHandlerRouter {
             WeChatNewsMessageHandler weChatNewsMessageHandler,
             WeChatSubscribeEventHandler weChatSubscribeEventHandler,
             WeChatScannHandler weChatScannHandler,
-            WeChatUnsubscribeHandler weChatUnsubscribeHandler
+            WeChatUnsubscribeHandler weChatUnsubscribeHandler,
+            WeChatImageMessageHandler weChatImageMessageHandler
     ){
 //        map.put(WeChatConstant.XmlMsgType.TEXT, weChatTextMessageHandler);
         map.put(WeChatConstant.EventType.CLICK.toLowerCase(), weChatClickEventMessageHandler);
@@ -40,6 +41,7 @@ public class WeChatMessageHandlerRouter {
         map.put(WeChatConstant.EventType.SCAN, weChatScannHandler);
         map.put(WeChatConstant.EventType.SCANCODE_PUSH, weChatScancodePushMessageHandler);
         map.put(WeChatConstant.EventType.UNSUBSCRIBE, weChatUnsubscribeHandler);
+        map.put(WeChatConstant.EventType.MEDIA_ID, weChatImageMessageHandler);
     }
 
     public static WeChatMessageHandler router(WeChatMessage weChatMessage){

+ 33 - 0
src/main/java/com/ematou/wxservice/service/MaterialService.java

@@ -0,0 +1,33 @@
+package com.ematou.wxservice.service;
+
+import com.ematou.wxservice.entity.pojo.Material;
+import com.ematou.wxservice.mapper.MaterialMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MaterialService {
+
+
+    @Autowired
+    private MaterialMapper materialMapper;
+
+    public int save(Material material){
+        return materialMapper.insertMaterial(material);
+    }
+
+    public int update(Material material){
+        return materialMapper.updateMaterial(material);
+    }
+
+    public Material queryByMediaId(String mediaId){
+        return materialMapper.queryMaterialByMediaId(mediaId);
+    }
+
+    public Material queryByFileName(String fileName){
+        return materialMapper.queryMaterialByFileName(fileName);
+    }
+    public int deleteByMediaId(String mediaId){
+        return materialMapper.deleteMaterialByMediaId(mediaId);
+    }
+}

+ 1 - 5
src/main/java/com/ematou/wxservice/service/UserInfoService.java

@@ -1,17 +1,13 @@
 package com.ematou.wxservice.service;
 
-import com.alibaba.fastjson.JSON;
-import com.ematou.wxservice.api.WeChatApi;
 import com.ematou.wxservice.api.WeChatApiRestTemplate;
 import com.ematou.wxservice.common.utils.SmsUtil;
 import com.ematou.wxservice.config.SmsConfig;
 import com.ematou.wxservice.entity.pojo.ScannVO;
 import com.ematou.wxservice.entity.pojo.UserInfo;
-import com.ematou.wxservice.entity.vo.AccessToken;
 import com.ematou.wxservice.entity.vo.BindingInfo;
 import com.ematou.wxservice.mapper.UserInfoMapper;
-import org.apache.ibatis.annotations.Param;
-import org.omg.IOP.Encoding;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;

+ 77 - 4
src/main/java/com/ematou/wxservice/service/WeChatService.java

@@ -5,8 +5,10 @@ import com.alibaba.fastjson.JSONObject;
 import com.ematou.wxservice.api.WeChatApi;
 import com.ematou.wxservice.api.WeChatApiRestTemplate;
 import com.ematou.wxservice.common.constant.WeChatConstant;
+import com.ematou.wxservice.common.utils.DateUtil;
 import com.ematou.wxservice.common.utils.SignUtil;
 import com.ematou.wxservice.config.WeChatGeneralConfig;
+import com.ematou.wxservice.entity.pojo.Material;
 import com.ematou.wxservice.entity.vo.AccessToken;
 import com.ematou.wxservice.entity.vo.BindingInfo;
 import com.ematou.wxservice.entity.vo.TemplateMessage;
@@ -17,13 +19,12 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import org.springframework.util.ResourceUtils;
 import org.springframework.util.StringUtils;
 
+import java.io.File;
 import java.text.DecimalFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
+import java.util.*;
 
 /**
  * @author lhm
@@ -43,6 +44,9 @@ public class WeChatService {
 
     @Autowired
     UserInfoMapper userInfoMapper;
+
+    @Autowired
+    private MaterialService materialService;
     @Autowired
     WeChatMessageService weChatMessageService;
     @Value("${wechat}")
@@ -227,4 +231,73 @@ public class WeChatService {
         result.put("signature", sign);
         return result;
     }
+
+
+    public String mediaUpload(String eventKey) {
+        try {
+            File file = null;
+            if (eventKey.equals(WeChatConstant.CustomEventKey.BUSINESS_COOPERATION)) {
+                file = ResourceUtils.getFile("classpath:static/images/business-cooperation.png");
+            } else if (eventKey.equals(WeChatConstant.CustomEventKey.AFTER_SALE_SERVICE)) {
+                file = ResourceUtils.getFile("classpath:static/images/after-sale-service.png");
+            }
+            boolean flag = false;
+            String mediaId ="";
+            String fileName = file.getName();
+            logger.info("fileName:{}", fileName);
+            Material material = materialService.queryByFileName(fileName);
+
+            logger.info("查询永久素材数据:{}", JSON.toJSONString(material));
+            String accessToken = this.getAccessToken().getAccessToken();
+            if(!Objects.isNull(material)){
+                mediaId = material.getMediaId();
+                String url = String.format(WeChatApi.MEDIA_GET.getUrl(), accessToken);
+                String requestBody = "{ \"media_id\": \"" + mediaId + "\" }";
+                String res = weChatApiRestTemplate.postForOther(url, requestBody);
+                if(res.contains("errcode")){
+                    flag = true;
+                }
+            }else {
+                flag = true;
+            }
+
+            if(flag) {
+                //在数据库和公众号服务器上未查到图片素材
+                String url = String.format(WeChatApi.MEDIA_UPLOAD.getUrl(), accessToken);
+                //String result = weChatApiRestTemplate.doPostByFile(url, null, file, "");
+                String result = weChatApiRestTemplate.postByStream(url, file);
+
+                JSONObject resObj = JSON.parseObject(result);
+                mediaId = resObj.getString("media_id");
+            }
+
+            if(Objects.isNull(material)){
+                long length = file.length();
+                material = new Material();
+                material.setMediaId(mediaId);
+                material.setFileName(fileName);
+                material.setFilePath(file.getPath());
+                material.setFileSize(length);
+                material.setFileType(WeChatConstant.XmlMsgType.IMAGE);
+                material.setCreateTime(DateUtil.formatDate(new Date()));
+
+                logger.info("添加永久素材数据:{}", JSON.toJSONString(material));
+                materialService.save(material);
+            }else {
+                if(!mediaId.equals(material.getMediaId())) {
+                    material.setMediaId(mediaId);
+                    material.setModTime(DateUtil.formatDate(new Date()));
+
+                    logger.info("修改永久素材数据:{}", JSON.toJSONString(material));
+                    materialService.update(material);
+                }
+            }
+            return mediaId;
+
+        } catch (Exception e) {
+            logger.error("上传公众号永久素材异常:", e);
+        }
+        return "";
+    }
+
 }

+ 89 - 0
src/main/resources/mybatis/MaterialMapper.xml

@@ -0,0 +1,89 @@
+<?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.ematou.wxservice.mapper.MaterialMapper">
+
+    <sql id="Base_Column_List">
+        media_id,
+        file_name,
+        file_size,
+        file_path,
+        file_type,
+        creator_id,
+        create_time,
+        moder_id,
+        mod_time
+    </sql>
+
+    <insert id="insertMaterial" >
+        insert into mp_material ( <include refid="Base_Column_List"/> )
+        values (#{material.mediaId},
+                #{material.fileName},
+                #{material.fileSize},
+                #{material.filePath},
+                #{material.fileType},
+                #{material.creatorId},
+                #{material.createTime},
+                #{material.moderId},
+                #{material.modTime}
+        )
+    </insert>
+
+
+    <update id="updateMaterial">
+        update mp_material
+        <set>
+            <if test="material.mediaId != null">
+                media_id=#{material.mediaId},
+            </if>
+            <if test="material.fileName != null">
+                file_name=#{material.fileName},
+            </if>
+            <if test="material.fileSize != null">
+                file_size=#{material.fileSize},
+            </if>
+            <if test="material.filePath != null">
+                file_path=#{material.filePath},
+            </if>
+            <if test="material.fileType != null">
+                file_type=#{material.fileType},
+            </if>
+            <if test="material.moderId != null">
+                moder_id=#{material.moderId},
+            </if>
+            <if test="material.modTime != null">
+                mod_time=#{material.modTime},
+            </if>
+            <if test="material.tmst != null">
+                tmst=#{material.tmst},
+            </if>
+        </set>
+        <if test="material.id">
+            where id=#{material.id}
+        </if>
+    </update>
+
+    <select id="queryMaterialByFileName" resultType="com.ematou.wxservice.entity.pojo.Material">
+        select
+        <include refid="Base_Column_List"/>
+        from mp_material
+        where 1=1
+        <if test="fileName != null">
+            and file_name = #{fileName}
+        </if>
+    </select>
+
+    <select id="queryMaterialByMediaId" resultType="com.ematou.wxservice.entity.pojo.Material">
+        select <include refid="Base_Column_List"/>
+            from mp_material
+        where media_id=#{mediaId}
+    </select>
+
+
+    <delete id="deleteMaterialByMediaId" >
+        delete from mp_material
+        where media_id=#{mediaId}
+    </delete>
+
+</mapper>

BIN
src/main/resources/static/images/after-sale-service.png


BIN
src/main/resources/static/images/business-cooperation.png