Переглянути джерело

初始化代码:
from:http://192.168.0.115:3000/4dkankan_back/4dkankanAPI.git
branch:1.0.1
version:0e45213c66

tianboguang 3 роки тому
коміт
2efc23d78b
100 змінених файлів з 7398 додано та 0 видалено
  1. 290 0
      4dkankan-api-common/pom.xml
  2. 39 0
      4dkankan-api-common/src/main/java/api/common/enums/IdStarterEnum.java
  3. 47 0
      4dkankan-api-common/src/main/java/api/common/enums/ResultCodeEnum.java
  4. 45 0
      4dkankan-api-common/src/main/java/api/common/exception/CommonBaseException.java
  5. 36 0
      4dkankan-api-common/src/main/java/api/common/exception/GlobalExceptionHandler.java
  6. 15 0
      4dkankan-api-common/src/main/java/api/common/model/CommonKey.java
  7. 103 0
      4dkankan-api-common/src/main/java/api/common/model/Result.java
  8. 120 0
      4dkankan-api-common/src/main/java/api/common/utils/AuthCheckUtils.java
  9. 62 0
      4dkankan-api-common/src/main/java/api/common/utils/Base64Converter.java
  10. 115 0
      4dkankan-api-common/src/main/java/api/common/utils/DataUtils.java
  11. 839 0
      4dkankan-api-common/src/main/java/api/common/utils/FileUtils.java
  12. 183 0
      4dkankan-api-common/src/main/java/api/common/utils/HttpClientUtil.java
  13. 425 0
      4dkankan-api-common/src/main/java/api/common/utils/JedisUtil.java
  14. 73 0
      4dkankan-api-common/src/main/java/api/common/utils/JsonUtils.java
  15. 229 0
      4dkankan-api-common/src/main/java/api/common/utils/OssMultipartUpload.java
  16. 57 0
      4dkankan-api-common/src/main/java/api/common/utils/SHAUtils.java
  17. 26 0
      4dkankan-api-common/src/main/java/api/common/utils/UUidGenerator.java
  18. 149 0
      4dkankan-api-common/src/main/java/api/common/utils/UploadToOssUtil.java
  19. 100 0
      4dkankan-house-api/pom.xml
  20. BIN
      4dkankan-house-api/readMeDoc/1592562858664_格式化房源数据接口代码实现脑图.jpg
  21. BIN
      4dkankan-house-api/readMeDoc/open-api房源数据操作脑图.xmind
  22. BIN
      4dkankan-house-api/readMeDoc/看房4DKanKan开放api说明文档V1.1.docx
  23. 57 0
      4dkankan-house-api/src/main/java/house/api/HouseApiApplication.java
  24. 28 0
      4dkankan-house-api/src/main/java/house/api/base/configs/MyBatisPlusConfig.java
  25. 95 0
      4dkankan-house-api/src/main/java/house/api/base/configs/RedisConfig.java
  26. 49 0
      4dkankan-house-api/src/main/java/house/api/base/configs/SwaggerApp.java
  27. 21 0
      4dkankan-house-api/src/main/java/house/api/base/constVo/PageDataVo.java
  28. 22 0
      4dkankan-house-api/src/main/java/house/api/base/constVo/request/FourDgetHouseVo.java
  29. 118 0
      4dkankan-house-api/src/main/java/house/api/base/constVo/request/RecommendHouseVo.java
  30. 17 0
      4dkankan-house-api/src/main/java/house/api/base/constVo/request/TmDeveloperRequestVo.java
  31. 123 0
      4dkankan-house-api/src/main/java/house/api/base/constVo/request/TmHouseInfoRequestVo.java
  32. 40 0
      4dkankan-house-api/src/main/java/house/api/base/constVo/response/DeveloperAuthorityRspDto.java
  33. 16 0
      4dkankan-house-api/src/main/java/house/api/base/dao/TmDeveloperAuthorityDao.java
  34. 16 0
      4dkankan-house-api/src/main/java/house/api/base/dao/TmDeveloperDao.java
  35. 16 0
      4dkankan-house-api/src/main/java/house/api/base/dao/TmHouseInfoDao.java
  36. 16 0
      4dkankan-house-api/src/main/java/house/api/base/dao/TmHouseRecommendDao.java
  37. 16 0
      4dkankan-house-api/src/main/java/house/api/base/dao/TmRoomIdLogDao.java
  38. 85 0
      4dkankan-house-api/src/main/java/house/api/base/entity/TmDeveloper.java
  39. 67 0
      4dkankan-house-api/src/main/java/house/api/base/entity/TmDeveloperAuthority.java
  40. 198 0
      4dkankan-house-api/src/main/java/house/api/base/entity/TmHouseInfo.java
  41. 49 0
      4dkankan-house-api/src/main/java/house/api/base/entity/TmHouseRecommend.java
  42. 46 0
      4dkankan-house-api/src/main/java/house/api/base/entity/TmRoomIdLog.java
  43. 36 0
      4dkankan-house-api/src/main/java/house/api/base/exception/ControllerHanderException.java
  44. 50 0
      4dkankan-house-api/src/main/java/house/api/base/generator/GeneratorTestData.java
  45. 104 0
      4dkankan-house-api/src/main/java/house/api/base/generator/MysqlGenerator.java
  46. 16 0
      4dkankan-house-api/src/main/java/house/api/base/service/ITmDeveloperAuthorityService.java
  47. 16 0
      4dkankan-house-api/src/main/java/house/api/base/service/ITmDeveloperService.java
  48. 16 0
      4dkankan-house-api/src/main/java/house/api/base/service/ITmHouseInfoService.java
  49. 16 0
      4dkankan-house-api/src/main/java/house/api/base/service/ITmHouseRecommendService.java
  50. 16 0
      4dkankan-house-api/src/main/java/house/api/base/service/ITmRoomIdLogService.java
  51. 20 0
      4dkankan-house-api/src/main/java/house/api/base/service/impl/TmDeveloperAuthorityServiceImpl.java
  52. 20 0
      4dkankan-house-api/src/main/java/house/api/base/service/impl/TmDeveloperServiceImpl.java
  53. 20 0
      4dkankan-house-api/src/main/java/house/api/base/service/impl/TmHouseInfoServiceImpl.java
  54. 20 0
      4dkankan-house-api/src/main/java/house/api/base/service/impl/TmHouseRecommendServiceImpl.java
  55. 20 0
      4dkankan-house-api/src/main/java/house/api/base/service/impl/TmRoomIdLogServiceImpl.java
  56. 413 0
      4dkankan-house-api/src/main/java/house/api/controller/FourDHouseController.java
  57. 25 0
      4dkankan-house-api/src/main/java/house/api/controller/TmDeveloperController.java
  58. 636 0
      4dkankan-house-api/src/main/java/house/api/controller/TmHouseInfoController.java
  59. 40 0
      4dkankan-house-api/src/main/java/house/api/enums/DeveloperTerminalType.java
  60. 77 0
      4dkankan-house-api/src/main/resources/application-dev.properties
  61. 77 0
      4dkankan-house-api/src/main/resources/application-prod.properties
  62. 72 0
      4dkankan-house-api/src/main/resources/application-test.properties
  63. 3 0
      4dkankan-house-api/src/main/resources/application.properties
  64. 61 0
      4dkankan-house-api/src/main/resources/log4j2.xml
  65. 5 0
      4dkankan-house-api/src/main/resources/mybatis/mappers/TmDeveloperAuthorityMapper.xml
  66. 5 0
      4dkankan-house-api/src/main/resources/mybatis/mappers/TmDeveloperMapper.xml
  67. 5 0
      4dkankan-house-api/src/main/resources/mybatis/mappers/TmHouseInfoMapper.xml
  68. 5 0
      4dkankan-house-api/src/main/resources/mybatis/mappers/TmHouseRecommendMapper.xml
  69. 424 0
      4dkankan-shop-api/pom.xml
  70. BIN
      4dkankan-shop-api/readMeDoc/看店4DKanKan开放api说明文档V1.0.docx
  71. 54 0
      4dkankan-shop-api/src/main/java/shop/api/ShopApiApplication.java
  72. 28 0
      4dkankan-shop-api/src/main/java/shop/api/base/config/MyBatisPlusConfig.java
  73. 95 0
      4dkankan-shop-api/src/main/java/shop/api/base/config/RedisConfig.java
  74. 49 0
      4dkankan-shop-api/src/main/java/shop/api/base/config/SwaggerApp.java
  75. 18 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/MyTmGoodsInfoDao.java
  76. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/TmBrandInfoDao.java
  77. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/TmCommentCountDao.java
  78. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/TmDeveloperAuthorityDao.java
  79. 20 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/TmGoodsInfoDao.java
  80. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/TmHotShopDao.java
  81. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/TmLikeCountDao.java
  82. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/TmUserCommentLogDao.java
  83. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/dao/TmUserLikeLogDao.java
  84. 104 0
      4dkankan-shop-api/src/main/java/shop/api/base/entity/TmBrandInfo.java
  85. 49 0
      4dkankan-shop-api/src/main/java/shop/api/base/entity/TmCommentCount.java
  86. 67 0
      4dkankan-shop-api/src/main/java/shop/api/base/entity/TmDeveloperAuthority.java
  87. 113 0
      4dkankan-shop-api/src/main/java/shop/api/base/entity/TmGoodsInfo.java
  88. 53 0
      4dkankan-shop-api/src/main/java/shop/api/base/entity/TmHotShop.java
  89. 49 0
      4dkankan-shop-api/src/main/java/shop/api/base/entity/TmLikeCount.java
  90. 61 0
      4dkankan-shop-api/src/main/java/shop/api/base/entity/TmUserCommentLog.java
  91. 49 0
      4dkankan-shop-api/src/main/java/shop/api/base/entity/TmUserLikeLog.java
  92. 99 0
      4dkankan-shop-api/src/main/java/shop/api/base/generator/MysqlGenerator.java
  93. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/service/ITmBrandInfoService.java
  94. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/service/ITmCommentCountService.java
  95. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/service/ITmDeveloperAuthorityService.java
  96. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/service/ITmGoodsInfoService.java
  97. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/service/ITmHotShopService.java
  98. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/service/ITmLikeCountService.java
  99. 16 0
      4dkankan-shop-api/src/main/java/shop/api/base/service/ITmUserCommentLogService.java
  100. 0 0
      4dkankan-shop-api/src/main/java/shop/api/base/service/ITmUserLikeLogService.java

+ 290 - 0
4dkankan-api-common/pom.xml

@@ -0,0 +1,290 @@
+<?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.4dkankan.api.common</groupId>
+    <artifactId>4dkankan-api-common</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <packaging>jar</packaging>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
+    </properties>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.2.5.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-classic</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <!-- <scope>compile</scope>-->
+            <exclusions>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-classic</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-core</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+
+
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.5</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>1.8.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.boot</groupId>
+            <artifactId>nacos-config-spring-boot-starter</artifactId>
+            <version>0.2.6</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-io</groupId>
+                    <artifactId>commons-io</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <dependency>
+            <groupId>com.alibaba.boot</groupId>
+            <artifactId>nacos-discovery-spring-boot-starter</artifactId>
+            <version>0.2.6</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-io</groupId>
+                    <artifactId>commons-io</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>4.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+
+        <!--devtools热部署-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional>
+            <scope>true</scope>
+        </dependency>
+
+        <!--内置的tomcat容器-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+           <!-- <scope>provided</scope>-->
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.tomcat.embed</groupId>
+                    <artifactId>tomcat-embed-websocket</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.1</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.3.1.tmp</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mybatis</groupId>
+                    <artifactId>mybatis</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.mybatis</groupId>
+                    <artifactId>mybatis-spring</artifactId>
+                </exclusion>
+
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.3.1.tmp</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+            <version>2.1</version>
+        </dependency>
+
+
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>slf4j-api</artifactId>
+                    <groupId>org.slf4j</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis-typehandlers-jsr310</artifactId>
+            <version>1.0.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-redis</artifactId>
+            <!--这里不使用单独的版本号,使用spring-boot的默认版本号,不然会冲突 -!>
+<!-            <version>2.1.4.RELEASE</version>-->
+        </dependency>
+
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>${maven-surefire-plugin.version}</version>
+                <configuration>
+                    <skipTests>true</skipTests>    <!--默认关掉单元测试 -->
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 39 - 0
4dkankan-api-common/src/main/java/api/common/enums/IdStarterEnum.java

