Просмотр исходного кода

微信网页登录基础接口

lijilei 3 лет назад
Родитель
Сommit
fae0ed3a2e
21 измененных файлов с 1454 добавлено и 11 удалено
  1. 16 1
      book-push/pom.xml
  2. 2 0
      book-push/src/main/java/com/book/push/Application.java
  3. 128 0
      book-push/src/main/java/com/book/push/config/WxMpConfiguration.java
  4. 77 0
      book-push/src/main/java/com/book/push/config/WxMpProperties.java
  5. 52 0
      book-push/src/main/java/com/book/push/controller/MenuIndexController.java
  6. 29 5
      book-push/src/main/java/com/book/push/controller/WxPortalController.java
  7. 26 5
      book-push/src/main/java/com/book/push/controller/WxRedirectController.java
  8. 24 0
      book-push/src/main/java/com/book/push/dao/mapper/CustomMapper.java
  9. 21 0
      book-push/src/main/java/com/book/push/dao/mapper/UserMapper.java
  10. 105 0
      book-push/src/main/java/com/book/push/dao/pojo/Custom.java
  11. 145 0
      book-push/src/main/java/com/book/push/dao/pojo/User.java
  12. 18 0
      book-push/src/main/java/com/book/push/service/dao/CustomService.java
  13. 14 0
      book-push/src/main/java/com/book/push/service/dao/UserService.java
  14. 26 0
      book-push/src/main/java/com/book/push/service/dao/impl/CustomServiceImpl.java
  15. 23 0
      book-push/src/main/java/com/book/push/service/dao/impl/UserServiceImpl.java
  16. 12 0
      book-push/src/main/java/com/book/push/task/KefuTask.java
  17. 52 0
      book-push/src/main/resources/application-dev.yml
  18. 52 0
      book-push/src/main/resources/application-test.yml
  19. 5 0
      book-push/src/main/resources/application.yml
  20. 261 0
      book-push/src/main/resources/mapper/CustomMapper.xml
  21. 366 0
      book-push/src/main/resources/mapper/UserMapper.xml

+ 16 - 1
book-push/pom.xml

@@ -101,7 +101,16 @@
             <artifactId>spring-boot-configuration-processor</artifactId>
             <optional>true</optional>
         </dependency>
-
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>3.3.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.jedis-lock</groupId>
+            <artifactId>jedis-lock</artifactId>
+            <version>1.0.0</version>
+        </dependency>
         <!-- lombok -->
         <dependency>
             <groupId>org.projectlombok</groupId>
@@ -118,6 +127,12 @@
             <artifactId>fastjson</artifactId>
             <version>1.2.75</version>
         </dependency>
+        <!--mybatis-->
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>1.3.2</version>
+        </dependency>
 
     </dependencies>
 </project>

+ 2 - 0
book-push/src/main/java/com/book/push/Application.java

@@ -1,5 +1,6 @@
 package com.book.push;
 
+import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 
@@ -8,6 +9,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
  * @author win7
  */
 @SpringBootApplication
+@MapperScan("com.book.push.dao.mapper")
 public class Application {
     public static void main(String[] args) {
         SpringApplication.run(Application.class);

+ 128 - 0
book-push/src/main/java/com/book/push/config/WxMpConfiguration.java

@@ -0,0 +1,128 @@
+package com.book.push.config;
+
+import com.book.push.handler.*;
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.common.redis.JedisWxRedisOps;
+import me.chanjar.weixin.mp.api.WxMpMessageRouter;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
+import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
+import me.chanjar.weixin.mp.config.impl.WxMpRedisConfigImpl;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPoolConfig;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static me.chanjar.weixin.common.api.WxConsts.EventType;
+import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
+import static me.chanjar.weixin.common.api.WxConsts.EventType.UNSUBSCRIBE;
+import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
+import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
+import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
+import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;
+
+/**
+ * wechat mp configuration
+ *
+ * @author win7
+ */
+@AllArgsConstructor
+@Configuration
+@EnableConfigurationProperties(WxMpProperties.class)
+public class WxMpConfiguration {
+    private final LogHandler logHandler;
+    private final NullHandler nullHandler;
+    private final KfSessionHandler kfSessionHandler;
+    private final StoreCheckNotifyHandler storeCheckNotifyHandler;
+    private final LocationHandler locationHandler;
+    private final MenuHandler menuHandler;
+    private final MsgHandler msgHandler;
+    private final UnsubscribeHandler unsubscribeHandler;
+    private final SubscribeHandler subscribeHandler;
+    private final ScanHandler scanHandler;
+    private final WxMpProperties properties;
+
+    @Bean
+    public WxMpService wxMpService() {
+        // 代码里 getConfigs()处报错的同学,请注意仔细阅读项目说明,你的IDE需要引入lombok插件!!!!
+        final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
+        if (configs == null) {
+            throw new RuntimeException("请配置公众号相关参数!");
+        }
+
+        WxMpService service = new WxMpServiceImpl();
+        service.setMultiConfigStorages(configs
+            .stream().map(a -> {
+                WxMpDefaultConfigImpl configStorage;
+                if (this.properties.isUseRedis()) {
+                    final WxMpProperties.RedisConfig redisConfig = this.properties.getRedisConfig();
+                    JedisPoolConfig poolConfig = new JedisPoolConfig();
+                    JedisPool jedisPool = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
+                       -1, redisConfig.getPassword());
+                    configStorage = new WxMpRedisConfigImpl(new JedisWxRedisOps(jedisPool), a.getAppId());
+                } else {
+                    configStorage = new WxMpDefaultConfigImpl();
+                }
+
+                configStorage.setAppId(a.getAppId());
+                configStorage.setSecret(a.getSecret());
+                configStorage.setToken(a.getToken());
+                configStorage.setAesKey(a.getAesKey());
+                return configStorage;
+            }).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
+
+
+
+        return service;
+    }
+
+    @Bean
+    public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
+        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
+
+        // 记录所有事件的日志 (异步执行)
+        newRouter.rule().handler(this.logHandler).next();
+
+        // 接收客服会话管理事件
+        newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)
+            .handler(this.kfSessionHandler).end();
+        newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)
+            .handler(this.kfSessionHandler).end();
+        newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)
+            .handler(this.kfSessionHandler).end();
+
+        // 门店审核事件
+        newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();
+
+        // 自定义菜单事件
+        newRouter.rule().async(false).msgType(EVENT).event(EventType.CLICK).handler(this.menuHandler).end();
+
+        // 点击菜单连接事件
+        newRouter.rule().async(false).msgType(EVENT).event(EventType.VIEW).handler(this.nullHandler).end();
+
+        // 关注事件
+        newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();
+
+        // 取消关注事件
+        newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end();
+
+        // 上报地理位置事件
+        newRouter.rule().async(false).msgType(EVENT).event(EventType.LOCATION).handler(this.locationHandler).end();
+
+        // 接收地理位置消息
+        newRouter.rule().async(false).msgType(XmlMsgType.LOCATION).handler(this.locationHandler).end();
+
+        // 扫码事件
+        newRouter.rule().async(false).msgType(EVENT).event(EventType.SCAN).handler(this.scanHandler).end();
+
+        // 默认
+        newRouter.rule().async(false).handler(this.msgHandler).end();
+
+        return newRouter;
+    }
+
+}

