Browse Source

'第一次提交'

lym 4 years ago
parent
commit
6ded0c2c3c
30 changed files with 2850 additions and 0 deletions
  1. 146 0
      pom.xml
  2. 16 0
      src/main/java/com/hw/Application.java
  3. 41 0
      src/main/java/com/hw/config/SwaggerConfig.java
  4. 307 0
      src/main/java/com/hw/controller/WechatOpenidController.java
  5. 59 0
      src/main/java/com/hw/dao/WechatInfoMapper.java
  6. 65 0
      src/main/java/com/hw/entity/WechatInfo.java
  7. 29 0
      src/main/java/com/hw/form/WechatInfoForm.java
  8. 40 0
      src/main/java/com/hw/service/WechatInfoService.java
  9. 67 0
      src/main/java/com/hw/service/impl/WhatInfoServiceImpl.java
  10. 478 0
      src/main/java/com/hw/util/EasyHttpUtils.java
  11. 143 0
      src/main/java/com/hw/util/RedisUtils.java
  12. 361 0
      src/main/java/com/hw/util/StringUtils.java
  13. 164 0
      src/main/java/com/hw/util/base/BaseController.java
  14. 31 0
      src/main/java/com/hw/util/base/ResponseBase.java
  15. 87 0
      src/main/java/com/hw/util/base/ResultVO.java
  16. 37 0
      src/main/java/com/hw/util/base/RetHead.java
  17. 158 0
      src/main/java/com/hw/util/enums/CommonEnum.java
  18. 90 0
      src/main/java/com/hw/util/enums/ResultEnum.java
  19. 8 0
      src/main/java/com/hw/util/exception/CommitException.java
  20. 112 0
      src/main/java/com/hw/util/exception/GlobalDefaultExceptionHandler.java
  21. 35 0
      src/main/java/com/hw/util/exception/GlobalException.java
  22. 52 0
      src/main/resources/application-dev.properties
  23. 1 0
      src/main/resources/application-pro.properties
  24. 1 0
      src/main/resources/application-test.properties
  25. 4 0
      src/main/resources/application.properties
  26. 47 0
      src/main/resources/generatorConfig.xml
  27. 52 0
      src/main/resources/logConfig/logConfig.xml
  28. 152 0
      src/main/resources/mappers/WechatInfoMapper.xml
  29. 11 0
      src/main/resources/sql/创建表和默认数据.sql
  30. 56 0
      src/main/resources/swagger-ui.html

+ 146 - 0
pom.xml

@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.hw</groupId>
+    <artifactId>wechat-openiddata</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>jar</packaging>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.2.10.RELEASE</version>
+    </parent>
+
+    <dependencies>
+        <!--<dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starters</artifactId>
+            <version>2.2.11.RELEASE</version>
+        </dependency>-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>2.2.10.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+            <version>1.3.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis</artifactId>
+            <version>3.5.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.74</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+
+        <!-- swagger2 -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <!--<dependency>
+            <groupId>org.crazycake</groupId>
+            <artifactId>shiro-redis</artifactId>
+            <version>2.4.2.1-RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-spring</artifactId>
+            <version>1.4.0</version>
+        </dependency>-->
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- 自生产代码配置 -->
+            <plugin>
+                <groupId>org.mybatis.generator</groupId>
+                <artifactId>mybatis-generator-maven-plugin</artifactId>
+                <version>1.3.5</version>
+                <dependencies>
+                    <dependency>
+                        <groupId> mysql</groupId>
+                        <artifactId> mysql-connector-java</artifactId>
+                        <version>5.1.39</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.mybatis.generator</groupId>
+                        <artifactId>mybatis-generator-core</artifactId>
+                        <version>1.3.5</version>
+                    </dependency>
+                </dependencies>
+                <executions>
+                    <execution>
+                        <id>Generate MyBatis Artifacts</id>
+                        <phase>deploy</phase>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <!--允许移动生成的文件 -->
+                    <verbose>true</verbose>
+                    <!-- 是否覆盖 -->
+                    <overwrite>true</overwrite>
+                    <!-- 自动生成的配置 -->
+                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
+                </configuration>
+            </plugin>
+
+            <!-- 打包方式 -->
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 16 - 0
src/main/java/com/hw/Application.java

@@ -0,0 +1,16 @@
+package com.hw;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@MapperScan(basePackages = {"com.hw.dao"})
+@EnableScheduling
+@SpringBootApplication
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class);
+    }
+}

+ 41 - 0
src/main/java/com/hw/config/SwaggerConfig.java

@@ -0,0 +1,41 @@
+package com.hw.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+
+    //api接口包扫描路径
+    public static final String SWAGGER_SCAN_BASE_PACKAGE = "com.hw";
+
+    public static final String VERSION = "1.0.0";
+
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                .apis(RequestHandlerSelectors.basePackage(SWAGGER_SCAN_BASE_PACKAGE))
+                //.apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any()) // 可以根据url路径设置哪些请求加入文档,忽略哪些请求
+                .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("系统api接口文档") //设置文档的标题
+                .description("系统api接口文档") // 设置文档的描述
+                .version(VERSION) // 设置文档的版本信息-> 1.0.0 Version information
+                .termsOfServiceUrl("API TERMS URL") // 设置文档的License信息->1.3 License information
+                .build();
+    }
+}

+ 307 - 0
src/main/java/com/hw/controller/WechatOpenidController.java

@@ -0,0 +1,307 @@
+package com.hw.controller;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.github.pagehelper.PageInfo;
+import com.hw.form.WechatInfoForm;
+import com.hw.service.WechatInfoService;
+import com.hw.util.EasyHttpUtils;
+import com.hw.util.RedisUtils;
+import com.hw.util.StringUtils;
+import com.hw.util.base.BaseController;
+import com.hw.util.base.ResponseBase;
+import com.hw.util.base.ResultVO;
+import com.hw.util.exception.GlobalException;
+import io.swagger.annotations.*;
+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.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 原公众号openid与新公众号openid转换
+ * lym
+ */
+@RestController
+@RequestMapping("/wechatOpenid")
+@Api(description="原公众号openid与新公众号openid转换")
+public class WechatOpenidController extends BaseController {
+
+    private Logger log = LoggerFactory.getLogger(WechatOpenidController.class);
+
+    @Autowired
+    private WechatInfoService wechatInfoService;
+
+    @Autowired
+    private RedisUtils redisUtils;
+
+    /**
+     * 设置微信的appid
+     */
+    @Value("${wx.ma.appId}")
+    private String oldAppId;
+
+    /**
+     * 设置微信的app secret
+     */
+    @Value("${wx.ma.secret}")
+    private String oldSecret;
+
+    /**
+     * 新微信的appid
+     */
+    @Value("${newwx.ma.appId}")
+    private String newAppId;
+
+    /**
+     * 新微信的app secret
+     */
+    @Value("${newwx.ma.secret}")
+    private String newSecret;
+
+    private final static String CARBONOLDWHAT_ACCESS_TOKEN = "carbonoldwhat_access_token";
+
+    private final static String CARBONNEWWHAT_ACCESS_TOKEN = "carbonnewwhat_access_token";
+
+    private final static String WECHAT_API_URl = "https://api.weixin.qq.com/cgi-bin/";
+
+    /**
+     * 获取旧公众号openid
+     * lym
+     * @return
+     */
+    @ApiOperation(value = "获取原公众号关注用户openid",notes = "获取原公众号关注用户openid")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "nextOpenid",value = "第一个openid",dataType = "String")
+    })
+    @ApiResponse(code = 0,message = "操作成功")
+    @GetMapping("/getOpenids")
+    public ResponseBase getOpenids(String nextOpenid){
+        if (StringUtils.isEmpty(nextOpenid)){
+            nextOpenid = "";
+        }
+        int addNum = addOpenid(nextOpenid,0,0);
+        ResultVO resultVO = new ResultVO();
+        if (addNum == 0){
+            resultVO.setMsg("没有可拉取的openid");
+        }else {
+            resultVO.setMsg("拉取保存openid"+ addNum +"条");
+        }
+        return responseSuccess(resultVO);
+    }
+
+    /**
+     *  获取access_token,一天2000次,一次获取的token两小时内有效
+     *  lym
+     * @return
+     */
+    private String getAccessToken(String wxAppid,String wxSecret,String accessTokenRedisKey){
+        if (redisUtils.existsKey(accessTokenRedisKey)){
+            return (String) redisUtils.getValue(accessTokenRedisKey);
+        }
+        String get = EasyHttpUtils.LoadInstance().get(WECHAT_API_URl +"/token?grant_type=client_credential&appid="+ wxAppid +"&secret=" + wxSecret);
+        log.info(get);
+        if (StringUtils.isNotEmpty(get)) {
+            JSONObject jsonObject = JSONObject.parseObject(get);
+            if (jsonObject.containsKey("access_token")){
+                //缓存
+                int time = (int) jsonObject.get("expires_in");
+                redisUtils.setValue(accessTokenRedisKey,jsonObject.getString("access_token"),time, TimeUnit.SECONDS);
+                return jsonObject.getString("access_token");
+            }
+        }
+
+        log.info("获取token失败");
+        throw new GlobalException("获取token失败,请联系管理员!");
+    }
+
+    /**
+     * 一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足,上一次调用得到的返回中的next_openid值,作为下一次调用中的next_openid值
+     * lym
+     * @param nextOpenid
+     */
+    private int addOpenid(String nextOpenid,int num,int addNum) {
+        //获取access_token
+        String accessToken = getAccessToken(oldAppId,oldSecret,CARBONOLDWHAT_ACCESS_TOKEN);
+        //获取关注用户
+        String getChatopenids = EasyHttpUtils.LoadInstance().get(WECHAT_API_URl +"/user/get?access_token=" + accessToken + "&next_openid=" + nextOpenid);
+        log.info(getChatopenids);
+        if (getChatopenids.contains("errcode")){
+            throw new GlobalException("获取openids失败,请联系管理员!");
+        }
+        if (StringUtils.isNotEmpty(getChatopenids) && getChatopenids.contains("data")
+                && getChatopenids.contains("openid") && !getChatopenids.contains("errcode")) {
+            JSONObject jsonObject = JSONObject.parseObject(getChatopenids);
+            int gzTotal = 0, getTotal = 0;
+            List<String> openids = new ArrayList();
+            if (jsonObject.containsKey("total")) {//关注用户数
+                gzTotal = jsonObject.getInteger("total");
+            }
+            if (jsonObject.containsKey("count")) {//获取用户数
+                getTotal = jsonObject.getInteger("count");
+                num += getTotal;
+            }
+            if (jsonObject.containsKey("data")) {
+                String data = jsonObject.getString("data");
+                if (StringUtils.isNotEmpty(data) && data.contains("openid")) {
+                    JSONObject dataObject = JSONObject.parseObject(data);
+                    JSONArray openidArr = dataObject.getJSONArray("openid");
+                    //openids = Arrays.asList(dataObject.getString("openid").replace(",",""));
+                    for (int i = 0;i < openidArr.size();i++){
+                        openids.add(openidArr.getString(i));
+                    }
+                    //保存关注用户openid
+                    int i = wechatInfoService.batchAdd(openids,oldAppId);
+                    log.info("保存关注用户openid:"+ i);
+                    if (i > 0){
+                        addNum += i;
+                    }
+
+                }
+            }
+
+            if (num < gzTotal){ //多次拉取
+                if (jsonObject.containsKey("next_openid")){
+                    nextOpenid = jsonObject.getString("next_openid");
+                }
+                addOpenid(nextOpenid,num,addNum);
+            }
+        }
+
+        return addNum;
+    }
+
+    /**
+     * 转换openid
+     * lym
+     * @return
+     */
+    @ApiOperation(value = "迁移后新旧openid转换",notes = "迁移后新旧openid转换")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "appid",value = "旧公众号appid",dataType = "String"),
+            @ApiImplicitParam(name = "pageSize",value = "每次转换数量,最多100",dataType = "int")
+    })
+    @ApiResponse(code = 0,message = "操作成功")
+    @GetMapping("/changeOpenids")
+    public ResponseBase changeOpenids(String appid,@RequestParam(defaultValue = "100",required = false) int pageSize){
+        if (StringUtils.isEmpty(appid)){
+            appid = oldAppId;
+        }
+        if (pageSize > 100){
+            pageSize = 100;
+        }
+
+        ResultVO resultVO = new ResultVO();
+        int editNum = change(appid,1,pageSize,0);
+        if (editNum < 1){
+            resultVO.setMsg("无可转换openid,请确认原公众号与目标公众号是否存在迁移关系!");
+        }else {
+            resultVO.setMsg("转换完成");
+        }
+        return responseSuccess(resultVO);
+    }
+
+    /**
+     * 转换
+     * lym
+     * @param appid
+     * @param editNum
+     * @return
+     */
+    private int change(String appid,int pageNo,int pageSize,int editNum){
+        WechatInfoForm from = new WechatInfoForm();
+        from.setOldAppid(appid);
+        from.setPageNo(pageNo);
+        from.setPageSize(pageSize); //因一次只能转换100个,所以取100个
+        PageInfo<List<String>> listPageInfo = wechatInfoService.selectOldOpenids(from);
+        int total = (int) listPageInfo.getTotal();
+        if (total > 0) {
+            List<List<String>> openidList = listPageInfo.getList();
+            Map param = new HashMap();
+            param.put("from_appid", oldAppId); //原帐号的appid
+            param.put("openid_list", openidList); //需要转换的openid
+            //获取新公众号access_token
+            String accessToken = getAccessToken(newAppId, newSecret, CARBONNEWWHAT_ACCESS_TOKEN);
+            //帐号迁移15天后,该转换接口将会失效、无法拉取到数据
+            String result = EasyHttpUtils.LoadInstance().post(WECHAT_API_URl +"/changeopenid?access_token=" + accessToken, (JSONObject) JSONObject.toJSON(param));
+            log.info(result);
+            if (StringUtils.isNotEmpty(result)){
+                JSONObject jsonObject = JSONObject.parseObject(result);
+                if (jsonObject.containsKey("errcode") && jsonObject.getInteger("errcode") == 0 && jsonObject.containsKey("result_list")){
+                    JSONArray resultList = (JSONArray) jsonObject.get("result_list");
+                    if (resultList != null && resultList.size() > 0){ //组装对应openid
+                        List<WechatInfoForm> editList = new ArrayList<>();
+                        WechatInfoForm infoFrom = null;
+                        for (int i = 0;i < resultList.size();i++){
+                            JSONObject object = resultList.getJSONObject(i);
+                            if (object.containsKey("err_msg") && "ok".equals(object.getString("err_msg"))){
+                                infoFrom = new WechatInfoForm();
+                                infoFrom.setOldOpenid(object.getString("ori_openid"));
+                                infoFrom.setNewOpenid(object.getString("new_openid"));
+                                infoFrom.setOldAppid(appid);
+                                editList.add(infoFrom);
+                            }
+                        }
+
+                        if (editList != null && editList.size() > 0){
+                           int i = wechatInfoService.batchUpdate(editList); //修改迁移对应openid
+                            if (i > 0){
+                                editNum += i;
+                            }
+                        }
+
+                        int pageNum = total/pageSize;
+                        int yNum = total%pageSize;
+                        if (yNum > 0){ //不整除分页加1
+                            pageNum += 1;
+                        }
+                        if (pageNo < pageNum){
+                            pageNo += 1;
+                            change(appid,pageNo,pageSize,editNum);
+                        }
+                    }
+                }
+                if (jsonObject.containsKey("errcode") && jsonObject.getInteger("errcode") != 0){
+                    throw new GlobalException("openid转换失败,请检查参数或确认原公众号与目标公众号是否存在迁移关系!!");
+                }
+            }
+
+            /* 测试批量修改 */
+            /*List<WechatInfoForm> editList = new ArrayList<>();
+            WechatInfoForm infoFrom = null;
+            for (int i = 0; i < openidList.size(); i++) {
+                infoFrom = new WechatInfoForm();
+                infoFrom.setOldOpenid(String.valueOf(openidList.get(i)));
+                infoFrom.setNewOpenid(String.valueOf(new Random().nextInt(20)));
+                infoFrom.setOldAppid(appid);
+                editList.add(infoFrom);
+            }
+
+
+            if (editList != null && editList.size() > 0) {
+                int i = wechatInfoService.batchUpdate(editList); //修改迁移对应openid
+                if (i > 0) {
+                    editNum += i;
+                }
+            }*/
+
+            int pageNum = total/pageSize;
+            int yNum = total%pageSize;
+            if (yNum > 0){ //不整除分页加1
+                pageNum += 1;
+            }
+            if (pageNo < pageNum){
+                pageNo += 1;
+                change(appid,pageNo,pageSize,editNum);
+            }
+        }
+        return editNum;
+    }
+}