@@ -0,0 +1,39 @@
+package api.common.enums;
+
+/**
+ * @author abnerhou
+ * @date 2020/4/22 17:19
+ * @desciption
+ */
+public enum IdStarterEnum {
+
+    DEFAULT("1001" ,"默认表id初始值"),
+    RELATION("1010" ,"关联关系Id的初始值"),
+    DEVELOPER("1020" ,"开发者id的初始值"),
+    ROOM_ID("1050" ,"ROOM ID的初始值"),
+    APP_ID("1030" ,"开发者应用id的初始值"),
+    APP_SECRET("1040" ,"开发者应用密钥的初始值"),
+    GOODS_INFO_ID("1050" ,"商品信息Id的初始值"),
+    HOT_SHOP_ID("1060" ,"商品热点id的初始值"),
+    BRAND_INFO_ID("1070" ,"商家id的初始值"),
+    LIKE_ID("1080" ,"点赞商家记录id的初始值"),
+    LIKE_LOG_ID("1090" ,"点赞记录id的初始值"),
+    ;
+
+    private String starter;
+
+    private String desc;
+
+    IdStarterEnum(String starter, String desc) {
+        this.starter = starter;
+        this.desc = desc;
+    }
+
+    public String getStarter() {
+        return starter;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 47 - 0
4dkankan-api-common/src/main/java/api/common/enums/ResultCodeEnum.java

@@ -0,0 +1,47 @@
+package api.common.enums;
+
+/**
+ * @author abnerhou
+ * @date 2020/5/6 8:23
+ * @desciption
+ */
+public enum ResultCodeEnum {
+
+    D3001(3001 , "缺少必要参数" , true),
+    D3002(3002 , "token非法" , false),
+    D3003(3003 , "APP ID 缺失" ,false),
+    D3004(3004 , "入参数据缺失" , true),
+    D3005(3005 , "权限不足", true),
+    D3006(3006 , "非法的APP ID" , false),
+    D3007(3007 , "时间超时" , true),
+    D3008(3008 , "解析数据签名失败" , true),
+    D3009(3009 , "数据已经被篡改" , true),
+    D3010(3010 , "终端用户类型非法" , true),
+    D3011(3011 , "非法的用户类型" , true),
+
+    D100(3100 , "系统异常" , true),
+    D101(3101 , "数据异常" , true),
+    ;
+
+    ResultCodeEnum(Integer code, String desc , Boolean canBeReplace) {
+        this.code = code;
+        this.desc = desc;
+        this.canBeReplace = canBeReplace;
+    }
+
+    private Integer code;
+    private String desc;
+    private Boolean canBeReplace;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public Boolean getCanBeReplace() {
+        return canBeReplace;
+    }
+}

+ 45 - 0
4dkankan-api-common/src/main/java/api/common/exception/CommonBaseException.java

@@ -0,0 +1,45 @@
+package api.common.exception;
+
+import api.common.enums.ResultCodeEnum;
+import lombok.Data;
+
+/**
+ * @author abnerhou
+ * @date 2020/5/25 11:39
+ * @desciption
+ */
+@Data
+public class CommonBaseException extends RuntimeException{
+    private static final long serialVersionUID = 2899335020273674737L;
+
+    private Integer code;
+
+    private String msg;
+
+    public CommonBaseException(Integer code, String msg){
+        super(msg);
+        this.code = code;
+        this.msg = msg;
+    }
+
+
+    public CommonBaseException(ResultCodeEnum resultCodeEnum){
+        super(resultCodeEnum.getDesc());
+        this.code = resultCodeEnum.getCode();
+        this.msg = resultCodeEnum.getDesc();
+    }
+
+    public CommonBaseException(ResultCodeEnum resultCodeEnum , String replaceMsg){
+        super(resultCodeEnum.getDesc());
+        this.code = resultCodeEnum.getCode();
+        if(resultCodeEnum.getCanBeReplace()){
+            this.msg = replaceMsg;
+        }else{
+            this.msg = resultCodeEnum.getDesc();
+        }
+    }
+
+
+
+
+}

+ 36 - 0
4dkankan-api-common/src/main/java/api/common/exception/GlobalExceptionHandler.java

@@ -0,0 +1,36 @@
+package api.common.exception;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/1 18:02
+ * @desciption
+ */
+
+
+import api.common.model.Result;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.http.HttpStatus;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 全局异常捕获统一返回客户端
+ */
+//@Log4j2
+//@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+   /* @ResponseBody
+    @ExceptionHandler(CommonBaseException.class)
+    @ResponseStatus(HttpStatus.OK)
+    public Result runtimeExceptionHandler(HttpServletRequest request, CommonBaseException e) {
+        log.error(request.getRequestURI() + ":" + e.getMsg());
+        return Result.failure(StringUtils.isEmpty(e.getCode()) ? Result.CODE_FAILURE : e.getCode(), e.getMsg());
+    }*/
+
+}

+ 15 - 0
4dkankan-api-common/src/main/java/api/common/model/CommonKey.java

@@ -0,0 +1,15 @@
+package api.common.model;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/5 12:02
+ * @desciption
+ */
+public class CommonKey {
+
+    public static String APP_ID = "appId";
+    public static String APP_SECRET = "keyWord";
+    public static String TIME_STAMP = "timeStamp";
+    public static String SIGN = "sign";
+    public static String TOKEN = "token";
+}

+ 103 - 0
4dkankan-api-common/src/main/java/api/common/model/Result.java

@@ -0,0 +1,103 @@
+package api.common.model;
+
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 通用返回类
+ *
+ * @author
+ */
+@Data
+public class Result<T> implements Serializable {
+    private static final long serialVersionUID = -1491499610244557029L;
+    public static final String SUCCESS_MSG = "操作成功";
+    public static Integer CODE_SUCCESS = 0;
+    public static Integer CODE_FAILURE = -1;
+    public static String[] NOOP = new String[]{};
+
+    /**
+     * 处理状态:0: 成功, 1: 失败
+     */
+    private Integer code;
+    /**
+     * 消息
+     */
+    private String msg;
+    /**
+     * 返回数据
+     */
+
+    private T data;
+
+
+    public Result(Integer code, String msg, T data) {
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    /**
+     * 处理成功,并返回数据
+     *
+     * @param data 数据对象
+     * @return data
+     */
+    public static Result success(Object data) {
+        return new Result(CODE_SUCCESS, SUCCESS_MSG, data);
+    }
+    /**
+     * 处理成功
+     *
+     * @return data
+     */
+    public static  Result success() {
+        return new  Result(CODE_SUCCESS, SUCCESS_MSG, NOOP);
+    }
+    /**
+     * 处理成功
+     *
+     * @param msg 消息
+     * @return data
+     */
+    public static  Result success(String msg) {
+        return new  Result(CODE_SUCCESS, msg, NOOP);
+    }
+    /**
+     * 处理成功
+     *
+     * @param msg  消息
+     * @param data 数据对象
+     * @return data
+     */
+    public static  Result success(String msg, Object data) {
+        return new  Result(CODE_SUCCESS, msg, data);
+    }
+    /**
+     * 处理失败,并返回数据(一般为错误信息)
+     *
+     * @param code 错误代码
+     * @param msg  消息
+     * @return data
+     */
+    public static  Result failure(Integer code, String msg) {
+        return new  Result(code, msg, NOOP);
+    }
+    /**
+     * 处理失败
+     *
+     * @param msg 消息
+     * @return data
+     */
+    public static  Result failure(String msg) {
+        return failure(CODE_FAILURE, msg);
+    }
+
+    @Override
+    public String toString() {
+        return "JsonResult [code=" + code + ", msg=" + msg + ", data="
+                + data + "]";
+    }
+}

+ 120 - 0
4dkankan-api-common/src/main/java/api/common/utils/AuthCheckUtils.java

@@ -0,0 +1,120 @@
+package api.common.utils;
+
+import api.common.enums.ResultCodeEnum;
+import api.common.exception.CommonBaseException;
+import api.common.model.CommonKey;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.*;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/30 11:10
+ * @desciption
+ */
+@Log4j2
+public class AuthCheckUtils {
+
+    public static void checkBaseData(HttpServletRequest request){
+        if(null == request){
+            throw  new CommonBaseException(ResultCodeEnum.D101 , "请求入参缺失");
+        }
+        String appId = request.getParameter(CommonKey.APP_ID);
+        String token = request.getParameter(CommonKey.TOKEN);
+        String sign = request.getParameter(CommonKey.SIGN);
+        Long timeStamp = DataUtils.getLongReturnNullIfNotExit(request.getParameter(CommonKey.TIME_STAMP));
+        log.info("获取到的appId={} ,token={} , sign={} , timeStamp={}", appId, token, sign, timeStamp);
+
+        if (!StringUtils.isNoneBlank(appId, token, sign)) {
+            throw new CommonBaseException(ResultCodeEnum.D3004, "appId、token、sign都不能为空");
+        }
+        if (null == timeStamp) {
+            throw new CommonBaseException(ResultCodeEnum.D3004, "缺失时间戳");
+        }
+        log.info("签名基础数据校验完成");
+    }
+
+    public static  String getObjectFromRequest(HttpServletRequest request){
+        if(null == request){
+            throw  new CommonBaseException(ResultCodeEnum.D101 , "请求入参缺失");
+        }
+        String requestBodyStr = "";
+        try {
+            InputStreamReader inputStreamReader = new InputStreamReader(request.getInputStream());
+            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+            requestBodyStr = IOUtils.toString(bufferedReader);
+        } catch (IOException e) {
+            log.error("读取http request的body出现异常:{}", e);
+            throw new CommonBaseException(ResultCodeEnum.D3008);
+        }
+        log.info("收到的请求体为:{}", requestBodyStr);
+        if (StringUtils.isBlank(requestBodyStr)) {
+            throw new CommonBaseException(ResultCodeEnum.D3004, "请求数据格式有误");
+        }
+
+        return requestBodyStr;
+    }
+
+
+    public static void checkDataModify(String requestBodyStr ,Long timeStamp ,
+                                 String sign , String appSecret){
+        //校验数据是否被篡改
+
+        Map<String , Object> requestDataMap = JSONObject.parseObject(requestBodyStr);
+        if(null == requestDataMap){
+            log.error("请求数据转换成map失败");
+            throw new CommonBaseException(ResultCodeEnum.D101);
+        }
+        String enCodeBodyStr = "";
+
+
+        Map<String , Object> sortMap = sortMapByKey(requestDataMap);
+        enCodeBodyStr = JSONObject.toJSONString(sortMap);
+
+        String unEnCodeSign = enCodeBodyStr + appSecret + timeStamp;
+
+        log.info("待加密的数据为:{}", unEnCodeSign);
+        String enCodeStr = SHAUtils.getSHA256(unEnCodeSign);
+        log.info("解析出来的签名:{},上送的签名:{}", enCodeStr, sign);
+        if (!StringUtils.equals(enCodeStr, sign)) {
+            throw new CommonBaseException(ResultCodeEnum.D3009);
+        }
+    }
+
+    /**
+     *  根据map的key进行字典升序排序
+     * @param map
+     * @return map
+     */
+    public static   Map<String, Object> sortMapByKey(Map<String, Object>map) {
+        Map<String, Object> treemap = new TreeMap<String, Object>(map);
+        List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(treemap.entrySet());
+        Collections.sort(list, new Comparator<Map.Entry<String, Object>>() {
+            @Override
+            public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
+                return StringUtils.compare(o1.getKey() , o2.getKey());
+            }
+        });
+        return treemap;
+    }
+
+    public static boolean isDataModifiedWithSHA256(String src, String target , String salt) {
+        if (!StringUtils.equals(SHAUtils.getSHA256(src + salt), SHAUtils.getSHA256(target + salt))) {
+            //数据有更新、修改
+            return true;
+
+        } else {
+            //数据没有修改
+            return false;
+
+        }
+    }
+}

+ 62 - 0
4dkankan-api-common/src/main/java/api/common/utils/Base64Converter.java

@@ -0,0 +1,62 @@
+package api.common.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Base64;
+
+/**
+ * @author abnerhou
+ * @date 2020/5/27 16:24
+ * @desciption
+ */
+public class Base64Converter {
+
+
+    final static Base64.Encoder encoder = Base64.getEncoder();
+    final static Base64.Decoder decoder = Base64.getDecoder();
+
+    /**
+     * 给字符串加密
+     * @param text
+     * @return
+     */
+    public static String encode(String text) {
+        byte[] textByte = new byte[0];
+        try {
+            textByte = text.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        String encodedText = encoder.encodeToString(textByte);
+        return encodedText;
+    }
+
+    /**
+     * 将加密后的字符串进行解密
+     * @param encodedText
+     * @return
+     */
+    public static String decode(String encodedText) {
+        String text = null;
+        try {
+            text = new String(decoder.decode(encodedText), "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return text;
+    }
+
+    /**
+     * 根据逻辑截取加密后的密码
+     * @param text
+     * @return
+     */
+    public static String subText(String text){
+        //去掉前8位字符串
+        text = text.substring(8);
+        //去掉后8位字符串
+        text = text.substring(0, text.length() - 8);
+        //最后两个字符串换到前面,并且去掉剩下的后8位字符串
+        String result = text.substring(text.length() - 2) + text.substring(0, text.length() - 10);
+        return result;
+    }
+}

+ 115 - 0
4dkankan-api-common/src/main/java/api/common/utils/DataUtils.java

@@ -0,0 +1,115 @@
+package api.common.utils;
+
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author abnerhou
+ * @date 2020/4/23 17:35
+ * @desciption
+ */
+@Component
+public class DataUtils {
+
+    public static BigDecimal getBigDecimalObj(Object data) {
+
+        if (null == data) {
+            return null;
+        } else if (data instanceof String) {
+            String dataStr = (String) data;
+            if (!StringUtils.isEmpty(dataStr.trim())) {
+                return new BigDecimal(dataStr.trim());
+            }
+        } else if (data instanceof Long) {
+            Long dataLong = (Long) data;
+            return BigDecimal.valueOf(dataLong);
+        } else if (data instanceof Integer) {
+            Integer dataInt = (Integer) data;
+            return BigDecimal.valueOf(dataInt);
+
+        } else if (data instanceof Double) {
+            Double dataDouble = (Double) data;
+            return BigDecimal.valueOf(dataDouble);
+        }
+
+        return null;
+
+    }
+
+    public static Integer getInteger(Object object) {
+        if (null == object) {
+            return new Integer(0);
+        }
+        if (object instanceof String) {
+            String ojStr = (String) object;
+            if (StringUtils.isEmpty(ojStr)) {
+                //TODO:在斟酌这里的处理方式
+                return new Integer(0);
+            } else {
+                return new Integer(Integer.parseInt(ojStr.trim()));
+            }
+        } else if (object instanceof Integer) {
+            return (Integer) object;
+        } else if (object instanceof Long) {
+            return (Integer) object;
+        } else if (object instanceof Double) {
+            return (Integer) object;
+        } else {
+            return new Integer(0);
+        }
+    }
+
+    public static Long getLongReturnNullIfNotExit(Object num){
+        if(null == num){
+            return null;
+        }else if(num instanceof String){
+            if(!StringUtils.isEmpty((String) num)){
+                String numStr = (String) num;
+                return Long.parseLong(numStr.trim());
+            }
+        }else if(num instanceof Integer){
+            return (Long) num;
+        }else if(num instanceof  Long){
+            return (Long) num;
+        }
+        return null;
+    }
+
+    public static Integer getIntegerWithDefault(Object object, boolean withDefault) {
+        if (null == object) {
+
+            return withDefault ? new Integer(0) : null;
+        }
+        if (object instanceof String) {
+            String ojStr = (String) object;
+            if (StringUtils.isEmpty(ojStr)) {
+
+                return withDefault ? new Integer(0) : null;
+            } else {
+                return new Integer(Integer.parseInt(ojStr.trim()));
+            }
+        } else if (object instanceof Integer) {
+            return (Integer) object;
+        } else if (object instanceof Long) {
+            return (Integer) object;
+        } else if (object instanceof Double) {
+            return (Integer) object;
+        } else {
+            return withDefault ? new Integer(0) : null;
+        }
+    }
+
+    public static Map<String, Object> assembleResult(long totalNum, long totalPageNum, long currPageNum, Object list) {
+        Map<String, Object> resultMap = new HashMap<>();
+        resultMap.put("totalNum", totalNum);
+        resultMap.put("totalPageNum", totalPageNum);
+        resultMap.put("curPage", currPageNum);
+        resultMap.put("list", list);
+        return resultMap;
+    }
+
+}

+ 839 - 0
4dkankan-api-common/src/main/java/api/common/utils/FileUtils.java

@@ -0,0 +1,839 @@
+package api.common.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipFile;
+import org.apache.tools.zip.ZipOutputStream;
+import org.springframework.util.ResourceUtils;
+import org.springframework.web.multipart.MultipartFile;
+import sun.misc.BASE64Decoder;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.*;
+
+@Slf4j
+public class FileUtils {
+
+    //文件路径+名称
+    private static String fileNameTemp;
+
+    public static void uploadImg(String path, String base64Data)
+            throws Exception {
+        byte[] bt = null;
+        try {
+            BASE64Decoder decoder = new BASE64Decoder();
+            if (base64Data.startsWith("data:image/png;base64,")) {
+                bt = decoder.decodeBuffer(base64Data.replace("data:image/png;base64,", ""));
+            } else if (base64Data.startsWith("data:image/jpeg;base64,")) {
+                bt = decoder.decodeBuffer(base64Data.replace("data:image/jpeg;base64,", ""));
+            } else if (base64Data.startsWith("data:image/bmp;base64,")) {
+                bt = decoder.decodeBuffer(base64Data.replace("data:image/bmp;base64,", ""));
+            } else {
+                return;
+            }
+            writeBinary(bt, path);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static void writeBinary(byte[] buf, String filePath) throws Exception {
+        File fout = new File(filePath);
+        if (!fout.getParentFile().exists()) {
+            fout.getParentFile().mkdirs();
+        }
+        FileOutputStream fos = new FileOutputStream(fout);
+        ByteArrayInputStream stream = new ByteArrayInputStream(buf);
+        BufferedOutputStream bos = new BufferedOutputStream(fos);//设置输出路径
+        BufferedInputStream bis = new BufferedInputStream(stream);
+        int b = -1;
+        while ((b = bis.read()) != -1) {
+            bos.write(b);
+        }
+        bis.close();
+        bos.close();
+    }
+
+    public static boolean createDir(String destDirName) {
+        File dir = new File(destDirName);
+        if (dir.exists()) {
+            System.out.println("创建目录" + destDirName + "失败,目标目录已经存在");
+            return false;
+        }
+        if (!destDirName.endsWith(File.separator)) {
+            destDirName = destDirName + File.separator;
+        }
+        //创建目录  
+        if (dir.mkdirs()) {
+            System.out.println("创建目录" + destDirName + "成功!");
+            return true;
+        } else {
+            System.out.println("创建目录" + destDirName + "失败!");
+            return false;
+        }
+    }
+
+
+    /**
+     * 创建文件
+     *
+     * @param fileName    文件名称
+     * @param fileContent 文件内容
+     * @return 是否创建成功,成功则返回true
+     */
+    public static boolean createFile(String path, String fileName, String fileContent) {
+        Boolean bool = false;
+        fileNameTemp = path + fileName + ".json";//文件路径+名称+文件类型
+        File file = new File(fileNameTemp);
+        try {
+            File folder = new File(path);
+            if (!folder.exists()) {
+                folder.mkdirs();
+            }
+            //如果文件不存在,则创建新的文件
+            if (!file.exists()) {
+                file.createNewFile();
+                bool = true;
+                System.out.println("success create file,the file is " + fileNameTemp);
+                //创建文件成功后,写入内容到文件里
+                writeFileContent(fileNameTemp, fileContent);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return bool;
+    }
+
+    /**
+     * 向文件中写入内容
+     *
+     * @param filePath 文件路径与名称
+     * @param newstr   写入的内容
+     * @return
+     * @throws IOException
+     */
+    public static boolean writeFileContent(String filePath, String newstr) throws IOException {
+        Boolean bool = false;
+        String filein = newstr + "\r\n";//新写入的行,换行
+        String temp = "";
+
+        FileInputStream fis = null;
+        InputStreamReader isr = null;
+        BufferedReader br = null;
+        FileOutputStream fos = null;
+        PrintWriter pw = null;
+        try {
+            File file = new File(filePath);//文件路径(包括文件名称)
+            //将文件读入输入流
+            fis = new FileInputStream(file);
+            isr = new InputStreamReader(fis);
+            br = new BufferedReader(isr);
+            StringBuffer buffer = new StringBuffer();
+
+            //文件原有内容
+            for (int i = 0; (temp = br.readLine()) != null; i++) {
+                buffer.append(temp);
+                // 行与行之间的分隔符 相当于“\n”
+                buffer = buffer.append(System.getProperty("line.separator"));
+            }
+            buffer.append(filein);
+
+            fos = new FileOutputStream(file);
+            pw = new PrintWriter(fos);
+            pw.write(buffer.toString().toCharArray());
+            pw.flush();
+            bool = true;
+        } catch (Exception e) {
+            // TODO: handle exception
+            e.printStackTrace();
+        } finally {
+            //不要忘记关闭
+            if (pw != null) {
+                pw.close();
+            }
+            if (fos != null) {
+                fos.close();
+            }
+            if (br != null) {
+                br.close();
+            }
+            if (isr != null) {
+                isr.close();
+            }
+            if (fis != null) {
+                fis.close();
+            }
+        }
+        return bool;
+    }
+
+
+    public static String parseFile(MultipartFile multipartFile , String fileBackupPath) {
+        File directory = new File(fileBackupPath);
+        if (!directory.exists()) {
+            directory.mkdirs();
+        }
+        String fileName = fileBackupPath.concat(multipartFile.getOriginalFilename());
+        log.info("上传的文件名:{}", fileName);
+        File file = new File(fileName);
+        if(file.exists()){
+            deleteFile(fileName);
+            file = new File(fileName);
+        }
+        try {
+            InputStream is = multipartFile.getInputStream();
+            FileOutputStream os = new FileOutputStream(file);
+            byte[] b = new byte[2048];
+            int length;
+            while ((length = is.read(b)) > 0) {
+                os.write(b, 0, length);
+            }
+            is.close();
+            os.close();
+        } catch (IOException e) {
+            log.info("文件存储本地出现异常:{}", e);
+        }
+        return fileName;
+    }
+
+
+
+
+
+    /**
+     * 删除单个文件
+     *
+     * @param fileName 要删除的文件的文件名
+     * @return 单个文件删除成功返回true,否则返回false
+     */
+    public static boolean deleteFile(String fileName) {
+        File file = new File(fileName);
+        if (file.exists() && file.isFile()) {
+            if (file.delete()) {
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * 根据路径删除指定的目录,无论存在与否
+     *
+     * @param sPath 要删除的目录path
+     * @return 删除成功返回 true,否则返回 false。
+     */
+    public static boolean deleteFolder(String sPath) {
+        boolean flag = false;
+        File file = new File(sPath);
+        // 判断目录或文件是否存在
+        if (!file.exists()) {  // 不存在返回 false
+            return flag;
+        } else {
+            // 判断是否为文件
+            if (file.isFile()) {  // 为文件时调用删除文件方法
+                return deleteFile(sPath);
+            } else {  // 为目录时调用删除目录方法
+                return deleteDirectory(sPath);
+            }
+        }
+    }
+
+    /**
+     * 删除目录以及目录下的文件
+     *
+     * @param sPath 被删除目录的路径
+     * @return 目录删除成功返回true,否则返回false
+     */
+    public static boolean deleteDirectory(String sPath) {
+        //如果sPath不以文件分隔符结尾,自动添加文件分隔符
+        if (!sPath.endsWith(File.separator)) {
+            sPath = sPath + File.separator;
+        }
+        File dirFile = new File(sPath);
+        //如果dir对应的文件不存在,或者不是一个目录,则退出
+        if (!dirFile.exists() || !dirFile.isDirectory()) {
+            return false;
+        }
+        boolean flag = true;
+        //删除文件夹下的所有文件(包括子目录)
+        File[] files = dirFile.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            //删除子文件
+            if (files[i].isFile()) {
+                flag = deleteFile(files[i].getAbsolutePath());
+                if (!flag) {
+                    break;
+                }
+            } //删除子目录
+            else {
+                flag = deleteDirectory(files[i].getAbsolutePath());
+                if (!flag) {
+                    break;
+                }
+            }
+        }
+        if (!flag) {
+            return false;
+        }
+        //删除当前目录
+        if (dirFile.delete()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    //按行读文件
+    public static String readFile(String path) throws Exception {
+        File f = new File(path);
+        if (!f.exists()) {
+            return null;
+        }
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
+        BufferedInputStream in = null;
+        try {
+            in = new BufferedInputStream(new FileInputStream(f));
+            int buf_size = 1024;
+            byte[] buffer = new byte[buf_size];
+            int len = 0;
+            while (-1 != (len = in.read(buffer, 0, buf_size))) {
+                bos.write(buffer, 0, len);
+            }
+            return bos.toString();
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw e;
+        } finally {
+            try {
+                in.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            bos.close();
+        }
+    }
+
+    public static boolean copyFile(String srcFileName, String destFileName, boolean overlay) {
+        File srcFile = new File(srcFileName);
+        // 判断源文件是否存在
+        if (!srcFile.exists()) {
+            return false;
+        } else if (!srcFile.isFile()) {
+            return false;
+        }
+        // 判断目标文件是否存在
+        File destFile = new File(destFileName);
+        if (destFile.exists()) {
+            // 如果目标文件存在并允许覆盖
+            if (overlay) {
+                // 删除已经存在的目标文件,无论目标文件是目录还是单个文件
+                new File(destFileName).delete();
+            }
+        } else {
+            // 如果目标文件所在目录不存在,则创建目录
+            if (!destFile.getParentFile().exists()) {
+                // 目标文件所在目录不存在
+                if (!destFile.getParentFile().mkdirs()) {
+                    // 复制文件失败:创建目标文件所在目录失败
+                    return false;
+                }
+            }
+        }
+        // 复制文件
+        int byteread = 0; // 读取的字节数
+        InputStream in = null;
+        OutputStream out = null;
+        try {
+            in = new FileInputStream(srcFile);
+            out = new FileOutputStream(destFile);
+            byte[] buffer = new byte[1024];
+
+            while ((byteread = in.read(buffer)) != -1) {
+                out.write(buffer, 0, byteread);
+            }
+            return true;
+        } catch (IOException e) {
+            return false;
+        } finally {
+            try {
+                if (out != null) {
+                    out.close();
+                }
+                if (in != null) {
+                    in.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * 从网络Url中下载文件
+     *
+     * @param urlStr
+     * @param fileName
+     * @param savePath
+     * @return
+     * @throws IOException
+     */
+    public static boolean downLoadFromUrl(String urlStr, String fileName, String savePath) {
+        FileOutputStream fos = null;
+        InputStream inputStream = null;
+        try {
+            URL url = new URL(urlStr);
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            // 设置超时间为3秒
+            conn.setConnectTimeout(3 * 1000);
+            // 防止屏蔽程序抓取而返回403错误
+            conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+
+            // 得到输入流
+            inputStream = conn.getInputStream();
+            // 获取自己数组
+            byte[] getData = readInputStream(inputStream);
+
+            // 文件保存位置
+            File saveDir = new File(savePath);
+            if (!saveDir.exists()) {
+                saveDir.mkdirs();
+            }
+            String filePath = saveDir + File.separator + fileName;
+            String filePathFolder = filePath.substring(0, filePath.lastIndexOf("/") + 1);
+            createDir(filePathFolder);
+
+            File file = new File(filePath);
+            fos = new FileOutputStream(file);
+            fos.write(getData);
+            if (fos != null) {
+                fos.close();
+            }
+            if (inputStream != null) {
+                inputStream.close();
+            }
+            System.out.println("info:" + url + " download success");
+        } catch (FileNotFoundException e) {
+            return false;
+        } catch (IOException e) {
+            return false;
+        } finally {
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 从输入流中获取字节数组
+     *
+     * @param inputStream
+     * @return
+     * @throws IOException
+     */
+    private static 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();
+    }
+
+
+    public static void writeFile(String filePath, String str) throws IOException {
+        File fout = new File(filePath);
+        if (!fout.getParentFile().exists()) {
+            fout.getParentFile().mkdirs();
+        }
+        if (!fout.exists()) {
+            fout.createNewFile();
+        }
+        FileOutputStream fos = new FileOutputStream(fout);
+        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
+        bw.write(str);
+        bw.close();
+    }
+
+    /**
+     * 将byte数组写入文件
+     *
+     * @param path
+     * @param fileName
+     * @param content
+     * @throws IOException
+     */
+    public static void writeFile(String path, String fileName, byte[] content)
+            throws IOException {
+        try {
+            File f = new File(path);
+            if (!f.exists()) {
+                f.mkdirs();
+            }
+            FileOutputStream fos = new FileOutputStream(path + fileName);
+            fos.write(content);
+            fos.close();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 向json文件写入参数,重复的覆盖,多的新增
+     *
+     * @return
+     */
+    public static void writeJsonFile(String path, Map<String, Object> map) throws Exception {
+        String str = readFile(path);
+        JSONObject json = new JSONObject();
+        if (str != null) {
+            json = JSONObject.parseObject(str);
+        } else {
+            File file = new File(path);
+            if (!file.getParentFile().exists()) {
+                file.getParentFile().mkdirs();
+            }
+            if (!file.exists()) {
+                file.createNewFile();
+            }
+        }
+        Iterator entries = map.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry entry = (Map.Entry) entries.next();
+            json.put(String.valueOf(entry.getKey()), entry.getValue());
+        }
+
+        writeFile(path, json.toString());
+    }
+
+    public static void decompress(String srcPath, String dest) throws Exception {
+
+        File file = new File(srcPath);
+
+        if (!file.exists()) {
+
+            throw new RuntimeException(srcPath + "所指文件不存在");
+
+        }
+
+        ZipFile zf = new ZipFile(file);
+
+        Enumeration entries = zf.getEntries();
+
+        ZipEntry entry = null;
+
+        while (entries.hasMoreElements()) {
+
+            entry = (ZipEntry) entries.nextElement();
+
+            log.info("解压" + entry.getName());
+
+            if (entry.isDirectory()) {
+
+                String dirPath = dest + File.separator + entry.getName();
+
+                File dir = new File(dirPath);
+
+                dir.mkdirs();
+
+            } else {
+
+                // 表示文件
+
+                File f = new File(dest + File.separator + entry.getName());
+
+                if (!f.exists()) {
+
+                    //String dirs = FileUtils.getParentPath(f);
+                    String dirs = f.getParent();
+
+                    File parentDir = new File(dirs);
+
+                    parentDir.mkdirs();
+
+
+                }
+
+                f.createNewFile();
+
+                // 将压缩文件内容写入到这个文件中
+
+                InputStream is = zf.getInputStream(entry);
+
+                FileOutputStream fos = new FileOutputStream(f);
+
+
+                int count;
+
+                byte[] buf = new byte[8192];
+
+                while ((count = is.read(buf)) != -1) {
+
+                    fos.write(buf, 0, count);
+
+                }
+
+                is.close();
+
+                fos.close();
+
+            }
+
+        }
+
+    }
+
+    public static void zipFile(String zipFileName, String inputFileName)
+            throws Exception {
+        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFileName));
+        out.setEncoding("UTF-8");
+        File inputFile = new File(inputFileName);
+        zipIt(out, inputFile, "", true);
+        out.close();
+    }
+
+    /*
+     * 能支持中文的压缩 参数base 开始为"" first 开始为true
+     */
+    public static void zipIt(ZipOutputStream out, File f,
+                             String base, boolean first) throws Exception {
+        if (f.isDirectory()) {
+            File[] fl = f.listFiles();
+            if (first) {
+                first = false;
+            } else {
+                base = base + "/";
+            }
+            for (int i = 0; i < fl.length; i++) {
+                zipIt(out, fl[i], base + fl[i].getName(), first);
+            }
+        } else {
+            if (first) {
+                base = f.getName();
+            }
+            out.putNextEntry(new org.apache.tools.zip.ZipEntry(base));
+            FileInputStream in = new FileInputStream(f);
+            int b;
+            while ((b = in.read()) != -1) {
+                out.write(b);
+            }
+            in.close();
+        }
+    }
+
+    //删除文件夹
+    public static void delFolder(String folderPath) {
+        try {
+            delAllFile(folderPath); //删除完里面所有内容
+            String filePath = folderPath;
+            filePath = filePath.toString();
+            File myFilePath = new File(filePath);
+            myFilePath.delete(); //删除空文件夹
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    //删除指定文件夹下的所有文件
+    public static boolean delAllFile(String path) {
+        boolean flag = false;
+        File file = new File(path);
+        if (!file.exists()) {
+            return flag;
+        }
+        if (!file.isDirectory()) {
+            return flag;
+        }
+        String[] tempList = file.list();
+        File temp = null;
+        if (tempList != null) {
+            for (int i = 0; i < tempList.length; i++) {
+                if (path.endsWith(File.separator)) {
+                    temp = new File(path + tempList[i]);
+                } else {
+                    temp = new File(path + File.separator + tempList[i]);
+                }
+                if (temp.isFile()) {
+                    temp.delete();
+                }
+                if (temp.isDirectory()) {
+                    delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
+                    delFolder(path + "/" + tempList[i]);//再删除空文件夹
+                    flag = true;
+                }
+            }
+        }
+
+        //再删除当前空文件夹
+        file.delete();
+        return flag;
+    }
+
+    public static List<String> readfileNamesForDirectory(String path, String except) {
+        try {
+            File file = new File(path);
+            if (file.isDirectory()) {
+                String[] fileNames = file.list();
+                List<String> list = new ArrayList<String>();
+                if (fileNames != null) {
+                    for (int i = 0; i < fileNames.length; ++i) {
+                        if (fileNames[i].toLowerCase().endsWith(except)) {
+                            list.add(fileNames[i]);
+                        }
+                    }
+                }
+
+                return list;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    //递归获取文件中所有文件的路径
+    public static List<String> readfilePath(String path, List<String> urlList) {
+        try {
+            File file = new File(path);
+            if (file != null && file.isDirectory()) {
+                File[] files = file.listFiles();
+
+                if (files != null) {
+                    for (int i = 0; i < files.length; ++i) {
+                        if (files[i].isDirectory()) {
+                            readfilePath(files[i].getAbsolutePath(), urlList);
+                        } else {
+                            urlList.add(files[i].getAbsolutePath());
+                        }
+                    }
+                }
+                return urlList;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return urlList;
+    }
+
+    public static void saveImageToDisk(String accessToken, String mediaId, String picName, String picPath, InputStream inputStream)
+            throws Exception {
+        byte[] data = new byte[10240];
+        int len = 0;
+        FileOutputStream fileOutputStream = null;
+        try {
+            fileOutputStream = new FileOutputStream(picPath + picName + ".amr");
+            while ((len = inputStream.read(data)) != -1) {
+                fileOutputStream.write(data, 0, len);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (fileOutputStream != null) {
+                try {
+                    fileOutputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * @param content base64内容
+     * @param path    输出文件路径,需要后缀名
+     * @return
+     */
+    public static boolean base64ToFileWriter(String content, String path) {
+        if (content == null) {
+            return false;
+        }
+        BASE64Decoder decoder = new BASE64Decoder();
+        try {
+            // decoder
+            byte[] b = decoder.decodeBuffer(content);
+            // processing data
+            for (int i = 0; i < b.length; ++i) {
+                if (b[i] < 0) {
+                    b[i] += 256;
+                }
+            }
+            OutputStream out = new FileOutputStream(path);
+            out.write(b);
+            out.flush();
+            out.close();
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
+     * 获取类路径(classes路径)
+     */
+    public static String getResource() {
+        String path = "";
+        try {
+            path = ResourceUtils.getURL("classpath:").getPath();
+            path = URLDecoder.decode(path, "utf-8");
+        } catch (Exception e) {
+        }
+        return path;
+    }
+
+    /**
+     * 判断文件大小处于限制内
+     *
+     * @param fileLen  文件长度
+     * @param fileSize 限制大小
+     * @param fileUnit 限制的单位(B,K,M,G)
+     * @return
+     */
+    public static boolean checkFileSizeIsLimit(Long fileLen, double fileSize, String fileUnit) {
+//        long len = file.length();
+        double fileSizeCom = 0;
+        if ("B".equals(fileUnit.toUpperCase())) {
+            fileSizeCom = (double) fileLen;
+        } else if ("K".equals(fileUnit.toUpperCase())) {
+            fileSizeCom = (double) fileLen / 1024;
+        } else if ("M".equals(fileUnit.toUpperCase())) {
+            fileSizeCom = (double) fileLen / (1024 * 1024);
+        } else if ("G".equals(fileUnit.toUpperCase())) {
+            fileSizeCom = (double) fileLen / (1024 * 1024 * 1024);
+        }
+        if (fileSizeCom > fileSize) {
+            return false;
+        }
+        return true;
+
+    }
+
+}

+ 183 - 0
4dkankan-api-common/src/main/java/api/common/utils/HttpClientUtil.java

@@ -0,0 +1,183 @@
+package api.common.utils;
+
+import lombok.extern.log4j.Log4j2;
+import org.apache.http.NameValuePair;
+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.utils.URIBuilder;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * @author abnerhou
+ * @date 2020/5/11 17:48
+ * @desciption
+ */
+@Log4j2
+public class HttpClientUtil {
+
+    public static String doGet(String url, Map<String, String> param) {
+
+        // 创建Httpclient对象
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+
+        String resultString = "";
+        CloseableHttpResponse response = null;
+        try {
+            // 创建uri
+            URIBuilder builder = new URIBuilder(url);
+            if (param != null) {
+                for (String key : param.keySet()) {
+                    builder.addParameter(key, param.get(key));
+                }
+            }
+            URI uri = builder.build();
+
+            // 创建http GET请求
+            HttpGet httpGet = new HttpGet(uri);
+
+            // 执行请求
+            response = httpclient.execute(httpGet);
+            // 判断返回状态是否为200
+            if (response.getStatusLine().getStatusCode() == 200) {
+                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
+            }
+        } catch (Exception e) {
+            log.error("http调用执行get出错:{}" , e);
+        } finally {
+            try {
+                if (response != null) {
+                    response.close();
+                }
+                httpclient.close();
+            } catch (IOException e) {
+               log.error("http调用执行get关闭资源出错:{}" , e);
+            }
+        }
+        return resultString;
+    }
+
+    public static String doGet(String url) {
+        return doGet(url, null);
+    }
+
+    public static String doPost(String url, Map<String, Object> param) {
+        // 创建Httpclient对象
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpResponse response = null;
+        String resultString = "";
+        try {
+            // 创建Http Post请求
+            HttpPost httpPost = new HttpPost(url);
+//            httpPost.setHeader("contentType" , "application/x-www-form-urlencoded;charset=UTF-8");
+            // 创建参数列表
+            if (param != null) {
+                List<NameValuePair> paramList = new ArrayList<>();
+                for (String key : param.keySet()) {
+                    paramList.add(new BasicNameValuePair(key, param.get(key).toString()));
+                }
+                // 模拟表单
+                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
+                httpPost.setEntity(entity);
+            }
+            // 执行http请求
+            response = httpClient.execute(httpPost);
+            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
+        } catch (Exception e) {
+            log.error("http执行post调用出错:{}" , e);
+        } finally {
+            try {
+                if(null != response){
+                    response.close();
+                }
+            } catch (IOException e) {
+                log.error("http执行post调用关闭资源出错:{}" , e);
+            }
+        }
+
+        return resultString;
+    }
+
+    public static String doPost(String url) {
+        return doPost(url, null);
+    }
+
+    public static String doPostJson(String url, String json) {
+        // 创建Httpclient对象
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpResponse response = null;
+        String resultString = "";
+        try {
+            // 创建Http Post请求
+            HttpPost httpPost = new HttpPost(url);
+            // 创建请求内容
+            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
+            httpPost.setEntity(entity);
+            // 执行http请求
+            response = httpClient.execute(httpPost);
+            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
+        } catch (Exception e) {
+            log.error("http执行post调用出错:{}" , e);
+        } finally {
+            try {
+                if(null != response){
+                    response.close();
+                }
+            } catch (IOException e) {
+                log.error("http执行post调用关闭资源出错:{}" , e);
+            }
+        }
+
+        return resultString;
+    }
+
+    public static String doPostJsonWithHeader(String url, String json ,Map<String, Object> headers) {
+        // 创建Httpclient对象
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        CloseableHttpResponse response = null;
+        String resultString = "";
+        try {
+            // 创建Http Post请求
+            HttpPost httpPost = new HttpPost(url);
+            // 创建请求内容
+            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
+            httpPost.setEntity(entity);
+
+            if(!CollectionUtils.isEmpty(headers)){
+                for (Map.Entry<String,Object> entry : headers.entrySet()){
+                    httpPost.addHeader(entry.getKey() , (String) entry.getValue());
+                }
+            }
+            // 执行http请求
+            response = httpClient.execute(httpPost);
+            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
+        } catch (Exception e) {
+            log.error("http执行post调用出错:{}" , e);
+        } finally {
+            try {
+                if(null != response){
+                    response.close();
+                }
+            } catch (IOException e) {
+                log.error("http执行post调用关闭资源出错:{}" , e);
+            }
+        }
+
+        return resultString;
+    }
+
+}

+ 425 - 0
4dkankan-api-common/src/main/java/api/common/utils/JedisUtil.java

@@ -0,0 +1,425 @@
+package api.common.utils;
+
+import lombok.extern.log4j.Log4j2;
+import redis.clients.jedis.*;
+
+import java.io.*;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+
+/**
+ * Redis client base on jedis 根据继承类的不同,
+ * jedis实例方式不用:JedisSimpleFactry/JedisPoolFactry/ShardedJedisPoolFactry
+ * <p>
+ * 2015-7-10 18:34:07
+ * <p>
+ * # for redis (sharded.jedis.address=host01:port,host02:port)
+ * sharded.jedis.address=127.0.0.1:6379,127.0.0.1:6379,127.0.0.1:6379
+ */
+@Log4j2
+public class JedisUtil {
+    
+    private static final int DEFAULT_EXPIRE_TIME = 7200; // 默认过期时间,单位/秒, 60*60*2=2H, 两小时
+    private static String address;
+    private static JedisPoolConfig config;
+
+    public static void init(String address, JedisPoolConfig config) {
+        JedisUtil.address = address;
+        JedisUtil.config = config;
+    }
+
+    // ------------------------ ShardedJedisPool ------------------------
+    /**
+     * 方式01: Redis单节点 + Jedis单例 : Redis单节点压力过重, Jedis单例存在并发瓶颈 》》不可用于线上
+     * new Jedis("127.0.0.1", 6379).get("cache_key");
+     * 方式02: Redis单节点 + JedisPool单节点连接池 》》 Redis单节点压力过重,负载和容灾比较差
+     * new JedisPool(new JedisPoolConfig(), "127.0.0.1", 6379, 10000).getResource().get("cache_key");
+     * 方式03: Redis集群(通过client端集群,一致性哈希方式实现) + Jedis多节点连接池 》》Redis集群,负载和容灾较好, ShardedJedisPool一致性哈希分片,读写均匀,动态扩充
+     * new ShardedJedisPool(new JedisPoolConfig(), new LinkedList<JedisShardInfo>());
+     */
+
+    private static ShardedJedisPool shardedJedisPool;
+    private static ReentrantLock INSTANCE_INIT_LOCL = new ReentrantLock(false);
+
+
+    private static final String LOCK_SUCCESS = "OK";
+    private static final String SET_IF_NOT_EXIST = "NX";
+    private static final String SET_WITH_EXPIRE_TIME = "PX";
+    private static final Long RELEASE_SUCCESS = 1L;
+
+    /**
+     * 获取ShardedJedis实例
+     *
+     * @return
+     */
+    private static ShardedJedis getInstance() {
+        if (shardedJedisPool == null) {
+            try {
+                if (INSTANCE_INIT_LOCL.tryLock(2, TimeUnit.SECONDS)) {
+                    try {
+                        if (shardedJedisPool == null) {
+                            // JedisShardInfo List
+                            List<JedisShardInfo> jedisShardInfos = new LinkedList<JedisShardInfo>();
+
+                            String[] addressArr = address.split(",");
+                            for (int i = 0; i < addressArr.length; i++) {
+                                String[] addressInfo = addressArr[i].split(":");
+                                String host = addressInfo[0];
+                                int port = Integer.valueOf(addressInfo[1]);
+                                JedisShardInfo jedisShardInfo = new JedisShardInfo(host, port, 10000);
+                                jedisShardInfos.add(jedisShardInfo);
+                            }
+                            shardedJedisPool = new ShardedJedisPool(config, jedisShardInfos);
+                            log.info(">>>>>>>>>>> xxl-sso, JedisUtil.ShardedJedisPool init success.");
+                        }
+
+                    } finally {
+                        INSTANCE_INIT_LOCL.unlock();
+                    }
+                }
+
+            } catch (InterruptedException e) {
+                log.error("系统异常:", e);
+            }
+        }
+
+        if (shardedJedisPool == null) {
+            throw new NullPointerException(">>>>>>>>>>> xxl-sso, JedisUtil.ShardedJedisPool is null.");
+        }
+
+        ShardedJedis shardedJedis = shardedJedisPool.getResource();
+        return shardedJedis;
+    }
+
+    // ------------------------ serialize and unserialize ------------------------
+
+    /**
+     * 将对象-->byte[] (由于jedis中不支持直接存储object所以转换成byte[]存入)
+     *
+     * @param object
+     * @return
+     */
+    private static byte[] serialize(Object object) {
+        ObjectOutputStream oos = null;
+        ByteArrayOutputStream baos = null;
+        try {
+            // 序列化
+            baos = new ByteArrayOutputStream();
+            oos = new ObjectOutputStream(baos);
+            oos.writeObject(object);
+            byte[] bytes = baos.toByteArray();
+            return bytes;
+        } catch (Exception e) {
+            log.error("{}", e);
+        } finally {
+            try {
+                oos.close();
+                baos.close();
+            } catch (IOException e) {
+                log.error("{}", e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 将byte[] -->Object
+     *
+     * @param bytes
+     * @return
+     */
+    private static Object unserialize(byte[] bytes) {
+        ByteArrayInputStream bais = null;
+        try {
+            // 反序列化
+            bais = new ByteArrayInputStream(bytes);
+            ObjectInputStream ois = new ObjectInputStream(bais);
+            return ois.readObject();
+        } catch (Exception e) {
+            log.error("{}", e);
+        } finally {
+            try {
+                bais.close();
+            } catch (IOException e) {
+                log.error("{}", e);
+            }
+        }
+        return null;
+    }
+
+    // ------------------------ jedis util ------------------------
+    /**
+     * 存储简单的字符串或者是Object 因为jedis没有分装直接存储Object的方法,所以在存储对象需斟酌下
+     * 存储对象的字段是不是非常多而且是不是每个字段都用到,如果是的话那建议直接存储对象,
+     * 否则建议用集合的方式存储,因为redis可以针对集合进行日常的操作很方便而且还可以节省空间
+     */
+
+    /**
+     * Set String
+     *
+     * @param key
+     * @param value
+     * @param seconds 存活时间,单位/秒
+     * @return
+     */
+    public static String setStringValue(String key, String value, int seconds) {
+        String result = null;
+        ShardedJedis client = getInstance();
+        try {
+            result = client.setex(key, seconds, value);
+        } catch (Exception e) {
+            log.info("{}", e);
+        } finally {
+            client.close();
+        }
+        return result;
+    }
+
+    /**
+     * Set String (默认存活时间, 2H)
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public static String setStringValue(String key, String value) {
+        return setStringValue(key, value, DEFAULT_EXPIRE_TIME);
+    }
+
+    /**
+     * Set Object
+     *
+     * @param key
+     * @param obj
+     * @param seconds 存活时间,单位/秒
+     */
+    public static String setObjectValue(String key, Object obj, int seconds) {
+        String result = null;
+        ShardedJedis client = getInstance();
+        try {
+            result = client.setex(key.getBytes(), seconds, serialize(obj));
+        } catch (Exception e) {
+            log.info("{}", e);
+        } finally {
+            client.close();
+        }
+        return result;
+    }
+
+    /**
+     * Set Object (默认存活时间, 2H)
+     *
+     * @param key
+     * @param obj
+     * @return
+     */
+    public static String setObjectValue(String key, Object obj) {
+        return setObjectValue(key, obj, DEFAULT_EXPIRE_TIME);
+    }
+
+    /**
+     * Get String
+     *
+     * @param key
+     * @return
+     */
+    public static String getStringValue(String key) {
+        String value = null;
+        ShardedJedis client = getInstance();
+        try {
+            value = client.get(key);
+        } catch (Exception e) {
+            log.info("", e);
+        } finally {
+            client.close();
+        }
+        return value;
+    }
+
+    /**
+     * Get Object
+     *
+     * @param key
+     * @return
+     */
+    public static Object getObjectValue(String key) {
+        Object obj = null;
+        ShardedJedis client = getInstance();
+        try {
+            byte[] bytes = client.get(key.getBytes());
+            if (bytes != null && bytes.length > 0) {
+                obj = unserialize(bytes);
+            }
+        } catch (Exception e) {
+            log.info("", e);
+        } finally {
+            client.close();
+        }
+        return obj;
+    }
+
+    /**
+     * Delete
+     *
+     * @param key
+     * @return Integer reply, specifically:
+     * an integer greater than 0 if one or more keys were removed
+     * 0 if none of the specified key existed
+     */
+    public static Long del(String key) {
+        Long result = null;
+        ShardedJedis client = getInstance();
+        try {
+            result = client.del(key);
+        } catch (Exception e) {
+            log.info("{}", e);
+        } finally {
+            client.close();
+        }
+        return result;
+    }
+
+    /**
+     * incrBy	value值加i
+     *
+     * @param key
+     * @param i
+     * @return new value after incr
+     */
+    public static Long incrBy(String key, int i) {
+        Long result = null;
+        ShardedJedis client = getInstance();
+        try {
+            result = client.incrBy(key, i);
+        } catch (Exception e) {
+            log.info("{}", e);
+        } finally {
+            client.close();
+        }
+        return result;
+    }
+
+    /**
+     * exists
+     *
+     * @param key
+     * @return Boolean reply, true if the key exists, otherwise false
+     */
+    public static boolean exists(String key) {
+        Boolean result = null;
+        ShardedJedis client = getInstance();
+        try {
+            result = client.exists(key);
+        } catch (Exception e) {
+            log.info("{}", e);
+        } finally {
+            client.close();
+        }
+        return result;
+    }
+
+    /**
+     * expire	重置存活时间
+     *
+     * @param key
+     * @param seconds 存活时间,单位/秒
+     * @return Integer reply, specifically:
+     * 1: the timeout was set.
+     * 0: the timeout was not set since the key already has an associated timeout (versions lt 2.1.3), or the key does not exist.
+     */
+    public static long expire(String key, int seconds) {
+        Long result = null;
+        ShardedJedis client = getInstance();
+        try {
+            result = client.expire(key, seconds);
+        } catch (Exception e) {
+            log.info("{}", e);
+        } finally {
+            client.close();
+        }
+        return result;
+    }
+
+    /**
+     * expireAt		设置存活截止时间
+     *
+     * @param key
+     * @param unixTime 存活截止时间戳
+     * @return
+     */
+    public static long expireAt(String key, long unixTime) {
+        Long result = null;
+        ShardedJedis client = getInstance();
+        try {
+            result = client.expireAt(key, unixTime);
+        } catch (Exception e) {
+            log.info("{}", e);
+        } finally {
+            client.close();
+        }
+        return result;
+    }
+
+    /**
+     * 尝试获取分布式锁
+     *
+     * @param lockKey    锁
+     * @param requestId  请求标识
+     * @param expireTime 超期时间
+     * @return 是否获取成功
+     */
+    public static boolean tryLock(String lockKey, String requestId, int expireTime) {
+        // nx ,px
+//        String result = getInstance().set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
+        String result = getInstance().set(lockKey, requestId);
+        if (LOCK_SUCCESS.equals(result)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 释放分布式锁
+     *
+     * @param lockKey   锁
+     * @param requestId 请求标识
+     * @return 是否释放成功
+     */
+    public static boolean releaseLock(String lockKey, String requestId) {
+        Jedis jedis = (Jedis) getInstance().getShard(lockKey);
+        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
+        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
+        if (RELEASE_SUCCESS.equals(result)) {
+            return true;
+        }
+        return false;
+    }
+
+    public static void main(String[] args) {
+		/*init("127.0.0.1:6379");
+		setObjectValue("key", "666");
+		System.out.println(getObjectValue("key"));*/
+
+
+        String key = "key";
+        String request = UUID.randomUUID().toString();
+        try {
+            boolean lock = tryLock(key, request, 10 * 1000);
+            if (!lock) {
+                System.out.println("locked error");
+                return;
+            }
+            //do something
+        } finally {
+            releaseLock(key, request);
+        }
+
+
+    }
+
+}

+ 73 - 0
4dkankan-api-common/src/main/java/api/common/utils/JsonUtils.java

@@ -0,0 +1,73 @@
+package api.common.utils;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.List;
+
+/**
+ * @author abnerhou
+ * @date 2020/5/11 17:37
+ * @desciption
+ */
+public class JsonUtils {
+
+    // 定义jackson对象
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    /**
+     * 将对象转换成json字符串。
+     * <p>Title: pojoToJson</p>
+     * <p>Description: </p>
+     * @param data
+     * @return
+     */
+    public static String objectToJson(Object data) {
+        try {
+            String string = MAPPER.writeValueAsString(data);
+            return string;
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将json结果集转化为对象
+     *
+     * @param jsonData json数据
+     * @param beanType 对象中的object类型
+     * @return
+     */
+    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
+        try {
+            T t = MAPPER.readValue(jsonData, beanType);
+            return t;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将json数据转换成pojo对象list
+     * <p>Title: jsonToList</p>
+     * <p>Description: </p>
+     * @param jsonData
+     * @param beanType
+     * @return
+     */
+    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
+        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
+        try {
+            List<T> list = MAPPER.readValue(jsonData, javaType);
+            return list;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+}

+ 229 - 0
4dkankan-api-common/src/main/java/api/common/utils/OssMultipartUpload.java

@@ -0,0 +1,229 @@
+package api.common.utils;
+
+import com.aliyun.oss.*;
+import com.aliyun.oss.model.*;
+import lombok.extern.log4j.Log4j2;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author abnerhou
+ * @date 2020/5/28 9:02
+ * @desciption
+ */
+
+@Log4j2
+public class OssMultipartUpload {
+    private static String endpoint = "*** Provide OSS endpoint ***";
+    private static String accessKeyId = "*** Provide your AccessKeyId ***";
+    private static String accessKeySecret = "*** Provide your AccessKeySecret ***";
+
+    private static OSS client = null;
+
+    private static String bucketName = "*** Provide bucket name ***";
+    private static String key = "*** Provide key ***";
+    private static String localFilePath = "*** Provide local file path ***";
+
+    private static ExecutorService executorService = Executors.newFixedThreadPool(5);
+    private static List<PartETag> partETags = Collections.synchronizedList(new ArrayList<PartETag>());
+
+    public static void doUpload(File sampleFile) throws IOException {
+
+        if(null == sampleFile || !sampleFile.exists()){
+            log.error("文件为空或者不存在");
+            return;
+        }
+        /*
+         * Constructs a client instance with your account for accessing OSS
+         */
+        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
+        conf.setIdleConnectionTime(1000);
+        client = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, conf);
+
+        try {
+            /*
+             * Claim a upload id firstly
+             */
+            String uploadId = claimUploadId();
+            System.out.println("Claiming a new upload id " + uploadId + "\n");
+
+            /*
+             * Calculate how many parts to be divided
+             */
+            final long partSize = 5 * 1024 * 1024L;   // 5MB
+            long fileLength = sampleFile.length();
+            int partCount = (int) (fileLength / partSize);
+            if (fileLength % partSize != 0) {
+                partCount++;
+            }
+            if (partCount > 10000) {
+                throw new RuntimeException("Total parts count should not exceed 10000");
+            } else {
+                System.out.println("Total parts count " + partCount + "\n");
+            }
+
+            /*
+             * Upload multiparts to your bucket
+             */
+            System.out.println("Begin to upload multiparts to OSS from a file\n");
+            for (int i = 0; i < partCount; i++) {
+                long startPos = i * partSize;
+                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
+                executorService.execute(new PartUploader(sampleFile, startPos, curPartSize, i + 1, uploadId));
+            }
+
+            /*
+             * Waiting for all parts finished
+             */
+            executorService.shutdown();
+            while (!executorService.isTerminated()) {
+                try {
+                    executorService.awaitTermination(5, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+
+            /*
+             * Verify whether all parts are finished
+             */
+            if (partETags.size() != partCount) {
+                throw new IllegalStateException("Upload multiparts fail due to some parts are not finished yet");
+            } else {
+                System.out.println("Succeed to complete multiparts into an object named " + key + "\n");
+            }
+
+            /*
+             * View all parts uploaded recently
+             */
+            listAllParts(uploadId);
+
+            /*
+             * Complete to upload multiparts
+             */
+            completeMultipartUpload(uploadId);
+
+            /*
+             * Fetch the object that newly created at the step below.
+             */
+         /*   System.out.println("Fetching an object");
+            client.getObject(new GetObjectRequest(bucketName, key), new File(localFilePath));*/
+
+        } catch (OSSException oe) {
+            System.out.println("Caught an OSSException, which means your request made it to OSS, "
+                    + "but was rejected with an error response for some reason.");
+            System.out.println("Error Message: " + oe.getErrorMessage());
+            System.out.println("Error Code:       " + oe.getErrorCode());
+            System.out.println("Request ID:      " + oe.getRequestId());
+            System.out.println("Host ID:           " + oe.getHostId());
+        } catch (ClientException ce) {
+            System.out.println("Caught an ClientException, which means the client encountered "
+                    + "a serious internal problem while trying to communicate with OSS, "
+                    + "such as not being able to access the network.");
+            System.out.println("Error Message: " + ce.getMessage());
+        } finally {
+            /*
+             * Do not forget to shut down the client finally to release all allocated resources.
+             */
+            if (client != null) {
+                client.shutdown();
+            }
+        }
+    }
+
+    private static class PartUploader implements Runnable {
+
+        private File localFile;
+        private long startPos;
+
+        private long partSize;
+        private int partNumber;
+        private String uploadId;
+
+        public PartUploader(File localFile, long startPos, long partSize, int partNumber, String uploadId) {
+            this.localFile = localFile;
+            this.startPos = startPos;
+            this.partSize = partSize;
+            this.partNumber = partNumber;
+            this.uploadId = uploadId;
+        }
+
+        @Override
+        public void run() {
+            InputStream instream = null;
+            try {
+                instream = new FileInputStream(this.localFile);
+                instream.skip(this.startPos);
+
+                UploadPartRequest uploadPartRequest = new UploadPartRequest();
+                uploadPartRequest.setBucketName(bucketName);
+                uploadPartRequest.setKey(key);
+                uploadPartRequest.setUploadId(this.uploadId);
+                uploadPartRequest.setInputStream(instream);
+                uploadPartRequest.setPartSize(this.partSize);
+                uploadPartRequest.setPartNumber(this.partNumber);
+
+                UploadPartResult uploadPartResult = client.uploadPart(uploadPartRequest);
+                System.out.println("Part#" + this.partNumber + " done\n");
+                synchronized (partETags) {
+                    partETags.add(uploadPartResult.getPartETag());
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            } finally {
+                if (instream != null) {
+                    try {
+                        instream.close();
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+    }
+
+    private static String claimUploadId() {
+        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, key);
+        InitiateMultipartUploadResult result = client.initiateMultipartUpload(request);
+        return result.getUploadId();
+    }
+
+    private static void completeMultipartUpload(String uploadId) {
+        // Make part numbers in ascending order
+        Collections.sort(partETags, new Comparator<PartETag>() {
+
+            @Override
+            public int compare(PartETag p1, PartETag p2) {
+                return p1.getPartNumber() - p2.getPartNumber();
+            }
+        });
+
+        System.out.println("Completing to upload multiparts\n");
+        CompleteMultipartUploadRequest completeMultipartUploadRequest =
+                new CompleteMultipartUploadRequest(bucketName, key, uploadId, partETags);
+        client.completeMultipartUpload(completeMultipartUploadRequest);
+    }
+
+    private static void listAllParts(String uploadId) {
+        System.out.println("Listing all parts......");
+        ListPartsRequest listPartsRequest = new ListPartsRequest(bucketName, key, uploadId);
+        PartListing partListing = client.listParts(listPartsRequest);
+
+        int partCount = partListing.getParts().size();
+        for (int i = 0; i < partCount; i++) {
+            PartSummary partSummary = partListing.getParts().get(i);
+            System.out.println("\tPart#" + partSummary.getPartNumber() + ", ETag=" + partSummary.getETag());
+        }
+        System.out.println();
+    }
+}

+ 57 - 0
4dkankan-api-common/src/main/java/api/common/utils/SHAUtils.java

@@ -0,0 +1,57 @@
+package api.common.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/5 11:33
+ * @desciption
+ */
+public class SHAUtils {
+
+    /**
+     * 利用java原生的类实现SHA256加密
+     *
+     * @param str
+     * @return
+     */
+    public static String getSHA256(String str) {
+        MessageDigest messageDigest;
+        String encodestr = "";
+        try {
+            messageDigest = MessageDigest.getInstance("SHA-256");
+            messageDigest.update(str.getBytes("UTF-8"));
+            encodestr = byte2Hex(messageDigest.digest());
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return encodestr;
+    }
+
+
+    //15 转16进制
+
+    /**
+     * 将byte转为16进制
+     *
+     * @param bytes
+     * @return
+     */
+    public static String byte2Hex(byte[] bytes) {
+        StringBuffer stringBuffer = new StringBuffer();
+        String temp = null;
+        for (int i = 0; i < bytes.length; i++) {
+            temp = Integer.toHexString(bytes[i] & 0xFF);
+            if (temp.length() == 1) {
+                //1得到一位的进行补0操作
+                stringBuffer.append("0");
+            }
+            stringBuffer.append(temp);
+        }
+        return stringBuffer.toString();
+    }
+}

+ 26 - 0
4dkankan-api-common/src/main/java/api/common/utils/UUidGenerator.java

@@ -0,0 +1,26 @@
+package api.common.utils;
+
+import lombok.extern.log4j.Log4j2;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * @author abnerhou
+ * @date 2020/4/22 16:39
+ * @desciption
+ */
+@Component
+@Log4j2
+public class UUidGenerator {
+
+    public static String generatorUuid(String starter) {
+        StringBuilder stringBuilder = new StringBuilder();
+        String tmp = UUID.randomUUID().toString().replace("-", "");
+        tmp = tmp.substring(tmp.length() - 15);
+        stringBuilder.append(starter).append(tmp).append((new Date()).getTime());
+        return stringBuilder.toString();
+    }
+
+}

+ 149 - 0
4dkankan-api-common/src/main/java/api/common/utils/UploadToOssUtil.java

@@ -0,0 +1,149 @@
+package api.common.utils;
+
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.model.OSSObjectSummary;
+import com.aliyun.oss.model.ObjectListing;
+import com.aliyun.oss.model.PutObjectResult;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author abnerhou
+ * @date 2020/5/25 16:26
+ * @desciption
+ */
+@Log4j2
+@Component
+public class UploadToOssUtil {
+
+    @Value("${oss.point}")
+    private String ossEndPoint;
+
+    @Value("${oss.key}")
+    private String ossAppkey;
+
+    @Value("${oss.secrey}")
+    private String ossAppSecret;
+
+    @Value("${oss.bucket}")
+    private String ossBucket;
+
+
+    public void delete(String key1) throws IOException {
+        OSSClient ossClient = new OSSClient(ossEndPoint, ossAppkey, ossAppSecret);
+        try {
+            // bucketMgr.delete(bucketname, key);
+
+            // 2019-2-28 启动aliyun oss 空间
+            ossClient.deleteObject(ossBucket, key1);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    public void uploadThenDelete(String filePath, String key1) {
+        OSSClient ossClient = new OSSClient(ossEndPoint, ossAppkey, ossAppSecret);
+        try {
+            File file = new File(filePath);
+            if (!file.exists()) {
+                log.error("要上传的文件不存在:" + filePath);
+            }
+
+            ossClient.putObject(ossBucket, key1, new File(filePath));
+
+        } catch (Exception e) {
+            log.error(e.toString() + filePath);
+        }finally {
+            if(null != ossClient){
+                ossClient.shutdown();
+                FileUtils.deleteFile(filePath);
+                log.info("关闭oss 客户端,并且删除上传的本地文件");
+            }
+        }
+    }
+
+    public void upload2(String filePath, String key1) {
+        OSSClient ossClient = new OSSClient(ossEndPoint, ossAppkey, ossAppSecret);
+        try {
+            // 调用put方法上传
+            // Response res = uploadManager.put(FilePath, key, getUpToken(key));
+            // 打印返回的信息
+            // log.info(res.bodyString());
+
+            // 2019-2-28 启动aliyun oss 空间
+            ossClient.putObject(ossBucket, key1, new File(filePath));
+        } catch (Exception e) {
+            log.error(e.toString() + filePath);
+        }
+    }
+
+    //上传的数据是文件夹,参数是文件夹路径,key是上传后的文件名
+    public void uploadMulFiles(Map<String, String> filepaths) {
+        if (filepaths == null) {
+            return;
+        }
+//		log.info("开始批量上传到七牛:" + new Date().toString());
+        Long start = System.currentTimeMillis();
+        log.info("开始批量上传到阿里云:" + start);
+        if (filepaths.size() > 50) {
+            for (String filePath : filepaths.keySet()) {
+                // log.info("文件:"+key);
+                upload2(filePath, filepaths.get(filePath));
+            }
+        } else {
+            for (String filePath : filepaths.keySet()) {
+//				log.info("文件:" + filePath + "到七牛:" + filepaths.get(filePath));
+                log.info("文件:" + filePath + "到阿里云:" + filepaths.get(filePath));
+                uploadThenDelete(filePath, filepaths.get(filePath));
+            }
+        }
+        log.info("批量上传阿里云完毕:" + (System.currentTimeMillis() - start));
+    }
+
+    public int deleteFile(String prefix){
+        OSSClient ossClient = new OSSClient(ossEndPoint, ossAppkey, ossAppSecret);
+        ObjectListing objectListing = ossClient.listObjects(ossBucket, prefix);
+        List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
+        try {
+            for (OSSObjectSummary s : sums) {
+                delete(s.getKey());
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return sums.size();
+    }
+
+
+    public String upload5(String filePath, String key1) {
+        OSSClient ossClient = new OSSClient(ossEndPoint, ossAppkey, ossAppSecret);
+        PutObjectResult result = null;
+        try {
+            File file = new File(filePath);
+            if (!file.exists()) {
+                log.error("要上传的文件不存在:" + filePath);
+            }
+
+
+            result = ossClient.putObject(ossBucket, key1, new File(filePath));
+
+        } catch (Exception e) {
+            log.error(e.toString() + filePath);
+        }
+
+        log.info(" getETag : " + result.getETag());
+        log.info("1 : " + result.toString());
+        log.info("2 : " + result.getRequestId());
+        log.info("3 : " + result.getClientCRC());
+        log.info("4 : " + result.getResponse());
+        log.info("5 : " + result.getServerCRC());
+        return result.getETag();
+    }
+}

+ 100 - 0
4dkankan-house-api/pom.xml

@@ -0,0 +1,100 @@
+<?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.4dkankan.house.api</groupId>
+    <artifactId>4dkankan-house-api</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <description>四维看房开放api</description>
+
+    <packaging>war</packaging>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.2.5.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
+        <latest.version>0.2.1</latest.version>
+    </properties>
+
+
+    <dependencies>
+
+        <!-- swagger-ui -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.8.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.8.0</version>
+        </dependency>
+      <!--  <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-web</artifactId>
+            <version>1.4.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-spring</artifactId>
+            <version>1.4.0</version>
+        </dependency>-->
+
+
+        <dependency>
+            <groupId>com.4dkankan.api.common</groupId>
+            <artifactId>4dkankan-api-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+           <!-- <version>4.0.0</version>
+            <scope>provided</scope>-->
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>open_api_vrhouse_01</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>${maven-surefire-plugin.version}</version>
+                <configuration>
+                    <skipTests>true</skipTests>    <!--默认关掉单元测试 -->
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+
+</project>

BIN
4dkankan-house-api/readMeDoc/1592562858664_格式化房源数据接口代码实现脑图.jpg


BIN
4dkankan-house-api/readMeDoc/open-api房源数据操作脑图.xmind


BIN
4dkankan-house-api/readMeDoc/看房4DKanKan开放api说明文档V1.1.docx


+ 57 - 0
4dkankan-house-api/src/main/java/house/api/HouseApiApplication.java

@@ -0,0 +1,57 @@
+package house.api;
+
+import com.alibaba.nacos.api.annotation.NacosInjected;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.NamingService;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/4 12:25
+ * @desciption
+ */
+@SpringBootApplication
+@EnableCaching
+@EnableScheduling
+@EnableAsync
+@RestController
+@MapperScan(basePackages = {"house.api"})
+public class HouseApiApplication extends SpringBootServletInitializer {
+
+    @NacosInjected
+    private NamingService namingService;
+
+    @Value("${server.port}")
+    private int serverPort;
+
+    @Value("${spring.application.name}")
+    private String applicationName;
+
+    @PostConstruct
+    public void registerInstance() throws NacosException {
+        namingService.registerInstance(applicationName,"127.0.0.1",serverPort);
+    }
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+        return application.sources(HouseApiApplication.class);
+    }
+
+    public static void main(String[] args) {
+        SpringApplication springApplication = new SpringApplication(HouseApiApplication.class);
+        springApplication.addListeners(new ApplicationPidFileWriter());
+        springApplication.run(args);
+    }
+}

+ 28 - 0
4dkankan-house-api/src/main/java/house/api/base/configs/MyBatisPlusConfig.java

@@ -0,0 +1,28 @@
+package house.api.base.configs;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/3 14:53
+ * @desciption
+ */
+@Configuration
+public class MyBatisPlusConfig {
+
+    @Bean
+    public PaginationInterceptor paginationInterceptor() {
+        //mybatis-plus分页配置
+        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
+        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
+        // paginationInterceptor.setOverflow(false);
+        // 设置最大单页限制数量,默认 500 条,-1 不受限制
+        // paginationInterceptor.setLimit(500);
+        // 开启 count 的 join 优化,只针对部分 left join
+        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
+        return paginationInterceptor;
+    }
+}

+ 95 - 0
4dkankan-house-api/src/main/java/house/api/base/configs/RedisConfig.java

@@ -0,0 +1,95 @@
+package house.api.base.configs;
+
+import api.common.utils.JedisUtil;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import redis.clients.jedis.JedisPoolConfig;
+
+@Log4j2
+@Configuration
+@EnableCaching
+@ConfigurationProperties
+public class RedisConfig extends CachingConfigurerSupport implements InitializingBean {
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        log.warn("redis.address:"+address);
+        JedisUtil.init(address, jedisPoolConfig());
+    }
+
+    @Value("${spring.redis.database}")
+    private int database;
+    @Value("${spring.redis.host}")
+    private String host;
+    @Value("${spring.redis.port}")
+    private int port;
+    @Value("${spring.redis.password}")
+    private String password;
+    @Value("${spring.redis.timeout}")
+    private String timeout;
+    @Value("${spring.redis.jedis.pool.max-idle}")
+    private int maxIdle;
+    @Value("${spring.redis.jedis.pool.min-idle}")
+    private int minIdle;
+    @Value("${spring.redis.host}:${spring.redis.port}")
+    private String address;
+
+    /**
+     * redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
+     * @param redisConnectionFactory
+     * @return
+     */
+    @Bean
+    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+
+        // 使用Jackson2JsonRedisSerialize 替换默认序列化
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+
+        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+
+        // 设置value的序列化规则和 key的序列化规则
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.afterPropertiesSet();
+        return redisTemplate;
+    }
+    /**
+     * 连接池配置
+     * @Description:
+     * @return
+     */
+    @Bean
+    public JedisPoolConfig jedisPoolConfig() {
+        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
+        jedisPoolConfig.setMaxIdle(maxIdle);
+        jedisPoolConfig.setMinIdle(minIdle);
+//        jedisPoolConfig.setMaxTotal(maxTotal);			            // 最大连接数, 默认8个
+//        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);	        // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
+        jedisPoolConfig.setTestOnBorrow(true);		                // 在获取连接的时候检查有效性, 默认false
+        jedisPoolConfig.setTestOnReturn(true);                      // 调用returnObject方法时,是否进行有效检查
+        jedisPoolConfig.setTestWhileIdle(true);		                // Idle时进行连接扫描
+        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(30000);	//表示idle object evitor两次扫描之间要sleep的毫秒数
+        jedisPoolConfig.setNumTestsPerEvictionRun(10);			    //表示idle object evitor每次扫描的最多的对象数
+        jedisPoolConfig.setMinEvictableIdleTimeMillis(60000);	    //表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
+        return jedisPoolConfig;
+    }
+}

+ 49 - 0
4dkankan-house-api/src/main/java/house/api/base/configs/SwaggerApp.java

@@ -0,0 +1,49 @@
+package house.api.base.configs;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @author abnerhou
+ * @date 2020/5/15 18:27
+ * @desciption
+ */
+@Configuration
+@EnableSwagger2
+@Profile("dev")
+public class SwaggerApp {
+
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                //为当前包路径
+                .apis(RequestHandlerSelectors.basePackage("house.api"))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    //构建 api文档的详细信息函数,注意这里的注解引用的是哪个
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                //页面标题
+                .title("四维看房开放api接口")
+                //创建人
+                .contact(new Contact("Abner", "", "houweiyu@cgaii.com"))
+                //版本号
+                .version("1.0")
+                //描述
+                .description("开放api的接口")
+                .build();
+    }
+}

+ 21 - 0
4dkankan-house-api/src/main/java/house/api/base/constVo/PageDataVo.java

@@ -0,0 +1,21 @@
+package house.api.base.constVo;
+
+import house.api.base.entity.TmHouseInfo;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/12 10:29
+ * @desciption
+ */
+@Data
+public class PageDataVo {
+
+
+    private Integer curPage;
+    private Integer totalNum;
+    private Integer totalPageNum;
+    private List<TmHouseInfo> list;
+}

+ 22 - 0
4dkankan-house-api/src/main/java/house/api/base/constVo/request/FourDgetHouseVo.java

@@ -0,0 +1,22 @@
+package house.api.base.constVo.request;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/5 21:10
+ * @desciption
+ */
+@Data
+@ApiModel(value="FourDgetHouseVo对象", description="")
+public class FourDgetHouseVo {
+
+    private String agencyUserId;
+
+
+    private String userId;
+
+    private String sceneNum;
+
+}

+ 118 - 0
4dkankan-house-api/src/main/java/house/api/base/constVo/request/RecommendHouseVo.java

@@ -0,0 +1,118 @@
+package house.api.base.constVo.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/8 11:House
+ * @desciption
+ */
+@Data
+@ApiModel(value="RecommendHouseVo对象", description="")
+public class RecommendHouseVo implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "房源唯一主键")
+    private String houseId;
+
+    @ApiModelProperty(value = "参考总价")
+    private BigDecimal houseReferencePrice;
+
+    @ApiModelProperty(value = "户型")
+    private String houseType;
+
+    @ApiModelProperty(value = "房源面积")
+    private Double houseArea;
+
+    @ApiModelProperty(value = "房源朝向")
+    private String houseOrientation;
+
+    @ApiModelProperty(value = "楼盘id")
+    private String estateId;
+
+    @ApiModelProperty(value = "楼盘的房源均价")
+    private BigDecimal estateReferenceAveragePrice;
+
+    @ApiModelProperty(value = "最早交房日期")
+    private LocalDate earlistHandOver;
+
+    @ApiModelProperty(value = "最早开盘时间")
+    private LocalDate onSaleTime;
+
+    @ApiModelProperty(value = "楼盘开发商")
+    private String estateDeveloper;
+
+    @ApiModelProperty(value = "产权年限")
+    private Integer estatePeriodInt;
+
+    @ApiModelProperty(value = "楼盘地址")
+    private String estateAddress;
+
+    @ApiModelProperty(value = "楼盘简介视频地址")
+    private String estateIntroduceVideo;
+
+    @ApiModelProperty(value = "楼盘介绍照片集地址")
+    private String estateImages;
+
+    @ApiModelProperty(value = "楼盘经度")
+    private BigDecimal estateLongitude;
+
+    @ApiModelProperty(value = "楼盘未读")
+    private BigDecimal estateLatitude;
+
+    @ApiModelProperty(value = "经纪人唯一id")
+    private String agencyId;
+
+    @ApiModelProperty(value = "经纪人姓名")
+    private String agencyName;
+
+    @ApiModelProperty(value = "经纪人门店")
+    private String agencyStore;
+
+    @ApiModelProperty(value = "经纪人标签")
+    private String agencyTag;
+
+    @ApiModelProperty(value = "经纪人手机号码")
+    private String agnencyPhone;
+
+    @ApiModelProperty(value = "经纪人半年成交量")
+    private Integer agencyHalfYearVolume;
+
+    @ApiModelProperty(value = "经纪人平均成交周期(天)")
+    private Double agencyDealAverage;
+
+    @ApiModelProperty(value = "经纪人近30天带看数(套)")
+    private Integer agencyRecentRecommend;
+
+    @ApiModelProperty(value = "经纪人头像地址")
+    private String agencyAvatar;
+
+    @ApiModelProperty(value = "经纪人工作证照片地址")
+    private String agencyPassImage;
+
+    @ApiModelProperty(value = "用户唯一id")
+    private String userId;
+
+    @ApiModelProperty(value = "用户名字")
+    private String userName;
+
+    @ApiModelProperty(value = "回调域名")
+    private String callBackUrl;
+
+    @ApiModelProperty(value = "vr同屏带看房间号")
+    private String communicateRoomId;
+
+    @ApiModelProperty(value = "四维看看相机的场景码")
+    private String sceneNum;
+
+    @ApiModelProperty(value = "请求端的类型:经纪人:agent,用户;customer")
+    private String terminalType;
+
+}

+ 17 - 0
4dkankan-house-api/src/main/java/house/api/base/constVo/request/TmDeveloperRequestVo.java

@@ -0,0 +1,17 @@
+package house.api.base.constVo.request;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/16 20:20
+ * @desciption
+ */
+
+@Data
+@ApiModel(value="TmDeveloperRequestVo对象", description="TmDeveloperRequestVo对象")
+public class TmDeveloperRequestVo {
+
+
+}

+ 123 - 0
4dkankan-house-api/src/main/java/house/api/base/constVo/request/TmHouseInfoRequestVo.java

@@ -0,0 +1,123 @@
+package house.api.base.constVo.request;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/4 16:38
+ * @desciption
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmHouseInfoRequestVo对象", description="")
+public class TmHouseInfoRequestVo implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "房源唯一主键")
+    private String houseId;
+
+    @ApiModelProperty(value = "参考总价")
+    private BigDecimal houseReferencePrice;
+
+    @ApiModelProperty(value = "户型")
+    private String houseType;
+
+    @ApiModelProperty(value = "房源面积")
+    private Double houseArea;
+
+    @ApiModelProperty(value = "房源朝向")
+    private String houseOrientation;
+
+    @ApiModelProperty(value = "楼盘id")
+    private String estateId;
+
+    @ApiModelProperty(value = "楼盘的房源均价")
+    private BigDecimal estateReferenceAveragePrice;
+
+    @ApiModelProperty(value = "最早交房日期")
+    private LocalDate earlistHandOver;
+
+    @ApiModelProperty(value = "最早开盘时间")
+    private LocalDate onSaleTime;
+
+    @ApiModelProperty(value = "楼盘开发商")
+    private String estateDeveloper;
+
+    @ApiModelProperty(value = "产权年限")
+    private Integer estatePeriodInt;
+
+    @ApiModelProperty(value = "楼盘地址")
+    private String estateAddress;
+
+    @ApiModelProperty(value = "楼盘简介视频地址")
+    private String estateIntroduceVideo;
+
+    @ApiModelProperty(value = "楼盘介绍照片集地址")
+    private String estateImages;
+
+    @ApiModelProperty(value = "楼盘经度")
+    private BigDecimal estateLongitude;
+
+    @ApiModelProperty(value = "楼盘未读")
+    private BigDecimal estateLatitude;
+
+    @ApiModelProperty(value = "经纪人唯一id")
+    private String agencyId;
+
+    @ApiModelProperty(value = "经纪人姓名")
+    private String agencyName;
+
+    @ApiModelProperty(value = "经纪人门店")
+    private String agencyStore;
+
+    @ApiModelProperty(value = "经纪人标签")
+    private String agencyTag;
+
+    @ApiModelProperty(value = "经纪人手机号码")
+    private String agnencyPhone;
+
+    @ApiModelProperty(value = "经纪人半年成交量")
+    private Integer agencyHalfYearVolume;
+
+    @ApiModelProperty(value = "经纪人平均成交周期(天)")
+    private Double agencyDealAverage;
+
+    @ApiModelProperty(value = "经纪人近30天带看数(套)")
+    private Integer agencyRecentRecommend;
+
+    @ApiModelProperty(value = "经纪人头像地址")
+    private String agencyAvatar;
+
+    @ApiModelProperty(value = "经纪人工作证照片地址")
+    private String agencyPassImage;
+
+    @ApiModelProperty(value = "用户唯一id")
+    private String userId;
+
+    @ApiModelProperty(value = "用户名字")
+    private String userName;
+
+    @ApiModelProperty(value = "回调域名")
+    private String callBackUrl;
+
+    @ApiModelProperty(value = "开发者应用id")
+    private String appId;
+
+    @ApiModelProperty(value = "开发者token")
+    private String appToken;
+
+    @ApiModelProperty(value = "数据签名")
+    private String appSign;
+
+
+}

+ 40 - 0
4dkankan-house-api/src/main/java/house/api/base/constVo/response/DeveloperAuthorityRspDto.java

@@ -0,0 +1,40 @@
+package house.api.base.constVo.response;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author abnerhou
+ * @date 2020/7/8 10:14
+ * @desciption
+ */
+@Data
+public class DeveloperAuthorityRspDto {
+    @ApiModelProperty(value = "权限id")
+    private String appId;
+
+    @ApiModelProperty(value = "是否展示页面底部四维logo : 1 展示 0不展示")
+    private Integer showKankanFoot;
+
+    @ApiModelProperty(value = "是否展示经纪人门店:1 展示 0不展示")
+    private Integer showAgencyStore;
+
+    @ApiModelProperty(value = "是否展示经纪公司品牌:1 展示 0不展示")
+    private Integer showAgencyBrand;
+
+    @ApiModelProperty(value = "是否使用客户用户头像:1 使用 0 不使用")
+    private Integer useCostomerUserAvatar;
+
+    @ApiModelProperty(value = "是否将消息订阅post的body的参数拼接到url上:Y 是, N 否")
+    private String appendNoticeBody;
+
+    @ApiModelProperty(value = "是否展示委托授权:1 展示 0 不展示")
+    private Integer showDelegateAuth;
+
+    @ApiModelProperty(value = "是否展示房源信息: 1展示 0 不展示")
+    private Integer showHouseInfo;
+
+    @ApiModelProperty(value = "是否展示工作证: 1 展示 0 不展示")
+    private Integer showWorkPic;
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/dao/TmDeveloperAuthorityDao.java

@@ -0,0 +1,16 @@
+package house.api.base.dao;
+
+import house.api.base.entity.TmDeveloperAuthority;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 开发者权限控制表 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+public interface TmDeveloperAuthorityDao extends BaseMapper<TmDeveloperAuthority> {
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/dao/TmDeveloperDao.java

@@ -0,0 +1,16 @@
+package house.api.base.dao;
+
+import house.api.base.entity.TmDeveloper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 开发者信息表 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+public interface TmDeveloperDao extends BaseMapper<TmDeveloper> {
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/dao/TmHouseInfoDao.java

@@ -0,0 +1,16 @@
+package house.api.base.dao;
+
+import house.api.base.entity.TmHouseInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 房源信息表 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-10-14
+ */
+public interface TmHouseInfoDao extends BaseMapper<TmHouseInfo> {
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/dao/TmHouseRecommendDao.java

@@ -0,0 +1,16 @@
+package house.api.base.dao;
+
+import house.api.base.entity.TmHouseRecommend;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 房源和推荐房源的关联关系表 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+public interface TmHouseRecommendDao extends BaseMapper<TmHouseRecommend> {
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/dao/TmRoomIdLogDao.java

@@ -0,0 +1,16 @@
+package house.api.base.dao;
+
+import house.api.base.entity.TmRoomIdLog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 房间号历史记录 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-30
+ */
+public interface TmRoomIdLogDao extends BaseMapper<TmRoomIdLog> {
+
+}

+ 85 - 0
4dkankan-house-api/src/main/java/house/api/base/entity/TmDeveloper.java

@@ -0,0 +1,85 @@
+package house.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 开发者信息表
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmDeveloper对象", description="开发者信息表")
+public class TmDeveloper implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "开发者id")
+    private String developerId;
+
+    @ApiModelProperty(value = "开发者应用id")
+    private String appId;
+
+    @ApiModelProperty(value = "开发者所属公司统一社会信用代码")
+    private String companyCreditCode;
+
+    @ApiModelProperty(value = "开发者应用密钥")
+    private String appSecret;
+
+    @ApiModelProperty(value = "模式")
+    private String state;
+
+    @ApiModelProperty(value = "使用的微信小程序的app id")
+    private String wxAppId;
+
+    @ApiModelProperty(value = "开发者所属公司")
+    private String company;
+
+    @ApiModelProperty(value = "开发者所属公司固话号码")
+    private String tel;
+
+    @ApiModelProperty(value = "开发者所属公司法人名字")
+    private String legalPersonName;
+
+    @ApiModelProperty(value = "开发者所属公司法人手机号码")
+    private String legalPersonPhone;
+
+    @ApiModelProperty(value = "是否可用: 2审批通过 1 待审批 0 不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最新修改时间")
+    private LocalDateTime lastModifyDatetime;
+
+    @ApiModelProperty(value = "openApi回调开发者接口的url")
+    private String callBackUrl;
+
+    @ApiModelProperty(value = "管理者手机号")
+    private String adminPhone;
+
+    @ApiModelProperty(value = "管理者邮箱")
+    private String adminEmail;
+
+    @ApiModelProperty(value = "微信小程序校验文件链接")
+    private String wxMiniProgramFile;
+
+    @ApiModelProperty(value = "所属领域")
+    private String domainType;
+
+    @ApiModelProperty(value = "是否需要将返回参数拼到url上:Y 需要 N不需要")
+    private String respondToUrl;
+
+
+}

+ 67 - 0
4dkankan-house-api/src/main/java/house/api/base/entity/TmDeveloperAuthority.java

@@ -0,0 +1,67 @@
+package house.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 开发者权限控制表
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmDeveloperAuthority对象", description="开发者权限控制表")
+public class TmDeveloperAuthority implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "权限id")
+    private String appId;
+
+    @ApiModelProperty(value = "是否展示页面底部四维logo : 1 展示 0不展示")
+    private Integer showKankanFoot;
+
+    @ApiModelProperty(value = "是否展示经纪人门店:1 展示 0不展示")
+    private Integer showAgencyStore;
+
+    @ApiModelProperty(value = "是否展示经纪公司品牌:1 展示 0不展示")
+    private Integer showAgencyBrand;
+
+    @ApiModelProperty(value = "是否使用客户用户头像:1 使用 0 不使用")
+    private Integer useCostomerUserAvatar;
+
+    @ApiModelProperty(value = "是否将消息订阅post的body的参数拼接到url上:Y 是, N 否")
+    private String appendNoticeBody;
+
+    @ApiModelProperty(value = "回调url")
+    private String callBackUrl;
+
+    @ApiModelProperty(value = "是否可用: 1可用 0 不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最后更新时间")
+    private LocalDateTime lastModifyDatetime;
+
+    @ApiModelProperty(value = "是否展示委托授权:1 展示 0 不展示")
+    private Integer showDelegateAuth;
+
+    @ApiModelProperty(value = "是否展示房源信息: 1展示 0 不展示")
+    private Integer showHouseInfo;
+
+    @ApiModelProperty(value = "是否展示工作证: 1 展示 0 不展示")
+    private Integer showWorkPic;
+
+
+}

+ 198 - 0
4dkankan-house-api/src/main/java/house/api/base/entity/TmHouseInfo.java

@@ -0,0 +1,198 @@
+package house.api.base.entity;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 房源信息表
+ * </p>
+ *
+ * @author abner
+ * @since 2020-10-14
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmHouseInfo对象", description="房源信息表")
+public class TmHouseInfo implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "请求id")
+    private String requestId;
+
+    @ApiModelProperty(value = "房源唯一主键")
+    private String houseId;
+
+    @ApiModelProperty(value = "参考总价")
+    private BigDecimal houseReferencePrice;
+
+    @ApiModelProperty(value = "户型")
+    private String houseType;
+
+    @ApiModelProperty(value = "房源面积")
+    private Double houseArea;
+
+    @ApiModelProperty(value = "房源朝向")
+    private String houseOrientation;
+
+    @ApiModelProperty(value = "楼盘id")
+    private String estateId;
+
+    @ApiModelProperty(value = "楼盘的房源均价")
+    private BigDecimal estateReferenceAveragePrice;
+
+    @ApiModelProperty(value = "最早交房日期")
+    private LocalDate earlistHandOver;
+
+    @ApiModelProperty(value = "最早开盘时间")
+    private LocalDate onSaleTime;
+
+    @ApiModelProperty(value = "楼盘开发商")
+    private String estateDeveloper;
+
+    @ApiModelProperty(value = "产权年限")
+    private Integer estatePeriodInt;
+
+    @ApiModelProperty(value = "楼盘地址")
+    private String estateAddress;
+
+    @ApiModelProperty(value = "楼盘简介视频地址")
+    private String estateIntroduceVideo;
+
+    @ApiModelProperty(value = "楼盘介绍照片集地址")
+    private String estateImages;
+
+    @ApiModelProperty(value = "楼盘经度")
+    private BigDecimal estateLongitude;
+
+    @ApiModelProperty(value = "楼盘未读")
+    private BigDecimal estateLatitude;
+
+    @ApiModelProperty(value = "楼盘详情封面照片地址")
+    private String estateCoverImage;
+
+    @ApiModelProperty(value = "视频简介封面照片地址")
+    private String estateVideoCoverImage;
+
+    @ApiModelProperty(value = "经纪人唯一id")
+    private String agencyId;
+
+    @ApiModelProperty(value = "经纪人姓名")
+    private String agencyName;
+
+    @ApiModelProperty(value = "经纪人门店")
+    private String agencyStore;
+
+    @ApiModelProperty(value = "经纪人标签")
+    private String agencyTag;
+
+    @ApiModelProperty(value = "经纪人手机号码")
+    private String agnencyPhone;
+
+    @ApiModelProperty(value = "经纪人半年成交量")
+    private Integer agencyHalfYearVolume;
+
+    @ApiModelProperty(value = "经纪人平均成交周期(天)")
+    private Double agencyDealAverage;
+
+    @ApiModelProperty(value = "经纪人近30天带看数(套)")
+    private Integer agencyRecentRecommend;
+
+    @ApiModelProperty(value = "经纪人头像地址")
+    private String agencyAvatar;
+
+    @ApiModelProperty(value = "经纪人工作证照片地址")
+    private String agencyPassImage;
+
+    @ApiModelProperty(value = "经纪人标签图标地址")
+    private String agencyTagImage;
+
+    @ApiModelProperty(value = "用户唯一id")
+    private String userId;
+
+    @ApiModelProperty(value = "用户名字")
+    private String userName;
+
+    @ApiModelProperty(value = "回调域名")
+    private String callBackUrl;
+
+    @ApiModelProperty(value = "开发者应用id")
+    private String appId;
+
+    @ApiModelProperty(value = "开发者token")
+    private String appToken;
+
+    @ApiModelProperty(value = "数据签名")
+    private String appSign;
+
+    @ApiModelProperty(value = "自定义内容")
+    private String customContent;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最新修改时间")
+    private LocalDateTime lastModifyDatetime;
+
+    @ApiModelProperty(value = "vr同屏带看房间号")
+    private String communicateRoomId;
+
+    @ApiModelProperty(value = "四维看看相机的场景码")
+    private String sceneNum;
+
+    @ApiModelProperty(value = "请求端的类型:经纪人:agent,用户;customer")
+    private String terminalType;
+
+    @ApiModelProperty(value = "推荐房源列表")
+    private String recommendHouses;
+
+    @ApiModelProperty(value = "房源标题")
+    private String houseTitle;
+
+    @ApiModelProperty(value = "房源户型照片地址")
+    private String houseTypeImages;
+
+    @ApiModelProperty(value = "视频简介描述")
+    private String estateIntroduceVideoDesc;
+
+    @ApiModelProperty(value = "是否可用: 1 可用, 0 已删除")
+    private Integer enable;
+
+    @ApiModelProperty(value = "经纪公司品牌名称")
+    private String agencyCompanyName;
+
+    @ApiModelProperty(value = "用户头像地址")
+    private String userAvatar;
+
+    @ApiModelProperty(value = "开发者用户logo")
+    private String developerLogo;
+
+    @ApiModelProperty(value = "开发者用户标题")
+    private String developerTitle;
+
+    @ApiModelProperty(value = "开发者用户描述")
+    private String developerDesc;
+
+    @ApiModelProperty(value = "开发者用户分享二维码地址")
+    private String developerQrCode;
+
+    @ApiModelProperty(value = "开发者用户分享二维码缺失的文字描述")
+    private String developerQrCodeDesc;
+
+    @ApiModelProperty(value = "四维的默认分享码")
+    private String wxAqrCode;
+
+    @ApiModelProperty(value = "带看主页面公司logo链接")
+    private String homePageLogo;
+
+
+}

+ 49 - 0
4dkankan-house-api/src/main/java/house/api/base/entity/TmHouseRecommend.java

@@ -0,0 +1,49 @@
+package house.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 房源和推荐房源的关联关系表
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmHouseRecommend对象", description="房源和推荐房源的关联关系表")
+public class TmHouseRecommend implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "关联关系ID")
+    private String relationNo;
+
+    @ApiModelProperty(value = "当前房源的vr场景码")
+    private String sceneNum;
+
+    @ApiModelProperty(value = "推荐的房源的vr场景码")
+    private String recommendSceneNum;
+
+    @ApiModelProperty(value = "是否可用:1可用,0不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最后修改时间")
+    private LocalDateTime lastModifyDatetime;
+
+    @ApiModelProperty(value = "房源和推荐房源所属的经纪人id")
+    private String agencyId;
+
+
+}

+ 46 - 0
4dkankan-house-api/src/main/java/house/api/base/entity/TmRoomIdLog.java

@@ -0,0 +1,46 @@
+package house.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 房间号历史记录
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-30
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmRoomIdLog对象", description="房间号历史记录")
+public class TmRoomIdLog implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "记录ID")
+    private String logId;
+
+    @ApiModelProperty(value = "vr同屏带看房间号")
+    private String communicateRoomId;
+
+    @ApiModelProperty(value = "是否可用:1->可用;0->不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最新更新时间")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "场景码")
+    private String sceneNum;
+
+
+}

+ 36 - 0
4dkankan-house-api/src/main/java/house/api/base/exception/ControllerHanderException.java

@@ -0,0 +1,36 @@
+package house.api.base.exception;
+
+import api.common.exception.CommonBaseException;
+import api.common.model.Result;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author abnerhou
+ * @date 2020/9/27 19:09
+ * @desciption
+ */
+@ControllerAdvice
+public class ControllerHanderException {
+
+    @ExceptionHandler(CommonBaseException.class)
+    @ResponseBody
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    //在这个方法里定义我们需要返回的格式
+//    public Map<String, Object> handleUserNotExistException(CommonBaseException ex){
+    public Result handleUserNotExistException(CommonBaseException e){
+       /* Map<String, Object> result = new HashMap<>();
+        result.put("code", ex.getCode());
+        result.put("msg", ex.getMsg());
+        return result;*/
+        return Result.failure(null == e.getCode() ? Result.CODE_FAILURE : e.getCode(), e.getMsg());
+    }
+
+}

Різницю між файлами не показано, бо вона завелика
+ 50 - 0
4dkankan-house-api/src/main/java/house/api/base/generator/GeneratorTestData.java


+ 104 - 0
4dkankan-house-api/src/main/java/house/api/base/generator/MysqlGenerator.java

@@ -0,0 +1,104 @@
+package house.api.base.generator;
+
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import org.hibernate.validator.internal.util.privilegedactions.GetResource;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/3 14:54
+ * @desciption
+ */
+public class MysqlGenerator {
+
+    final static String  dirPath = "D://";
+
+
+    public static void main(String[] args) {
+        AutoGenerator mpg = new AutoGenerator();
+
+        GlobalConfig gc = new GlobalConfig();
+        String projectPath = System.getProperty("user.dir");
+        gc.setOutputDir(projectPath + "/4dkankan-house-api/src/main/java");
+        gc.setAuthor("abner");   // 作者
+        gc.setOpen(false);      //生成代码后是否打开文件夹
+        gc.setSwagger2(true);
+        gc.setMapperName("%sDao");
+//        gc.setXmlName("%sMapper");
+//        gc.setControllerName("%sController");
+        gc.setFileOverride(true);//是否覆盖
+        mpg.setGlobalConfig(gc);
+
+        DataSourceConfig dsc = new DataSourceConfig();
+        dsc.setUrl("jdbc:mysql://120.25.146.52:3306/4dhouse-api?useUnicode=true&serverTimezone=GMT&useSSL=false&characterEncoding=utf8");
+        dsc.setDriverName("com.mysql.jdbc.Driver");
+        dsc.setUsername("root");
+        dsc.setPassword("4dkk2020test%");
+        mpg.setDataSource(dsc);
+
+        // 包配置
+        PackageConfig pc = new PackageConfig();
+        pc.setModuleName("base"); // 模块名称, 这里可以根据不同模块来写
+        pc.setParent("house.api"); // 父包名
+        pc.setMapper("dao");
+        pc.setController("controller");
+
+        mpg.setPackageInfo(pc);
+
+        // 配置模板
+        TemplateConfig templateConfig = new TemplateConfig();
+
+        //控制 不生成 controller
+        templateConfig.setController("");
+
+        templateConfig.setXml(null);
+        mpg.setTemplate(templateConfig);
+
+
+        // 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】
+        InjectionConfig cfg = new InjectionConfig() {
+            @Override
+            public void initMap() {
+                Map<String, Object> map = new HashMap<String, Object>();
+                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
+                this.setMap(map);
+            }
+        };
+
+        // 调整 xml 生成目录演示
+        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();
+        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
+            @Override
+            public String outputFile(TableInfo tableInfo) {
+                return  "E:\\code\\projects\\dev_4dkankanAPI\\4dkankan-house-api\\src\\main\\resources\\mybatis\\mappers\\" + tableInfo.getEntityName() + "Mapper.xml";
+            }
+        });
+        cfg.setFileOutConfigList(focList);
+        mpg.setCfg(cfg);
+
+
+        // 策略配置
+        StrategyConfig strategy = new StrategyConfig();
+        strategy.setNaming(NamingStrategy.underline_to_camel);
+        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+//        strategy.setSuperEntityClass("house.api.base.model");
+
+        strategy.setEntityLombokModel(true);
+//        strategy.setInclude("tm_developer","tm_house_info","tm_house_recommend","tm_developer_authority");  // 如果要生成多个,这里可以传入String[]
+        strategy.setInclude("tm_house_info");  // 如果要生成多个,这里可以传入String[]
+//        strategy.setInclude("tm_room_id_log");  // 如果要生成多个,这里可以传入String[]
+        mpg.setStrategy(strategy);
+        //TODO:使用的时候,释放出来就可以了
+        mpg.execute();
+        System.out.println("代码自动生成执行完成");
+    }
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/service/ITmDeveloperAuthorityService.java

@@ -0,0 +1,16 @@
+package house.api.base.service;
+
+import house.api.base.entity.TmDeveloperAuthority;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 开发者权限控制表 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+public interface ITmDeveloperAuthorityService extends IService<TmDeveloperAuthority> {
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/service/ITmDeveloperService.java

@@ -0,0 +1,16 @@
+package house.api.base.service;
+
+import house.api.base.entity.TmDeveloper;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 开发者信息表 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+public interface ITmDeveloperService extends IService<TmDeveloper> {
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/service/ITmHouseInfoService.java

@@ -0,0 +1,16 @@
+package house.api.base.service;
+
+import house.api.base.entity.TmHouseInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 房源信息表 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-10-14
+ */
+public interface ITmHouseInfoService extends IService<TmHouseInfo> {
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/service/ITmHouseRecommendService.java

@@ -0,0 +1,16 @@
+package house.api.base.service;
+
+import house.api.base.entity.TmHouseRecommend;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 房源和推荐房源的关联关系表 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+public interface ITmHouseRecommendService extends IService<TmHouseRecommend> {
+
+}

+ 16 - 0
4dkankan-house-api/src/main/java/house/api/base/service/ITmRoomIdLogService.java

@@ -0,0 +1,16 @@
+package house.api.base.service;
+
+import house.api.base.entity.TmRoomIdLog;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 房间号历史记录 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-30
+ */
+public interface ITmRoomIdLogService extends IService<TmRoomIdLog> {
+
+}

+ 20 - 0
4dkankan-house-api/src/main/java/house/api/base/service/impl/TmDeveloperAuthorityServiceImpl.java

@@ -0,0 +1,20 @@
+package house.api.base.service.impl;
+
+import house.api.base.entity.TmDeveloperAuthority;
+import house.api.base.dao.TmDeveloperAuthorityDao;
+import house.api.base.service.ITmDeveloperAuthorityService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 开发者权限控制表 服务实现类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+@Service
+public class TmDeveloperAuthorityServiceImpl extends ServiceImpl<TmDeveloperAuthorityDao, TmDeveloperAuthority> implements ITmDeveloperAuthorityService {
+
+}

+ 20 - 0
4dkankan-house-api/src/main/java/house/api/base/service/impl/TmDeveloperServiceImpl.java

@@ -0,0 +1,20 @@
+package house.api.base.service.impl;
+
+import house.api.base.entity.TmDeveloper;
+import house.api.base.dao.TmDeveloperDao;
+import house.api.base.service.ITmDeveloperService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 开发者信息表 服务实现类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+@Service
+public class TmDeveloperServiceImpl extends ServiceImpl<TmDeveloperDao, TmDeveloper> implements ITmDeveloperService {
+
+}

+ 20 - 0
4dkankan-house-api/src/main/java/house/api/base/service/impl/TmHouseInfoServiceImpl.java

@@ -0,0 +1,20 @@
+package house.api.base.service.impl;
+
+import house.api.base.entity.TmHouseInfo;
+import house.api.base.dao.TmHouseInfoDao;
+import house.api.base.service.ITmHouseInfoService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 房源信息表 服务实现类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-10-14
+ */
+@Service
+public class TmHouseInfoServiceImpl extends ServiceImpl<TmHouseInfoDao, TmHouseInfo> implements ITmHouseInfoService {
+
+}

+ 20 - 0
4dkankan-house-api/src/main/java/house/api/base/service/impl/TmHouseRecommendServiceImpl.java

@@ -0,0 +1,20 @@
+package house.api.base.service.impl;
+
+import house.api.base.entity.TmHouseRecommend;
+import house.api.base.dao.TmHouseRecommendDao;
+import house.api.base.service.ITmHouseRecommendService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 房源和推荐房源的关联关系表 服务实现类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-07-23
+ */
+@Service
+public class TmHouseRecommendServiceImpl extends ServiceImpl<TmHouseRecommendDao, TmHouseRecommend> implements ITmHouseRecommendService {
+
+}

+ 20 - 0
4dkankan-house-api/src/main/java/house/api/base/service/impl/TmRoomIdLogServiceImpl.java

@@ -0,0 +1,20 @@
+package house.api.base.service.impl;
+
+import house.api.base.entity.TmRoomIdLog;
+import house.api.base.dao.TmRoomIdLogDao;
+import house.api.base.service.ITmRoomIdLogService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 房间号历史记录 服务实现类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-30
+ */
+@Service
+public class TmRoomIdLogServiceImpl extends ServiceImpl<TmRoomIdLogDao, TmRoomIdLog> implements ITmRoomIdLogService {
+
+}

+ 413 - 0
4dkankan-house-api/src/main/java/house/api/controller/FourDHouseController.java

@@ -0,0 +1,413 @@
+package house.api.controller;
+
+import api.common.enums.IdStarterEnum;
+import api.common.enums.ResultCodeEnum;
+import api.common.exception.CommonBaseException;
+import api.common.model.Result;
+import api.common.utils.HttpClientUtil;
+import api.common.utils.UUidGenerator;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import house.api.base.constVo.response.DeveloperAuthorityRspDto;
+import house.api.base.dao.*;
+import house.api.base.entity.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+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.ResponseBody;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/5 20:45
+ * @desciption
+ */
+@Log4j2
+@Api(tags = "开放api对内获取房源相关的接口")
+@Controller
+@RequestMapping("/4dage")
+public class FourDHouseController {
+
+    @Autowired
+    private  TmHouseInfoDao tmHouseInfoDao;
+
+    @Autowired
+    private TmDeveloperDao tmDeveloperDao;
+
+    @Autowired
+    private TmHouseRecommendDao tmHouseRecommendDao;
+
+    @Autowired
+    private TmDeveloperAuthorityDao tmDeveloperAuthorityDao;
+
+    @Autowired
+    private TmRoomIdLogDao tmRoomIdLogDao;
+
+
+
+    @ApiOperation(value = "4维内部请求房源信息")
+    @ResponseBody
+    @GetMapping(value = "/getHouseInfo")
+    @Transactional(rollbackFor = Exception.class)
+    public Result getHouseInfo(@RequestParam(value = "scene_code") String sceneCode,
+                               @RequestParam(value = "user_id") String userId,
+                               @RequestParam(value = "room_id") String roomId,
+                               @RequestParam(value = "terminal_type") String terminalType) {
+
+        if (StringUtils.isBlank(sceneCode)) {
+            throw new CommonBaseException(ResultCodeEnum.D3001);
+        }
+
+        log.info("上送的场景码为:{},终端类型为:{}", sceneCode, terminalType);
+        Instant stepOneStart = Instant.now();
+        Map<String, Object> result = new HashMap<>();
+        QueryWrapper<TmHouseInfo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("scene_num", sceneCode);
+        boolean setDefaultValue = false;
+        if(StringUtils.isBlank(roomId)){
+            //TODO:这里写死兼容看房一期发出去的传单的房源的数据
+            if("t-kZUcUeX".equals(sceneCode) || "t-VJjZMUl".equals(sceneCode)
+                    || "t-pnj0IJX".equals(sceneCode) || "t-XtYfLCO".equals(sceneCode)){
+                queryWrapper.orderByDesc("last_modify_datetime");
+                //这里直接捞取去掉roomId的
+
+            }else{
+                //没有上送roomId,则返回一个默认的数据:
+                queryWrapper.orderByDesc("last_modify_datetime");
+            }
+
+        }else{
+            queryWrapper.eq("communicate_room_id", roomId);
+        }
+        queryWrapper.eq("enable", 1);
+        queryWrapper.last("limit 1");
+        TmHouseInfo tmHouseInfo = tmHouseInfoDao.selectOne(queryWrapper);
+        if (null == tmHouseInfo) {
+            if("t-kZUcUeX".equals(sceneCode) || "t-VJjZMUl".equals(sceneCode)
+                    || "t-pnj0IJX".equals(sceneCode) || "t-XtYfLCO".equals(sceneCode)){
+                queryWrapper.orderByDesc("last_modify_datetime");
+                //自营产品,前端可能带上错误的roomId,则导致捞取不到数据
+                QueryWrapper<TmHouseInfo> newQuery = new QueryWrapper<>();
+                newQuery.eq("scene_num", sceneCode);
+                newQuery.orderByDesc("last_modify_datetime");
+                newQuery.eq("enable", 1);
+                newQuery.last("limit 1");
+                tmHouseInfo = tmHouseInfoDao.selectOne(newQuery);
+                if(null == tmHouseInfo){
+                    //设置默认经纪人的数据
+                    tmHouseInfo = getDefaultHouse();
+                }
+            }else{
+                //设置默认经纪人的数据
+                tmHouseInfo = getDefaultHouse();
+            }
+        }
+        Instant stepOneEnd = Instant.now();
+        long stepOneDuration = Duration.between(stepOneStart , stepOneEnd).toMillis();
+        log.info("======={}=============1、捞取房源数据耗时:{}===================" , "获取房源阶段" , stepOneDuration);
+        //覆盖推荐房源字段
+        Instant stepTwoStart = Instant.now();
+        List<TmHouseInfo> recList = getRecommends(tmHouseInfo);
+        tmHouseInfo.setRecommendHouses(JSON.toJSONString(recList));
+        Instant stepTwoEnd = Instant.now();
+        long stepTwoDuration = Duration.between(stepTwoStart , stepTwoEnd).toMillis();
+        log.info("========{}============2、生成推荐房源数据耗时:{}===================" ,"获取房源阶段" , stepTwoDuration);
+        result.put("houseInfo", tmHouseInfo);
+        QueryWrapper<TmDeveloperAuthority> authorityQueryWrapper = new QueryWrapper<>();
+        authorityQueryWrapper.eq("app_id" , tmHouseInfo.getAppId());
+        authorityQueryWrapper.eq("enable" , 1);
+        authorityQueryWrapper.last("limit 1");
+        TmDeveloperAuthority authority = tmDeveloperAuthorityDao.selectOne(authorityQueryWrapper);
+        if(null != authority){
+            DeveloperAuthorityRspDto authorityRspDto = new DeveloperAuthorityRspDto();
+            BeanUtils.copyProperties(authority , authorityRspDto);
+            result.put("authority", authorityRspDto);
+        }else{
+            log.warn("开发者[{}]没有配置权限,无需返回权限配置");
+        }
+        return Result.success("请求结束", result);
+    }
+
+    private TmHouseInfo getDefaultHouse(){
+        //设置默认经纪人的数据
+        TmHouseInfo tmHouseInfo = new TmHouseInfo();
+        tmHouseInfo.setAgencyName("梁经纪");
+        tmHouseInfo.setAgencyStore("唐家店");
+        tmHouseInfo.setAgencyTag("金牌经纪人");
+        tmHouseInfo.setAgencyHalfYearVolume(30);
+        tmHouseInfo.setAgencyDealAverage(20.100);
+        tmHouseInfo.setAgencyRecentRecommend(20);
+        tmHouseInfo.setAgnencyPhone("18666146677");
+        tmHouseInfo.setAgencyAvatar("https://houseoss.4dkankan.com/4dHouse/admin/upload/20200613164_643.png");
+        tmHouseInfo.setAgencyPassImage("https://houseoss.4dkankan.com/4dHouse/admin/upload/20200613161_655.jpg");
+        tmHouseInfo.setAgencyTagImage("https://houseoss.4dkankan.com/4dHouse/admin/icon/gold.svg");
+
+        tmHouseInfo.setHouseTitle("四维时代(示例)");
+        tmHouseInfo.setHouseId("10044206a85a89befda1604041890458");
+        tmHouseInfo.setHouseReferencePrice(new BigDecimal(9990000.00));
+        tmHouseInfo.setHouseType("5室5厅");
+        tmHouseInfo.setHouseArea(new Double(999.00));
+        tmHouseInfo.setHouseOrientation("正南");
+        tmHouseInfo.setEstateId("10056d40d3bb1377df91604041731341");
+        tmHouseInfo.setEstateReferenceAveragePrice(new BigDecimal(99999.00));
+        tmHouseInfo.setEarlistHandOver(LocalDate.now());
+        tmHouseInfo.setOnSaleTime(LocalDate.now());
+        tmHouseInfo.setEstateDeveloper("港湾一号");
+        tmHouseInfo.setEstatePeriodInt(70);
+        tmHouseInfo.setEstateAddress("港湾大道南");
+        tmHouseInfo.setEstateIntroduceVideo("https://houseoss.4dkankan.com/domain/4dhouse/big-0_x264.mp4");
+        tmHouseInfo.setEstateImages("{\"presale\":[],\"land\":[],\"land_use\":[],\"engineering\":[],\"start\":[],\"sand_table\":[],\"location\":[],\"reality\":[\"https://houseoss.4dkankan.com/4dHouse/admin/upload/2083_185.jpg\",\"https://houseoss.4dkankan.com/4dHouse/admin/upload/2083_193.jpg\",\"https://houseoss.4dkankan.com/4dHouse/admin/upload/2083_195.jpg\"],\"matching\":[],\"project\":[]}");
+        tmHouseInfo.setEstateCoverImage("https://houseoss.4dkankan.com/4dHouse/admin/upload/2083_185.jpg");
+        tmHouseInfo.setEstateVideoCoverImage("https://houseoss.4dkankan.com/domain/4dhouse/big-0_x264.jpg");
+        tmHouseInfo.setEstateLatitude(new BigDecimal(113.600484));
+        tmHouseInfo.setEstateLongitude(new BigDecimal(22.364160));
+        tmHouseInfo.setWxAqrCode("https://houseoss.4dkankan.com/domain/4dhouse/10044206a85a89befda1604041890458_QRCode.png");
+        return tmHouseInfo;
+    }
+
+    private List<TmHouseInfo> getRecommends(TmHouseInfo houseInfo) {
+        List<TmHouseInfo> houseInfoList = new ArrayList<>();
+        if (null != houseInfo) {
+            QueryWrapper<TmHouseRecommend> recommendQueryWrapper = new QueryWrapper<>();
+            recommendQueryWrapper.eq("scene_num", houseInfo.getSceneNum());
+            //TODO:这里去掉这个过滤,后面看看跟经纪人绑定的推荐房源如何处理
+//            recommendQueryWrapper.eq("agency_id", houseInfo.getAgencyId());
+            recommendQueryWrapper.eq("enable", 1);
+            recommendQueryWrapper.last("limit 50");
+            List<TmHouseRecommend> houseRecommendList = tmHouseRecommendDao.selectList(recommendQueryWrapper);
+
+            if (!CollectionUtils.isEmpty(houseRecommendList)) {
+                for (TmHouseRecommend recommend : houseRecommendList) {
+                    QueryWrapper<TmHouseInfo> queryWrapper = new QueryWrapper<>();
+                    queryWrapper.eq("scene_num", recommend.getRecommendSceneNum());
+                    queryWrapper.last("limit 1");
+                    TmHouseInfo tmHouseInfo = tmHouseInfoDao.selectOne(queryWrapper);
+                    if (null != tmHouseInfo) {
+                        houseInfoList.add(tmHouseInfo);
+                    }
+                }
+            }
+        }
+        return houseInfoList;
+    }
+
+    @ApiOperation(value = "4维内部请求推荐房源详情")
+    @ResponseBody
+    @GetMapping(value = "/getRecommend")
+    public Result<TmHouseInfo> getRecommendHouseDetail(@RequestParam(value = "scene_code") String sceneCode,
+                                                       @RequestParam(value = "user_id") String userId,
+                                                       @RequestParam(value = "terminal_type") String terminalType) {
+
+        if (StringUtils.isBlank(sceneCode)) {
+            throw new CommonBaseException(ResultCodeEnum.D3001);
+        }
+
+        log.info("上送的场景码为:{},终端类型为:{}", sceneCode, terminalType);
+        QueryWrapper<TmHouseRecommend> recommendQueryWrapper = new QueryWrapper<>();
+        recommendQueryWrapper.eq("scene_num", sceneCode);
+        recommendQueryWrapper.last("limit 5");
+        List<TmHouseRecommend> houseRecommendList = tmHouseRecommendDao.selectList(recommendQueryWrapper);
+        List<TmHouseInfo> houseInfoList = new ArrayList<>();
+        if (!CollectionUtils.isEmpty(houseRecommendList)) {
+            for (TmHouseRecommend recommend : houseRecommendList) {
+                QueryWrapper<TmHouseInfo> queryWrapper = new QueryWrapper<>();
+                queryWrapper.eq("scene_num", recommend.getRecommendSceneNum());
+                queryWrapper.last("limit 1");
+                TmHouseInfo tmHouseInfo = tmHouseInfoDao.selectOne(queryWrapper);
+                if (null != tmHouseInfo) {
+                    houseInfoList.add(tmHouseInfo);
+                }
+            }
+        }
+        return Result.success("请求结束", houseInfoList);
+    }
+
+
+    @ApiOperation(value = "4维内部请求-微信推送消息通知")
+    @ResponseBody
+    @GetMapping(value = "/wxSubscribe")
+    public Result<TmHouseInfo> subscribeNotification(@RequestParam(value = "scene_code") String sceneCode,
+                                                     @RequestParam(value = "user_id") String userId,
+                                                     @RequestParam(value = "agency_user_id") String agencyUserId,
+                                                     @RequestParam(value = "link") String link,
+                                                     @RequestParam(value = "terminal_type") String terminalType) {
+        if (!StringUtils.isNoneBlank(sceneCode, userId, agencyUserId , terminalType , link)) {
+            throw new CommonBaseException(ResultCodeEnum.D3001);
+        }
+
+        QueryWrapper<TmHouseInfo> houseInfoQueryWrapper = new QueryWrapper<>();
+        houseInfoQueryWrapper.eq("scene_num" , sceneCode);
+        houseInfoQueryWrapper.last("limit 1");
+        TmHouseInfo tmHouseInfo = tmHouseInfoDao.selectOne(houseInfoQueryWrapper);
+        if(null == tmHouseInfo){
+            throw new CommonBaseException(ResultCodeEnum.D101 , "找不到房源信息");
+        }
+
+        QueryWrapper<TmDeveloperAuthority> developerQueryWrapper = new QueryWrapper<>();
+        developerQueryWrapper.eq("app_id" , tmHouseInfo.getAppId());
+        developerQueryWrapper.eq("enable" , 1);
+        developerQueryWrapper.last("limit 1");
+        TmDeveloperAuthority developerAuthority  = tmDeveloperAuthorityDao.selectOne(developerQueryWrapper);
+        if(StringUtils.isBlank(developerAuthority.getCallBackUrl())){
+            throw new CommonBaseException(ResultCodeEnum.D101 , "回调地址为空,请联系客户配置");
+        }
+
+        Map<String , Object> data = new HashMap<>();
+        //推送消息当前支持用户发送给经纪人
+        data.put("fromId" , userId);
+        data.put("toId" , agencyUserId);
+        data.put("appId" , developerAuthority.getAppId());
+        data.put("sceneNum" , sceneCode);
+        data.put("link" , link);
+        if(StringUtils.isNotBlank(tmHouseInfo.getCustomContent())){
+            data.put("customContent" , tmHouseInfo.getCustomContent());
+        }
+        LocalDateTime now = LocalDateTime.now();
+        data.put("time" , now);
+        String url = developerAuthority.getCallBackUrl();
+        url += "/4dkankan/house/notify";
+        String result = "";
+        if(StringUtils.equals("Y" , developerAuthority.getAppendNoticeBody())){
+            //POST请求拼接参数到url上
+            url += "?fromId=" + userId + "&toId=" + agencyUserId + "&appId="
+                    + developerAuthority.getAppId() + "&sceneNum=" + sceneCode +
+                    "&link=" + link + "&time" + now;
+            if(StringUtils.isNotBlank(tmHouseInfo.getCustomContent())){
+                log.info("包含自定义字段:{}" , tmHouseInfo.getCustomContent());
+                Map<String ,Object> customMap = JSON.parseObject(tmHouseInfo.getCustomContent());
+                if(null != customMap){
+                    try {
+                        url += "&customContent=" + URLEncoder.encode(JSON.toJSONString(customMap) , "UTF-8");
+                    } catch (UnsupportedEncodingException e) {
+                        log.error("房源信息中客户自定义的字段执行url-encode出现异常:{}"  , e);
+                    }
+
+                }
+            }
+        }
+
+        log.info("请求回调的地址为:{},请求的内容为:{}" , url , JSON.toJSONString(data));
+        result = HttpClientUtil.doPostJson(url , JSON.toJSONString(data));
+        log.info("回调方返回结果为:{}" , result);
+        Result resObj = JSONObject.parseObject(result , Result.class);
+
+        return resObj;
+    }
+
+    @ApiOperation(value = "4维内部请求-语音同屏通知")
+    @ResponseBody
+    @GetMapping(value = "/voiceNotify")
+    public Result<TmHouseInfo> voiceNotification(@RequestParam(value = "scene_code") String sceneCode,
+                                                     @RequestParam(value = "user_id") String userId,
+                                                     @RequestParam(value = "agency_user_id") String agencyUserId,
+                                                     @RequestParam(value = "terminal_type") String terminalType) {
+        if (!StringUtils.isNoneBlank(sceneCode, userId, agencyUserId , terminalType)) {
+            throw new CommonBaseException(ResultCodeEnum.D3001);
+        }
+
+        QueryWrapper<TmHouseInfo> houseInfoQueryWrapper = new QueryWrapper<>();
+        houseInfoQueryWrapper.eq("scene_num" , sceneCode);
+        houseInfoQueryWrapper.last("limit 1");
+        TmHouseInfo tmHouseInfo = tmHouseInfoDao.selectOne(houseInfoQueryWrapper);
+        if(null == tmHouseInfo){
+            throw new CommonBaseException(ResultCodeEnum.D101 , "找不到房源信息");
+        }
+
+        QueryWrapper<TmDeveloper> developerQueryWrapper = new QueryWrapper<>();
+        developerQueryWrapper.eq("app_id" , tmHouseInfo.getAppId());
+        developerQueryWrapper.last("limit 1");
+        TmDeveloper tmDeveloper = tmDeveloperDao.selectOne(developerQueryWrapper);
+        if(StringUtils.isBlank(tmDeveloper.getCallBackUrl())){
+            throw new CommonBaseException(ResultCodeEnum.D101 , "回调地址为空,请联系客户配置");
+        }
+        Map<String , Object> data = new HashMap<>();
+        //推送消息当前支持用户发送给经纪人
+        data.put("fromId" , userId);
+        data.put("toId" , agencyUserId);
+        data.put("appid" , tmDeveloper.getAppId());
+        data.put("sceneNum" , sceneCode);
+        data.put("time" , LocalDateTime.now());
+        String url = tmDeveloper.getCallBackUrl();
+        url += "/4dkankan/house/voice";
+        log.info("请求回调的地址为:{}" , url);
+        String result = HttpClientUtil.doPostJson(url , JSON.toJSONString(data));
+
+        Result resObj = JSONObject.parseObject(result , Result.class);
+
+        return resObj;
+    }
+
+    @ApiOperation(value = "补存量的roomId的数据")
+    @ResponseBody
+    @GetMapping(value = "/packRoomId")
+    public Result voiceNotification() {
+
+        QueryWrapper<TmHouseInfo> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("enable" , 1);
+        queryWrapper.groupBy("communicate_room_id");
+        List<TmHouseInfo> list = tmHouseInfoDao.selectList(queryWrapper);
+        if(!CollectionUtils.isEmpty(list)){
+            for(TmHouseInfo houseInfo : list){
+                if(StringUtils.isNotBlank(houseInfo.getCommunicateRoomId())){
+                    QueryWrapper<TmRoomIdLog> roomIdLogQueryWrapper = new QueryWrapper<>();
+                    roomIdLogQueryWrapper.eq("communicate_room_id" , houseInfo.getCommunicateRoomId());
+                    roomIdLogQueryWrapper.eq("enable" , 1);
+                    roomIdLogQueryWrapper.last("limit 1");
+                    TmRoomIdLog tmRoomIdLog = tmRoomIdLogDao.selectOne(roomIdLogQueryWrapper);
+                    if(null != tmRoomIdLog){
+                        if(StringUtils.isBlank(tmRoomIdLog.getSceneNum()) || StringUtils.isBlank(tmRoomIdLog.getCommunicateRoomId())){
+                            tmRoomIdLog.setCommunicateRoomId(houseInfo.getCommunicateRoomId());
+                            tmRoomIdLog.setSceneNum(houseInfo.getSceneNum());
+                            tmRoomIdLog.setUpdateTime(LocalDateTime.now());
+                            UpdateWrapper<TmRoomIdLog> updateWrapper = new UpdateWrapper<>();
+                            updateWrapper.eq("log_id" , tmRoomIdLog.getLogId());
+                            updateWrapper.last("limit 1");
+                            int update = tmRoomIdLogDao.update(tmRoomIdLog , updateWrapper);
+                            if(update != 1){
+                                log.info("更新房源的[{}]的roomId失败" , houseInfo.getHouseId());
+                            }
+                        }
+                        continue;
+                    }
+                    tmRoomIdLog = new TmRoomIdLog();
+                    tmRoomIdLog.setLogId(UUidGenerator.generatorUuid(IdStarterEnum.DEFAULT.getStarter()));
+                    tmRoomIdLog.setCommunicateRoomId(houseInfo.getCommunicateRoomId());
+                    tmRoomIdLog.setEnable(1);
+                    tmRoomIdLog.setSceneNum(houseInfo.getSceneNum());
+                    tmRoomIdLog.setCreateTime(LocalDateTime.now());
+                    tmRoomIdLog.setUpdateTime(LocalDateTime.now());
+                    int insert = tmRoomIdLogDao.insert(tmRoomIdLog);
+                    if(insert != 1){
+                        log.error("插入houseId={}的roomId记录失败", houseInfo.getHouseId());
+                    }
+                }
+            }
+        }
+
+        return Result.success();
+    }
+
+
+}

+ 25 - 0
4dkankan-house-api/src/main/java/house/api/controller/TmDeveloperController.java

@@ -0,0 +1,25 @@
+package house.api.controller;
+
+
+import io.swagger.annotations.Api;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author abner
+ * @since 2020-06-04
+ */
+@Api(description = "开放api开发者管理相关接口")
+@Controller
+@RequestMapping("/base/tmDeveloper")
+@Log4j2
+public class TmDeveloperController {
+
+
+}
+

+ 636 - 0
4dkankan-house-api/src/main/java/house/api/controller/TmHouseInfoController.java

@@ -0,0 +1,636 @@
+package house.api.controller;
+
+
+import api.common.enums.IdStarterEnum;
+import api.common.enums.ResultCodeEnum;
+import api.common.exception.CommonBaseException;
+import api.common.model.CommonKey;
+import api.common.model.Result;
+import api.common.utils.DataUtils;
+import api.common.utils.JedisUtil;
+import api.common.utils.SHAUtils;
+import api.common.utils.UUidGenerator;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import house.api.base.dao.TmDeveloperDao;
+import house.api.base.dao.TmHouseInfoDao;
+import house.api.base.dao.TmHouseRecommendDao;
+import house.api.base.dao.TmRoomIdLogDao;
+import house.api.base.entity.TmDeveloper;
+import house.api.base.entity.TmHouseInfo;
+import house.api.base.entity.TmHouseRecommend;
+import house.api.base.entity.TmRoomIdLog;
+import house.api.enums.DeveloperTerminalType;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Controller;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.util.*;
+
+/**
+ * <p>
+ * 前端控制器
+ * </p>
+ *
+ * @author abner
+ * @since 2020-06-04
+ */
+
+@Log4j2
+@Api(description = "开放api房源数据格式化相关接口")
+@Controller
+@RequestMapping("/api/vrhouse")
+public class TmHouseInfoController {
+
+
+    @Autowired
+    private TmHouseInfoDao tmHouseInfoDao;
+
+    @Autowired
+    private TmDeveloperDao tmDeveloperDao;
+
+    @Autowired
+    private TmHouseRecommendDao tmHouseRecommendDao;
+
+    @Autowired
+    private TmRoomIdLogDao tmRoomIdLogDao;
+
+    @Value("${4dkankan.host.url}")
+    private String redirectVrUrl;
+
+    private static String SALT = "4dage";
+    private static String HOUSE_INFO_KEY = "houseInfo";
+    private static String REQUEST_BODY_STR_KEY = "reqBodyStr";
+    public static String SCENE_NUM_KEY = "SCENE_NUM";
+
+
+    @ApiOperation(value = "带看数据格式化接口")
+    @ResponseBody
+    @PostMapping(value = "/format")
+    @Transactional(rollbackFor = Exception.class)
+    public Result getSceneWithData(HttpServletRequest request, HttpServletResponse response) {
+
+        Instant totalStart = Instant.now();
+        String appId = request.getParameter(CommonKey.APP_ID);
+        String token = request.getParameter(CommonKey.TOKEN);
+        String sign = request.getParameter(CommonKey.SIGN);
+        Long timeStamp = DataUtils.getLongReturnNullIfNotExit(request.getParameter(CommonKey.TIME_STAMP));
+        log.info("获取到的appId={} ,token={} , sign={} , timeStamp={}", appId, token, sign, timeStamp);
+
+        if (!StringUtils.isNoneBlank(appId, token, sign)) {
+            throw new CommonBaseException(ResultCodeEnum.D3004, "appId、token、sign都不能为空");
+        }
+        if (null == timeStamp) {
+            throw new CommonBaseException(ResultCodeEnum.D3004, "缺失时间戳");
+        }
+        Instant stepOneStart = Instant.now();
+        //读取请求输入io流,解析houseInfo和请求体的字符串用于校验
+        Map<String ,Object> map = getAndCheckHouseInfo(request);
+        TmHouseInfo houseInfo = (TmHouseInfo) map.get(HOUSE_INFO_KEY);
+        String requestBodyStr = (String) map.get(REQUEST_BODY_STR_KEY);
+        //校验数据是否被篡改
+        checkDataModify(requestBodyStr , timeStamp , sign ,appId);
+
+        Instant stepOneEnd = Instant.now();
+        long stepOneDuration = Duration.between(stepOneStart , stepOneEnd).toMillis();
+        log.info("======{}========1、校验数据是否被篡改耗时:{}=============" ,houseInfo.getSceneNum() , stepOneDuration);
+        //从缓存中获取或者更新到db再更新到缓存
+        String roomId = houseInfo.getCommunicateRoomId();
+        if(StringUtils.isBlank(roomId)){
+            roomId = UUidGenerator.generatorUuid(IdStarterEnum.ROOM_ID.getStarter());
+            logRoomIdLog(roomId , houseInfo.getSceneNum());
+        }else{
+            //检查roomId是否合法
+            checkRoomId(roomId);
+        }
+        log.info("上送的二维码为:{}" , houseInfo.getWxAqrCode());
+        Instant stepTwoStart = Instant.now();
+        //更新db数据或者更新缓存
+        int insert = doDataCachedAndUpdate(houseInfo , appId , roomId);
+        Instant stepTwoEnd = Instant.now();
+        long stepTwoDuration = Duration.between(stepTwoStart , stepTwoEnd).toMillis();
+        log.info("======{}========2、插入房源数据耗时:{}=============" ,houseInfo.getSceneNum() , stepTwoDuration);
+        if (insert == 1) {
+            String redirectUrl = genVrLink(houseInfo);
+            Map<String, Object> resultMap = new HashMap<>();
+            resultMap.put("vrLink", redirectUrl);
+            resultMap.put("roomId", roomId);
+            //这里插入推荐房源,如果有
+            Instant stepThreeStart = Instant.now();
+            insertRecommends(houseInfo , appId ,roomId);
+            Instant stepThreeEnd = Instant.now();
+            long stepThreeDuration = Duration.between(stepThreeStart , stepThreeEnd).toMillis();
+            log.info("======={}========3、插入房源的推荐房源数据耗时:{}=============" ,houseInfo.getSceneNum() , stepThreeDuration);
+            Instant totalEnd = Instant.now();
+            long totalDuration = Duration.between(totalStart , totalEnd).toMillis();
+            log.info("======={}========格式化数据总耗时:{}=============" ,houseInfo.getSceneNum() , totalDuration);
+            return Result.success("成功", resultMap);
+        } else {
+            //理论上不会到这个分支
+            Instant totalEnd = Instant.now();
+            long totalDuration = Duration.between(totalStart , totalEnd).toMillis();
+            log.info("======={}========格式化数据总耗时:{}=============" ,houseInfo.getSceneNum() , totalDuration);
+            return Result.failure("数据提交失败,请重试");
+        }
+
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void insertRecommends(TmHouseInfo houseInfo , String appId , String roomId){
+        if(null != houseInfo && StringUtils.isNotBlank(houseInfo.getRecommendHouses())){
+            List<TmHouseInfo> recommendList = JSON.parseArray(houseInfo.getRecommendHouses() , TmHouseInfo.class);
+            if(!CollectionUtils.isEmpty(recommendList)){
+
+                for (TmHouseInfo recHouse : recommendList){
+                    if(StringUtils.isBlank(recHouse.getSceneNum())){
+                        log.warn("房源[{}]的推荐房源[{}]的场景码为空,不落库,跳过" , houseInfo.getHouseId() , recHouse.getHouseId());
+                        continue;
+                    }
+                    //1、先插入推荐房源
+                    int recInsert = doDataCachedAndUpdate(recHouse , appId , roomId);
+                    if(recInsert != 1){
+                        log.error("插入房源[{}]的推荐房源[{}]失败,将回滚" , houseInfo.getHouseId() , recHouse.getHouseId());
+                        throw new CommonBaseException(ResultCodeEnum.D101 , "插入推荐房源失败");
+                    }else{
+                        //这里插入房源和推荐房源的关联关系
+                        boolean needInsert = false;
+                        if(StringUtils.isNoneBlank(houseInfo.getAgencyId() , recHouse.getAgencyId())){
+                            if(StringUtils.equals(houseInfo.getAgencyId() , recHouse.getAgencyId())){
+                                ///2、先插入单向 A->B
+                                insertHouseRelation(houseInfo , recHouse);
+
+                                //3、插入双向 , B->A
+                                insertHouseRelation(recHouse , houseInfo);
+                                needInsert = true;
+                            }
+                        }
+                        if(!needInsert){
+                            log.warn("房源[{}]和推荐房源[{}]的经纪人不一样->[{}]-[{}],不生成关联关系" , houseInfo.getHouseId() ,recHouse.getHouseId(),
+                                    houseInfo.getAgencyId() , recHouse.getAgencyId());
+                        }
+
+                    }
+                }
+                //4、除了跟主房源建立固关联关系,这五个推荐房源还要相互建立关联关系
+                //TODO:这里可以优化下,这个时间复杂度是0(N^2)了
+                for(int i = 0 ; i < recommendList.size() ; i++){
+                    for(int j= i + 1 ; j < recommendList.size(); j++){
+                        boolean needInsert = false;
+                        if(StringUtils.isNoneBlank(recommendList.get(i).getAgencyId() , recommendList.get(j).getAgencyId())){
+                            if(StringUtils.equals(recommendList.get(i).getAgencyId() , recommendList.get(j).getAgencyId())){
+                                //A->B
+                                insertHouseRelation(recommendList.get(i) , recommendList.get(j));
+                                //B->A
+                                insertHouseRelation(recommendList.get(j) , recommendList.get(i));
+                                needInsert = true;
+                            }
+                        }
+                        if(!needInsert){
+                            log.warn("房源[{}]和推荐房源[{}]的经纪人不一样->[{}]-[{}],不生成关联关系" , recommendList.get(i).getHouseId() ,recommendList.get(j).getHouseId(),
+                                    recommendList.get(i).getAgencyId() , recommendList.get(j).getAgencyId());
+                        }
+
+                    }
+                }
+
+            }
+        }
+    }
+
+    private void checkRoomId(String roomId){
+        QueryWrapper<TmRoomIdLog> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("communicate_room_id" , roomId);
+        queryWrapper.eq("enable" , 1);
+        List<TmRoomIdLog> list = tmRoomIdLogDao.selectList(queryWrapper);
+        if(CollectionUtils.isEmpty(list)){
+            throw new CommonBaseException(ResultCodeEnum.D101 , "非法room id");
+        }
+        if(list.size() > 1){
+            throw new CommonBaseException(ResultCodeEnum.D101 , "一个roomId只能绑定一个场景");
+        }
+        log.info("roomId:{}合法" , roomId);
+    }
+
+
+    @Transactional(rollbackFor = Exception.class)
+    public void insertHouseRelation(TmHouseInfo mainHouse , TmHouseInfo recommendHouse){
+        if(null == mainHouse || null == recommendHouse){
+            log.error("参数不够,无法建立关联关系");
+        }
+        QueryWrapper<TmHouseRecommend> recommendQueryWrapper = new QueryWrapper<>();
+        recommendQueryWrapper.eq("scene_num" , mainHouse.getSceneNum());
+        recommendQueryWrapper.eq("recommend_scene_num" , recommendHouse.getSceneNum());
+        recommendQueryWrapper.eq("enable" , 1);
+        recommendQueryWrapper.last("limit 1");
+        TmHouseRecommend houseRecommend = tmHouseRecommendDao.selectOne(recommendQueryWrapper);
+        if(null != houseRecommend){
+            log.info("场景码为:[{}]的房源和场景码为:[{}]的房源关联关系已经绑定,无需重复绑定" , mainHouse.getSceneNum() , recommendHouse.getSceneNum());
+        }else{
+            //新增关联关系
+            if(!StringUtils.isNoneBlank(mainHouse.getSceneNum() , recommendHouse.getSceneNum())){
+                log.warn("房源[{}]和房源[{}]的场景有一个为空:[{}]-[{}]" , mainHouse.getHouseId() ,recommendHouse.getHouseId() , mainHouse.getSceneNum() , recommendHouse.getSceneNum());
+                return;
+            }
+            TmHouseRecommend recommend = new TmHouseRecommend();
+            recommend.setRelationNo(UUidGenerator.generatorUuid(IdStarterEnum.RELATION.getStarter()));
+            recommend.setEnable(1);
+            recommend.setSceneNum(mainHouse.getSceneNum());
+            recommend.setRecommendSceneNum(recommendHouse.getSceneNum());
+            recommend.setAgencyId(mainHouse.getAgencyId());
+            recommend.setCreateTime(LocalDateTime.now());
+            recommend.setLastModifyDatetime(LocalDateTime.now());
+            int recommendInsert = tmHouseRecommendDao.insert(recommend);
+            if(recommendInsert != 1){
+                log.error("插入主房源:[{}]和推荐房源[{}]的关联关系失败:", mainHouse.getSceneNum() , recommendHouse.getSceneNum());
+                throw new CommonBaseException(ResultCodeEnum.D101 , "插入房源和推荐房源关联关系失败");
+            }
+        }
+    }
+    @Transactional(rollbackFor = Exception.class)
+    public int doDataCachedAndUpdate(TmHouseInfo houseInfo , String appId , String roomId){
+        int insert = -1;
+        if (!JedisUtil.exists(SCENE_NUM_KEY + ":" + houseInfo.getSceneNum() + "-" + roomId)) {
+            //缓存中没有此场景的数据,则需要读表,,然后再比对数据是否需要update db,再更新redis缓存
+            log.info("缓存中不存在key为:{}的数据" , (SCENE_NUM_KEY + ":" + houseInfo.getSceneNum() + "-" + roomId));
+            insert = updateOrInsertHouseInfo(houseInfo, appId , roomId);
+
+        } else {
+            log.info("缓存存在数据,key={}" , (SCENE_NUM_KEY + ":" + houseInfo.getSceneNum() + "-" + roomId));
+            //缓存中有此场景码的缓存,将校验数据是否有更新,如果没更新,则不更新db
+            String redisBodyStr = JedisUtil.getStringValue(SCENE_NUM_KEY + ":" + houseInfo.getSceneNum() + "-" + roomId);
+            //先暂存上送的houseInfo数据
+            TmHouseInfo toCompare = houseInfo;
+            /**
+             * 剔除request_id,create_time,last_modify_datetime,appid,communication_room_id字段
+             * 因为缓存中的这些字段都是被剔除的了
+             * **/
+            initCompareHouseInfo(toCompare , null);
+            //比较redis缓存中的数据和上送的数据是否一样,一样则表示没有数据变更,无需刷新到数据控中
+            if (isDataModified(redisBodyStr, JSON.toJSONString(toCompare))) {
+                //数据有变更了,需要更新db和缓存
+                log.info("数据有修改,需要更新db和redis缓存的数据");
+                insert = updateOrInsertHouseInfo(houseInfo, appId , roomId);
+            } else {
+                log.info("数据无修改,只更新缓存即可");
+                insert = 1;
+                //缓存续期5个小时
+                JedisUtil.expire(SCENE_NUM_KEY + ":" + houseInfo.getSceneNum() + "-" + roomId, 18000);
+            }
+
+        }
+        return insert;
+    }
+
+    private Map<String ,Object> getAndCheckHouseInfo(HttpServletRequest request){
+        String requestBodyStr = "";
+        try {
+            InputStreamReader inputStreamReader = new InputStreamReader(request.getInputStream());
+            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+            requestBodyStr = IOUtils.toString(bufferedReader);
+        } catch (IOException e) {
+            log.error("读取http request的body出现异常:{}", e);
+            throw new CommonBaseException(ResultCodeEnum.D3008);
+        }
+        log.info("收到的请求体为:{}", requestBodyStr);
+        if (StringUtils.isBlank(requestBodyStr)) {
+            throw new CommonBaseException(ResultCodeEnum.D3004, "请求数据格式有误");
+        }
+
+        TmHouseInfo houseInfo = JSONObject.parseObject(requestBodyStr, TmHouseInfo.class);
+        if (null == houseInfo) {
+            throw new CommonBaseException(ResultCodeEnum.D3004, "请求数据格式有误");
+        }
+
+        if (StringUtils.isBlank(houseInfo.getSceneNum())) {
+            throw new CommonBaseException(ResultCodeEnum.D3004, "场景码不能为空");
+        }
+        Map<String ,Object> result = new HashMap<>();
+        result.put(HOUSE_INFO_KEY , houseInfo);
+        result.put(REQUEST_BODY_STR_KEY , requestBodyStr);
+        return result;
+    }
+
+    private void checkDataModify(String requestBodyStr ,Long timeStamp , String sign , String appId){
+        //校验数据是否被篡改
+        //TODO:这里需要改成从网关获取
+        QueryWrapper<TmDeveloper> developerQueryWrapper = new QueryWrapper<>();
+        developerQueryWrapper.eq("app_id", appId);
+        developerQueryWrapper.last("limit 1");
+        TmDeveloper tmDeveloper = tmDeveloperDao.selectOne(developerQueryWrapper);
+
+        if (tmDeveloper == null) {
+            throw new CommonBaseException(ResultCodeEnum.D3006);
+        }
+
+        Map<String , Object> requestDataMap = JSONObject.parseObject(requestBodyStr);
+        if(null == requestDataMap){
+            log.error("请求数据转换成map失败");
+            throw new CommonBaseException(ResultCodeEnum.D101);
+        }
+        String enCodeBodyStr = "";
+
+
+        Map<String , Object> sortMap = sortMapByKey(requestDataMap);
+        enCodeBodyStr = JSONObject.toJSONString(sortMap);
+
+        String unEnCodeSign = enCodeBodyStr + tmDeveloper.getAppSecret() + timeStamp;
+
+//        log.info("待加密的数据为:{}", unEnCodeSign);
+        String enCodeStr = SHAUtils.getSHA256(unEnCodeSign);
+        log.info("解析出来的签名:{},上送的签名:{}", enCodeStr, sign);
+        if (!StringUtils.equals(enCodeStr, sign)) {
+            throw new CommonBaseException(ResultCodeEnum.D3009);
+        }
+    }
+
+    /**
+     *  根据map的key进行字典升序排序
+     * @param map
+     * @return map
+     */
+    public  Map<String, Object> sortMapByKey(Map<String, Object>map) {
+        Map<String, Object> treemap = new TreeMap<String, Object>(map);
+        List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(treemap.entrySet());
+        Collections.sort(list, new Comparator<Map.Entry<String, Object>>() {
+            @Override
+            public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
+                return StringUtils.compare(o1.getKey() , o2.getKey());
+            }
+        });
+        return treemap;
+    }
+
+    /**
+     * 校验上送的数据与数据库中的数据查看是否数据有更新,
+     * 如有,则更新db的数据,并更新redis缓存的数据
+     */
+    private int updateOrInsertHouseInfo(TmHouseInfo latestHouseInfo, String appId , String roomId) {
+        int insert = -1;
+        //无需刷新缓存的情况只有一个:用户做了删除房源的操作,在更新房源之前,做了缓存的清理,所以无需更新缓存
+        boolean noNeedUpdateRedis = false;
+        if (null != latestHouseInfo) {
+            //先存下未修改的数据,例如last_modify_datetime和request_id字段的请求数据,用于缓存
+            TmHouseInfo tmpHouseInfo = latestHouseInfo;
+            //只捞取有效的房源信息,enable= 1
+//            TmHouseInfo dbHouseInfo = getHouseInfoFromDb(latestHouseInfo.getSceneNum(), null);
+            TmHouseInfo dbHouseInfo = getHouseInfoFromDb(latestHouseInfo.getSceneNum(), roomId);
+            if (null != dbHouseInfo) {
+
+                //非第一次插入,需要确认数据是否被修改了
+
+                //db中的数据和最新上送的数据比对,查看是否有更新
+                TmHouseInfo toCompare = dbHouseInfo;
+                //剔除可变字段
+                initCompareHouseInfo(toCompare , tmpHouseInfo);
+                if (isDataModified(JSON.toJSONString(toCompare), JSON.toJSONString(tmpHouseInfo))) {
+                    //数据有变更了,需要更新db和缓存
+                    //检查上送的houseId是否和数据库中的一致,一致则表示是有效的数据,否则认为是异常数据
+                    if(!StringUtils.equals(dbHouseInfo.getHouseId() , latestHouseInfo.getHouseId())){
+                        log.error("场景码[{}]下的有效的房源为:[{}],但是上送的为:[{}]" , latestHouseInfo.getSceneNum() ,
+                                dbHouseInfo.getHouseId() , latestHouseInfo.getHouseId());
+                        throw new CommonBaseException(ResultCodeEnum.D101 , "api上的房源数据没有及时删除,数据不一致");
+                    }
+
+                    //判断是否是删除房源操作
+                    log.info("当前房源的状态为:{}" , dbHouseInfo.getEnable());
+                    if(null != latestHouseInfo.getEnable() && latestHouseInfo.getEnable() == 0){
+                        log.info("场景码[{}]将执行房源[{}]的删除操作" , latestHouseInfo.getSceneNum() , latestHouseInfo.getHouseId());
+                        //如果有缓存,则先删除缓存,后面再逻辑删除
+                        if (JedisUtil.exists(SCENE_NUM_KEY + ":" + latestHouseInfo.getSceneNum()  + "-" + roomId)) {
+                            JedisUtil.del(SCENE_NUM_KEY + ":" + latestHouseInfo.getSceneNum() + "-" + roomId);
+                        }
+                        //这次请求,无需更新缓存了
+                        noNeedUpdateRedis = true;
+                        //置空这个场景关联的推荐房源
+                        latestHouseInfo.setRecommendHouses("");
+                        //删除关联关系
+                        delRecRelationBySceneNum(latestHouseInfo.getSceneNum() , dbHouseInfo.getAgencyId());
+
+                    }else{
+                        log.info("非删除操作");
+                    }
+
+                    //经纪人id变更了
+                    if(!StringUtils.equals(dbHouseInfo.getAgencyId() , latestHouseInfo.getAgencyId())){
+                        log.info("房源[{}]关联的经纪人由[{}]更改为[{}],需要删除原来的关联关系" , dbHouseInfo.getHouseId() , dbHouseInfo.getAgencyId() , latestHouseInfo.getAgencyId());
+                       //删除旧的agencyId关联的关联关系
+                        delRecRelationBySceneNum(latestHouseInfo.getSceneNum() , dbHouseInfo.getAgencyId());
+                    }
+                    UpdateWrapper<TmHouseInfo> houseInfoQueryWrapper = new UpdateWrapper<>();
+                    houseInfoQueryWrapper.eq("scene_num", dbHouseInfo.getSceneNum());
+                    houseInfoQueryWrapper.last("limit 1");
+                    latestHouseInfo.setRequestId(dbHouseInfo.getRequestId());
+                    initUpdateHouseInfo(latestHouseInfo, dbHouseInfo.getAppId());
+                    insert = tmHouseInfoDao.update(latestHouseInfo, houseInfoQueryWrapper);
+                    if (insert != 1) {
+                        throw new CommonBaseException(ResultCodeEnum.D101, "更新houseInfo数据失败");
+                    }
+                } else {
+                    //数据无变更,只更新缓存即可
+                    log.info("数据无修改,只需要更新redis缓存的数据,并返回给调用端");
+                    insert = 1;
+                }
+
+            } else {
+                //数据库中没有数据,属于第一次插入
+                initHouseInfo(latestHouseInfo, appId , roomId);
+                insert = tmHouseInfoDao.insert(latestHouseInfo);
+                if (insert != 1) {
+                    throw new CommonBaseException(ResultCodeEnum.D101, "更新houseInfo数据失败");
+                }
+            }
+            //设置到缓存,设置缓存5个小时,这里剔除了request_id,create_time,last_modify_datetime,appid,communication_room_id字段
+            if(!noNeedUpdateRedis){
+                JedisUtil.setStringValue(SCENE_NUM_KEY + ":" + latestHouseInfo.getSceneNum() + "-" + roomId, JSON.toJSONString(tmpHouseInfo), 18000);
+            }
+
+        }
+        return insert;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void logRoomIdLog(String roomId , String sceneNum){
+        if(StringUtils.isNotBlank(roomId)){
+            TmRoomIdLog tmRoomIdLog = new TmRoomIdLog();
+            tmRoomIdLog.setLogId(UUidGenerator.generatorUuid(IdStarterEnum.DEFAULT.getStarter()));
+            tmRoomIdLog.setCommunicateRoomId(roomId);
+            tmRoomIdLog.setEnable(1);
+            tmRoomIdLog.setSceneNum(sceneNum);
+            tmRoomIdLog.setCreateTime(LocalDateTime.now());
+            tmRoomIdLog.setUpdateTime(LocalDateTime.now());
+            int insert = tmRoomIdLogDao.insert(tmRoomIdLog);
+            if(insert != 1){
+                log.error("插入roomId记录失败");
+            }
+        }
+    }
+    /**
+     * 删除指定场景码的推荐房源的关联关系
+     * **/
+    private void delRecRelationBySceneNum(String sceneNum , String agencyId){
+        if(StringUtils.isNoneBlank(sceneNum , agencyId)){
+            QueryWrapper<TmHouseRecommend> recommendQueryWrapper = new QueryWrapper<>();
+            //TODO:这里去掉这个过滤,后面看看跟经纪人绑定的推荐房源如何处理
+//            recommendQueryWrapper.eq("agency_id" , agencyId);
+            recommendQueryWrapper.or().eq("scene_num" , sceneNum);
+            recommendQueryWrapper.or().eq("recommend_scene_num" , sceneNum);
+            List<TmHouseRecommend> needDelRecList = tmHouseRecommendDao.selectList(recommendQueryWrapper);
+            if(!CollectionUtils.isEmpty(needDelRecList)){
+                for( TmHouseRecommend houseRecommend : needDelRecList){
+                    QueryWrapper<TmHouseRecommend> delRecommendQuery = new QueryWrapper<>();
+                    delRecommendQuery.eq("relation_no" , houseRecommend.getRelationNo());
+                    delRecommendQuery.last("limit 1");
+                    houseRecommend.setEnable(0);
+                    int delRecResult = tmHouseRecommendDao.update(houseRecommend , delRecommendQuery);
+                    if(delRecResult != 1){
+                        log.error("删除关联关系失败,关联id=[{}]" , houseRecommend.getRelationNo());
+                        throw new CommonBaseException(ResultCodeEnum.D101, "移除旧的关联关系失败");
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * 新增插入的时候初始化的字段
+     **/
+    private void initHouseInfo(TmHouseInfo houseInfo, String appId , String roomId) {
+        houseInfo.setRequestId(UUidGenerator.generatorUuid(IdStarterEnum.DEFAULT.getStarter()));
+        houseInfo.setCreateTime(LocalDateTime.now());
+        houseInfo.setLastModifyDatetime(LocalDateTime.now());
+        houseInfo.setAppId(appId);
+        houseInfo.setCommunicateRoomId(roomId);
+    }
+
+    private void initCompareHouseInfo(TmHouseInfo houseInfo , TmHouseInfo fromSend) {
+        if(null != houseInfo){
+            houseInfo.setRequestId(null);
+            houseInfo.setCreateTime(null);
+            houseInfo.setLastModifyDatetime(null);
+            houseInfo.setAppId(null);
+            //客户第一次提交的过来的数据是没有roomId的
+            houseInfo.setCommunicateRoomId(null);
+        }
+
+        if(null != fromSend){
+            fromSend.setRequestId(null);
+            fromSend.setCreateTime(null);
+            fromSend.setLastModifyDatetime(null);
+            fromSend.setAppId(null);
+            //客户第一次提交的过来的数据是没有roomId的
+            fromSend.setCommunicateRoomId(null);
+        }
+
+    }
+
+    /**
+     * 更新数据的时候初始化的字段
+     **/
+    private void initUpdateHouseInfo(TmHouseInfo houseInfo, String appId) {
+        houseInfo.setLastModifyDatetime(LocalDateTime.now());
+        houseInfo.setAppId(appId);
+    }
+
+    private TmHouseInfo getHouseInfoFromDb(String sceneNum, String roomId) {
+        boolean needQuery = false;
+        QueryWrapper<TmHouseInfo> houseInfoQueryWrapper = new QueryWrapper<>();
+        if (StringUtils.isNotBlank(roomId)) {
+            houseInfoQueryWrapper.eq("communicate_room_id", roomId);
+//            houseInfoQueryWrapper.eq("house_id", roomId);
+            needQuery = true;
+        }
+        if (StringUtils.isNotBlank(sceneNum)) {
+            houseInfoQueryWrapper.eq("scene_num", sceneNum);
+            needQuery = true;
+        }
+        TmHouseInfo dbHouseInfo = null;
+        if (needQuery) {
+            //只捞取enable=1未删除的房源
+            houseInfoQueryWrapper.eq("enable", 1);
+            List<TmHouseInfo> list = tmHouseInfoDao.selectList(houseInfoQueryWrapper);
+            if(!CollectionUtils.isEmpty(list)){
+                if(list.size() > 1){
+                    //一个场景码下面有多个有效房源了,属于遗产情况
+                    log.error("场景码[{}]下面有多个有效的房源信息" , sceneNum);
+                    throw new CommonBaseException(ResultCodeEnum.D101 , "一个场景码绑定了多个有效房源");
+                }else if(list.size() == 1){
+                    //理论只会有一个
+                    dbHouseInfo = list.get(0);
+                }else{
+                    log.info("场景码:{}下面再api中还没有房源" , sceneNum);
+                }
+
+            }
+
+        }
+        return dbHouseInfo;
+    }
+
+    private boolean isDataModified(String src, String target) {
+        if (!StringUtils.equals(SHAUtils.getSHA256(src + SALT), SHAUtils.getSHA256(target + SALT))) {
+            //数据有更新、修改
+            return true;
+
+        } else {
+            //数据没有修改
+            return false;
+
+        }
+    }
+
+    private String genVrLink(TmHouseInfo houseInfo) {
+        String terminalTypeStr = houseInfo.getTerminalType();
+        String userId = "";
+        DeveloperTerminalType terminalType = DeveloperTerminalType.getByType(terminalTypeStr);
+        if (null != terminalType && terminalType.equals(DeveloperTerminalType.CUSTOMER)) {
+            //用户端
+            userId = houseInfo.getUserId();
+        } else if (null != terminalType && terminalType.equals(DeveloperTerminalType.AGENT)) {
+            //经纪人端
+            userId = houseInfo.getAgencyId();
+        } else {
+//            throw new CommonBaseException(ResultCodeEnum.D3010);
+            //给默认取值
+            userId = "";
+            terminalType  = DeveloperTerminalType.CUSTOMER;
+        }
+        /**
+         * 样例:
+         * vrHouse.html?m=t-XtYfLCO&appname=vrhouse&role=customer&room_id=F8Q1&user_id=456
+         * vrHouse.html?m=t-XtYfLCO&appname=vrhouse&role=agent&room_id=F8Q1&user_id=456
+         * */
+        String redirectUrl = redirectVrUrl + houseInfo.getSceneNum() //场景码
+                + "&appname=vrhouse&role=" + terminalType.getType(); //角色名
+
+        if(StringUtils.isNotBlank(houseInfo.getCommunicateRoomId())){
+            redirectUrl +=  "&room_id=" + houseInfo.getCommunicateRoomId();//roomId
+        }
+        if(StringUtils.isNotBlank(userId)){
+            redirectUrl += "&user_id=" + userId; //userId
+        }
+        log.info("生成的vr链接为:{}", redirectUrl);
+        return redirectUrl;
+    }
+}
+

+ 40 - 0
4dkankan-house-api/src/main/java/house/api/enums/DeveloperTerminalType.java

@@ -0,0 +1,40 @@
+package house.api.enums;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/5 18:16
+ * @desciption
+ */
+public enum DeveloperTerminalType {
+    CUSTOMER("customer" , "用户端"),
+    AGENT("agent" , "经纪人端"),
+    ;
+    private String type;
+    private String desc;
+
+    DeveloperTerminalType(String type, String desc) {
+        this.type = type;
+        this.desc = desc;
+    }
+
+    public  static  DeveloperTerminalType getByType(String type){
+        if(StringUtils.isNoneBlank(type)){
+            for (DeveloperTerminalType terminalType : DeveloperTerminalType.values()){
+                if(StringUtils.equals(terminalType.getType() , type)){
+                    return terminalType;
+                }
+            }
+        }
+        return null;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 77 - 0
4dkankan-house-api/src/main/resources/application-dev.properties

@@ -0,0 +1,77 @@
+server.port=8095
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.max-file-size=500MB
+spring.servlet.multipart.max-request-size=500MB
+
+
+spring.datasource.url=jdbc:mysql://120.25.146.52:3306/4dhouse-api?serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
+spring.datasource.username=root
+spring.datasource.password=4dkk2020test%
+spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
+
+
+# 初始化大小,最小,最大
+spring.datasource.initialSize=5
+spring.datasource.minIdle=5
+spring.datasource.maxActive=30
+# 配置获取连接等待超时的时间
+spring.datasource.maxWait=60000
+# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+spring.datasource.timeBetweenEvictionRunsMillis=60000
+# 配置一个连接在池中最小生存的时间,单位是毫秒
+spring.datasource.minEvictableIdleTimeMillis=300000
+spring.datasource.validationQuery=SELECT 1 FROM DUAL
+spring.datasource.testWhileIdle=true
+spring.datasource.testOnBorrow=false
+spring.datasource.testOnReturn=false
+# 打开PSCache,并且指定每个连接上PSCache的大小
+spring.datasource.poolPreparedStatements=true
+spring.datasource.maxPoolPreparedSta;tementPerConnectionSize=20
+# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
+spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+# 合并多个DruidDataSource的监控数据
+#spring.datasource.useGlobalDataSourceStat=true
+
+# 排除一些静态资源,以提高效率
+spring.datasource.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*
+
+
+#redis
+spring.redis.database=0
+spring.redis.host=127.0.0.1
+spring.redis.port=6379
+spring.redis.password=
+# 连接超时时间 单位 ms(毫秒)
+spring.redis.timeout=3000ms
+# 连接池中的最大空闲连接,默认值也是8。
+spring.redis.jedis.pool.max-idle=50
+# 连接池中的最小空闲连接,默认值也是0。
+spring.redis.jedis.pool.min-idle=8
+# 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
+spring.redis.jedis.pool.max-active=8
+# 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException
+spring.redis.jedis.pool.max-wait=-1ms
+
+
+#四维看看的登录域名
+4dkankan.host=https://test.4dkankan.com/
+4dkankan.host.url=https://test.4dkankan.com/vrHouse.html?m=
+4dkankan.vr.house.host=http://127.0.0.1:8085
+#oss配置
+oss.point=http://oss-cn-shenzhen.aliyuncs.com
+oss.key=LTAIUrvuHqj8pvry
+oss.secrey=JLOVl0k8Ke0aaM8nLMMiUAZ3EiiqI4
+oss.bucket=4d-tjw
+#本地文件临时存放路径
+file-path=D:/open_api/developer/temp_file/
+file-downloan-host=127.0.0.1
+
+
+spring.application.name=vrhouse-api-service
+
+logging.config: classpath:log4j2.xml
+
+
+
+

+ 77 - 0
4dkankan-house-api/src/main/resources/application-prod.properties

@@ -0,0 +1,77 @@
+server.port=8095
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.max-file-size=500MB
+spring.servlet.multipart.max-request-size=500MB
+
+spring.datasource.url=jdbc:mysql://127.0.0.1:3306/4dhouse-api?serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
+spring.datasource.username=root
+spring.datasource.password=4dkankancuikuan%
+spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
+
+
+# 初始化大小,最小,最大
+spring.datasource.initialSize=5
+spring.datasource.minIdle=5
+spring.datasource.maxActive=30
+# 配置获取连接等待超时的时间
+spring.datasource.maxWait=60000
+# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+spring.datasource.timeBetweenEvictionRunsMillis=60000
+# 配置一个连接在池中最小生存的时间,单位是毫秒
+spring.datasource.minEvictableIdleTimeMillis=300000
+spring.datasource.validationQuery=SELECT 1 FROM DUAL
+spring.datasource.testWhileIdle=true
+spring.datasource.testOnBorrow=false
+spring.datasource.testOnReturn=false
+# 打开PSCache,并且指定每个连接上PSCache的大小
+spring.datasource.poolPreparedStatements=true
+spring.datasource.maxPoolPreparedSta;tementPerConnectionSize=20
+
+# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
+spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+# 合并多个DruidDataSource的监控数据
+#spring.datasource.useGlobalDataSourceStat=true
+# druid连接池监控
+spring.datasource.stat-view-servlet.login-username=admin
+spring.datasource.stat-view-servlet.login-password=admin
+# 排除一些静态资源,以提高效率
+spring.datasource.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*
+
+
+
+
+#redis
+spring.redis.database=0
+spring.redis.host=127.0.0.1
+spring.redis.port=6379
+spring.redis.password=
+# 连接超时时间 单位 ms(毫秒)
+spring.redis.timeout=3000ms
+# 连接池中的最大空闲连接,默认值也是8。
+spring.redis.jedis.pool.max-idle=50
+# 连接池中的最小空闲连接,默认值也是0。
+spring.redis.jedis.pool.min-idle=8
+# 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
+spring.redis.jedis.pool.max-active=8
+# 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException
+spring.redis.jedis.pool.max-wait=-1ms
+
+#四维看看的登录域名
+4dkankan.host=https://4dkankan.com/
+4dkankan.host.url=https://4dkankan.com/vrHouse.html?m=
+4dkankan.vr.house.host=http://127.0.0.1:8087
+
+#oss配置
+
+oss.point=http://oss-cn-shenzhen.aliyuncs.com
+oss.key=LTAIUrvuHqj8pvry
+oss.secrey=JLOVl0k8Ke0aaM8nLMMiUAZ3EiiqI4
+oss.bucket=4d-tjw
+#本地文件临时存放路径
+file-path=open_api/developer/temp_file/
+file-downloan-host=127.0.0.1
+
+spring.application.name=vrhouse-api-service
+
+logging.config: classpath:log4j2.xml

+ 72 - 0
4dkankan-house-api/src/main/resources/application-test.properties

@@ -0,0 +1,72 @@
+server.port=8080
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.max-file-size=500MB
+spring.servlet.multipart.max-request-size=500MB
+
+
+spring.datasource.url=jdbc:mysql://120.25.146.52:3306/4dhouse-api?serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8&characterSetResults=utf8
+spring.datasource.username=root
+spring.datasource.password=4dkk2020test%
+spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
+
+
+# ��ʼ����С����С�����
+spring.datasource.initialSize=5
+spring.datasource.minIdle=5
+spring.datasource.maxActive=30
+# ���û�ȡ���ӵȴ���ʱ��ʱ��
+spring.datasource.maxWait=60000
+# ���ü����òŽ���һ�μ�⣬�����Ҫ�رյĿ������ӣ���λ�Ǻ���
+spring.datasource.timeBetweenEvictionRunsMillis=60000
+# ����һ�������ڳ�����С�����ʱ�䣬��λ�Ǻ���
+spring.datasource.minEvictableIdleTimeMillis=300000
+spring.datasource.validationQuery=SELECT 1 FROM DUAL
+spring.datasource.testWhileIdle=true
+spring.datasource.testOnBorrow=false
+spring.datasource.testOnReturn=false
+# ��PSCache������ָ��ÿ��������PSCache�Ĵ�С
+spring.datasource.poolPreparedStatements=true
+spring.datasource.maxPoolPreparedSta;tementPerConnectionSize=20
+# ͨ��connectProperties��������mergeSql���ܣ���SQL��¼
+spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+# �ϲ����DruidDataSource�ļ������
+#spring.datasource.useGlobalDataSourceStat=true
+
+# �ų�һЩ��̬��Դ�������Ч��
+spring.datasource.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*
+
+
+#redis
+spring.redis.database=0
+spring.redis.host=127.0.0.1
+spring.redis.port=6379
+spring.redis.password=
+# ���ӳ�ʱʱ�� ��λ ms�����룩
+spring.redis.timeout=3000ms
+# ���ӳ��е����������ӣ�Ĭ��ֵҲ��8��
+spring.redis.jedis.pool.max-idle=50
+# ���ӳ��е���С�������ӣ�Ĭ��ֵҲ��0��
+spring.redis.jedis.pool.min-idle=8
+# �����ֵΪ-1�����ʾ�����ƣ����pool�Ѿ�������maxActive��jedisʵ�������ʱpool��״̬Ϊexhausted(�ľ�)��
+spring.redis.jedis.pool.max-active=8
+# �ȴ��������ӵ����ʱ�䣬��λ���룬Ĭ��ֵΪ-1����ʾ������ʱ����������ȴ�ʱ�䣬��ֱ���׳�JedisConnectionException
+spring.redis.jedis.pool.max-wait=-1ms
+
+
+#��ά�����ĵ�¼����
+4dkankan.host=https://test.4dkankan.com/
+4dkankan.host.url=https://test.4dkankan.com/vrHouse.html?m=
+4dkankan.vr.house.host=http://127.0.0.1:8085
+#oss����
+oss.point=http://oss-cn-shenzhen.aliyuncs.com
+oss.key=LTAIUrvuHqj8pvry
+oss.secrey=JLOVl0k8Ke0aaM8nLMMiUAZ3EiiqI4
+oss.bucket=4d-tjw
+#�����ļ���ʱ���·��
+file-path=open_api/developer/temp_file/
+file-downloan-host=127.0.0.1
+
+spring.application.name=vrhouse-api-service
+
+logging.config: classpath:log4j2.xml

+ 3 - 0
4dkankan-house-api/src/main/resources/application.properties

@@ -0,0 +1,3 @@
+#spring.profiles.active=prod
+#spring.profiles.active=dev
+spring.profiles.active=test

+ 61 - 0
4dkankan-house-api/src/main/resources/log4j2.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<configuration status="INFO">
+    <!--全局参数-->
+    <Properties>
+        <Property name="pattern">%d{yyyy-MM-dd HH:mm:ss,SSS} [%thread]  |-%-5level   %c{1}:%L - %m%n</Property>
+        <property name="LOG_HOME">log/api/house/</property>
+        <property name="REQUEST_FILE_NAME">request</property>
+        <property name="INFO_FILE_NAME">house_api_info</property>
+    </Properties>
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT">
+            <ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
+            <PatternLayout>
+                <pattern>
+                    ${pattern}
+                </pattern>
+            </PatternLayout>
+        </Console>
+
+        <RollingFile  name="info-log"
+                                 fileName="${LOG_HOME}/${INFO_FILE_NAME}.log"
+                                 filePattern="${LOG_HOME}/$${date:yyyy-MM}/${INFO_FILE_NAME}-%d{yyyy-MM-dd}-%i.log">
+            <PatternLayout>
+                <pattern>
+                    ${pattern}
+                </pattern>
+            </PatternLayout>
+            <Policies>
+                <TimeBasedTriggeringPolicy modulate="true" interval="1"/>
+                <SizeBasedTriggeringPolicy size="200 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="200"/>
+        </RollingFile >
+
+        <RollingRandomAccessFile name="request-log"
+                                 fileName="${LOG_HOME}/${REQUEST_FILE_NAME}.log"
+                                 filePattern="${LOG_HOME}/$${date:yyyy-MM}/${REQUEST_FILE_NAME}-%d{yyyy-MM-dd}-%i.log">
+            <PatternLayout
+                    pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n"/>
+            <Policies>
+                <TimeBasedTriggeringPolicy/>
+                <SizeBasedTriggeringPolicy size="200 MB"/>
+            </Policies>
+            <DefaultRolloverStrategy max="200"/>
+        </RollingRandomAccessFile>
+    </Appenders>
+
+    <Loggers>
+        <Root level="info">
+            <AppenderRef ref="info-log" />
+            <AppenderRef ref="Console" />
+        </Root>
+        <Logger name="request" level="info"
+                additivity="false">
+            <AppenderRef ref="request-log"/>
+        </Logger>
+<!--        <Logger name="org.springframework">
+            <AppenderRef ref="Console" />
+        </Logger>-->
+    </Loggers>
+</configuration>

+ 5 - 0
4dkankan-house-api/src/main/resources/mybatis/mappers/TmDeveloperAuthorityMapper.xml

@@ -0,0 +1,5 @@
+<?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="house.api.base.dao.TmDeveloperAuthorityDao">
+
+</mapper>

+ 5 - 0
4dkankan-house-api/src/main/resources/mybatis/mappers/TmDeveloperMapper.xml

@@ -0,0 +1,5 @@
+<?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="house.api.base.dao.TmDeveloperDao">
+
+</mapper>

+ 5 - 0
4dkankan-house-api/src/main/resources/mybatis/mappers/TmHouseInfoMapper.xml

@@ -0,0 +1,5 @@
+<?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="house.api.base.dao.TmHouseInfoDao">
+
+</mapper>

+ 5 - 0
4dkankan-house-api/src/main/resources/mybatis/mappers/TmHouseRecommendMapper.xml

@@ -0,0 +1,5 @@
+<?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="house.api.base.dao.TmHouseRecommendDao">
+
+</mapper>

+ 424 - 0
4dkankan-shop-api/pom.xml

@@ -0,0 +1,424 @@
+<?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.4dkankan.shop.api</groupId>
+    <artifactId>4dkankan-shop-api</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <description>四维商圈开放api</description>
+
+
+    <packaging>war</packaging>
+
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
+        <nacos.latest.version>0.2.1</nacos.latest.version>
+    </properties>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.2.5.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-classic</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <!-- <scope>compile</scope>-->
+            <exclusions>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-classic</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-core</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+
+
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.5</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>slf4j-api</artifactId>
+                    <groupId>org.slf4j</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>4.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!--devtools热部署-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional>
+            <scope>true</scope>
+        </dependency>
+
+        <!--内置的tomcat容器-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-tomcat</artifactId>
+            <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.tomcat.embed</groupId>
+                    <artifactId>tomcat-embed-websocket</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.1</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.3.1.tmp</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mybatis</groupId>
+                    <artifactId>mybatis</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.mybatis</groupId>
+                    <artifactId>mybatis-spring</artifactId>
+                </exclusion>
+
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.3.1.tmp</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+            <version>2.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <!-- swagger-ui -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.8.0</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.8.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-web</artifactId>
+            <version>1.4.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-spring</artifactId>
+            <version>1.4.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+
+        <!--Redis-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-redis</artifactId>
+            <!--这里不使用单独的版本号,使用spring-boot的默认版本号,不然会冲突 -!>
+<!-            <version>2.1.4.RELEASE</version>-->
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.49</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis-typehandlers-jsr310</artifactId>
+            <version>1.0.1</version>
+        </dependency>
+       <!-- <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+            <version>2.9.2</version>
+        </dependency>-->
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>1.8.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baidu.aip</groupId>
+            <artifactId>java-sdk</artifactId>
+            <version>4.15.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.4dkankan.api.common</groupId>
+            <artifactId>4dkankan-api-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.datatype</groupId>
+                    <artifactId>jackson-datatype-jsr310</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-io</groupId>
+                    <artifactId>commons-io</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-web</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-log4j2</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>org.projectlombok</groupId>
+                    <artifactId>lombok</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>com.aliyun.oss</groupId>
+                    <artifactId>aliyun-sdk-oss</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>redis.clients</groupId>
+                    <artifactId>jedis</artifactId>
+                </exclusion>
+
+                <exclusion>
+                    <groupId>com.alibaba</groupId>
+                    <artifactId>fastjson</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.ant</groupId>
+                    <artifactId>ant</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.boot</groupId>
+            <artifactId>nacos-config-spring-boot-starter</artifactId>
+            <version>0.2.6</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-io</groupId>
+                    <artifactId>commons-io</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.alibaba</groupId>
+                    <artifactId>fastjson</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <dependency>
+            <groupId>com.alibaba.boot</groupId>
+            <artifactId>nacos-discovery-spring-boot-starter</artifactId>
+            <version>0.2.6</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.alibaba</groupId>
+                    <artifactId>fastjson</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-io</groupId>
+                    <artifactId>commons-io</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+    </dependencies>
+
+
+    <build>
+        <finalName>open_api_shop_01</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <version>${maven-surefire-plugin.version}</version>
+                <configuration>
+                    <skipTests>true</skipTests>    <!--默认关掉单元测试 -->
+                </configuration>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.properties</include>
+                    <include>**/*.xml</include>
+                </includes>
+                <filtering>false</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*.properties</include>
+                    <include>**/*.xml</include>
+                </includes>
+                <filtering>false</filtering>
+            </resource>
+        </resources>
+
+    </build>
+
+</project>

BIN
4dkankan-shop-api/readMeDoc/看店4DKanKan开放api说明文档V1.0.docx


+ 54 - 0
4dkankan-shop-api/src/main/java/shop/api/ShopApiApplication.java

@@ -0,0 +1,54 @@
+package shop.api;
+
+import com.alibaba.nacos.api.annotation.NacosInjected;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.api.naming.NamingService;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+import javax.annotation.PostConstruct;
+
+/*import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;*/
+
+/**
+ * @author abnerhou
+ * @date 2020/6/4 12:25
+ * @desciption
+ */
+//@EnableFeignClients
+//@EnableDiscoveryClient
+@SpringBootApplication
+@MapperScan(basePackages = {"shop.api.**.dao"})
+public class ShopApiApplication extends SpringBootServletInitializer {
+
+    @NacosInjected
+    private NamingService namingService;
+
+    @Value("${server.port}")
+    private int serverPort;
+
+    @Value("${spring.application.name}")
+    private String applicationName;
+
+    @PostConstruct
+    public void registerInstance() throws NacosException {
+        namingService.registerInstance(applicationName, "127.0.0.1", serverPort);
+    }
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+        return application.sources(ShopApiApplication.class);
+    }
+
+    public static void main(String[] args) {
+        SpringApplication springApplication = new SpringApplication(ShopApiApplication.class);
+        springApplication.addListeners(new ApplicationPidFileWriter());
+        springApplication.run(args);
+    }
+}

+ 28 - 0
4dkankan-shop-api/src/main/java/shop/api/base/config/MyBatisPlusConfig.java

@@ -0,0 +1,28 @@
+package shop.api.base.config;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/3 14:53
+ * @desciption
+ */
+@Configuration
+public class MyBatisPlusConfig {
+
+    @Bean
+    public PaginationInterceptor paginationInterceptor() {
+        //mybatis-plus分页配置
+        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
+        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
+        // paginationInterceptor.setOverflow(false);
+        // 设置最大单页限制数量,默认 500 条,-1 不受限制
+        // paginationInterceptor.setLimit(500);
+        // 开启 count 的 join 优化,只针对部分 left join
+        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
+        return paginationInterceptor;
+    }
+}

+ 95 - 0
4dkankan-shop-api/src/main/java/shop/api/base/config/RedisConfig.java

@@ -0,0 +1,95 @@
+package shop.api.base.config;
+
+import api.common.utils.JedisUtil;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import redis.clients.jedis.JedisPoolConfig;
+
+@Log4j2
+@Configuration
+@EnableCaching
+@ConfigurationProperties
+public class RedisConfig extends CachingConfigurerSupport implements InitializingBean {
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        log.warn("redis.address:"+address);
+        JedisUtil.init(address, jedisPoolConfig());
+    }
+
+    @Value("${spring.redis.database}")
+    private int database;
+    @Value("${spring.redis.host}")
+    private String host;
+    @Value("${spring.redis.port}")
+    private int port;
+    @Value("${spring.redis.password}")
+    private String password;
+    @Value("${spring.redis.timeout}")
+    private String timeout;
+    @Value("${spring.redis.jedis.pool.max-idle}")
+    private int maxIdle;
+    @Value("${spring.redis.jedis.pool.min-idle}")
+    private int minIdle;
+    @Value("${spring.redis.host}:${spring.redis.port}")
+    private String address;
+
+    /**
+     * redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
+     * @param redisConnectionFactory
+     * @return
+     */
+    @Bean
+    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+
+        // 使用Jackson2JsonRedisSerialize 替换默认序列化
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+
+        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+
+        // 设置value的序列化规则和 key的序列化规则
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.afterPropertiesSet();
+        return redisTemplate;
+    }
+    /**
+     * 连接池配置
+     * @Description:
+     * @return
+     */
+    @Bean
+    public JedisPoolConfig jedisPoolConfig() {
+        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
+        jedisPoolConfig.setMaxIdle(maxIdle);
+        jedisPoolConfig.setMinIdle(minIdle);
+//        jedisPoolConfig.setMaxTotal(maxTotal);			            // 最大连接数, 默认8个
+//        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);	        // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间,  默认-1
+        jedisPoolConfig.setTestOnBorrow(true);		                // 在获取连接的时候检查有效性, 默认false
+        jedisPoolConfig.setTestOnReturn(true);                      // 调用returnObject方法时,是否进行有效检查
+        jedisPoolConfig.setTestWhileIdle(true);		                // Idle时进行连接扫描
+        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(30000);	//表示idle object evitor两次扫描之间要sleep的毫秒数
+        jedisPoolConfig.setNumTestsPerEvictionRun(10);			    //表示idle object evitor每次扫描的最多的对象数
+        jedisPoolConfig.setMinEvictableIdleTimeMillis(60000);	    //表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
+        return jedisPoolConfig;
+    }
+}

+ 49 - 0
4dkankan-shop-api/src/main/java/shop/api/base/config/SwaggerApp.java

@@ -0,0 +1,49 @@
+package shop.api.base.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @author abnerhou
+ * @date 2020/5/15 18:27
+ * @desciption
+ */
+@Configuration
+@EnableSwagger2
+@Profile({"dev","test"})
+public class SwaggerApp {
+
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                //为当前包路径
+                .apis(RequestHandlerSelectors.basePackage("shop.api"))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    //构建 api文档的详细信息函数,注意这里的注解引用的是哪个
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                //页面标题
+                .title("四维看店开放api接口")
+                //创建人
+                .contact(new Contact("Abner", "", "houweiyu@cgaii.com"))
+                //版本号
+                .version("1.0")
+                //描述
+                .description("开放api的接口")
+                .build();
+    }
+}

+ 18 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/MyTmGoodsInfoDao.java

@@ -0,0 +1,18 @@
+package shop.api.base.dao;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import shop.api.base.entity.TmGoodsInfo;
+import shop.api.base.vo.response.ResponseTmGoodsInfo;
+
+/**
+ * @author abnerhou
+ * @date 2020/10/20 14:40
+ * @desciption
+ */
+public interface MyTmGoodsInfoDao extends BaseMapper<TmGoodsInfo> {
+
+    IPage<ResponseTmGoodsInfo> queryGoodsWithBoundStatus(IPage<TmGoodsInfo> page, @Param("ew") QueryWrapper<TmGoodsInfo> queryWrapper);
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/TmBrandInfoDao.java

@@ -0,0 +1,16 @@
+package shop.api.base.dao;
+
+import shop.api.base.entity.TmBrandInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 商家信息表 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-25
+ */
+public interface TmBrandInfoDao extends BaseMapper<TmBrandInfo> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/TmCommentCountDao.java

@@ -0,0 +1,16 @@
+package shop.api.base.dao;
+
+import shop.api.base.entity.TmCommentCount;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-18
+ */
+public interface TmCommentCountDao extends BaseMapper<TmCommentCount> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/TmDeveloperAuthorityDao.java

@@ -0,0 +1,16 @@
+package shop.api.base.dao;
+
+import shop.api.base.entity.TmDeveloperAuthority;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 开发者权限控制表 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-12-09
+ */
+public interface TmDeveloperAuthorityDao extends BaseMapper<TmDeveloperAuthority> {
+
+}

+ 20 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/TmGoodsInfoDao.java

@@ -0,0 +1,20 @@
+package shop.api.base.dao;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.ibatis.annotations.Param;
+import shop.api.base.entity.TmGoodsInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 商品信息表 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-25
+ */
+public interface TmGoodsInfoDao extends BaseMapper<TmGoodsInfo> {
+
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/TmHotShopDao.java

@@ -0,0 +1,16 @@
+package shop.api.base.dao;
+
+import shop.api.base.entity.TmHotShop;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 场景码热点和商品关联关系表(仅四维内部使用) Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-14
+ */
+public interface TmHotShopDao extends BaseMapper<TmHotShop> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/TmLikeCountDao.java

@@ -0,0 +1,16 @@
+package shop.api.base.dao;
+
+import shop.api.base.entity.TmLikeCount;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 店铺点赞统计表 Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-17
+ */
+public interface TmLikeCountDao extends BaseMapper<TmLikeCount> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/TmUserCommentLogDao.java

@@ -0,0 +1,16 @@
+package shop.api.base.dao;
+
+import shop.api.base.entity.TmUserCommentLog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-18
+ */
+public interface TmUserCommentLogDao extends BaseMapper<TmUserCommentLog> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/dao/TmUserLikeLogDao.java

@@ -0,0 +1,16 @@
+package shop.api.base.dao;
+
+import shop.api.base.entity.TmUserLikeLog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-17
+ */
+public interface TmUserLikeLogDao extends BaseMapper<TmUserLikeLog> {
+
+}

+ 104 - 0
4dkankan-shop-api/src/main/java/shop/api/base/entity/TmBrandInfo.java

@@ -0,0 +1,104 @@
+package shop.api.base.entity;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 商家信息表
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmBrandInfo对象", description="商家信息表")
+public class TmBrandInfo implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "主键ID")
+    private String requestId;
+
+    @ApiModelProperty(value = "商家ID")
+    private String brandId;
+
+    @ApiModelProperty(value = "商家名称")
+    private String brandName;
+
+    @ApiModelProperty(value = "描述")
+    private String simpleDesc;
+
+    @ApiModelProperty(value = "排序")
+    private Integer sortOrder;
+
+    @ApiModelProperty(value = "是否展示")
+    private Boolean isShow;
+
+    @ApiModelProperty(value = "类型")
+    private Integer type;
+
+    @ApiModelProperty(value = "分类名称")
+    private String typeName;
+
+    @ApiModelProperty(value = "场景码")
+    private String sceneNum;
+
+    @ApiModelProperty(value = "场景名称")
+    private String scenenName;
+
+    @ApiModelProperty(value = "微信分享二维码地址")
+    private String shareWxQrCode;
+
+    @ApiModelProperty(value = "店铺地址")
+    private String address;
+
+    @ApiModelProperty(value = "店铺简介照片集")
+    private String picList;
+
+    @ApiModelProperty(value = "经度")
+    private BigDecimal longitude;
+
+    @ApiModelProperty(value = "纬度")
+    private BigDecimal latitude;
+
+    @ApiModelProperty(value = "视频简介地址")
+    private String introduceVideo;
+
+    @ApiModelProperty(value = "视频简介的第一帧")
+    private String introduceVideoCover;
+
+    @ApiModelProperty(value = "店铺封面照片")
+    private String imageCover;
+
+    @ApiModelProperty(value = "商家所属数据的开发者ID")
+    private String appId;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最新更新时间")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "是否可用;1->可用;0->不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "场景视频数据")
+    private String sceneVideoData;
+
+    @ApiModelProperty(value = "起源的小程序")
+    private String origin;
+
+    @ApiModelProperty(value = "联系电话")
+    private String contractPhone;
+
+
+}

+ 49 - 0
4dkankan-shop-api/src/main/java/shop/api/base/entity/TmCommentCount.java

@@ -0,0 +1,49 @@
+package shop.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmCommentCount对象", description="")
+public class TmCommentCount implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "唯一ID")
+    private String countId;
+
+    @ApiModelProperty(value = "店铺ID")
+    private String brandId;
+
+    @ApiModelProperty(value = "来源")
+    private String origin;
+
+    @ApiModelProperty(value = "是否可用:1->可用;0->不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最新更新时间")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "统计数")
+    private Integer sum;
+
+
+}

+ 67 - 0
4dkankan-shop-api/src/main/java/shop/api/base/entity/TmDeveloperAuthority.java

@@ -0,0 +1,67 @@
+package shop.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 开发者权限控制表
+ * </p>
+ *
+ * @author abner
+ * @since 2020-12-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmDeveloperAuthority对象", description="开发者权限控制表")
+public class TmDeveloperAuthority implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "权限id")
+    private String appId;
+
+    @ApiModelProperty(value = "是否展示页面底部四维logo : 1 展示 0不展示")
+    private Integer showKankanFoot;
+
+    @ApiModelProperty(value = "是否展示经纪人门店:1 展示 0不展示")
+    private Integer showAgencyStore;
+
+    @ApiModelProperty(value = "是否展示经纪公司品牌:1 展示 0不展示")
+    private Integer showAgencyBrand;
+
+    @ApiModelProperty(value = "是否使用客户用户头像:1 使用 0 不使用")
+    private Integer useCostomerUserAvatar;
+
+    @ApiModelProperty(value = "是否将消息订阅post的body的参数拼接到url上:Y 是, N 否")
+    private String appendNoticeBody;
+
+    @ApiModelProperty(value = "回调url")
+    private String callBackUrl;
+
+    @ApiModelProperty(value = "是否可用: 1可用 0 不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最后更新时间")
+    private LocalDateTime lastModifyDatetime;
+
+    @ApiModelProperty(value = "是否展示委托授权:1 展示 0 不展示")
+    private Integer showDelegateAuth;
+
+    @ApiModelProperty(value = "是否展示房源信息: 1展示 0 不展示")
+    private Integer showHouseInfo;
+
+    @ApiModelProperty(value = "是否展示工作证: 1 展示 0 不展示")
+    private Integer showWorkPic;
+
+
+}

+ 113 - 0
4dkankan-shop-api/src/main/java/shop/api/base/entity/TmGoodsInfo.java

@@ -0,0 +1,113 @@
+package shop.api.base.entity;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 商品信息表
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmGoodsInfo对象", description="商品信息表")
+public class TmGoodsInfo implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "请求id")
+    private String requestId;
+
+    @ApiModelProperty(value = "商品id")
+    private String goodsId;
+
+    @ApiModelProperty(value = "商品名称")
+    private String goodsName;
+
+    @ApiModelProperty(value = "商品是否在售")
+    private Integer goodsIsOnSale;
+
+    @ApiModelProperty(value = "商品展示图片列表")
+    private String goodsImageList;
+
+    @ApiModelProperty(value = "实际最低售价")
+    private BigDecimal retailPriceLow;
+
+    @ApiModelProperty(value = "实际最高售价")
+    private BigDecimal retailPriceHigh;
+
+    @ApiModelProperty(value = "实际售价范围")
+    private String retailPriceStr;
+
+    @ApiModelProperty(value = "商品描述")
+    private String goodsDesc;
+
+    @ApiModelProperty(value = "商品所属的类别id")
+    private String goodsCategoryId;
+
+    @ApiModelProperty(value = "商品所属的类别名称")
+    private String goodsCategoryName;
+
+    @ApiModelProperty(value = "商品库存")
+    private Integer goodsNumber;
+
+    @ApiModelProperty(value = "商品添加时间")
+    private LocalDateTime goodsAddTime;
+
+    @ApiModelProperty(value = "商品更新时间")
+    private LocalDateTime goodsUpdateTime;
+
+    @ApiModelProperty(value = "商品主图链接")
+    private String goodsPrimaryPicUrl;
+
+    @ApiModelProperty(value = "商品子图链接")
+    private String goodsListPicUrl;
+
+    @ApiModelProperty(value = "商品是否热点商品")
+    private Boolean goodsIsHot;
+
+    @ApiModelProperty(value = "商品市场价")
+    private BigDecimal goodsMarketPrice;
+
+    @ApiModelProperty(value = "商品属性类别名称")
+    private String attributeCategoryName;
+
+    @ApiModelProperty(value = "商品所属品牌的id")
+    private String brandId;
+
+    @ApiModelProperty(value = "商品所属品牌名称")
+    private String brandName;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最后更新时间")
+    private LocalDateTime lastModifyDatetime;
+
+    @ApiModelProperty(value = "是否可用: 1 可用 0不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "商品所属的场景码")
+    private String sceneNum;
+
+    @ApiModelProperty(value = "商品所属的开发者ID")
+    private String appId;
+
+    @ApiModelProperty(value = "客户自己商城url")
+    private String realShopUrl;
+
+    @ApiModelProperty(value = "来源小程序名称")
+    private String origin;
+
+
+}

+ 53 - 0
4dkankan-shop-api/src/main/java/shop/api/base/entity/TmHotShop.java

@@ -0,0 +1,53 @@
+package shop.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 场景码热点和商品关联关系表(仅四维内部使用)
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-14
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmHotShop对象", description="场景码热点和商品关联关系表(仅四维内部使用)")
+public class TmHotShop implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "id")
+    private String id;
+
+    @ApiModelProperty(value = "热点id")
+    private String hotId;
+
+    @ApiModelProperty(value = "商品id")
+    private String goodId;
+
+    @ApiModelProperty(value = "场景码")
+    private String sceneNum;
+
+    @ApiModelProperty(value = "热点里卡夹的sid")
+    private String pageSid;
+
+    @ApiModelProperty(value = "起源的小程序")
+    private String origin;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime lastModifyDatetime;
+
+    @ApiModelProperty(value = "是否可以用: 1可用,0不可用")
+    private Integer enable;
+
+
+}

+ 49 - 0
4dkankan-shop-api/src/main/java/shop/api/base/entity/TmLikeCount.java

@@ -0,0 +1,49 @@
+package shop.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 店铺点赞统计表
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmLikeCount对象", description="店铺点赞统计表")
+public class TmLikeCount implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "唯一ID")
+    private String likeId;
+
+    @ApiModelProperty(value = "店铺ID")
+    private String brandId;
+
+    @ApiModelProperty(value = "来源平台")
+    private String origin;
+
+    @ApiModelProperty(value = "当前收获的赞数")
+    private Integer sum;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最新修改时间")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "是否可用:1->可用;0->不可用")
+    private Integer enable;
+
+
+}

+ 61 - 0
4dkankan-shop-api/src/main/java/shop/api/base/entity/TmUserCommentLog.java

@@ -0,0 +1,61 @@
+package shop.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmUserCommentLog对象", description="")
+public class TmUserCommentLog implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "唯一ID")
+    private String logId;
+
+    @ApiModelProperty(value = "用户ID")
+    private String userId;
+
+    @ApiModelProperty(value = "用户名")
+    private String userName;
+
+    @ApiModelProperty(value = "店铺ID")
+    private String brandId;
+
+    @ApiModelProperty(value = "是否可用: 1->可用;0->不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最新更新时间")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "评论内容")
+    private String content;
+
+    @ApiModelProperty(value = "平台来源")
+    private String origin;
+
+    @ApiModelProperty(value = "父评论ID")
+    private String parentId;
+
+    @ApiModelProperty(value = "用户头像")
+    private String userAvatar;
+
+
+}

+ 49 - 0
4dkankan-shop-api/src/main/java/shop/api/base/entity/TmUserLikeLog.java

@@ -0,0 +1,49 @@
+package shop.api.base.entity;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="TmUserLikeLog对象", description="")
+public class TmUserLikeLog implements Serializable {
+
+    private static final long serialVersionUID=1L;
+
+    @ApiModelProperty(value = "唯一ID")
+    private String logId;
+
+    @ApiModelProperty(value = "赞ID")
+    private String likeId;
+
+    @ApiModelProperty(value = "用户ID")
+    private String userId;
+
+    @ApiModelProperty(value = "创建时间")
+    private LocalDateTime createTime;
+
+    @ApiModelProperty(value = "最后更新时间")
+    private LocalDateTime updateTime;
+
+    @ApiModelProperty(value = "是否可用: 1->可用;0->不可用")
+    private Integer enable;
+
+    @ApiModelProperty(value = "点赞动作: 1->点赞; -1->取消点赞")
+    private Integer type;
+
+
+}

+ 99 - 0
4dkankan-shop-api/src/main/java/shop/api/base/generator/MysqlGenerator.java

@@ -0,0 +1,99 @@
+package shop.api.base.generator;
+
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author abnerhou
+ * @date 2020/6/3 14:54
+ * @desciption
+ */
+public class MysqlGenerator {
+
+
+    public static void main(String[] args) {
+        AutoGenerator mpg = new AutoGenerator();
+
+        GlobalConfig gc = new GlobalConfig();
+        String projectPath = System.getProperty("user.dir");
+        gc.setOutputDir(projectPath + "/4dkankan-shop-api/src/main/java");
+        gc.setAuthor("abner");   // 作者
+        gc.setOpen(false);      //生成代码后是否打开文件夹
+        gc.setSwagger2(true);
+        gc.setMapperName("%sDao");
+//        gc.setXmlName("%sMapper");
+//        gc.setControllerName("%sController");
+        gc.setFileOverride(true);//是否覆盖
+        mpg.setGlobalConfig(gc);
+
+        DataSourceConfig dsc = new DataSourceConfig();
+        dsc.setUrl("jdbc:mysql://120.25.146.52:3306/4dshop-api?useUnicode=true&serverTimezone=GMT&useSSL=false&characterEncoding=utf8");
+        dsc.setDriverName("com.mysql.jdbc.Driver");
+        dsc.setUsername("root");
+        dsc.setPassword("4dkk2020test%");
+        mpg.setDataSource(dsc);
+
+        // 包配置
+        PackageConfig pc = new PackageConfig();
+        pc.setModuleName("base"); // 模块名称, 这里可以根据不同模块来写
+        pc.setParent("shop.api"); // 父包名
+        pc.setMapper("dao");
+        pc.setController("controller");
+
+        mpg.setPackageInfo(pc);
+
+        // 配置模板
+        TemplateConfig templateConfig = new TemplateConfig();
+
+        //控制 不生成 controller
+        templateConfig.setController("");
+
+        templateConfig.setXml(null);
+        mpg.setTemplate(templateConfig);
+
+
+        // 注入自定义配置,可以在 VM 中使用 cfg.abc 【可无】
+        InjectionConfig cfg = new InjectionConfig() {
+            @Override
+            public void initMap() {
+                Map<String, Object> map = new HashMap<String, Object>();
+                map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-mp");
+                this.setMap(map);
+            }
+        };
+
+        // 调整 xml 生成目录演示
+        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();
+        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
+            @Override
+            public String outputFile(TableInfo tableInfo) {
+                return  "E:\\code\\projects\\dev_4dkankanAPI\\4dkankan-shop-api\\src\\main\\resources\\mybatis\\mappers\\" + tableInfo.getEntityName() + "Mapper.xml";
+            }
+        });
+        cfg.setFileOutConfigList(focList);
+        mpg.setCfg(cfg);
+
+
+        // 策略配置
+        StrategyConfig strategy = new StrategyConfig();
+        strategy.setNaming(NamingStrategy.underline_to_camel);
+        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+//        strategy.setSuperEntityClass("house.api.base.model");
+
+        strategy.setEntityLombokModel(true);
+//        strategy.setInclude("tm_goods_info","tm_hot_shop","tm_brand_info");  // 如果要生成多个,这里可以传入String[]
+        strategy.setInclude("tm_developer_authority");  // 如果要生成多个,这里可以传入String[]
+        mpg.setStrategy(strategy);
+        //TODO:使用的时候,释放出来就可以了
+        mpg.execute();
+        System.out.println("代码自动生成执行完成");
+    }
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/service/ITmBrandInfoService.java

@@ -0,0 +1,16 @@
+package shop.api.base.service;
+
+import shop.api.base.entity.TmBrandInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 商家信息表 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-25
+ */
+public interface ITmBrandInfoService extends IService<TmBrandInfo> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/service/ITmCommentCountService.java

@@ -0,0 +1,16 @@
+package shop.api.base.service;
+
+import shop.api.base.entity.TmCommentCount;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-18
+ */
+public interface ITmCommentCountService extends IService<TmCommentCount> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/service/ITmDeveloperAuthorityService.java

@@ -0,0 +1,16 @@
+package shop.api.base.service;
+
+import shop.api.base.entity.TmDeveloperAuthority;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 开发者权限控制表 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-12-09
+ */
+public interface ITmDeveloperAuthorityService extends IService<TmDeveloperAuthority> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/service/ITmGoodsInfoService.java

@@ -0,0 +1,16 @@
+package shop.api.base.service;
+
+import shop.api.base.entity.TmGoodsInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 商品信息表 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-25
+ */
+public interface ITmGoodsInfoService extends IService<TmGoodsInfo> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/service/ITmHotShopService.java

@@ -0,0 +1,16 @@
+package shop.api.base.service;
+
+import shop.api.base.entity.TmHotShop;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 场景码热点和商品关联关系表(仅四维内部使用) 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-09-14
+ */
+public interface ITmHotShopService extends IService<TmHotShop> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/service/ITmLikeCountService.java

@@ -0,0 +1,16 @@
+package shop.api.base.service;
+
+import shop.api.base.entity.TmLikeCount;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 店铺点赞统计表 服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-17
+ */
+public interface ITmLikeCountService extends IService<TmLikeCount> {
+
+}

+ 16 - 0
4dkankan-shop-api/src/main/java/shop/api/base/service/ITmUserCommentLogService.java

@@ -0,0 +1,16 @@
+package shop.api.base.service;
+
+import shop.api.base.entity.TmUserCommentLog;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author abner
+ * @since 2020-11-18
+ */
+public interface ITmUserCommentLogService extends IService<TmUserCommentLog> {
+
+}

+ 0 - 0
4dkankan-shop-api/src/main/java/shop/api/base/service/ITmUserLikeLogService.java


Деякі файли не було показано, через те що забагато файлів було змінено