+ 77 - 0
book-push/src/main/java/com/book/push/config/WxMpProperties.java

@@ -0,0 +1,77 @@
+package com.book.push.config;
+
+import lombok.Data;
+import org.apache.logging.log4j.core.util.JsonUtils;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+/**
+ * wechat mp properties
+ *
+ * @author Binary Wang(https://github.com/binarywang)
+ */
+@Data
+@ConfigurationProperties(prefix = "wx.mp")
+public class WxMpProperties {
+    /**
+     * 是否使用redis存储access token
+     */
+    private boolean useRedis;
+
+    /**
+     * redis 配置
+     */
+    private RedisConfig redisConfig;
+
+    @Data
+    public static class RedisConfig {
+        /**
+         * redis服务器 主机地址
+         */
+        private String host;
+
+        /**
+         * redis服务器 端口号
+         */
+        private Integer port;
+
+        /**
+         * redis服务器 密码
+         */
+        private String password;
+    }
+
+    /**
+     * 多个公众号配置信息
+     */
+    private List<MpConfig> configs;
+
+    @Data
+    public static class MpConfig {
+        /**
+         * 设置微信公众号的appid
+         */
+        private String appId;
+
+        /**
+         * 设置微信公众号的app secret
+         */
+        private String secret;
+
+        /**
+         * 设置微信公众号的token
+         */
+        private String token;
+
+        /**
+         * 设置微信公众号的EncodingAESKey
+         */
+        private String aesKey;
+    }
+
+    @Override
+    public String toString() {
+        return JsonUtils.toJson(this);
+    }
+}

+ 52 - 0
book-push/src/main/java/com/book/push/controller/MenuIndexController.java

@@ -0,0 +1,52 @@
+package com.book.push.controller;
+
+/**
+ * created in 2021/8/17
+ * Project: book-store
+ *
+ * @author win7
+ */
+
+import com.book.push.dao.pojo.User;
+import com.book.push.service.dao.UserService;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * @author
+ */
+@AllArgsConstructor
+@RestController
+@RequestMapping("/menu/index")
+public class MenuIndexController {
+
+    /**
+     * //FIXME
+     *
+     * 重定向urL,需要改
+     */
+    public static final String REDIRECT_URL = "/wx/redirect/{appid}/greet";
+
+    @GetMapping("/{state}")
+    public String BookMain(HttpServletRequest request, @PathVariable String state) {
+
+        StringBuffer url = request.getRequestURL();
+        String contextUrl = url.delete(url.length() - request.getRequestURI().length(), url.length()).append("/").toString();
+        String[] split = contextUrl.split("\\.");
+        String appid = split[0];
+
+        String auto2Url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=SCOPE&state=%s#wechat_redirect ";
+        String redirect_url = REDIRECT_URL.replace("{appid}",appid);
+        String format = String.format(auto2Url, appid, redirect_url, state);
+        return "redirect:" + format;
+
+
+    }
+
+
+}

+ 29 - 5
book-push/src/main/java/com/book/push/controller/WxPortalController.java

@@ -10,8 +10,8 @@ import org.apache.commons.lang3.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
 /**
- *
  * 微信认证
+ *
  * @author
  */
 @Slf4j
@@ -22,6 +22,16 @@ public class WxPortalController {
     private final WxMpService wxService;
     private final WxMpMessageRouter messageRouter;
 
+    /**
+     * GET
+     *
+     * @param appid
+     * @param signature
+     * @param timestamp
+     * @param nonce
+     * @param echostr
+     * @return
+     */
     @GetMapping(produces = "text/plain;charset=utf-8")
     public String authGet(@PathVariable String appid,
                           @RequestParam(name = "signature", required = false) String signature,
@@ -30,7 +40,7 @@ public class WxPortalController {
                           @RequestParam(name = "echostr", required = false) String echostr) {
 
         log.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature,
-            timestamp, nonce, echostr);
+                timestamp, nonce, echostr);
         if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
             throw new IllegalArgumentException("请求参数非法,请核实!");
         }
@@ -46,6 +56,20 @@ public class WxPortalController {
         return "非法请求";
     }
 