+ 59 - 0
src/main/java/com/hw/dao/WechatInfoMapper.java

@@ -0,0 +1,59 @@
+package com.hw.dao;
+
+import com.hw.entity.WechatInfo;
+import com.hw.form.WechatInfoForm;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface WechatInfoMapper {
+    int deleteByPrimaryKey(String guid);
+
+    int insert(WechatInfo record);
+
+    int insertSelective(WechatInfo record);
+
+    WechatInfo selectByPrimaryKey(String guid);
+
+    int updateByPrimaryKeySelective(WechatInfo record);
+
+    int updateByPrimaryKey(WechatInfo record);
+
+    /**
+     * 已存在公众号openid
+     * lym
+     * @return
+     */
+    List<WechatInfo> selectList(WechatInfoForm whatInfoFrom);
+
+    /**
+     * 已存在公众号openid
+     * lym
+     * @param appid
+     * @return
+     */
+    String getOpenids(@Param("list") List<String> list,@Param("appid") String appid);
+
+    /**
+     * 批量添加
+     * lym
+     * @param list
+     * @return
+     */
+    int batchAdd(@Param("list") List<WechatInfo> list);
+
+    /**
+     * 查询旧公众号openid
+     * lym
+     * @return
+     */
+    List<String> selectOldOpenids(WechatInfoForm whatInfoFrom);
+
+    /**
+     * 批量修改
+     * lym
+     * @param list
+     * @return
+     */
+    int batchUpdate(@Param("list") List<WechatInfoForm> list);
+}

+ 65 - 0
src/main/java/com/hw/entity/WechatInfo.java

@@ -0,0 +1,65 @@
+package com.hw.entity;
+
+import java.util.Date;
+
+public class WechatInfo {
+    private String guid;
+
+    private String oldAppid;
+
+    private String oldOpenid;
+
+    private String newOpenid;
+
+    private Date createTime;
+
+    private Date modifiedTime;
+
+    public String getGuid() {
+        return guid;
+    }
+
+    public void setGuid(String guid) {
+        this.guid = guid == null ? null : guid.trim();
+    }
+
+    public String getOldAppid() {
+        return oldAppid;
+    }
+
+    public void setOldAppid(String oldAppid) {
+        this.oldAppid = oldAppid == null ? null : oldAppid.trim();
+    }
+
+    public String getOldOpenid() {
+        return oldOpenid;
+    }
+
+    public void setOldOpenid(String oldOpenid) {
+        this.oldOpenid = oldOpenid == null ? null : oldOpenid.trim();
+    }
+
+    public String getNewOpenid() {
+        return newOpenid;
+    }
+
+    public void setNewOpenid(String newOpenid) {
+        this.newOpenid = newOpenid == null ? null : newOpenid.trim();
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getModifiedTime() {
+        return modifiedTime;
+    }
+
+    public void setModifiedTime(Date modifiedTime) {
+        this.modifiedTime = modifiedTime;
+    }
+}

+ 29 - 0
src/main/java/com/hw/form/WechatInfoForm.java

@@ -0,0 +1,29 @@
+package com.hw.form;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class WechatInfoForm {
+    private String guid;
+
+    @ApiModelProperty(value = "旧公众号appid",example = "旧公众号appid")
+    private String oldAppid;
+
+    @ApiModelProperty(value = "旧公众号openid",example = "旧公众号openid")
+    private String oldOpenid;
+
+    @ApiModelProperty(value = "新公众号openid",example = "新公众号openid")
+    private String newOpenid;
+
+    private Date createTime;
+
+    private Date modifiedTime;
+
+    protected Integer pageNo = 0;
+
+    protected Integer pageSize = 10;
+
+}

+ 40 - 0
src/main/java/com/hw/service/WechatInfoService.java

@@ -0,0 +1,40 @@
+package com.hw.service;
+
+import com.github.pagehelper.PageInfo;
+import com.hw.entity.WechatInfo;
+import com.hw.form.WechatInfoForm;
+
+import java.util.List;
+
+public interface WechatInfoService{
+
+    /**
+     * 已存在公众号openid
+     * lym
+     * @return
+     */
+    PageInfo<List<WechatInfo>> selectList(WechatInfoForm whatInfoFrom);
+
+    /**
+     * 批量添加
+     * lym
+     * @param list
+     * @return
+     */
+    int batchAdd(List<String> list,String appid);
+
+    /**
+     * 查询旧公众号openid
+     * lym
+     * @return
+     */
+    PageInfo<List<String>> selectOldOpenids(WechatInfoForm whatInfoFrom);
+
+    /**
+     * 批量修改
+     * lym
+     * @param list
+     * @return
+     */
+    int batchUpdate(List<WechatInfoForm> list);
+}

+ 67 - 0
src/main/java/com/hw/service/impl/WhatInfoServiceImpl.java

@@ -0,0 +1,67 @@
+package com.hw.service.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.hw.dao.WechatInfoMapper;
+import com.hw.entity.WechatInfo;
+import com.hw.form.WechatInfoForm;
+import com.hw.service.WechatInfoService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class WhatInfoServiceImpl implements WechatInfoService {
+
+    @Resource
+    private WechatInfoMapper wechatInfoMapper;
+
+    @Override
+    public PageInfo<List<WechatInfo>> selectList(WechatInfoForm wechatInfoForm) {
+        PageHelper.startPage(wechatInfoForm.getPageNo(),wechatInfoForm.getPageSize());
+        List<String> list = wechatInfoMapper.selectOldOpenids(wechatInfoForm);
+        return new PageInfo(list);
+    }
+
+    @Override
+    public int batchAdd(List<String> list,String appid) {
+        if (list != null && list.size() > 0){
+            String openids = wechatInfoMapper.getOpenids(list,appid);
+            List<WechatInfo> addList = new ArrayList<>();
+            WechatInfo info = null;
+            for (String openid:list){
+                if (openids != null && openids.contains(openid)){//已保存
+                    continue;
+                }
+                info = new WechatInfo();
+                info.setOldAppid(appid);
+                info.setOldOpenid(openid);
+                addList.add(info);
+            }
+
+            if (addList != null && addList.size() > 0){ //批量添加
+                return wechatInfoMapper.batchAdd(addList);
+            }
+        }
+
+        return 0;
+    }
+
+    @Override
+    public PageInfo<List<String>> selectOldOpenids(WechatInfoForm wechatInfoForm) {
+        PageHelper.startPage(wechatInfoForm.getPageNo(),wechatInfoForm.getPageSize());
+        List<String> list = wechatInfoMapper.selectOldOpenids(wechatInfoForm);
+        return new PageInfo(list);
+    }
+
+    @Override
+    public int batchUpdate(List<WechatInfoForm> list) {
+        if (list != null && list.size() > 0){
+            return wechatInfoMapper.batchUpdate(list);
+        }
+        return 0;
+    }
+
+}

+ 478 - 0
src/main/java/com/hw/util/EasyHttpUtils.java

@@ -0,0 +1,478 @@
+/**
+ * @Title: EasyHttpUtils.java
+ * @Package com.elite.common.utils.httpclient
+ * @Description: TODO(用一句话描述该文件做什么)
+ * @author admin
+ * @date 2016523日 下午5:30:48
+ * @version V1.0
+ */
+package com.hw.util;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.*;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.client.config.CookieSpecs;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLContexts;
+import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.client.LaxRedirectStrategy;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLException;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ *
+ * @version 1.0
+ */
+@Slf4j
+public class EasyHttpUtils {
+
+    private static final Logger LOGG = LoggerFactory.getLogger(EasyHttpUtils.class);
+    //连接池最大数量
+    private static final int HTTPCLIENT_CONNECTION_COUNT = 200;
+    //单个路由最大连接数量
+    private static final int HTTPCLIENT_MAXPERROUTE_COUNT = 2;
+    //连接超时
+    private static final int HTTPCLIENT_CONNECT_TIMEOUT = 600000;
+    //socket超时
+    private static final int HTTPCLIENT_SOCKET_TIMEOUT = 600000;
+
+    // 创建httpclient连接池
+    private PoolingHttpClientConnectionManager httpClientConnectionManager = null;
+
+    private static final EasyHttpUtils EASY_HTTP_UTILS = new EasyHttpUtils();
+
+
+    public static EasyHttpUtils LoadInstance() {
+
+        return EASY_HTTP_UTILS;
+    }
+
+    private EasyHttpUtils() {
+        initHttpClient();
+    }
+
+
+    /**
+     * @Title: initHttpUtils
+     * @Description: TODO(这里用一句话描述这个方法的作用)
+     */
+    private void initHttpClient() {
+        //创建httpclient连接池
+        httpClientConnectionManager = new PoolingHttpClientConnectionManager();
+        //设置连接池最大数量  
+        httpClientConnectionManager.setMaxTotal(HTTPCLIENT_CONNECTION_COUNT);
+        //设置单个路由最大连接数量  
+        httpClientConnectionManager.setDefaultMaxPerRoute(HTTPCLIENT_MAXPERROUTE_COUNT);
+    }
+
+
+    //请求重试机制
+
+    HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
+        @Override
+        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
+            if (executionCount >= 3) {
+                // 超过三次则不再重试请求  
+                return false;
+            }
+            if (exception instanceof InterruptedIOException) {
+                // Timeout  
+                return false;
+            }
+            if (exception instanceof UnknownHostException) {
+                // Unknown host  
+                return false;
+            }
+            if (exception instanceof ConnectTimeoutException) {
+                // Connection refused  
+                return false;
+            }
+            if (exception instanceof SSLException) {
+                // SSL handshake exception  
+                return false;
+            }
+            HttpClientContext clientContext = HttpClientContext.adapt(context);
+            HttpRequest request = clientContext.getRequest();
+            boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
+            if (idempotent) {
+                // Retry if the request is considered idempotent  
+                return true;
+            }
+            return false;
+        }
+    };
+
+    public CloseableHttpClient getHttpClient() {
+        // 创建全局的requestConfig  
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setConnectTimeout(HTTPCLIENT_CONNECT_TIMEOUT)
+                .setSocketTimeout(HTTPCLIENT_SOCKET_TIMEOUT)
+                .setCookieSpec(CookieSpecs.BEST_MATCH).build();
+        // 声明重定向策略对象  
+        LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
+
+        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientConnectionManager)
+                .setDefaultRequestConfig(requestConfig)
+                .setRedirectStrategy(redirectStrategy)
+                .setRetryHandler(myRetryHandler)
+                .build();
+        return httpClient;
+    }
+
+
+    /**
+     * HttpClient连接SSL 
+     */
+    public void ssl(String urlStr, String keyPath, String keypass) {
+        CloseableHttpClient httpclient = null;
+        try {
+            RequestConfig requestConfig = RequestConfig.custom()
+                    .setConnectTimeout(HTTPCLIENT_CONNECT_TIMEOUT)
+                    .setSocketTimeout(HTTPCLIENT_SOCKET_TIMEOUT)
+                    .setCookieSpec(CookieSpecs.BEST_MATCH).build();
+            LaxRedirectStrategy redirectStrategy = new LaxRedirectStrategy();
+            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+            FileInputStream instream = new FileInputStream(new File(keyPath));
+            try {
+                // 加载keyStore   
+                trustStore.load(instream, keypass.toCharArray());
+            } catch (CertificateException e) {
+                e.printStackTrace();
+            } finally {
+                try {
+                    instream.close();
+                } catch (Exception ignore) {
+                }
+            }
+            // 相信自己的CA和所有自签名的证书  
+            SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
+            // 只允许使用TLSv1协议  
+            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
+                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+            httpclient = HttpClients.custom().setConnectionManager(httpClientConnectionManager)
+                    .setDefaultRequestConfig(requestConfig)
+                    .setRedirectStrategy(redirectStrategy)
+                    .setRetryHandler(myRetryHandler).setSSLSocketFactory(sslsf).build();
+            // 创建http请求(get方式)  
+            HttpGet httpget = new HttpGet(urlStr);
+
+            CloseableHttpResponse response = httpclient.execute(httpget);
+            try {
+                HttpEntity entity = response.getEntity();
+                LOGG.info("----------------------------------------");
+                LOGG.info(String.valueOf(response.getStatusLine()));
+                if (entity != null) {
+                    LOGG.info("Response content length: " + entity.getContentLength());
+                    LOGG.info(EntityUtils.toString(entity));
+                    EntityUtils.consume(entity);
+                }
+            } finally {
+                response.close();
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (KeyManagementException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } catch (KeyStoreException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    /**
+     * 发送 post请求访问本地应用并根据传递参数不同返回不同结果 
+     */
+    public void post(String urlString, Map<String, Object> params) {
+        // 创建默认的httpClient实例. 
+        LOGG.info("urlString:=========>" + urlString);
+        CloseableHttpClient httpclient = this.getHttpClient();
+        if ("".equals(urlString) || urlString == null) {
+            return;
+        }
+        // 创建httppost    
+        HttpPost httppost = new HttpPost(urlString);
+        // 创建参数队列    
+        List<NameValuePair> formparams = new ArrayList<NameValuePair>();
+        if (params != null && params.size() > 0) {
+            for (String key : params.keySet()) {
+                formparams.add(new BasicNameValuePair(key, (String) params.get(key)));
+            }
+        }
+        UrlEncodedFormEntity uefEntity;
+        try {
+            uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
+            httppost.setEntity(uefEntity);
+            LOGG.info("executing request " + httppost.getURI());
+            CloseableHttpResponse response = httpclient.execute(httppost);
+            try {
+                HttpEntity entity = response.getEntity();
+                if (entity != null) {
+                    EntityUtils.consume(entity);
+                }
+            } finally {
+                response.close();
+            }
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (UnsupportedEncodingException e1) {
+            e1.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public String post(String urlString, JSONObject params) {
+        StringBuilder result = new StringBuilder();
+        // 创建默认的httpClient实例.    
+        CloseableHttpClient httpclient = this.getHttpClient();
+        if ("".equals(urlString) || urlString == null) {
+            return null;
+        }
+        // 创建httppost    
+        HttpPost httppost = new HttpPost(urlString);
+        // 创建参数队列   
+        httppost.addHeader("Content-type", "application/json; charset=utf-8");
+        httppost.setHeader("Accept", "application/json");
+        httppost.setEntity(new StringEntity(params.toJSONString(), Charset.forName("UTF-8")));
+        try {
+            LOGG.info("executing request " + httppost.getURI());
+            CloseableHttpResponse response = httpclient.execute(httppost);
+            HttpEntity entity = null;
+            try {
+                int httpCode = response.getStatusLine().getStatusCode();
+                if (httpCode == HttpURLConnection.HTTP_OK && response != null) {
+                    entity = response.getEntity();
+                    //读取服务器返回的json数据(接受json服务器数据)
+                    InputStream inputStream = entity.getContent();
+                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
+                    // 读字符串用的。
+                    BufferedReader reader = new BufferedReader(inputStreamReader);
+                    String str;
+                    while ((str = reader.readLine()) != null) {
+                        result.append(str);
+                    }
+                    reader.close();
+                    return result.toString();
+                }
+            } finally {
+                EntityUtils.consume(entity);
+                response.close();
+            }
+        } catch (ClientProtocolException e) {
+            LOGG.error(e.getMessage(), e);
+        } catch (UnsupportedEncodingException e) {
+            LOGG.error(e.getMessage(), e);
+        } catch (IOException e) {
+            LOGG.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    /**
+     * 发送 get请求
+     */
+    public String get(String urlStr) {
+        StringBuilder result = new StringBuilder();
+        CloseableHttpClient httpclient = this.getHttpClient();
+        try {
+            // 创建httpget.
+            HttpGet httpget = new HttpGet(urlStr);
+            LOGG.info("executing request " + httpget.getURI());
+            // 执行get请求.
+            CloseableHttpResponse response = httpclient.execute(httpget);
+            HttpEntity entity = null;
+            try {
+                int httpCode = response.getStatusLine().getStatusCode();
+                if (httpCode == HttpURLConnection.HTTP_OK && response != null) {
+                    entity = response.getEntity();
+                    //读取服务器返回的json数据(接受json服务器数据)
+                    InputStream inputStream = entity.getContent();
+                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
+                    // 读字符串用的。
+                    BufferedReader reader = new BufferedReader(inputStreamReader);
+                    String str;
+                    while ((str = reader.readLine()) != null) {
+                        result.append(str);
+                    }
+                    reader.close();
+                    return result.toString();
+                }
+
+            } finally {
+                EntityUtils.consume(entity);
+                response.close();
+            }
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 发送 get请求 有header
+     */
+    public String get(String urlStr,List<Map<String,String>> headerParams) {
+        StringBuilder result = new StringBuilder();
+        CloseableHttpClient httpclient = this.getHttpClient();
+        try {
+            // 创建httpget.
+            HttpGet httpget = new HttpGet(urlStr);
+            LOGG.info("executing request " + httpget.getURI());
+            if (headerParams != null && headerParams.size() > 0){
+                for (Map<String,String> map:headerParams){
+                    httpget.setHeader(map.get("name"),map.get("value"));
+                }
+            }
+
+            // 执行get请求.
+            CloseableHttpResponse response = httpclient.execute(httpget);
+            HttpEntity entity = null;
+            try {
+                int httpCode = response.getStatusLine().getStatusCode();
+                log.info(String.valueOf(httpCode));
+                if (httpCode == HttpURLConnection.HTTP_OK && response != null) {
+                    entity = response.getEntity();
+                    //读取服务器返回的json数据(接受json服务器数据)
+                    InputStream inputStream = entity.getContent();
+                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
+                    // 读字符串用的。
+                    BufferedReader reader = new BufferedReader(inputStreamReader);
+                    String str;
+                    while ((str = reader.readLine()) != null) {
+                        result.append(str);
+                    }
+                    reader.close();
+                    return result.toString();
+                }
+
+            } finally {
+                EntityUtils.consume(entity);
+                response.close();
+            }
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    public String getUrlToImg(String urlStr,String fileName,String filePath) {
+        StringBuilder result = new StringBuilder();
+        CloseableHttpClient httpclient = this.getHttpClient();
+        try {
+            // 创建httpget.
+            HttpGet httpget = new HttpGet(urlStr);
+            LOGG.info("executing request " + httpget.getURI());
+            // 执行get请求.
+            CloseableHttpResponse response = httpclient.execute(httpget);
+            HttpEntity entity = null;
+            FileOutputStream fos = null;
+            try {
+                File file = new File(fileName);
+                int httpCode = response.getStatusLine().getStatusCode();
+                if (httpCode == HttpURLConnection.HTTP_OK && response != null) {
+                    entity = response.getEntity();
+                    //读取服务器返回的json数据(接受json服务器数据)
+                    InputStream inputStream = entity.getContent();
+                    Header header = entity.getContentType();
+                    log.info("==============>{}",header.getName());
+                    log.info("==============>{}",header.getValue());
+                    log.info("==============>{}",header.getElements());
+                    String type = header.getValue();
+                    String imageType="jpeg";
+                    if(type.indexOf("/")!=-1){
+                        int flagIndex = type.indexOf("/");
+                        imageType = type.substring(flagIndex + 1);
+                        if (!imageType.equals("gif")) {
+                            imageType = "jpeg";
+                        }
+                    }
+                    byte[] imageData = this.readInputStream(inputStream);
+                    log.info("filePath=====================>{}",filePath);
+                    File saveDir = new File(filePath);
+                    if (!saveDir.exists()) {
+                        saveDir.mkdir();
+                    }
+                    File saveFile = new File(saveDir +File.separator+fileName + "." + imageType);
+                    fos = new FileOutputStream(saveFile);
+                    fos.write(imageData);
+                    if (fos != null) {
+                        fos.flush();
+                        fos.close();
+                    }
+                    if (inputStream != null) {
+                        inputStream.close();
+                    }
+                    log.info("info:{}{}.{}download success",filePath,fileName,imageType);
+                    return imageType;
+                }
+            } finally {
+                EntityUtils.consume(entity);
+                response.close();
+                fos.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private byte[] readInputStream(InputStream inputStream) throws IOException {
+        byte[] buffer = new byte[1024];
+        int len = 0;
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        while ((len = inputStream.read(buffer)) != -1) {
+            bos.write(buffer, 0, len);
+        }
+        bos.close();
+        return bos.toByteArray();
+    }
+
+}
+	
+	
+

+ 143 - 0
src/main/java/com/hw/util/RedisUtils.java

@@ -0,0 +1,143 @@
+package com.hw.util;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.PostConstruct;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * @author xiezt
+ */
+@Component("redisUtils")
+@Slf4j
+public class RedisUtils {
+
+    @Autowired
+    @Qualifier("redisTemplate")
+    RedisTemplate template;
+
+    @Autowired
+    @Qualifier("stringRedisTemplate")
+    StringRedisTemplate stringRedisTemplate;
+
+    @Bean
+    CountDownLatch latch() {
+        return new CountDownLatch(1);
+    }
+
+//    @Bean
+//    StringRedisTemplate stringTemplate(RedisConnectionFactory connectionFactory) {
+//        return new StringRedisTemplate(connectionFactory);
+//    }
+
+    @PostConstruct
+    public void init() {
+        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
+        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(
+                Object.class);
+        ObjectMapper om = new ObjectMapper();
+        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+        jackson2JsonRedisSerializer.setObjectMapper(om);
+        template.setKeySerializer(stringSerializer);
+        template.setValueSerializer(jackson2JsonRedisSerializer);
+        template.setHashKeySerializer(stringSerializer);
+        template.setHashValueSerializer(jackson2JsonRedisSerializer);
+        template.afterPropertiesSet();
+    }
+
+    public void setValue(String key, Object val) {
+        template.opsForValue().set(key, val);
+    }
+
+    public void setValue(String key, Object val, int time, TimeUnit unit) {
+        template.opsForValue().set(key, val, time, unit);
+    }
+
+    public void setValue(String key, Object val, long time, TimeUnit unit) {
+        template.opsForValue().set(key, val, time, unit);
+    }
+
+    public Object getValue(String key) {
+        return template.opsForValue().get(key);
+    }
+
+    public void multiSet(Map<String, Object> map) {
+        template.opsForValue().multiSet(map);
+    }
+
+    public List<Object> multiGet(Collection<String> keys) {
+        return template.opsForValue().multiGet(keys);
+    }
+
+    public long incr(String key, long delta) {
+        return template.opsForValue().increment(key, delta);
+    }
+
+    public void lpush(String key, String value) {
+        template.opsForList().leftPush(key, value);
+    }
+
+    public List<Object> range(String key, int start, int end) {
+        return template.opsForList().range(key, start, end);
+    }
+
+    public Object rpop(String key) {
+        return template.opsForList().rightPop(key);
+    }
+
+    public void setHash(String key, Map<String, Object> map) {
+        template.opsForHash().putAll(key, map);
+    }
+
+    public Object getHash(String key, String prop) {
+        return template.opsForHash().get(key, prop);
+    }
+
+    /**
+     * 删除key
+     */
+    public void deleteKey(String key) {
+        template.delete(key);
+    }
+
+    public boolean existsKey(String key) {
+        return template.hasKey(key);
+    }
+
+    public void lengthenExpire(String key) {
+        template.expire(key, 3600, TimeUnit.SECONDS);
+    }
+
+    public Map getHashAll(String key) {
+        Map map = new HashMap();
+        map.put("keys", template.opsForHash().keys(key));
+        map.put("vals", template.opsForHash().values(key));
+        return map;
+    }
+
+    public Set<String> keys(String key) {
+        return stringRedisTemplate.keys(key);
+    }
+}

+ 361 - 0
src/main/java/com/hw/util/StringUtils.java

@@ -0,0 +1,361 @@
+package com.hw.util;
+
+
+import com.hw.util.enums.CommonEnum;
+import com.hw.util.exception.GlobalException;
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+
+public final class StringUtils {
+
+    /**
+     * The empty String {@code ""}.
+     * @since 2.0
+     */
+    public static final String EMPTY = "";
+
+    final static Map<Integer, String> ZONE_NUM = new HashMap<>();
+    public static final String TRUE = "1";
+    public static final String FALSE = "0";
+
+    private static Pattern CELLPHONE = Pattern
+            .compile("^(13[0-9]{9})|(18[0-9]{9})|(14[0-9]{9})|(17[0-9]{9})|(15[0-9]{9})$");
+
+    private static Pattern EMAIL = Pattern
+            .compile("^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\\.([a-zA-Z0-9_-])+)+$");
+
+    private static Pattern INTEGER = Pattern.compile("[0-9]*");
+
+    static {
+        ZONE_NUM.put(11, "北京");
+        ZONE_NUM.put(12, "天津");
+        ZONE_NUM.put(13, "河北");
+        ZONE_NUM.put(14, "山西");
+        ZONE_NUM.put(15, "内蒙古");
+        ZONE_NUM.put(21, "辽宁");
+        ZONE_NUM.put(22, "吉林");
+        ZONE_NUM.put(23, "黑龙江");
+        ZONE_NUM.put(31, "上海");
+        ZONE_NUM.put(32, "江苏");
+        ZONE_NUM.put(33, "浙江");
+        ZONE_NUM.put(34, "安徽");
+        ZONE_NUM.put(35, "福建");
+        ZONE_NUM.put(36, "江西");
+        ZONE_NUM.put(37, "山东");
+        ZONE_NUM.put(41, "河南");
+        ZONE_NUM.put(42, "湖北");
+        ZONE_NUM.put(43, "湖南");
+        ZONE_NUM.put(44, "广东");
+        ZONE_NUM.put(45, "广西");
+        ZONE_NUM.put(46, "海南");
+        ZONE_NUM.put(50, "重庆");
+        ZONE_NUM.put(51, "四川");
+        ZONE_NUM.put(52, "贵州");
+        ZONE_NUM.put(53, "云南");
+        ZONE_NUM.put(54, "西藏");
+        ZONE_NUM.put(61, "陕西");
+        ZONE_NUM.put(62, "甘肃");
+        ZONE_NUM.put(63, "青海");
+        ZONE_NUM.put(64, "新疆");
+        ZONE_NUM.put(71, "台湾");
+        ZONE_NUM.put(81, "香港");
+        ZONE_NUM.put(82, "澳门");
+        ZONE_NUM.put(91, "外国");
+    }
+
+    final static int[] PARITYBIT = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
+    final static int[] POWER_LIST = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
+    final static char[] UPPER_LIST = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
+            'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
+
+    /**
+     * 身份证验证
+     */
+    public static boolean isIDCard(String certNo) {
+        if (certNo == null || (certNo.length() != 15 && certNo.length() != 18)) {
+            return false;
+        }
+        final char[] cs = certNo.toUpperCase().toCharArray();
+        //校验位数
+        int power = 0;
+        for (int i = 0; i < cs.length; i++) {
+            if (i == cs.length - 1 && cs[i] == 'X') {
+                break;//最后一位可以 是X或x
+            }
+            if (cs[i] < '0' || cs[i] > '9') {
+                return false;
+            }
+            if (i < cs.length - 1) {
+                power += (cs[i] - '0') * POWER_LIST[i];
+            }
+        }
+
+        //校验区位码
+        if (!ZONE_NUM.containsKey(Integer.valueOf(certNo.substring(0, 2)))) {
+            return false;
+        }
+
+        //校验年份
+        String year = certNo.length() == 15 ? getIdcardCalendar() + certNo.substring(6, 8)
+                : certNo.substring(6, 10);
+
+        final int iyear = Integer.parseInt(year);
+        if (iyear < 1900 || iyear > Calendar.getInstance().get(Calendar.YEAR)) {
+            return false;
+            //1900年的PASS,超过今年的PASS
+        }
+
+        //校验月份
+        String month = certNo.length() == 15 ? certNo.substring(8, 10) : certNo.substring(10, 12);
+        final int imonth = Integer.parseInt(month);
+        if (imonth < 1 || imonth > 12) {
+            return false;
+        }
+
+        //校验天数
+        String day = certNo.length() == 15 ? certNo.substring(10, 12) : certNo.substring(12, 14);
+        final int iday = Integer.parseInt(day);
+        if (iday < 1 || iday > 31) {
+            return false;
+        }
+
+        //校验"校验码"
+        if (certNo.length() == 15) {
+            return true;
+        }
+        return cs[cs.length - 1] == PARITYBIT[power % 11];
+    }
+
+    private static int getIdcardCalendar() {
+        GregorianCalendar curDay = new GregorianCalendar();
+        int curYear = curDay.get(Calendar.YEAR);
+        int year2bit = Integer.parseInt(String.valueOf(curYear).substring(2));
+        return year2bit;
+    }
+
+    public static boolean isEmpty(String str) {
+        if (null == str || "".equals(str)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static boolean isNotEmpty(String str) {
+        return !isEmpty(str);
+    }
+
+    public static boolean getBoolean(String str) {
+        if (TRUE.equals(str)) {
+            return true;
+        } else if (FALSE.equals(str)) {
+            return false;
+        } else {
+            throw new GlobalException(CommonEnum.ILLEGAL_PARAMETER_ERROR.getIndex(),
+                    CommonEnum.ILLEGAL_PARAMETER_ERROR.getValue());
+        }
+    }
+
+    public static String getStr(Boolean b) {
+        if (b == null) {
+            return "";
+        } else if (true == b) {
+            return TRUE;
+        } else {
+            return FALSE;
+        }
+    }
+
+    /**
+     * 通过文件路径得到文件后缀名。如:hello.txt得到.txt
+     *
+     * @param filePath 文件路径
+     */
+    public static String getFileSuffix(String filePath) {
+        int pointIndex = filePath.lastIndexOf(".");
+        return filePath.substring(pointIndex, filePath.length());
+    }
+
+    public static String getFileNameWithoutSuffix(File file) {
+        String fileName = file.getName();
+        int pointIndex = fileName.lastIndexOf(".");
+        return fileName.substring(0, pointIndex);
+    }
+
+    public static boolean isEmail(String str) {
+        if (StringUtils.isEmpty(str)) {
+            return false;
+        }
+
+        Matcher m = EMAIL.matcher(str);
+        return m.matches();
+    }
+
+    public static boolean isCellPhone(String str) {
+        if (isEmpty(str)) {
+            return false;
+        }
+
+        Matcher m = CELLPHONE.matcher(str);
+        return m.matches();
+    }
+
+    /**
+     * 生成手机验证码
+     *
+     * @return 长度为6的数字字符串
+     */
+    public static String getVilidateCode() {
+        char[] codeSequence = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+        StringBuffer codeStr = new StringBuffer();
+        for (int i = 0; i < 6; i++) {
+            int j = (int) (Math.random() * 10);
+            codeStr.append(codeSequence[j]);
+        }
+        return codeStr.toString();
+    }
+
+
+
+    public static boolean isInteger(String str) {
+        if (isEmpty(str)) {
+            return false;
+        }
+        Matcher isNum = INTEGER.matcher(str);
+        return isNum.matches();
+    }
+
+    /**
+     * 小数点保留方法
+     *
+     * @param value 需要处理的数值
+     * @param scale 需要保留的小数位数
+     */
+    public static float round(double value, int scale) {
+        if (scale < 0) {
+            throw new IllegalArgumentException("The scale must be a positive integer or zero");
+        }
+        BigDecimal bigDecimal = new BigDecimal(Double.toString(value));
+        BigDecimal one = new BigDecimal("1");
+        return bigDecimal.divide(one, scale, BigDecimal.ROUND_HALF_UP).floatValue();
+    }
+
+    public static String sHA1(String decript) {
+        try {
+            MessageDigest digest = MessageDigest.getInstance("SHA-1");
+            digest.update(decript.getBytes());
+            byte[] messageDigest = digest.digest();
+            StringBuffer hexString = new StringBuffer();
+            for (int i = 0; i < messageDigest.length; i++) {
+                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
+                if (shaHex.length() < 2) {
+                    hexString.append(0);
+                }
+                hexString.append(shaHex);
+            }
+            return hexString.toString();
+
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    public static String getFieldName(String fieldName) {
+        return fieldName
+                .replaceFirst(fieldName.substring(0), fieldName.substring(0).toLowerCase());
+    }
+
+    /**
+     * 根据oauth2入口参数找到定向到前端的路由
+     */
+    public static String translateRoute(String route) {
+        route = StringUtils.isEmpty(route) ? "" : route;
+        String redirectRoute = route.replaceAll("!", "/").replaceAll("~", "?");
+        return redirectRoute;
+    }
+
+    public synchronized static String getRandomUpper(int lenght) {
+        Random random = new Random();
+        StringBuffer upperStr = new StringBuffer();
+        for (int i = 0; i < lenght; i++) {
+            upperStr.append(UPPER_LIST[random.nextInt(UPPER_LIST.length)]);
+        }
+        return upperStr.toString();
+    }
+    /**
+     * MD5加密
+     */
+    public static String md5(String encryptedObject) {
+        try {
+            char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
+                    'D', 'E', 'F'};
+            MessageDigest md5 = MessageDigest.getInstance("MD5");
+            md5.update(encryptedObject.getBytes());
+            byte[] digest = md5.digest();
+            int j = digest.length;
+            char[] chars = new char[j * 2];
+            int k = 0;
+            for (int i = 0; i < j; i++) {
+                byte byte0 = digest[i];
+                chars[k++] = hexDigits[byte0 >>> 4 & 0xf];
+                chars[k++] = hexDigits[byte0 & 0xf];
+            }
+            return new String(chars);
+        } catch (Exception e) {
+            throw new GlobalException(CommonEnum.ENCRYPTION_ERROR.getIndex(), CommonEnum.ENCRYPTION_ERROR.getValue());
+        }
+    }
+
+    public static String checkoutPwd(String pwd) {
+        //需要进行对应的接密操作
+        //1.获取盐值
+        String salt = pwd.substring(0, 5);
+        String key = "b8d11ee289394be688ef3a4f6968efed";
+        String time1 = StringUtils.md5((key).substring(0, 8)).substring(0, 5);
+        //做超时判断
+        if (!time1.equalsIgnoreCase(salt)) {
+            throw new GlobalException(CommonEnum.LOGIN_TIMEOUT.getIndex(),CommonEnum.LOGIN_TIMEOUT.getValue());
+        }
+        //2.去除盐值
+        String replace = pwd.replace(salt, "");
+        //3.还原base64前的密码值
+        String s = null;
+        try {
+            s = new String(Base64.getDecoder().decode(replace), "utf-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return s;
+    }
+
+    /**
+     * * 判断一个对象是否为空
+     *
+     * @param object Object
+     * @return true:为空 false:非空
+     */
+    public static boolean isNull(Object object)
+    {
+        return object == null;
+    }
+
+    /**
+     * * 判断一个对象是否非空
+     *
+     * @param object Object
+     * @return true:非空 false:空
+     */
+    public static boolean isNotNull(Object object)
+    {
+        return !isNull(object);
+    }
+}

+ 164 - 0
src/main/java/com/hw/util/base/BaseController.java

@@ -0,0 +1,164 @@
+package com.hw.util.base;
+
+import com.hw.util.enums.ResultEnum;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 控制器基类
+ *
+ * @author yys
+ */
+@Component
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class BaseController {
+
+    protected static final String ACCESS_TOKEN = "accessToken";
+
+    /**
+     * 无业务数据成功返回
+     *
+     * @return
+     */
+    protected ResultVO success() {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setData(null);
+        return resultVO;
+    }
+
+    /**
+     * 无业务数据失败返回
+     *
+     * @return
+     */
+    protected ResultVO failure() {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setCode(ResultEnum.FAILURE.getCode());
+        resultVO.setMsg(ResultEnum.FAILURE.getMsg());
+        resultVO.setData(null);
+        return resultVO;
+    }
+
+    protected ResultVO failure(String message) {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setCode(ResultEnum.FAILURE.getCode());
+        resultVO.setMsg(message);
+        resultVO.setData(null);
+        return resultVO;
+    }
+
+    /**
+     * 有业务数据成功返回
+     *
+     * @param data
+     * @return
+     */
+    protected ResultVO success(Object data, long count) {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setData(data);
+        resultVO.setCount(count);
+        return resultVO;
+    }
+
+    /**
+     * 有业务数据成功返回
+     *
+     * @param data
+     * @return
+     */
+    protected ResultVO success(Object data) {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setData(data);
+        return resultVO;
+    }
+
+    /**
+     * 有业务数据成功返回
+     *
+     * @return
+     */
+    protected ResultVO error(String msg) {
+        ResultVO resultVO = new ResultVO();
+        resultVO.setCode(1);
+        resultVO.setData(msg);
+        return resultVO;
+    }
+
+    /**
+     * 操作成功后,返回结果(前后端分离)
+     *
+     * @param resultVO
+     * @return
+     */
+    protected ResponseBase responseSuccess(ResultVO resultVO) {
+        ResponseBase responseBase = new ResponseBase(resultVO.getData());
+        RetHead retHead = new RetHead();
+        retHead.setErrCode(resultVO.getCode().shortValue());
+        retHead.setErrMsg(resultVO.getMsg());
+        retHead.setTotal(resultVO.getCount());
+        responseBase.setRetHead(retHead);
+        return responseBase;
+    }
+
+
+    /**
+     * 操作异常后,返回结果(前后端分离)
+     *
+     * @param resultVO
+     * @return
+     */
+    protected ResponseBase responseError(ResultVO resultVO) {
+        RetHead retHead = new RetHead();
+        retHead.setErrCode(resultVO.getCode().shortValue());
+        retHead.setErrMsg(resultVO.getMsg());
+        return new ResponseBase(retHead);
+    }
+
+    /**
+     * 操作异常后,返回结果(前后端分离)
+     *
+     * @return
+     */
+    protected ResponseBase responseError(Integer errCode, String errMsg) {
+        RetHead retHead = new RetHead();
+        retHead.setErrCode(errCode.shortValue());
+        retHead.setErrMsg(errMsg);
+        return new ResponseBase(retHead);
+    }
+
+    /**
+     * 判断调用服务是否成功
+     *
+     * @param resultVO
+     * @return
+     */
+    public boolean isSuccess(ResultVO resultVO) {
+        return ResultEnum.SUCCESS.getCode().equals(resultVO.getCode());
+    }
+
+    /**
+     * 获取response对象
+     *
+     * @return
+     */
+    protected HttpServletResponse getResponseObject() {
+        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
+                .getRequestAttributes();
+        return requestAttributes.getResponse();
+    }
+
+    /**
+     * 获取request对象
+     *
+     * @return
+     */
+    protected HttpServletRequest getRequestObject() {
+        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
+                .getRequestAttributes();
+        return requestAttributes.getRequest();
+    }
+}

+ 31 - 0
src/main/java/com/hw/util/base/ResponseBase.java

@@ -0,0 +1,31 @@
+package com.hw.util.base;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@ApiModel(value = "web响应类", description = "web响应类")
+public class ResponseBase<T> implements Serializable {
+
+    @ApiModelProperty(value = "返回头信息")
+    private RetHead retHead;
+
+    @ApiModelProperty(value = "返回内容信息")
+    private T retBody;
+
+    public ResponseBase() {
+
+    }
+
+    public ResponseBase(T retBody) {
+        this.retBody = retBody;
+    }
+
+    public ResponseBase(RetHead retHead) {
+        this.retHead = retHead;
+    }
+
+}

+ 87 - 0
src/main/java/com/hw/util/base/ResultVO.java

@@ -0,0 +1,87 @@
+package com.hw.util.base;
+
+import com.hw.util.enums.ResultEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 服务调用统一返回封装类
+ *
+ * @param <T>
+ * @author yys
+ */
+@Data
+@ApiModel(value = "client响应类", description = "client响应类")
+public class ResultVO<T> {
+
+    private static final Integer DEFAULT_COUNT = 0;
+    /**
+     * 状态码 (默认值:0
+     */
+    @ApiModelProperty(value = "响应码", example = "响应码")
+    private Integer code = ResultEnum.SUCCESS.getCode();
+    /**
+     * 状态提示信息 (默认值:成功)
+     */
+    @ApiModelProperty(value = "返回信息", example = "返回信息")
+    private String msg = ResultEnum.SUCCESS.getMsg();
+
+    /**
+     * 记录总数,默认是0
+     */
+    private long count = DEFAULT_COUNT;
+    /**
+     * 业务数据
+     */
+    @ApiModelProperty(value = "返回内容", example = "返回内容")
+    private T data;
+
+    public ResultVO() {
+        super();
+    }
+
+    public ResultVO(Integer code, String msg) {
+        super();
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public ResultVO(Integer code, String msg, T data) {
+        super();
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public ResultVO(Integer code, String msg, long count, T data) {
+        super();
+        this.code = code;
+        this.msg = msg;
+        this.count = count;
+        this.data = data;
+    }
+
+    public ResultVO(ResultEnum resultEnum) {
+        super();
+        this.code = resultEnum.getCode();
+        this.msg = resultEnum.getMsg();
+    }
+
+    public ResultVO(ResultEnum resultEnum, T data, long count) {
+        super();
+        this.code = resultEnum.getCode();
+        this.msg = resultEnum.getMsg();
+        this.data = data;
+        this.count = count;
+    }
+
+    public ResultVO(ResultEnum resultEnum, T data) {
+        super();
+        this.code = resultEnum.getCode();
+        this.msg = resultEnum.getMsg();
+        this.data = data;
+        this.count = count;
+    }
+
+}

+ 37 - 0
src/main/java/com/hw/util/base/RetHead.java

@@ -0,0 +1,37 @@
+package com.hw.util.base;
+
+import com.hw.util.enums.ResultEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+
+/**
+ * @author xiezt
+ */
+@Data
+@ApiModel(value = "接口返回信息", description = "接口返回信息")
+public class RetHead implements Serializable {
+
+    public RetHead() {
+
+    }
+
+    public RetHead(ResultEnum resultEnum) {
+        this.errCode = Short.valueOf(resultEnum.getCode().toString());
+        this.errMsg = resultEnum.getMsg();
+    }
+
+    @ApiModelProperty(value = "返回响应码", example = "返回响应码")
+    private short errCode;
+
+    @ApiModelProperty(value = "返回响应信息", example = "返回响应信息")
+    private String errMsg;
+
+    @ApiModelProperty(value = "总记录数")
+    private Long total = 0L;
+
+
+}

+ 158 - 0
src/main/java/com/hw/util/enums/CommonEnum.java

@@ -0,0 +1,158 @@
+package com.hw.util.enums;
+
+
+import com.hw.util.exception.GlobalException;
+
+/**
+ * @author xiezt
+ */
+
+public enum CommonEnum {
+    MEN("男", 1),
+    WOMEN("女", 2),
+
+    INCREASE("增长", 1),
+    FALLING("下降", 2),
+
+    COUNTRY("country", 0),
+    PROVINCE("province", 1),
+    CITY("city", 2),
+    DISTRICT("county", 3),
+    TOWN("town", 4),
+    VILLAGE("village", 5),
+
+    SUCCESS("成功", 0),
+    FAILURE("失败", 1),
+
+    USER_CANCEL("用户已经注销,请联系管理员", 1001),
+    PASSWORD_ERROR("密码错误", 1002),
+    USER_UNREGISTERED_ERROR("用户未注册", 1003),
+    RE_LOGIN("认证失败,请重新登录!", 1004),
+    UNBOUND_REGION_ERROR("此账户未绑定区域,请联系管理员!", 1005),
+    USER_NAME_REPEATED("用户名称已经存在", 1006),
+    USER_TELEPHONE_REPEATED("电话号码已经存在", 1007),
+    TELEPHONE_FORMAL_ERROR("电话号码格式错误", 1008),
+    RE_LOGOUT("未正确退出,请重新退出", 1009),
+    UNIQUE_CHECK_ERROR("重复", 1101),
+    ENCRYPTION_ERROR("加密操作失败", 1102),
+    ILLEGAL_PARAMETER_ERROR("参数非法", 2001),
+    PARAMETER_NOT_NULL("参数不能为空", 2002),
+    ID_NOT_NULL("id不能为空", 2009),
+    TYPE_REFERENCED("类型被引用,请先删除引用", 2003),
+    FILE_NOT_NULL("文件不能为空", 2004),
+    FILE_CONTENT_NOT_NULL("文件内容不能为空", 2005),
+    FILE_UPLOAD_FAIL("文件上传失败", 2006),
+    DATE_TIME_FORMAT_ERR("请按正确的时间格式填写,格式为:年-月-日,例如:2018-06-28", 2007),
+    COORDINATE_PARSE_ERROR("坐标解析错误", 2008),
+    DEL_FAILURE("删除失败,对应用户不存在", 2009),
+    DEL_CURRENT_LOGIN_INFO("不能修改当前登录人信息", 2010),
+    DEL_ADMIN("不能修改超级管理员信息", 2011),
+    PERCENT_TO_DOUBLE_ERROR("百分数转换double格式错误", 2012),
+    PRODUCT_NAME_REPEATED("该商品已经存在", 3001),
+    FILE_NOT_FOUND("文件不存在", 3002),
+    FILE_REPEATED("文件已存在", 3003),
+    MAX_UPLOAD_SIZE_EXCEEDED("文件过大无法上传", 3004),
+    ROLE_NAME_REPEATED("角色名称已经存在", 3002),
+    ROLE_MENU_NOT_FOUND("权限范围不可为空", 3014),
+    MENU_NAME_REPEATED("菜单名称已经存在", 3003),
+    PASSWORD_REPEAT("修改前后密码不能相同", 3004),
+    USER_INFO_ERROR("用户信息有误", 3005),
+    TOO_BIG_A_DOCUMENT("文件内容过大,无法上传", 3006),
+    FILE_TYPE_ERROR("上传文件格式错误,仅支持.xls和.xlsx两种格式的文件", 3007),
+    NUMBER_FORMAT("格式异常", 3009),
+    FILE_CANNOT_BE_FOUND("文件未找到", 3010),
+    DATE_TIME_PARSE("时间格式异常,请使用指定时间格式", 3011),
+    OPERATOR_ERROR("不是对应办理人无法办理", 3012),
+    RECOMMEND_EXCEED("推荐文章不能超过五条", 3013),
+    AREA_ID_REPEATED("区域名称已经存在", 3015),
+    AREA_ID_NOT_FOUND("区域名称不存在", 3016),
+    CRAWLER_ASTRICT("省级账号才能查看爬虫信息", 3017),
+    IP_ERROR("无效IP", 3018),
+    ADMIN_ASTRICT("超级管理员不涉及业务操作", 3019),
+    NO_AUTHORITY("权限不足,请联系管理员!", 3020),
+    EVIDENCE_NOT_FOUND("请上传相应证据再进行举报", 3021),
+    EXCEL_DATA_VOID("数据为空无法下载", 3022),
+    AUTH_CODE_ERROR("验证码错误", 3023),
+    TIME_TYPE_ERROR("时间类型只能为天(1)和月(3)", 3024),
+    TITLE_IS_NULL("文章标题不能为空", 3025),
+    IS_RECOMMEND_IS_NULL("文章需表明是否首页推荐", 3026),
+    CONTENT_IS_NULL("文章内容不能为空", 3027),
+    COVER_IS_NULL("推荐文章必须上传封面图片", 3028),
+    AUTH_CODE_TIME_OUT("验证码超时", 3029),
+    LOGIN_TIMEOUT("秘钥错误", 3030),
+    AREA_NO_FOUND("地区不在当前用户范围内,请重新选择", 3031),
+    DATA_ERROR("导入数据时间格式异常", 3032),
+    INTEGER_VAIL("必须为整数", 3033),
+    AREA_UNMATCH_ROLE("用户角色不在地区范围内,请重新选择", 3034),
+    USER_INFO_RESTRICT("不是对应创建人无法进行相应操作", 3035),
+    ARG_NO_FOUND("参数名称与系统中名称不匹配", 3036),
+    DATA_NO_FOUND("导入数据中日期不能为空", 3037),
+    PRODUCT_NAME_NO_FOUND("导入数据中产品名称不能为空", 3038),
+    MARKET_NAME_FOUND("导入数据中市场名称不能为空", 3039),
+    DEL_STATE("事件已举报完成,证据无法删除", 3040),
+    ABNORMAL_ACCOUNT("账号异常", 3041),
+    AREA_USER_FOUND("区域被用户引用,请先删除区域下的用户", 3042),
+    ROLE_USER_FOUND("角色被用户引用,请先删除角色下的用户", 3043),
+    ROLE_SYS("不可以删除系统默认创建的角色", 3044),
+    ROLE_NO_FOUND("角色不存在", 3045),
+    MENU_NO_FOUND("请增加上级和本级默认角色的菜单权限", 3046),
+    AREA_NO_MATCH("只允许修改本级的菜单权限", 3047),
+    ROLE_DEFAULT("只允许上级修改系统创建的默认角色", 3048),
+    THE_CALLING_SYSTEM_DID_NOT_START("调用系统未正常启动", 3049),
+    BUSINESS_INFORMATION_CANNOT_BE_EMPTY("农企信息不能为空", 3050),
+    PRICING_RELEASES_CANNOT_BE_EMPTY("定价发布信息不能为空", 3051),
+    THE_ACCOUNT_IS_BANNED("账号被禁,无法使用", 3052),
+    THREAD_BLOCKING_EXCEPTION("账号被禁,无法使用", 3053),
+    ROLE_OF_SPOT("不允许修改或删除收购点权限角色", 3054),
+    INFORMATION_CANNOT_BE_REMOVED_BY_REFERENCE("信息被引用,无法删除", 3055),
+    THE_CONTENT_IS_TOO_LARGE_TO_SAVE("内容过长无法保存", 3056),
+    CANNOT_BE_DELETED_IN_USE("农企信息在使用中,不能删除", 3057),
+    ACQUISITION_POINT_CANNOT_BE_EMPTY("收购点不能为空", 3058),
+    COLLECTION_SPOT_NAME_REPEATED("收购点名称已存在", 3059),
+    INTERNAL_ERROR("系统错误,请联系管理员!", 9999);
+
+
+    private String value;
+    private Integer index;
+
+    CommonEnum(String sex, Integer index) {
+        this.setValue(sex);
+        this.setIndex(index);
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public static String getSex(Short index) {
+        if (index.shortValue() == MEN.index.shortValue()) {
+            return MEN.getValue();
+        } else if (index.shortValue() == WOMEN.index.shortValue()) {
+            return WOMEN.getValue();
+        } else {
+            return null;
+        }
+    }
+
+    public static Short getIndex(String sex) {
+        if (sex.trim().equals(MEN.value)) {
+            return Short.valueOf(MEN.getIndex().toString());
+        } else if (sex.trim().equals(WOMEN.value)) {
+            return Short.valueOf(WOMEN.getIndex().toString());
+        } else {
+            throw new GlobalException("性别输入异常,性别只能为:男、女!");
+        }
+    }
+
+    public Integer getIndex() {
+        return index;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public void setIndex(Integer index) {
+        this.index = index;
+    }
+}

+ 90 - 0
src/main/java/com/hw/util/enums/ResultEnum.java

@@ -0,0 +1,90 @@
+package com.hw.util.enums;
+
+import lombok.Getter;
+
+/**
+ * 服务接口返回状态信息枚举定义
+ *
+ * @author yys
+ */
+@Getter
+public enum ResultEnum {
+
+    SUCCESS(0, "操作成功"),
+    FAILURE(1, "操作失败"),
+    FAILED(-1, "非法用户,请输入正确的accessToken"),
+    SYS_ERROR(500, "系统开小差了,请稍后再试"),
+    SYS_BREAK_ERROR(501, "系统服务中断,请稍后再试"),
+    SYS_PASSWD_ERROR(502, "旧密码验证错误,请重试"),
+    PERMISSION_DENIED(403, "没有权限"),
+    ACCOUNT_ALREADY_LOGIN(404, "该账号已经在其他设备上登录"),
+    NOT_LOGIN(401, "请先登录"),
+    RELOGIN(402, "请重新登录"),
+    LOGIN_ACCOUNT_MISS(407, "账号有错误,请检查账号信息"),
+    LOGIN_PWD_MISS(408, "密码有误,请重新输入"),
+    LOGIN_FORBIDED(406, "用户被禁用,请联系管理员"),
+    TOKEN_EXPIRED(405, "登录已过期,请重新登录"),
+    CODE_EXPIRED(409, "验证码不正确,请重新输入"),
+    FAIL_LOGIN_LOGIN_NAME(600, "用户账号或密码不正确"),
+    LOGINING_USER(601, "用户正在登陆系统,不能删除"),
+    ASSAY_APPLIED(602, "请勿重复提交检验申请"),
+    USER_IS_NOT(603, "用户已存在,请登录"),
+    WECHAT_USER_NOT_EXIST(604, "投诉用户不存在"),
+    ENCRYPTION_ERROR(605, "加密操作失败"),
+    PARAMETER_NOT_NULL(606, "参数不能为空"),
+    PARAMETER_INPUT_ERROR(620, "错误的输入参数!"),
+    FILE_NOT_FOUND(607, "文件不存在"),
+    USER_IS_HAVA(608, "用户登陆错误"),
+    WRONG_PHONE(609, "手机号相关错误"),
+    FORM_VALIDATION(610, "表单验证相关错误"),
+    CODE_ERROR(611, "验证码错误或已过期"),
+    FAILED_AUTHORIZE_LOGIN(612, "授权登录失败"),
+    LOGIN_FAILED(613, "登录失败"),
+    USER_IS_NUll(614, "用户数据不存在"),
+    USER_IS_BINDING(615, "该手机号已被使用"),
+    ORDER_PAY_DUPLICATE(622, "订单已支付,请勿重复支付!"),
+    ORDER_PAY_COMPLETE(623, "订单已完成,请勿再次支付!"),
+    GOODS_BUY_AUTH(624, "该用户购买商品超出购买权限!"),
+    WX_AUTH_INFO_SUCCESS(625, "微信认证信息检测成功!"),
+    WX_AUTH_INFO_FAIL(626, "微信认证信息检测失败!"),
+    SIGNATURE_OK(718, "签名成功"),
+    SIGNATURE_ERROR(719, "签名失败"),
+    FILE_UPLOAD_ERROR(720, "文件上传失败!"),
+    
+    NOT_SUPPURT_REQUEST(907,"请求方式不支持");
+
+
+    private Integer code;
+
+    private String msg;
+
+    ResultEnum(Integer code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    /**
+     * 通过枚举code获取枚举msg
+     */
+    public static String getMsgByCode(Integer code) {
+        for (ResultEnum resultEnum : ResultEnum.values()) {
+            if (code.equals(resultEnum.getCode())) {
+                return resultEnum.getMsg();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 通过枚举code获取枚举对象
+     */
+    public static ResultEnum getResultEnumByCode(Integer code) {
+        for (ResultEnum resultEnum : ResultEnum.values()) {
+            if (code.equals(resultEnum.getCode())) {
+                return resultEnum;
+            }
+        }
+        return null;
+    }
+
+}

+ 8 - 0
src/main/java/com/hw/util/exception/CommitException.java

@@ -0,0 +1,8 @@
+package com.hw.util.exception;
+
+public class CommitException extends RuntimeException {
+
+    public CommitException(String s) {
+        super(s);
+    }
+}

+ 112 - 0
src/main/java/com/hw/util/exception/GlobalDefaultExceptionHandler.java

@@ -0,0 +1,112 @@
+package com.hw.util.exception;
+
+
+import com.hw.util.base.ResponseBase;
+import com.hw.util.base.ResultVO;
+import com.hw.util.base.RetHead;
+import com.hw.util.enums.ResultEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.CannotAcquireLockException;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.util.CollectionUtils;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.FileNotFoundException;
+import java.util.List;
+
+
+@Slf4j
+@CrossOrigin
+@RestControllerAdvice
+public class GlobalDefaultExceptionHandler {
+
+    @ExceptionHandler(value = CommitException.class)
+    public ResponseBase defaultErrorHandler(HttpServletRequest req, CommitException e) {
+        log.error(req.getRequestURL() + "<:=====:>" +
+                req.getMethod() + "<:=====:>" +
+                req.getQueryString() + "<:=====:>" +
+                e.getMessage());
+        e.printStackTrace();
+        RetHead retHead = new RetHead();
+        retHead.setErrCode((short) 1);
+        retHead.setErrMsg(e.getMessage());
+        return new ResponseBase(retHead);
+    }
+    @ExceptionHandler(value = CannotAcquireLockException.class)
+    public ResponseBase defaultErrorHandler(HttpServletRequest req, CannotAcquireLockException e) {
+        log.error(req.getRequestURL() + "<:=====:>" +
+                req.getMethod() + "<:=====:>" +
+                req.getQueryString() + "<:=====:>" +
+                e.getMessage());
+        e.printStackTrace();
+        RetHead retHead = new RetHead();
+        retHead.setErrCode((short) 1);
+        retHead.setErrMsg("当前系统整理数据稍后再试!");
+        return new ResponseBase(retHead);
+    }
+
+
+    @ExceptionHandler(value = Exception.class)
+    public ResponseBase defaultErrorHandler(
+            HttpServletRequest req, Exception e) {
+
+        log.error(req.getRequestURL() + "<:=====:>" +
+                req.getMethod() + "<:=====:>" +
+                req.getQueryString() + "<:=====:>" +
+                e.getMessage());
+        e.printStackTrace();
+
+        ResultVO resultVO = new ResultVO();
+
+        if (e instanceof RuntimeException) {
+            log.error(e.getClass().toString());
+            resultVO.setCode(1);
+            resultVO.setMsg(e.getMessage());
+            //resultVO.setMsg("操作失败!");
+        } else if (e instanceof GlobalException) {
+            log.error(e.getClass().toString());
+            GlobalException globalException = (GlobalException) e;
+            Integer code = globalException.getCode();
+            String msg = globalException.getMessage();
+            resultVO.setCode(code);
+            resultVO.setMsg(msg);
+        } else if (e instanceof MethodArgumentNotValidException) {
+            log.error(e.getClass().toString());
+            List<ObjectError> allErrors = ((MethodArgumentNotValidException) e).getBindingResult()
+                    .getAllErrors();
+            if (!CollectionUtils.isEmpty(allErrors)) {
+                String errorMessage = allErrors.get(0).getDefaultMessage();
+                log.error(errorMessage);
+                resultVO.setCode(ResultEnum.FAILURE.getCode());
+                resultVO.setMsg(errorMessage);
+            }
+        } else if (e instanceof MissingServletRequestParameterException) {
+            log.error(e.getClass().toString());
+            resultVO.setCode(ResultEnum.PARAMETER_NOT_NULL.getCode());
+            resultVO.setMsg(ResultEnum.PARAMETER_NOT_NULL.getMsg());
+        } else if (e instanceof HttpMessageNotReadableException) {
+            log.error(e.getClass().toString());
+            resultVO.setCode(ResultEnum.PARAMETER_NOT_NULL.getCode());
+            resultVO.setMsg(ResultEnum.PARAMETER_NOT_NULL.getMsg());
+        } else if (e instanceof FileNotFoundException) {
+            log.error(e.getClass().toString());
+            resultVO.setCode(ResultEnum.FILE_NOT_FOUND.getCode());
+            resultVO.setMsg(ResultEnum.FILE_NOT_FOUND.getMsg());
+        } else {
+            log.error(e.getClass().toString() + ":" + e.getMessage());
+            resultVO.setCode(ResultEnum.FAILURE.getCode());
+            resultVO.setMsg(ResultEnum.FAILURE.getMsg());
+        }
+
+        RetHead retHead = new RetHead();
+        retHead.setErrCode(resultVO.getCode().shortValue());
+        retHead.setErrMsg(resultVO.getMsg());
+        return new ResponseBase(retHead);
+    }
+}

+ 35 - 0
src/main/java/com/hw/util/exception/GlobalException.java

@@ -0,0 +1,35 @@
+package com.hw.util.exception;
+
+import com.hw.util.enums.ResultEnum;
+
+/**
+ * @author JYJ
+ */
+public class GlobalException extends RuntimeException {
+
+
+    private Integer code;
+
+    public GlobalException(String errorMessage) {
+        super(errorMessage);
+    }
+
+    public GlobalException(Integer code, String msg) {
+        this(msg);
+        this.setCode(code);
+    }
+
+    public GlobalException(ResultEnum resultEnum) {
+        this(resultEnum.getMsg());
+        this.setCode(resultEnum.getCode());
+    }
+
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+}

+ 52 - 0
src/main/resources/application-dev.properties

@@ -0,0 +1,52 @@
+server.port=19001
+spring.application.name=pull-openiddata
+
+#mysql datasource setting
+spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
+spring.datasource.url=jdbc:mysql://172.16.90.201:3306/wechat-openid-data?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false&&allowMultiQueries=true
+spring.datasource.username=root
+spring.datasource.password=123456
+spring.datasource.initialSize=5
+spring.datasource.minIdle=5
+spring.datasource.maxActive=20
+spring.datasource.maxWait=60000
+spring.datasource.timeBetweenEvictionRunsMillis=60000
+spring.datasource.minEvictableIdleTimeMillis=30000
+spring.datasource.validationQuery=SELECT 1
+spring.datasource.testWhileIdle=true
+spring.datasource.testOnBorrow=false
+spring.datasource.testOnReturn=false
+spring.datasource.poolPreparedStatements=true
+spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
+spring.datasource.filters=stat,wall
+spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=2000
+#mybatis setting
+mybatis.type-aliases-package=com.hw.entity
+mybatis.mapper-locations=classpath:mappers/*.xml
+mybatis.check-config-location=true
+mybatis.executor-type=simple
+#pagehelper setting
+pagehelper.helperDialect=mysql
+pagehelper.reasonable=true
+pagehelper.supportMethodsArguments=true
+pagehelper.params=count=countSql
+
+spring.redis.database=0
+spring.redis.host=127.0.0.1
+spring.redis.port=6379
+spring.redis.jedis.pool.max-idle=8
+spring.redis.jedis.pool.min-idle=0
+spring.redis.jedis.pool.max-active=10
+spring.redis.jedis.pool.max-wait=-1
+spring.redis.timeout=5000
+
+#原公众号appId
+wx.ma.appId=wxbe90cc7c5233dd84
+#原公众号secret
+wx.ma.secret=ec4a18ce1a7bcf17cf592c3d57cec68a
+
+#新公众号appId
+newwx.ma.appId=wxbe90cc7c5233dd84
+#新公众号secret
+newwx.ma.secret=ec4a18ce1a7bcf17cf592c3d57cec68a

+ 1 - 0
src/main/resources/application-pro.properties

@@ -0,0 +1 @@
+server.port=18001

+ 1 - 0
src/main/resources/application-test.properties

@@ -0,0 +1 @@
+server.port=18002

+ 4 - 0
src/main/resources/application.properties

@@ -0,0 +1,4 @@
+spring.profiles.active=dev
+
+#ÈÕÖ¾
+logging.config=classpath:logConfig/logConfig.xml

+ 47 - 0
src/main/resources/generatorConfig.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE generatorConfiguration
+        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
+        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
+<generatorConfiguration>
+    <context id="DB2Tables" targetRuntime="MyBatis3">
+        <commentGenerator>
+            <property name="suppressDate" value="true"/>
+            <property name="suppressAllComments" value="true"/>
+        </commentGenerator>
+        <!--数据库链接地址账号密码-->
+        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
+                        connectionURL="jdbc:mysql://172.16.90.201:3306/wechat-openid-data?characterEncoding=UTF-8"
+                        userId="root" password="123456">
+        </jdbcConnection>
+        <javaTypeResolver>
+            <property name="forceBigDecimals" value="false"/>
+        </javaTypeResolver>
+        <!--生成Model类存放位置-->
+        <javaModelGenerator targetPackage="com.hw.entity"
+                            targetProject="src/main/java">
+            <property name="enableSubPackages" value="true"/>
+            <property name="trimStrings" value="true"/>
+        </javaModelGenerator>
+        <!--生成映射文件存放位置-->
+        <sqlMapGenerator targetPackage="mappers" targetProject="src/main/resources">
+            <property name="enableSubPackages" value="true"/>
+        </sqlMapGenerator>
+        <!--生成Dao类存放位置-->
+        <!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
+                type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
+                type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
+                type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口
+        -->
+        <javaClientGenerator type="XMLMAPPER" targetPackage="com.hw.dao"
+                             targetProject="src/main/java">
+            <property name="enableSubPackages" value="true"/>
+        </javaClientGenerator>
+        <!--生成对应表及类名-->
+        <table tableName="t_wechat_info" domainObjectName="WechatInfo" enableCountByExample="false"
+               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
+               selectByExampleQueryId="false"></table>
+        <!--<table tableName="t_base_dictionary_type" domainObjectName="BaseDictionaryType" enableCountByExample="false"
+               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false"
+               selectByExampleQueryId="false"></table>-->
+    </context>
+</generatorConfiguration>

+ 52 - 0
src/main/resources/logConfig/logConfig.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE configuration>
+<configuration>
+    <!-- %m输出的信息,%p日志级别,%t线程名,%d日期,%c类的全名,%i索引【从数字0开始递增】,,, -->
+    <!-- appender是configuration的子节点,是负责写日志的组件。 -->
+    <!-- ConsoleAppender:把日志输出到控制台 -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d %p (%file:%line\)- %m%n</pattern>
+            <!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+    <!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
+    <!-- 以下的大概意思是:1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是sys.log -->
+    <!--             2.如果日期没有发生变化,但是当前日志的文件大小超过1KB时,对当前日志进行分割 重命名-->
+    <appender name="syslog"
+              class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <File>log/what-openiddata.log</File>
+        <!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 -->
+        <!-- TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
+            <!-- 文件名:log/sys.2018-06-21.0.log -->
+            <fileNamePattern>log/what-openiddata.%d.%i.log</fileNamePattern>
+            <!-- 每产生一个日志文件,该日志文件的保存期限为30天 -->
+            <maxHistory>30</maxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy  class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <!-- maxFileSize:这是活动文件的大小,默认值是10MB-->
+                <maxFileSize>5MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+        <encoder>
+            <!-- pattern节点,用来设置日志的输入格式 -->
+            <pattern>
+                %d %p (%file:%line\)- %m%n
+            </pattern>
+            <!-- 记录日志的编码 -->
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+    </appender>
+    <!-- 控制台输出日志级别 -->
+    <root level="info">
+        <appender-ref ref="STDOUT" />
+    </root>
+    <!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 -->
+    <!-- com.hywa为根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG -->
+    <!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE  -->
+    <logger name="com.hw" level="DEBUG">
+        <appender-ref ref="syslog" />
+    </logger>
+</configuration>

+ 152 - 0
src/main/resources/mappers/WechatInfoMapper.xml

@@ -0,0 +1,152 @@
+<?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.hw.dao.WechatInfoMapper">
+  <resultMap id="BaseResultMap" type="com.hw.entity.WechatInfo">
+    <id column="guid" jdbcType="CHAR" property="guid" />
+    <result column="old_appid" jdbcType="VARCHAR" property="oldAppid" />
+    <result column="old_openid" jdbcType="VARCHAR" property="oldOpenid" />
+    <result column="new_openid" jdbcType="VARCHAR" property="newOpenid" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="modified_time" jdbcType="TIMESTAMP" property="modifiedTime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    guid, old_appid, old_openid, new_openid, create_time, modified_time
+  </sql>
+  <select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
+    select 
+    <include refid="Base_Column_List" />
+    from t_wechat_info
+    where guid = #{guid,jdbcType=CHAR}
+  </select>
+  <delete id="deleteByPrimaryKey" parameterType="java.lang.String">
+    delete from t_wechat_info
+    where guid = #{guid,jdbcType=CHAR}
+  </delete>
+  <insert id="insert" parameterType="com.hw.entity.WechatInfo">
+    insert into t_wechat_info (guid, old_appid, old_openid, 
+      new_openid, create_time, modified_time
+      )
+    values (#{guid,jdbcType=CHAR}, #{oldAppid,jdbcType=VARCHAR}, #{oldOpenid,jdbcType=VARCHAR}, 
+      #{newOpenid,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{modifiedTime,jdbcType=TIMESTAMP}
+      )
+  </insert>
+  <insert id="insertSelective" parameterType="com.hw.entity.WechatInfo">
+    insert into t_wechat_info
+    <trim prefix="(" suffix=")" suffixOverrides=",">
+      <if test="guid != null">
+        guid,
+      </if>
+      <if test="oldAppid != null">
+        old_appid,
+      </if>
+      <if test="oldOpenid != null">
+        old_openid,
+      </if>
+      <if test="newOpenid != null">
+        new_openid,
+      </if>
+      <if test="createTime != null">
+        create_time,
+      </if>
+      <if test="modifiedTime != null">
+        modified_time,
+      </if>
+    </trim>
+    <trim prefix="values (" suffix=")" suffixOverrides=",">
+      <if test="guid != null">
+        #{guid,jdbcType=CHAR},
+      </if>
+      <if test="oldAppid != null">
+        #{oldAppid,jdbcType=VARCHAR},
+      </if>
+      <if test="oldOpenid != null">
+        #{oldOpenid,jdbcType=VARCHAR},
+      </if>
+      <if test="newOpenid != null">
+        #{newOpenid,jdbcType=VARCHAR},
+      </if>
+      <if test="createTime != null">
+        #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="modifiedTime != null">
+        #{modifiedTime,jdbcType=TIMESTAMP},
+      </if>
+    </trim>
+  </insert>
+  <update id="updateByPrimaryKeySelective" parameterType="com.hw.entity.WechatInfo">
+    update t_wechat_info
+    <set>
+      <if test="oldAppid != null">
+        old_appid = #{oldAppid,jdbcType=VARCHAR},
+      </if>
+      <if test="oldOpenid != null">
+        old_openid = #{oldOpenid,jdbcType=VARCHAR},
+      </if>
+      <if test="newOpenid != null">
+        new_openid = #{newOpenid,jdbcType=VARCHAR},
+      </if>
+      <if test="createTime != null">
+        create_time = #{createTime,jdbcType=TIMESTAMP},
+      </if>
+      <if test="modifiedTime != null">
+        modified_time = #{modifiedTime,jdbcType=TIMESTAMP},
+      </if>
+    </set>
+    where guid = #{guid,jdbcType=CHAR}
+  </update>
+  <update id="updateByPrimaryKey" parameterType="com.hw.entity.WechatInfo">
+    update t_wechat_info
+    set old_appid = #{oldAppid,jdbcType=VARCHAR},
+      old_openid = #{oldOpenid,jdbcType=VARCHAR},
+      new_openid = #{newOpenid,jdbcType=VARCHAR},
+      create_time = #{createTime,jdbcType=TIMESTAMP},
+      modified_time = #{modifiedTime,jdbcType=TIMESTAMP}
+    where guid = #{guid,jdbcType=CHAR}
+  </update>
+
+  <!-- 已存在公众号openid lym -->
+  <select id="selectList" parameterType="com.hw.form.WechatInfoForm" resultType="com.hw.entity.WechatInfo">
+    select  <include refid="Base_Column_List"/> from t_wechat_info
+    where 1=1
+    <if test="oldAppid != null and oldAppid != ''">
+      and old_appid = #{oldAppid}
+    </if>
+    ORDER BY create_time ASC
+  </select>
+
+  <!-- 已存在公众号openid lym -->
+  <select id="getOpenids" parameterType="string" resultType="string">
+    SELECT GROUP_CONCAT(old_openid) FROM t_wechat_info
+    WHERE old_appid = #{appid}
+    <if test="list != null and list.size > 0">
+      AND old_openid IN
+      <foreach collection="list" item="item" open="(" separator="," close=")">
+        #{item}
+      </foreach>
+    </if>
+    GROUP BY old_appid
+  </select>
+
+  <!-- 批量添加 lym -->
+  <insert id="batchAdd" parameterType="com.hw.entity.WechatInfo">
+    insert into t_wechat_info (guid,old_appid,old_openid,create_time)
+    values
+    <foreach collection="list" item="item" open="(" separator="),(" close=")">
+      REPLACE(UUID(),"-",""),#{item.oldAppid},#{item.oldOpenid},NOW()
+    </foreach>
+  </insert>
+
+  <!-- 查询旧公众号openid lym -->
+  <select id="selectOldOpenids" parameterType="com.hw.form.WechatInfoForm" resultType="string">
+    SELECT old_openid FROM t_wechat_info
+    WHERE old_appid = #{oldAppid}
+    ORDER BY create_time ASC
+  </select>
+
+  <!-- 批量修改 lym -->
+  <update id="batchUpdate" parameterType="com.hw.form.WechatInfoForm">
+    <foreach collection="list" item="item" separator=";">
+      UPDATE t_wechat_info SET new_openid = #{item.newOpenid},modified_time = NOW() WHERE old_appid = #{item.oldAppid} and old_openid = #{item.oldOpenid}
+    </foreach>
+  </update>
+</mapper>

+ 11 - 0
src/main/resources/sql/创建表和默认数据.sql

@@ -0,0 +1,11 @@
+#创建表
+CREATE TABLE `t_wechat_info` (
+       `guid` char(32) CHARACTER SET utf8mb4 NOT NULL DEFAULT '1' COMMENT '序列',
+       `old_appid` varchar(50) DEFAULT NULL COMMENT '旧公众号appid',
+       `old_openid` varchar(50) DEFAULT NULL COMMENT '旧微信openid',
+       `new_openid` varchar(50) DEFAULT NULL COMMENT '新微信openid',
+       `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+       `modified_time` datetime DEFAULT NULL COMMENT '修改时间',
+       PRIMARY KEY (`guid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='新旧公众号openid信息';
+

+ 56 - 0
src/main/resources/swagger-ui.html

@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Swagger UI</title>
+    <link rel="icon" type="image/png" href="webjars/springfox-swagger-ui/images/favicon-32x32.png" sizes="32x32"/>
+    <link rel="icon" type="image/png" href="webjars/springfox-swagger-ui/images/favicon-16x16.png" sizes="16x16"/>
+    <link href='webjars/springfox-swagger-ui/css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
+    <link href='webjars/springfox-swagger-ui/css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
+    <link href='webjars/springfox-swagger-ui/css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
+    <link href='webjars/springfox-swagger-ui/css/reset.css' media='print' rel='stylesheet' type='text/css'/>
+    <link href='webjars/springfox-swagger-ui/css/print.css' media='print' rel='stylesheet' type='text/css'/>
+
+    <script src='webjars/springfox-swagger-ui/lib/object-assign-pollyfill.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/jquery-1.8.0.min.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/jquery.slideto.min.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/jquery.wiggle.min.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/handlebars-4.0.5.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/lodash.min.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/backbone-min.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/swagger-ui.min.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/highlight.9.1.0.pack_extended.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/jsoneditor.min.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/marked.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lib/swagger-oauth.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/springfox.js' type='text/javascript'></script>
+
+    <!--国际化操作:选择中文版 -->
+    <script src='webjars/springfox-swagger-ui/lang/translator.js' type='text/javascript'></script>
+    <script src='webjars/springfox-swagger-ui/lang/zh-cn.js' type='text/javascript'></script>
+
+</head>
+
+<body class="swagger-section">
+<div id='header'>
+    <div class="swagger-ui-wrap">
+        <a id="logo" href="http://swagger.io">![](webjars/springfox-swagger-ui/images/logo_small.png)<span
+                class="logo__title">swagger</span></a>
+        <form id='api_selector'>
+            <div class='input'>
+                <select id="select_baseUrl" name="select_baseUrl"></select>
+            </div>
+            <div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl"
+                                      type="text"/></div>
+            <div id='auth_container'></div>
+            <div class='input'><a id="explore" class="header__btn" href="#" data-sw-translate>Explore</a></div>
+        </form>
+    </div>
+</div>
+
+<div id="message-bar" class="swagger-ui-wrap" data-sw-translate></div>
+<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
+</body>
+</html>