+
+    /**
+     * POST
+     *
+     * @param appid
+     * @param requestBody
+     * @param signature
+     * @param timestamp
+     * @param nonce
+     * @param openid
+     * @param encType
+     * @param msgSignature
+     * @return
+     */
     @PostMapping(produces = "application/xml; charset=UTF-8")
     public String post(@PathVariable String appid,
                        @RequestBody String requestBody,
@@ -56,8 +80,8 @@ public class WxPortalController {
                        @RequestParam(name = "encrypt_type", required = false) String encType,
                        @RequestParam(name = "msg_signature", required = false) String msgSignature) {
         log.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
-                + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
-            openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
+                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
+                openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
 
         if (!this.wxService.switchover(appid)) {
             throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
@@ -80,7 +104,7 @@ public class WxPortalController {
         } else if ("aes".equalsIgnoreCase(encType)) {
             // aes加密的消息
             WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
-                timestamp, nonce, msgSignature);
+                    timestamp, nonce, msgSignature);
             log.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
             WxMpXmlOutMessage outMessage = this.route(inMessage);
             if (outMessage == null) {

+ 26 - 5
book-push/src/main/java/com/book/push/controller/WxRedirectController.java

@@ -1,10 +1,14 @@
 package com.book.push.controller;
 
+import com.book.push.dao.pojo.User;
+import com.book.push.service.dao.UserService;
 import lombok.AllArgsConstructor;
 import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
 import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
+import org.checkerframework.checker.units.qual.A;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.ModelMap;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -12,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
 /**
+ * 接收微信重定向
  * @author win7
  */
 @AllArgsConstructor
@@ -19,25 +24,41 @@ import org.springframework.web.bind.annotation.RequestParam;
 @RequestMapping("/wx/redirect/{appid}")
 public class WxRedirectController {
     private final WxMpService wxService;
-
+    @Autowired
+    private UserService userService;
+    /**
+     * //FIXME
+     * 前端页面url
+     */
+    private final static String FRONT_URL = "/%s/%s/%d";
 
     /**
-     * 接收微信静默授权,获取用户信息
+     * 接收微信静默授权,获取用户信息,跳转前台页面
+     *
      * @param appid
      * @param code
      * @param map
      * @return
      */
     @RequestMapping("/greet")
-    public String greetUser(@PathVariable String appid, @RequestParam String code, ModelMap map) {
+    public String greetUser(@PathVariable String appid, @RequestParam String code, @RequestParam String state, ModelMap map) {
         if (!this.wxService.switchover(appid)) {
             throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
         }
 
         try {
             WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
-            WxOAuth2UserInfo user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
-            map.put("user", user);
+            WxOAuth2UserInfo wxOAuth2UserInfo = wxService.getOAuth2Service().getUserInfo(accessToken, null);
+            map.put("user", wxOAuth2UserInfo);
+            User user = new User();
+            user.setOpenid(wxOAuth2UserInfo.getOpenid());
+            user = userService.selectUserByUser(user);
+            if (user==null){
+                //todo
+            }
+            String openid = user.getOpenid();
+            String frontUrl = String.format(FRONT_URL, state, appid, user.getId());
+            return "redirect:" + frontUrl;
         } catch (WxErrorException e) {
             e.printStackTrace();
         }

+ 24 - 0
book-push/src/main/java/com/book/push/dao/mapper/CustomMapper.java

@@ -0,0 +1,24 @@
+package com.book.push.dao.mapper;
+
+
+import com.book.push.dao.pojo.Custom;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+@Repository
+public interface CustomMapper {
+    int deleteByPrimaryKey(Integer id);
+
+    int insert(Custom record);
+
+    int insertSelective(Custom record);
+
+    Custom selectByPrimaryKey(Integer id);
+
+    int updateByPrimaryKeySelective(Custom record);
+
+    int updateByPrimaryKey(Custom record);
+
+
+    List<Custom> selectListBeforeSendTime();
+}

+ 21 - 0
book-push/src/main/java/com/book/push/dao/mapper/UserMapper.java

@@ -0,0 +1,21 @@
+package com.book.push.dao.mapper;
+
+import com.book.push.dao.pojo.User;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface UserMapper {
+    int deleteByPrimaryKey(Long id);
+
+    int insert(User record);
+
+    int insertSelective(User record);
+
+    User selectByPrimaryKey(Long id);
+
+    int updateByPrimaryKeySelective(User record);
+
+    int updateByPrimaryKey(User record);
+
+    User selectByUser(User user);
+}

+ 105 - 0
book-push/src/main/java/com/book/push/dao/pojo/Custom.java

@@ -0,0 +1,105 @@
+package com.book.push.dao.pojo;
+
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * custom
+ * @author 
+ */
+@Data
+public class Custom implements Serializable {
+    /**
+     * ID
+     */
+    private Integer id;
+
+    /**
+     * 任务名称
+     */
+    private String title;
+
+    private Integer adminId;
+
+    /**
+     * 消息内容
+     */
+    private Object messageJson;
+
+    /**
+     * 发送时间
+     */
+    private Integer sendtime;
+
+    /**
+     * 接收用户
+     */
+    private Object userJson;
+
+    /**
+     * 发送总人数
+     */
+    private Integer sendNum;
+
+    /**
+     * 发送成功人数
+     */
+    private Integer successNum;
+
+    /**
+     * 发送失败人数
+     */
+    private Integer failNum;
+
+    /**
+     * 状态
+     */
+    private Object statue;
+
+    /**
+     * 创建时间
+     */
+    private Integer createtime;
+
+    /**
+     * 更新时间
+     */
+    private Integer updatetime;
+
+    /**
+     * 创建者admin_id
+     */
+    private Integer createdAdminId;
+
+    /**
+     * 客服消息素材推送记录表id(可空,默认0无关连)
+     */
+    private Integer customMediaPushId;
+
+    /**
+     * 文字链
+     */
+    private String messageText;
+
+    /**
+     * 类型:0=图文,1=文字链
+     */
+    private Object messageType;
+
+    /**
+     * 公众号id。official_account_type为0时,为admin表(渠道商)的id;official_account_type为1时,此字段为subscription表id。
+     */
+    private Integer officialAccountId;
+
+    /**
+     * 公众号类型:0=服务号,1=订阅号
+     */
+    private Object officialAccountType;
+
+    /**
+     * 创建来源 1:客服消息添加 2:群发
+     */
+    private Object createdFrom;
+
+    private static final long serialVersionUID = 1L;
+}

+ 145 - 0
book-push/src/main/java/com/book/push/dao/pojo/User.java

@@ -0,0 +1,145 @@
+package com.book.push.dao.pojo;
+
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * user
+ * @author 
+ */
+@Data
+public class User implements Serializable {
+    private Long id;
+
+    /**
+     * 微信openID
+     */
+    private String openid;
+
+    /**
+     * 微信unionid
+     */
+    private String unionid;
+
+    /**
+     * 访客id
+     */
+    private String visitor;
+
+    /**
+     * 昵称
+     */
+    private String nickname;
+
+    /**
+     * 状态值:0=未知,1=男性,2=女性
+     */
+    private Object sex;
+
+    /**
+     * 手机号
+     */
+    private String mobile;
+
+    /**
+     * 头像
+     */
+    private String avatar;
+
+    /**
+     * 关注公众号状态:1=已关注,0=未关注
+     */
+    private Object isSubscribe;
+
+    /**
+     * 关注引导公众号状态:1=已关注,0=未关注
+     */
+    private Object subscriptionExtend;
+
+    /**
+     * 关注时间
+     */
+    private Integer subscribeTime;
+
+    /**
+     * 喜好书籍分类
+     */
+    private String bookCategoryIds;
+
+    /**
+     * 微信交互时间戳
+     */
+    private Integer operateTime;
+
+    /**
+     * 首充状态:1=已充值,0=未充值
+     */
+    private Object isPay;
+
+    /**
+     * 充值看点数
+     */
+    private Integer kandian;
+
+    /**
+     * 赠送看点数
+     */
+    private Integer freeKandian;
+
+    /**
+     * VIP到期时间
+     */
+    private Integer vipEndtime;
+
+    /**
+     * 注册IP
+     */
+    private String registerIp;
+
+    /**
+     * 国家
+     */
+    private String country;
+
+    /**
+     * 区域
+     */
+    private String area;
+
+    /**
+     * 省份
+     */
+    private String province;
+
+    /**
+     * 城市
+     */
+    private String city;
+
+    /**
+     * isp服务商
+     */
+    private String isp;
+
+    /**
+     * 关联渠道商ID
+     */
+    private Integer channelId;
+
+    /**
+     * 状态值:0=禁用,1=正常
+     */
+    private Object state;
+
+    /**
+     * 创建时间
+     */
+    private Integer createtime;
+
+    /**
+     * 更新时间
+     */
+    private Integer updatetime;
+
+    private static final long serialVersionUID = 1L;
+}

+ 18 - 0
book-push/src/main/java/com/book/push/service/dao/CustomService.java

@@ -0,0 +1,18 @@
+package com.book.push.service.dao;
+
+import com.book.push.dao.pojo.Custom;
+
+import java.util.List;
+
+/**
+ * created in 2021/8/17
+ * Project: book-store
+ *
+ * @author win7
+ */
+
+public interface CustomService {
+
+     List<Custom> selectListBeforeSendTime();
+
+}

+ 14 - 0
book-push/src/main/java/com/book/push/service/dao/UserService.java

@@ -0,0 +1,14 @@
+package com.book.push.service.dao;
+
+import com.book.push.dao.pojo.User;
+
+/**
+ * created in 2021/8/17
+ * Project: book-store
+ *
+ * @author win7
+ */
+
+public interface UserService {
+     User selectUserByUser(User user);
+}

+ 26 - 0
book-push/src/main/java/com/book/push/service/dao/impl/CustomServiceImpl.java

@@ -0,0 +1,26 @@
+package com.book.push.service.dao.impl;
+
+import com.book.push.dao.mapper.CustomMapper;
+import com.book.push.dao.pojo.Custom;
+import com.book.push.service.dao.CustomService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * created in 2021/8/17
+ * Project: book-store
+ *
+ * @author win7
+ */
+@Service("customService")
+public class CustomServiceImpl implements CustomService {
+    @Autowired
+    private CustomMapper customMapper;
+
+    @Override
+    public List<Custom> selectListBeforeSendTime() {
+        return customMapper.selectListBeforeSendTime();
+    }
+}

+ 23 - 0
book-push/src/main/java/com/book/push/service/dao/impl/UserServiceImpl.java

@@ -0,0 +1,23 @@
+package com.book.push.service.dao.impl;
+
+import com.book.push.dao.mapper.UserMapper;
+import com.book.push.dao.pojo.User;
+import com.book.push.service.dao.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * created in 2021/8/17
+ * Project: book-store
+ *
+ * @author win7
+ */
+@Service("userService")
+public class UserServiceImpl implements UserService {
+    @Autowired
+    private UserMapper userMapper;
+    @Override
+    public User selectUserByUser(User user) {
+        return userMapper.selectByUser(user);
+    }
+}

+ 12 - 0
book-push/src/main/java/com/book/push/task/KefuTask.java

@@ -0,0 +1,12 @@
+package com.book.push.task;
+
+/**
+ * created in 2021/8/17
+ * Project: book-store
+ * 客服消息
+ *
+ * @author win7
+ */
+
+public class KefuTask {
+}

+ 52 - 0
book-push/src/main/resources/application-dev.yml

@@ -0,0 +1,52 @@
+server:
+  port: 8080
+
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://121.41.100.198:3306/test_cps?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
+    username: root
+    password: root
+    #下面为连接池补充设置
+    druid:
+      initial-size: 5 # 初始化
+      max-active: 5 # 最大
+      min-idle: 5 # 最小
+      max-wait: 6000 # 超时时间
+      time-between-eviction-runs-millis: 60000 # 每分钟检查一次空闲链接
+      min-evictable-idle-time-millis: 300000 # 空闲链接可以保持多久而不被驱逐
+      # 检测链接是否有效的query
+      validation-query: SELECT 1 FROM DUAL
+      test-while-idle: true # 检测到链接空闲时,验证是否有效
+      test-on-borrow: false # 申请链接时,不检测
+      test-on-return: false # 返回链接时,不检测
+      pool-prepared-statements: false # 是否缓存preparedStatement,oracle打开,mysql关闭
+      # 如果上面开启了游标,这里要设置一下大小,例如 50
+      max-pool-prepared-statement-per-connection-size: -1
+      # 统计、监控配置
+      filters: stat,wall # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
+      # 合并执行的相同sql,避免因为参数不同而统计多条sql语句;开启慢sql记录
+      connect-properties: config.stat.mergeSql=true;config.stat.slowSqlMillis=500
+      use-global-data-source-stat: true # 合并多个DruidDataSource的监控数据
+      stat-view-servlet:
+        enabled: true
+        login-username: tianyun
+        login-password: tianyunperfect
+        allow: # 默认运行所有
+        deny: # 默认即可
+        reset-enable: true
+
+
+mybatis:
+  type-aliases-package: com.book.server.entity
+  mapper-locations: classpath:mapper/*Mapper.xml
+
+
+# 设置debug模式下打印mysql
+logging:
+  level:
+    com:
+      book:
+        server:
+          mapper: debug

+ 52 - 0
book-push/src/main/resources/application-test.yml

@@ -0,0 +1,52 @@
+server:
+  port: 9999
+
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://www.tianyunperfect.cn:3306/test_cps?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
+    username: test_cps
+    password: xKysDECnJLXkMYdJ
+    #下面为连接池补充设置
+    druid:
+      initial-size: 5 # 初始化
+      max-active: 5 # 最大
+      min-idle: 5 # 最小
+      max-wait: 6000 # 超时时间
+      time-between-eviction-runs-millis: 60000 # 每分钟检查一次空闲链接
+      min-evictable-idle-time-millis: 300000 # 空闲链接可以保持多久而不被驱逐
+      # 检测链接是否有效的query
+      validation-query: SELECT 1 FROM DUAL
+      test-while-idle: true # 检测到链接空闲时,验证是否有效
+      test-on-borrow: false # 申请链接时,不检测
+      test-on-return: false # 返回链接时,不检测
+      pool-prepared-statements: false # 是否缓存preparedStatement,oracle打开,mysql关闭
+      # 如果上面开启了游标,这里要设置一下大小,例如 50
+      max-pool-prepared-statement-per-connection-size: -1
+      # 统计、监控配置
+      filters: stat,wall # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
+      # 合并执行的相同sql,避免因为参数不同而统计多条sql语句;开启慢sql记录
+      connect-properties: config.stat.mergeSql=true;config.stat.slowSqlMillis=500
+      use-global-data-source-stat: true # 合并多个DruidDataSource的监控数据
+      stat-view-servlet:
+        enabled: true
+        login-username: tianyun
+        login-password: tianyunperfect
+        allow: # 默认运行所有
+        deny: # 默认即可
+        reset-enable: true
+
+
+mybatis:
+  type-aliases-package: com.book.server.entity
+  mapper-locations: classpath:mapper/*Mapper.xml
+
+
+# 设置debug模式下打印mysql
+logging:
+  level:
+    com:
+      book:
+        server:
+          mapper: debug

+ 5 - 0
book-push/src/main/resources/application.yml

@@ -0,0 +1,5 @@
+spring:
+  spring:
+    # 环境 dev:开发环境|test:测试环境|prod:生产环境
+    profiles:
+      active: dev #激活的配置文件

+ 261 - 0
book-push/src/main/resources/mapper/CustomMapper.xml

@@ -0,0 +1,261 @@
+<?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.book.push.dao.mapper.CustomMapper">
+    <resultMap id="BaseResultMap" type="com.book.push.dao.pojo.Custom">
+        <id column="id" jdbcType="INTEGER" property="id"/>
+        <result column="title" jdbcType="VARCHAR" property="title"/>
+        <result column="admin_id" jdbcType="INTEGER" property="adminId"/>
+        <result column="message_json" jdbcType="OTHER" property="messageJson"/>
+        <result column="sendtime" jdbcType="INTEGER" property="sendtime"/>
+        <result column="user_json" jdbcType="OTHER" property="userJson"/>
+        <result column="send_num" jdbcType="INTEGER" property="sendNum"/>
+        <result column="success_num" jdbcType="INTEGER" property="successNum"/>
+        <result column="fail_num" jdbcType="INTEGER" property="failNum"/>
+        <result column="statue" jdbcType="OTHER" property="statue"/>
+        <result column="createtime" jdbcType="INTEGER" property="createtime"/>
+        <result column="updatetime" jdbcType="INTEGER" property="updatetime"/>
+        <result column="created_admin_id" jdbcType="INTEGER" property="createdAdminId"/>
+        <result column="custom_media_push_id" jdbcType="INTEGER" property="customMediaPushId"/>
+        <result column="message_text" jdbcType="VARCHAR" property="messageText"/>
+        <result column="message_type" jdbcType="OTHER" property="messageType"/>
+        <result column="official_account_id" jdbcType="INTEGER" property="officialAccountId"/>
+        <result column="official_account_type" jdbcType="OTHER" property="officialAccountType"/>
+        <result column="created_from" jdbcType="OTHER" property="createdFrom"/>
+    </resultMap>
+    <sql id="Base_Column_List">
+        id, title, admin_id, message_json, sendtime, user_json, send_num, success_num, fail_num,
+    statue, createtime, updatetime, created_admin_id, custom_media_push_id, `message_text`, 
+    message_type, official_account_id, official_account_type, created_from
+    </sql>
+    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
+        select
+        <include refid="Base_Column_List"/>
+        from custom
+        where id = #{id,jdbcType=INTEGER}
+    </select>
+    <select id="selectListBeforeSendTime" resultType="com.book.push.dao.pojo.Custom">
+        select *
+        from custom
+        where sendtime > UNIX_TIMESTAMP(NOW());
+
+    </select>
+    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
+        delete
+        from custom
+        where id = #{id,jdbcType=INTEGER}
+    </delete>
+    <insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.book.push.dao.pojo.Custom"
+            useGeneratedKeys="true">
+        insert into custom (title, admin_id, message_json,
+                            sendtime, user_json, send_num,
+                            success_num, fail_num, statue,
+                            createtime, updatetime, created_admin_id,
+                            custom_media_push_id, `message_text`, message_type,
+                            official_account_id, official_account_type, created_from)
+        values (#{title,jdbcType=VARCHAR}, #{adminId,jdbcType=INTEGER}, #{messageJson,jdbcType=OTHER},
+                #{sendtime,jdbcType=INTEGER}, #{userJson,jdbcType=OTHER}, #{sendNum,jdbcType=INTEGER},
+                #{successNum,jdbcType=INTEGER}, #{failNum,jdbcType=INTEGER}, #{statue,jdbcType=OTHER},
+                #{createtime,jdbcType=INTEGER}, #{updatetime,jdbcType=INTEGER}, #{createdAdminId,jdbcType=INTEGER},
+                #{customMediaPushId,jdbcType=INTEGER}, #{messageText,jdbcType=VARCHAR}, #{messageType,jdbcType=OTHER},
+                #{officialAccountId,jdbcType=INTEGER}, #{officialAccountType,jdbcType=OTHER},
+                #{createdFrom,jdbcType=OTHER})
+    </insert>
+    <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.book.push.dao.pojo.Custom"
+            useGeneratedKeys="true">
+        insert into custom
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="title != null">
+                title,
+            </if>
+            <if test="adminId != null">
+                admin_id,
+            </if>
+            <if test="messageJson != null">
+                message_json,
+            </if>
+            <if test="sendtime != null">
+                sendtime,
+            </if>
+            <if test="userJson != null">
+                user_json,
+            </if>
+            <if test="sendNum != null">
+                send_num,
+            </if>
+            <if test="successNum != null">
+                success_num,
+            </if>
+            <if test="failNum != null">
+                fail_num,
+            </if>
+            <if test="statue != null">
+                statue,
+            </if>
+            <if test="createtime != null">
+                createtime,
+            </if>
+            <if test="updatetime != null">
+                updatetime,
+            </if>
+            <if test="createdAdminId != null">
+                created_admin_id,
+            </if>
+            <if test="customMediaPushId != null">
+                custom_media_push_id,
+            </if>
+            <if test="messageText != null">
+                `message_text`,
+            </if>
+            <if test="messageType != null">
+                message_type,
+            </if>
+            <if test="officialAccountId != null">
+                official_account_id,
+            </if>
+            <if test="officialAccountType != null">
+                official_account_type,
+            </if>
+            <if test="createdFrom != null">
+                created_from,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="title != null">
+                #{title,jdbcType=VARCHAR},
+            </if>
+            <if test="adminId != null">
+                #{adminId,jdbcType=INTEGER},
+            </if>
+            <if test="messageJson != null">
+                #{messageJson,jdbcType=OTHER},
+            </if>
+            <if test="sendtime != null">
+                #{sendtime,jdbcType=INTEGER},
+            </if>
+            <if test="userJson != null">
+                #{userJson,jdbcType=OTHER},
+            </if>
+            <if test="sendNum != null">
+                #{sendNum,jdbcType=INTEGER},
+            </if>
+            <if test="successNum != null">
+                #{successNum,jdbcType=INTEGER},
+            </if>
+            <if test="failNum != null">
+                #{failNum,jdbcType=INTEGER},
+            </if>
+            <if test="statue != null">
+                #{statue,jdbcType=OTHER},
+            </if>
+            <if test="createtime != null">
+                #{createtime,jdbcType=INTEGER},
+            </if>
+            <if test="updatetime != null">
+                #{updatetime,jdbcType=INTEGER},
+            </if>
+            <if test="createdAdminId != null">
+                #{createdAdminId,jdbcType=INTEGER},
+            </if>
+            <if test="customMediaPushId != null">
+                #{customMediaPushId,jdbcType=INTEGER},
+            </if>
+            <if test="messageText != null">
+                #{messageText,jdbcType=VARCHAR},
+            </if>
+            <if test="messageType != null">
+                #{messageType,jdbcType=OTHER},
+            </if>
+            <if test="officialAccountId != null">
+                #{officialAccountId,jdbcType=INTEGER},
+            </if>
+            <if test="officialAccountType != null">
+                #{officialAccountType,jdbcType=OTHER},
+            </if>
+            <if test="createdFrom != null">
+                #{createdFrom,jdbcType=OTHER},
+            </if>
+        </trim>
+    </insert>
+    <update id="updateByPrimaryKeySelective" parameterType="com.book.push.dao.pojo.Custom">
+        update custom
+        <set>
+            <if test="title != null">
+                title = #{title,jdbcType=VARCHAR},
+            </if>
+            <if test="adminId != null">
+                admin_id = #{adminId,jdbcType=INTEGER},
+            </if>
+            <if test="messageJson != null">
+                message_json = #{messageJson,jdbcType=OTHER},
+            </if>
+            <if test="sendtime != null">
+                sendtime = #{sendtime,jdbcType=INTEGER},
+            </if>
+            <if test="userJson != null">
+                user_json = #{userJson,jdbcType=OTHER},
+            </if>
+            <if test="sendNum != null">
+                send_num = #{sendNum,jdbcType=INTEGER},
+            </if>
+            <if test="successNum != null">
+                success_num = #{successNum,jdbcType=INTEGER},
+            </if>
+            <if test="failNum != null">
+                fail_num = #{failNum,jdbcType=INTEGER},
+            </if>
+            <if test="statue != null">
+                statue = #{statue,jdbcType=OTHER},
+            </if>
+            <if test="createtime != null">
+                createtime = #{createtime,jdbcType=INTEGER},
+            </if>
+            <if test="updatetime != null">
+                updatetime = #{updatetime,jdbcType=INTEGER},
+            </if>
+            <if test="createdAdminId != null">
+                created_admin_id = #{createdAdminId,jdbcType=INTEGER},
+            </if>
+            <if test="customMediaPushId != null">
+                custom_media_push_id = #{customMediaPushId,jdbcType=INTEGER},
+            </if>
+            <if test="messageText != null">
+                `message_text` = #{messageText,jdbcType=VARCHAR},
+            </if>
+            <if test="messageType != null">
+                message_type = #{messageType,jdbcType=OTHER},
+            </if>
+            <if test="officialAccountId != null">
+                official_account_id = #{officialAccountId,jdbcType=INTEGER},
+            </if>
+            <if test="officialAccountType != null">
+                official_account_type = #{officialAccountType,jdbcType=OTHER},
+            </if>
+            <if test="createdFrom != null">
+                created_from = #{createdFrom,jdbcType=OTHER},
+            </if>
+        </set>
+        where id = #{id,jdbcType=INTEGER}
+    </update>
+    <update id="updateByPrimaryKey" parameterType="com.book.push.dao.pojo.Custom">
+        update custom
+        set title                 = #{title,jdbcType=VARCHAR},
+            admin_id              = #{adminId,jdbcType=INTEGER},
+            message_json          = #{messageJson,jdbcType=OTHER},
+            sendtime              = #{sendtime,jdbcType=INTEGER},
+            user_json             = #{userJson,jdbcType=OTHER},
+            send_num              = #{sendNum,jdbcType=INTEGER},
+            success_num           = #{successNum,jdbcType=INTEGER},
+            fail_num              = #{failNum,jdbcType=INTEGER},
+            statue                = #{statue,jdbcType=OTHER},
+            createtime            = #{createtime,jdbcType=INTEGER},
+            updatetime            = #{updatetime,jdbcType=INTEGER},
+            created_admin_id      = #{createdAdminId,jdbcType=INTEGER},
+            custom_media_push_id  = #{customMediaPushId,jdbcType=INTEGER},
+            `message_text`        = #{messageText,jdbcType=VARCHAR},
+            message_type          = #{messageType,jdbcType=OTHER},
+            official_account_id   = #{officialAccountId,jdbcType=INTEGER},
+            official_account_type = #{officialAccountType,jdbcType=OTHER},
+            created_from          = #{createdFrom,jdbcType=OTHER}
+        where id = #{id,jdbcType=INTEGER}
+    </update>
+</mapper>

+ 366 - 0
book-push/src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,366 @@
+<?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.book.push.dao.mapper.UserMapper">
+  <resultMap id="BaseResultMap" type="com.book.push.dao.pojo.User">
+    <id column="id" jdbcType="BIGINT" property="id" />
+    <result column="openid" jdbcType="VARCHAR" property="openid" />
+    <result column="unionid" jdbcType="VARCHAR" property="unionid" />
+    <result column="visitor" jdbcType="VARCHAR" property="visitor" />
+    <result column="nickname" jdbcType="VARCHAR" property="nickname" />
+    <result column="sex" jdbcType="OTHER" property="sex" />
+    <result column="mobile" jdbcType="CHAR" property="mobile" />
+    <result column="avatar" jdbcType="VARCHAR" property="avatar" />
+    <result column="is_subscribe" jdbcType="OTHER" property="isSubscribe" />
+    <result column="subscription_extend" jdbcType="OTHER" property="subscriptionExtend" />
+    <result column="subscribe_time" jdbcType="INTEGER" property="subscribeTime" />
+    <result column="book_category_ids" jdbcType="VARCHAR" property="bookCategoryIds" />
+    <result column="operate_time" jdbcType="INTEGER" property="operateTime" />
+    <result column="is_pay" jdbcType="OTHER" property="isPay" />
+    <result column="kandian" jdbcType="INTEGER" property="kandian" />
+    <result column="free_kandian" jdbcType="INTEGER" property="freeKandian" />
+    <result column="vip_endtime" jdbcType="INTEGER" property="vipEndtime" />
+    <result column="register_ip" jdbcType="VARCHAR" property="registerIp" />
+    <result column="country" jdbcType="VARCHAR" property="country" />
+    <result column="area" jdbcType="VARCHAR" property="area" />
+    <result column="province" jdbcType="VARCHAR" property="province" />
+    <result column="city" jdbcType="VARCHAR" property="city" />
+    <result column="isp" jdbcType="VARCHAR" property="isp" />
+    <result column="channel_id" jdbcType="INTEGER" property="channelId" />
+    <result column="state" jdbcType="OTHER" property="state" />
+    <result column="createtime" jdbcType="INTEGER" property="createtime" />
+    <result column="updatetime" jdbcType="INTEGER" property="updatetime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    id, openid, unionid, visitor, nickname, sex, mobile, avatar, is_subscribe, subscription_extend, 
+    subscribe_time, book_category_ids, operate_time, is_pay, kandian, free_kandian, vip_endtime, 
+    register_ip, country, area, province, city, isp, channel_id, `state`, createtime, 
+    updatetime
+  </sql>
+  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
+    select 
+    <include refid="Base_Column_List" />
+    from user
+    where id = #{id,jdbcType=BIGINT}
+  </select>
+    <select id="selectByUser" resultType="com.book.push.dao.pojo.User" parameterType="com.book.push.dao.pojo.User">
+
+        select id from user
+      <trim prefix="WHERE" prefixOverrides="AND | OR">
+        <if test="openid!=null and openid!=''">
+          and openid != #{openid}
+        </if>
+        <if test="mobile!=null and mobile!=''">
+          and mobile != #{mobile}
+        </if>
+        <if test="channel_id!=null and channel_id!=0">
+          and channel_id != #{channel_id}
+        </if>
+
+
+      </trim>
+
+
+
+    </select>
+    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
+    delete from user
+    where id = #{id,jdbcType=BIGINT}
+  </delete>
+  <insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.book.push.dao.pojo.User" useGeneratedKeys="true">
+    insert into user (openid, unionid, visitor, 
+      nickname, sex, mobile, avatar, 
+      is_subscribe, subscription_extend, subscribe_time, 
+      book_category_ids, operate_time, is_pay, 
+      kandian, free_kandian, vip_endtime, 
+      register_ip, country, area, 
+      province, city, isp, 
+      channel_id, `state`, createtime, 
+      updatetime)
+    values (#{openid,jdbcType=VARCHAR}, #{unionid,jdbcType=VARCHAR}, #{visitor,jdbcType=VARCHAR}, 
+      #{nickname,jdbcType=VARCHAR}, #{sex,jdbcType=OTHER}, #{mobile,jdbcType=CHAR}, #{avatar,jdbcType=VARCHAR}, 
+      #{isSubscribe,jdbcType=OTHER}, #{subscriptionExtend,jdbcType=OTHER}, #{subscribeTime,jdbcType=INTEGER}, 
+      #{bookCategoryIds,jdbcType=VARCHAR}, #{operateTime,jdbcType=INTEGER}, #{isPay,jdbcType=OTHER}, 
+      #{kandian,jdbcType=INTEGER}, #{freeKandian,jdbcType=INTEGER}, #{vipEndtime,jdbcType=INTEGER}, 
+      #{registerIp,jdbcType=VARCHAR}, #{country,jdbcType=VARCHAR}, #{area,jdbcType=VARCHAR}, 
+      #{province,jdbcType=VARCHAR}, #{city,jdbcType=VARCHAR}, #{isp,jdbcType=VARCHAR}, 
+      #{channelId,jdbcType=INTEGER}, #{state,jdbcType=OTHER}, #{createtime,jdbcType=INTEGER}, 
+      #{updatetime,jdbcType=INTEGER})
+  </insert>
+  <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="com.book.push.dao.pojo.User" useGeneratedKeys="true">
+    insert into user
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="openid != null">
+        openid,
+      </if>
+      <if test="unionid != null">
+        unionid,
+      </if>
+      <if test="visitor != null">
+        visitor,
+      </if>
+      <if test="nickname != null">
+        nickname,
+      </if>
+      <if test="sex != null">
+        sex,
+      </if>
+      <if test="mobile != null">
+        mobile,
+      </if>
+      <if test="avatar != null">
+        avatar,
+      </if>
+      <if test="isSubscribe != null">
+        is_subscribe,
+      </if>
+      <if test="subscriptionExtend != null">
+        subscription_extend,
+      </if>
+      <if test="subscribeTime != null">
+        subscribe_time,
+      </if>
+      <if test="bookCategoryIds != null">
+        book_category_ids,
+      </if>
+      <if test="operateTime != null">
+        operate_time,
+      </if>
+      <if test="isPay != null">
+        is_pay,
+      </if>
+      <if test="kandian != null">
+        kandian,
+      </if>
+      <if test="freeKandian != null">
+        free_kandian,
+      </if>
+      <if test="vipEndtime != null">
+        vip_endtime,
+      </if>
+      <if test="registerIp != null">
+        register_ip,
+      </if>
+      <if test="country != null">
+        country,
+      </if>
+      <if test="area != null">
+        area,
+      </if>
+      <if test="province != null">
+        province,
+      </if>
+      <if test="city != null">
+        city,
+      </if>
+      <if test="isp != null">
+        isp,
+      </if>
+      <if test="channelId != null">
+        channel_id,
+      </if>
+      <if test="state != null">
+        `state`,
+      </if>
+      <if test="createtime != null">
+        createtime,
+      </if>
+      <if test="updatetime != null">
+        updatetime,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="openid != null">
+        #{openid,jdbcType=VARCHAR},
+      </if>
+      <if test="unionid != null">
+        #{unionid,jdbcType=VARCHAR},
+      </if>
+      <if test="visitor != null">
+        #{visitor,jdbcType=VARCHAR},
+      </if>
+      <if test="nickname != null">
+        #{nickname,jdbcType=VARCHAR},
+      </if>
+      <if test="sex != null">
+        #{sex,jdbcType=OTHER},
+      </if>
+      <if test="mobile != null">
+        #{mobile,jdbcType=CHAR},
+      </if>
+      <if test="avatar != null">
+        #{avatar,jdbcType=VARCHAR},
+      </if>
+      <if test="isSubscribe != null">
+        #{isSubscribe,jdbcType=OTHER},
+      </if>
+      <if test="subscriptionExtend != null">
+        #{subscriptionExtend,jdbcType=OTHER},
+      </if>
+      <if test="subscribeTime != null">
+        #{subscribeTime,jdbcType=INTEGER},
+      </if>
+      <if test="bookCategoryIds != null">
+        #{bookCategoryIds,jdbcType=VARCHAR},
+      </if>
+      <if test="operateTime != null">
+        #{operateTime,jdbcType=INTEGER},
+      </if>
+      <if test="isPay != null">
+        #{isPay,jdbcType=OTHER},
+      </if>
+      <if test="kandian != null">
+        #{kandian,jdbcType=INTEGER},
+      </if>
+      <if test="freeKandian != null">
+        #{freeKandian,jdbcType=INTEGER},
+      </if>
+      <if test="vipEndtime != null">
+        #{vipEndtime,jdbcType=INTEGER},
+      </if>
+      <if test="registerIp != null">
+        #{registerIp,jdbcType=VARCHAR},
+      </if>
+      <if test="country != null">
+        #{country,jdbcType=VARCHAR},
+      </if>
+      <if test="area != null">
+        #{area,jdbcType=VARCHAR},
+      </if>
+      <if test="province != null">
+        #{province,jdbcType=VARCHAR},
+      </if>
+      <if test="city != null">
+        #{city,jdbcType=VARCHAR},
+      </if>
+      <if test="isp != null">
+        #{isp,jdbcType=VARCHAR},
+      </if>
+      <if test="channelId != null">
+        #{channelId,jdbcType=INTEGER},
+      </if>
+      <if test="state != null">
+        #{state,jdbcType=OTHER},
+      </if>
+      <if test="createtime != null">
+        #{createtime,jdbcType=INTEGER},
+      </if>
+      <if test="updatetime != null">
+        #{updatetime,jdbcType=INTEGER},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.book.push.dao.pojo.User">
+    update user
+    <set>
+      <if test="openid != null">
+        openid = #{openid,jdbcType=VARCHAR},
+      </if>
+      <if test="unionid != null">
+        unionid = #{unionid,jdbcType=VARCHAR},
+      </if>
+      <if test="visitor != null">
+        visitor = #{visitor,jdbcType=VARCHAR},
+      </if>
+      <if test="nickname != null">
+        nickname = #{nickname,jdbcType=VARCHAR},
+      </if>
+      <if test="sex != null">
+        sex = #{sex,jdbcType=OTHER},
+      </if>
+      <if test="mobile != null">
+        mobile = #{mobile,jdbcType=CHAR},
+      </if>
+      <if test="avatar != null">
+        avatar = #{avatar,jdbcType=VARCHAR},
+      </if>
+      <if test="isSubscribe != null">
+        is_subscribe = #{isSubscribe,jdbcType=OTHER},
+      </if>
+      <if test="subscriptionExtend != null">
+        subscription_extend = #{subscriptionExtend,jdbcType=OTHER},
+      </if>
+      <if test="subscribeTime != null">
+        subscribe_time = #{subscribeTime,jdbcType=INTEGER},
+      </if>
+      <if test="bookCategoryIds != null">
+        book_category_ids = #{bookCategoryIds,jdbcType=VARCHAR},
+      </if>
+      <if test="operateTime != null">
+        operate_time = #{operateTime,jdbcType=INTEGER},
+      </if>
+      <if test="isPay != null">
+        is_pay = #{isPay,jdbcType=OTHER},
+      </if>
+      <if test="kandian != null">
+        kandian = #{kandian,jdbcType=INTEGER},
+      </if>
+      <if test="freeKandian != null">
+        free_kandian = #{freeKandian,jdbcType=INTEGER},
+      </if>
+      <if test="vipEndtime != null">
+        vip_endtime = #{vipEndtime,jdbcType=INTEGER},
+      </if>
+      <if test="registerIp != null">
+        register_ip = #{registerIp,jdbcType=VARCHAR},
+      </if>
+      <if test="country != null">
+        country = #{country,jdbcType=VARCHAR},
+      </if>
+      <if test="area != null">
+        area = #{area,jdbcType=VARCHAR},
+      </if>
+      <if test="province != null">
+        province = #{province,jdbcType=VARCHAR},
+      </if>
+      <if test="city != null">
+        city = #{city,jdbcType=VARCHAR},
+      </if>
+      <if test="isp != null">
+        isp = #{isp,jdbcType=VARCHAR},
+      </if>
+      <if test="channelId != null">
+        channel_id = #{channelId,jdbcType=INTEGER},
+      </if>
+      <if test="state != null">
+        `state` = #{state,jdbcType=OTHER},
+      </if>
+      <if test="createtime != null">
+        createtime = #{createtime,jdbcType=INTEGER},
+      </if>
+      <if test="updatetime != null">
+        updatetime = #{updatetime,jdbcType=INTEGER},
+      </if>
+    </set>
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.book.push.dao.pojo.User">
+    update user
+    set openid = #{openid,jdbcType=VARCHAR},
+      unionid = #{unionid,jdbcType=VARCHAR},
+      visitor = #{visitor,jdbcType=VARCHAR},
+      nickname = #{nickname,jdbcType=VARCHAR},
+      sex = #{sex,jdbcType=OTHER},
+      mobile = #{mobile,jdbcType=CHAR},
+      avatar = #{avatar,jdbcType=VARCHAR},
+      is_subscribe = #{isSubscribe,jdbcType=OTHER},
+      subscription_extend = #{subscriptionExtend,jdbcType=OTHER},
+      subscribe_time = #{subscribeTime,jdbcType=INTEGER},
+      book_category_ids = #{bookCategoryIds,jdbcType=VARCHAR},
+      operate_time = #{operateTime,jdbcType=INTEGER},
+      is_pay = #{isPay,jdbcType=OTHER},
+      kandian = #{kandian,jdbcType=INTEGER},
+      free_kandian = #{freeKandian,jdbcType=INTEGER},
+      vip_endtime = #{vipEndtime,jdbcType=INTEGER},
+      register_ip = #{registerIp,jdbcType=VARCHAR},
+      country = #{country,jdbcType=VARCHAR},
+      area = #{area,jdbcType=VARCHAR},
+      province = #{province,jdbcType=VARCHAR},
+      city = #{city,jdbcType=VARCHAR},
+      isp = #{isp,jdbcType=VARCHAR},
+      channel_id = #{channelId,jdbcType=INTEGER},
+      `state` = #{state,jdbcType=OTHER},
+      createtime = #{createtime,jdbcType=INTEGER},
+      updatetime = #{updatetime,jdbcType=INTEGER}
+    where id = #{id,jdbcType=BIGINT}
+  </update>
+</mapper>