Browse Source

first commit

YinBin 1 year ago
commit
ecce002361
100 changed files with 11158 additions and 0 deletions
  1. 2 0
      README.md
  2. 386 0
      pom.xml
  3. 290 0
      top-core/pom.xml
  4. 75 0
      top-core/src/main/java/com/alipay/config/AlipayConfig.java
  5. 279 0
      top-core/src/main/java/com/alipay/sign/Base64.java
  6. 67 0
      top-core/src/main/java/com/alipay/sign/MD5.java
  7. 143 0
      top-core/src/main/java/com/alipay/sign/RSA.java
  8. 134 0
      top-core/src/main/java/com/alipay/util/AlipayCore.java
  9. 178 0
      top-core/src/main/java/com/alipay/util/AlipayNotify.java
  10. 335 0
      top-core/src/main/java/com/alipay/util/AlipaySubmit.java
  11. 111 0
      top-core/src/main/java/com/alipay/util/UtilDate.java
  12. 39 0
      top-core/src/main/java/com/alipay/util/UtilDistance.java
  13. 191 0
      top-core/src/main/java/com/alipay/util/httpClient/HttpProtocolHandler.java
  14. 152 0
      top-core/src/main/java/com/alipay/util/httpClient/HttpRequest.java
  15. 72 0
      top-core/src/main/java/com/alipay/util/httpClient/HttpResponse.java
  16. 27 0
      top-core/src/main/java/com/alipay/util/httpClient/HttpResultType.java
  17. 64 0
      top-core/src/main/java/com/tencent/Main.java
  18. 153 0
      top-core/src/main/java/com/tencent/WXPay.java
  19. 125 0
      top-core/src/main/java/com/tencent/bridge/IBridge.java
  20. 156 0
      top-core/src/main/java/com/tencent/business/DownloadBillBusiness.java
  21. 162 0
      top-core/src/main/java/com/tencent/business/RefundBusiness.java
  22. 197 0
      top-core/src/main/java/com/tencent/business/RefundQueryBusiness.java
  23. 422 0
      top-core/src/main/java/com/tencent/business/ScanPayBusiness.java
  24. 164 0
      top-core/src/main/java/com/tencent/common/Configure.java
  25. 200 0
      top-core/src/main/java/com/tencent/common/HttpRequest.java
  26. 199 0
      top-core/src/main/java/com/tencent/common/HttpsRequest.java
  27. 59 0
      top-core/src/main/java/com/tencent/common/Log.java
  28. 59 0
      top-core/src/main/java/com/tencent/common/MD5.java
  29. 28 0
      top-core/src/main/java/com/tencent/common/RandomStringGenerator.java
  30. 78 0
      top-core/src/main/java/com/tencent/common/Sign.java
  31. 120 0
      top-core/src/main/java/com/tencent/common/Signature.java
  32. 120 0
      top-core/src/main/java/com/tencent/common/Util.java
  33. 166 0
      top-core/src/main/java/com/tencent/common/XMLParser.java
  34. 40 0
      top-core/src/main/java/com/tencent/common/report/ReportRunable.java
  35. 31 0
      top-core/src/main/java/com/tencent/common/report/Reporter.java
  36. 21 0
      top-core/src/main/java/com/tencent/common/report/ReporterFactory.java
  37. 232 0
      top-core/src/main/java/com/tencent/common/report/protocol/ReportReqData.java
  38. 38 0
      top-core/src/main/java/com/tencent/common/report/protocol/ReportResData.java
  39. 69 0
      top-core/src/main/java/com/tencent/common/report/service/ReportService.java
  40. 137 0
      top-core/src/main/java/com/tencent/protocol/downloadbill_protocol/DownloadBillReqData.java
  41. 29 0
      top-core/src/main/java/com/tencent/protocol/downloadbill_protocol/DownloadBillResData.java
  42. 406 0
      top-core/src/main/java/com/tencent/protocol/pay_protocol/JSPayReqData.java
  43. 230 0
      top-core/src/main/java/com/tencent/protocol/pay_protocol/ScanPayReqData.java
  44. 208 0
      top-core/src/main/java/com/tencent/protocol/pay_protocol/UnifiedPayResData.java
  45. 127 0
      top-core/src/main/java/com/tencent/protocol/pay_query_protocol/ScanPayQueryReqData.java
  46. 236 0
      top-core/src/main/java/com/tencent/protocol/pay_query_protocol/ScanPayQueryResData.java
  47. 192 0
      top-core/src/main/java/com/tencent/protocol/refund_protocol/RefundReqData.java
  48. 168 0
      top-core/src/main/java/com/tencent/protocol/refund_protocol/RefundResData.java
  49. 100 0
      top-core/src/main/java/com/tencent/protocol/refund_query_protocol/RefundOrderData.java
  50. 160 0
      top-core/src/main/java/com/tencent/protocol/refund_query_protocol/RefundQueryReqData.java
  51. 187 0
      top-core/src/main/java/com/tencent/protocol/refund_query_protocol/RefundQueryResData.java
  52. 127 0
      top-core/src/main/java/com/tencent/protocol/reverse_protocol/ReverseReqData.java
  53. 104 0
      top-core/src/main/java/com/tencent/protocol/reverse_protocol/ReverseResData.java
  54. 42 0
      top-core/src/main/java/com/tencent/service/BaseService.java
  55. 46 0
      top-core/src/main/java/com/tencent/service/DownloadBillService.java
  56. 20 0
      top-core/src/main/java/com/tencent/service/IServiceRequest.java
  57. 36 0
      top-core/src/main/java/com/tencent/service/RefundQueryService.java
  58. 33 0
      top-core/src/main/java/com/tencent/service/RefundService.java
  59. 33 0
      top-core/src/main/java/com/tencent/service/ReverseService.java
  60. 34 0
      top-core/src/main/java/com/tencent/service/ScanPayQueryService.java
  61. 32 0
      top-core/src/main/java/com/tencent/service/ScanPayService.java
  62. 37 0
      top-core/src/main/java/com/tencent/service/UnifiedOrderPayService.java
  63. 41 0
      top-core/src/main/java/com/top/core/AbstractSpringBean.java
  64. 30 0
      top-core/src/main/java/com/top/core/base/GeoLocation.java
  65. 37 0
      top-core/src/main/java/com/top/core/controller/AbstractController.java
  66. 31 0
      top-core/src/main/java/com/top/core/controller/ModelController.java
  67. 21 0
      top-core/src/main/java/com/top/core/dao/CategoryDao.java
  68. 21 0
      top-core/src/main/java/com/top/core/dao/IntegralRecordDao.java
  69. 21 0
      top-core/src/main/java/com/top/core/dao/LevelDao.java
  70. 21 0
      top-core/src/main/java/com/top/core/dao/OrderDao.java
  71. 51 0
      top-core/src/main/java/com/top/core/dao/ProjectDao.java
  72. 21 0
      top-core/src/main/java/com/top/core/dao/SchoolDao.java
  73. 21 0
      top-core/src/main/java/com/top/core/dao/SpecialtyDao.java
  74. 19 0
      top-core/src/main/java/com/top/core/dao/TradeRecordDAO.java
  75. 30 0
      top-core/src/main/java/com/top/core/dao/UserDao.java
  76. 31 0
      top-core/src/main/java/com/top/core/domain/AbstractEntity.java
  77. 314 0
      top-core/src/main/java/com/top/core/domain/CategoryEntity.java
  78. 116 0
      top-core/src/main/java/com/top/core/domain/IntegralRecordEntity.java
  79. 101 0
      top-core/src/main/java/com/top/core/domain/LevelEntity.java
  80. 262 0
      top-core/src/main/java/com/top/core/domain/OrderEntity.java
  81. 356 0
      top-core/src/main/java/com/top/core/domain/ProjectEntity.java
  82. 91 0
      top-core/src/main/java/com/top/core/domain/SchoolEntity.java
  83. 103 0
      top-core/src/main/java/com/top/core/domain/SpecialtyEntity.java
  84. 123 0
      top-core/src/main/java/com/top/core/domain/TradeRecordEntity.java
  85. 163 0
      top-core/src/main/java/com/top/core/domain/UserInfoEntity.java
  86. 50 0
      top-core/src/main/java/com/top/core/service/CategoryService.java
  87. 68 0
      top-core/src/main/java/com/top/core/service/IntegralRecordService.java
  88. 107 0
      top-core/src/main/java/com/top/core/service/ObjectMapper.java
  89. 182 0
      top-core/src/main/java/com/top/core/service/OrderService.java
  90. 53 0
      top-core/src/main/java/com/top/core/service/ProjectService.java
  91. 53 0
      top-core/src/main/java/com/top/core/service/SchoolService.java
  92. 91 0
      top-core/src/main/java/com/top/core/service/SecurityManager.java
  93. 54 0
      top-core/src/main/java/com/top/core/service/SpecialtyService.java
  94. 57 0
      top-core/src/main/java/com/top/core/service/TradeRecordService.java
  95. 160 0
      top-core/src/main/java/com/top/core/service/UserService.java
  96. 46 0
      top-core/src/main/java/com/top/core/service/impl/AbstractService.java
  97. 29 0
      top-core/src/main/java/com/top/core/service/impl/FileService.java
  98. 22 0
      top-core/src/main/java/com/top/core/service/impl/GeoLocationService.java
  99. 25 0
      top-core/src/main/java/com/top/core/service/impl/SystemPropertyService.java
  100. 28 0
      top-core/src/main/java/com/top/core/utils/DateConverter.java

+ 2 - 0
README.md

@@ -0,0 +1,2 @@
+# top_online_weixin
+托普微信在线报名

+ 386 - 0
pom.xml

@@ -0,0 +1,386 @@
+<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/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.top</groupId>
+    <artifactId>top-online</artifactId>
+    <packaging>pom</packaging>
+    <version>1.0-SNAPSHOT</version>
+    <name>top-online</name>
+    <url>http://maven.apache.org</url>
+
+    <modules>
+        <module>top-core</module>
+        <module>top-web</module>
+    </modules>
+
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <org.springframework.version>4.1.6.RELEASE</org.springframework.version>
+        <hibernate.version>4.3.10.Final</hibernate.version>
+        <org.jsondoc.version>1.1.14</org.jsondoc.version>
+    </properties>
+
+    <repositories>
+        <repository>
+            <id>snoatype-snapshots</id>
+            <name>sonatype snapshots</name>
+            <url>http://oss.sonatype.org/content/repositories/snapshots</url>
+        </repository>
+    </repositories>
+
+    <dependencyManagement>
+        <dependencies>
+            <!-- JavaEE servlet api for tomcat. -->
+            <dependency>
+                <groupId>org.apache.tomcat</groupId>
+                <artifactId>tomcat-servlet-api</artifactId>
+                <version>8.0.20</version>
+                <scope>provided</scope>
+            </dependency>
+
+            <!-- BEGIN Spring framework -->
+            <!-- Spring MVC for Servlet Environments -->
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-webmvc</artifactId>
+                <version>${org.springframework.version}</version>
+            </dependency>
+
+            <!-- Various Application Context utilities, including EhCache, JavaMail,
+                Quartz, and Freemarker integration Define this if you need any of these integrations -->
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-context-support</artifactId>
+                <version>${org.springframework.version}</version>
+            </dependency>
+
+            <!-- Object-to-Relation-Mapping (ORM) integration with Hibernate, JPA,
+                and iBatis. -->
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-orm</artifactId>
+                <version>${org.springframework.version}</version>
+            </dependency>
+
+            <!-- Object-to-XML Mapping (OXM) abstraction and integration with JAXB,
+                JiBX, Castor, XStream, and XML Beans. (depends on spring-core, spring-beans,
+                spring-context) Define this if you need OXM (org.springframework.oxm.*) -->
+            <!--<dependency>-->
+            <!--<groupId>org.springframework</groupId>-->
+            <!--<artifactId>spring-oxm</artifactId>-->
+            <!--<version>${org.springframework.version}</version>-->
+            <!--</dependency>-->
+
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-aop</artifactId>
+                <version>${org.springframework.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-jms</artifactId>
+                <version>${org.springframework.version}</version>
+            </dependency>
+            <!-- END Spring framework -->
+
+            <!-- AspectJ -->
+            <dependency>
+                <groupId>org.aspectj</groupId>
+                <artifactId>aspectjrt</artifactId>
+                <version>1.6.11</version>
+            </dependency>
+            <dependency>
+                <groupId>org.aspectj</groupId>
+                <artifactId>aspectjweaver</artifactId>
+                <version>1.6.11</version>
+            </dependency>
+            <!-- AspectJ -->
+
+            <!-- json converter for Spring MVC -->
+            <dependency>
+                <groupId>com.fasterxml.jackson.core</groupId>
+                <artifactId>jackson-databind</artifactId>
+                <version>2.4.3</version>
+            </dependency>
+
+            <!-- JSTL lib -->
+            <dependency>
+                <groupId>javax.servlet</groupId>
+                <artifactId>jstl</artifactId>
+                <version>1.2</version>
+                <scope>compile</scope>
+            </dependency>
+
+            <!-- email support -->
+            <dependency>
+                <groupId>javax.mail</groupId>
+                <artifactId>mail</artifactId>
+                <version>1.4.7</version>
+            </dependency>
+
+            <!-- BEGIN Logging -->
+            <dependency>
+                <groupId>org.apache.logging.log4j.adapters</groupId>
+                <artifactId>log4j-slf4j-impl</artifactId>
+                <version>2.0-beta4</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.logging.log4j</groupId>
+                <artifactId>log4j-api</artifactId>
+                <version>2.0-rc1</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.logging.log4j</groupId>
+                <artifactId>log4j-core</artifactId>
+                <version>2.0-rc1</version>
+            </dependency>
+            <!-- END Logging -->
+
+            <!-- BEGIN JPA 2.0 Hibernate provider -->
+            <dependency>
+                <groupId>org.hibernate</groupId>
+                <artifactId>hibernate-entitymanager</artifactId>
+                <version>${hibernate.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <artifactId>jboss-logging</artifactId>
+                        <groupId>org.jboss.logging</groupId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.hibernate</groupId>
+                <artifactId>hibernate-c3p0</artifactId>
+                <version>${hibernate.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.hibernate</groupId>
+                <artifactId>hibernate-ehcache</artifactId>
+                <version>${hibernate.version}</version>
+            </dependency>
+
+            <!-- 覆盖hibernate的依赖 解决logging问题 -->
+            <dependency>
+                <groupId>com.mchange</groupId>
+                <artifactId>c3p0</artifactId>
+                <version>0.9.5</version>
+            </dependency>
+            <!-- END JPA 2.0 Hibernate provider -->
+
+            <!-- MySQL connector -->
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>5.1.24</version>
+            </dependency>
+
+            <!-- BEGIN Google core library for java-->
+            <dependency>
+                <groupId>com.google.guava</groupId>
+                <artifactId>guava</artifactId>
+                <version>18.0</version>
+            </dependency>
+            <!-- END Google core library for java-->
+
+            <!-- BEGIN Apache commons -->
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-lang3</artifactId>
+                <version>3.2.1</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>2.4</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-fileupload</groupId>
+                <artifactId>commons-fileupload</artifactId>
+                <version>1.3</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.httpcomponents</groupId>
+                <artifactId>httpclient</artifactId>
+                <version>4.3.6</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-codec</groupId>
+                <artifactId>commons-codec</artifactId>
+                <version>1.9</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-beanutils</groupId>
+                <artifactId>commons-beanutils</artifactId>
+                <version>1.9.1</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-net</groupId>
+                <artifactId>commons-net</artifactId>
+                <version>3.3</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-httpclient</groupId>
+                <artifactId>commons-httpclient</artifactId>
+                <version>3.1</version>
+            </dependency>
+            <!-- END Apache commons -->
+
+            <!-- SSH client -->
+            <dependency>
+                <groupId>ch.ethz.ganymed</groupId>
+                <artifactId>ganymed-ssh2</artifactId>
+                <version>262</version>
+            </dependency>
+
+            <!-- time library -->
+            <dependency>
+                <groupId>joda-time</groupId>
+                <artifactId>joda-time</artifactId>
+                <version>2.8</version>
+            </dependency>
+
+            <!-- JSON processor -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>1.2.6</version>
+            </dependency>
+
+
+            <!-- Object Mapping -->
+            <dependency>
+                <groupId>ma.glasnost.orika</groupId>
+                <artifactId>orika-core</artifactId>
+                <version>1.4.5</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.triiskelion</groupId>
+                <artifactId>tinyspring</artifactId>
+                <version>0.10.4-SNAPSHOT</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.reflections</groupId>
+                        <artifactId>reflections</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+
+            <!-- BEGIN JMS Client -->
+            <dependency>
+                <groupId>javax.jms</groupId>
+                <artifactId>jms-api</artifactId>
+                <version>1.1-rev-1</version>
+            </dependency>
+
+
+            <dependency>
+                <groupId>org.apache.activemq</groupId>
+                <artifactId>activemq-client</artifactId>
+                <version>5.10.1</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.activemq</groupId>
+                <artifactId>activemq-pool</artifactId>
+                <version>5.10.1</version>
+            </dependency>
+            <!-- END JMS Client -->
+
+            <dependency>
+                <groupId>jaxen</groupId>
+                <artifactId>jaxen</artifactId>
+                <version>1.1.1</version>
+            </dependency>
+
+            <dependency>
+                <groupId>dom4j</groupId>
+                <artifactId>dom4j</artifactId>
+                <version>1.6.1</version>
+            </dependency>
+
+            <!-- BEGIN test dependency -->
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>4.11</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-test</artifactId>
+                <version>${org.springframework.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <!-- END test dependency -->
+
+            <!-- RESTful api documentation  -->
+            <dependency>
+                <groupId>org.jsondoc</groupId>
+                <artifactId>jsondoc-core</artifactId>
+                <version>${org.jsondoc.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.jsondoc</groupId>
+                <artifactId>jsondoc-springmvc</artifactId>
+                <version>${org.jsondoc.version}</version>
+            </dependency>
+            <!--@ RESTful api documentation  -->
+
+            <dependency>
+                <groupId>com.intellij</groupId>
+                <artifactId>annotations</artifactId>
+                <version>12.0</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.googlecode.json-simple</groupId>
+                <artifactId>json-simple</artifactId>
+                <version>1.1.1</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.thoughtworks.xstream</groupId>
+                <artifactId>xstream</artifactId>
+                <version>1.4.8</version>
+            </dependency>
+
+            <dependency>
+                <groupId>xpp3</groupId>
+                <artifactId>xpp3</artifactId>
+                <version>1.1.4c</version>
+            </dependency>
+
+            <dependency>
+                <groupId>xmlpull</groupId>
+                <artifactId>xmlpull</artifactId>
+                <version>1.1.3.1</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.imgscalr</groupId>
+                <artifactId>imgscalr-lib</artifactId>
+                <version>4.2</version>
+            </dependency>
+
+            <!-- fastweixin api-->
+            <dependency>
+                <groupId>com.github.sd4324530</groupId>
+                <artifactId>fastweixin</artifactId>
+                <version>1.3.2</version>
+            </dependency>
+
+            <!--xml tool-->
+            <dependency>
+                <groupId>com.mycila</groupId>
+                <artifactId>mycila-xmltool</artifactId>
+                <version>4.4.ga</version>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+</project>

+ 290 - 0
top-core/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/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>top-online</artifactId>
+        <groupId>com.top</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.top</groupId>
+    <artifactId>top-core</artifactId>
+    <packaging>jar</packaging>
+    <version>1.0.0</version>
+    <name>top-core</name>
+
+    <build>
+        <plugins>
+            <!-- Set Java compiler level -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <!-- JavaEE servlet api for tomcat. -->
+        <dependency>
+            <groupId>org.apache.tomcat</groupId>
+            <artifactId>tomcat-servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- JPA API -->
+        <dependency>
+            <groupId>org.hibernate.javax.persistence</groupId>
+            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <version>1.0.0.Final</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- JSTL lib -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>jstl</artifactId>
+        </dependency>
+
+        <!-- JPA 2.0 Hibernate provider -->
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-entitymanager</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>jboss-logging</artifactId>
+                    <groupId>org.jboss.logging</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-c3p0</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-ehcache</artifactId>
+        </dependency>
+        <!-- JPA 2.0 Hibernate provider -->
+
+        <!-- MySQL connector -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- Logging -->
+        <dependency>
+            <groupId>org.apache.logging.log4j.adapters</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+        </dependency>
+        <!-- Logging -->
+
+        <!-- Spring Framework -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>commons-logging</groupId>
+                    <artifactId>commons-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+            <version>1.7.10</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-orm</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-aop</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-jms</artifactId>
+        </dependency>
+        <!-- Spring Framework -->
+
+        <!-- AspectJ -->
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjrt</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+        </dependency>
+        <!-- AspectJ -->
+
+        <!-- Mail client -->
+        <dependency>
+            <groupId>javax.mail</groupId>
+            <artifactId>mail</artifactId>
+            <version>1.4.7</version>
+        </dependency>
+
+        <!-- json converter for Spring MVC -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <!-- Http client -->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+
+        <!-- Spring-mvc utils -->
+        <dependency>
+            <groupId>org.triiskelion</groupId>
+            <artifactId>tinyspring</artifactId>
+        </dependency>
+
+        <!-- Object Mapping -->
+        <dependency>
+            <groupId>ma.glasnost.orika</groupId>
+            <artifactId>orika-core</artifactId>
+        </dependency>
+
+        <!-- SSH client -->
+        <dependency>
+            <groupId>ch.ethz.ganymed</groupId>
+            <artifactId>ganymed-ssh2</artifactId>
+        </dependency>
+
+        <!-- ActiveMQ client -->
+        <dependency>
+            <groupId>javax.jms</groupId>
+            <artifactId>jms-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.activemq</groupId>
+            <artifactId>activemq-client</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.activemq</groupId>
+            <artifactId>activemq-pool</artifactId>
+        </dependency>
+        <!-- ActiveMQ client -->
+
+        <!-- Code inspections -->
+        <dependency>
+            <groupId>com.intellij</groupId>
+            <artifactId>annotations</artifactId>
+        </dependency>
+
+        <!-- JSON processor -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-pool</groupId>
+            <artifactId>commons-pool</artifactId>
+            <version>1.6</version>
+        </dependency>
+
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+        </dependency>
+
+        <!-- RESTful api documentation  -->
+        <dependency>
+            <groupId>org.jsondoc</groupId>
+            <artifactId>jsondoc-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jsondoc</groupId>
+            <artifactId>jsondoc-springmvc</artifactId>
+        </dependency>
+        <!-- RESTful api documentation  -->
+
+        <dependency>
+            <groupId>org.imgscalr</groupId>
+            <artifactId>imgscalr-lib</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>xpp3</groupId>
+            <artifactId>xpp3</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>xmlpull</groupId>
+            <artifactId>xmlpull</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+        </dependency>
+
+        <!-- ****** TEST DEPENDENCIES ****** -->
+        <!-- junit -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!-- junit -->
+
+        <dependency>
+            <groupId>com.github.sd4324530</groupId>
+            <artifactId>fastweixin</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>

+ 75 - 0
top-core/src/main/java/com/alipay/config/AlipayConfig.java

@@ -0,0 +1,75 @@
+package com.alipay.config;
+
+/* *手机网页专用
+ *类名:AlipayConfig  手机网页专用
+ *功能:基础配置类
+ *详细:设置帐户有关信息及返回路径
+ *版本:3.3
+ *日期:2012-08-10
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
+	
+ *提示:如何获取安全校验码和合作身份者ID
+ *1.用您的签约支付宝账号登录支付宝网站(www.alipay.com)
+ *2.点击“商家服务”(https://b.alipay.com/order/myOrder.htm)
+ *3.点击“查询合作者身份(PID)”、“查询安全校验码(Key)”
+
+ *安全校验码查看时,输入支付密码后,页面呈灰色的现象,怎么办?
+ *解决方法:
+ *1、检查浏览器配置,不让浏览器做弹框屏蔽设置
+ *2、更换浏览器或电脑,重新登录查询。
+ */
+
+public class AlipayConfig {
+
+    //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
+    // 合作身份者ID,以2088开头由16位纯数字组成的字符串
+    public static String partner = "2088811518335407";
+
+    // 卖家收款支付宝帐户
+    static public String seller_email = "wtyqdtop@126.com";
+
+    // 交易安全检验码,由数字和字母组成的32位字符串
+    // 如果签名方式设置为“MD5”时,请设置该参数
+    public static String key = "iz3wx9e966k4ysgowvk4w4f0lrk3cdg5";
+
+    // 商户的私钥
+    // 如果签名方式设置为“0001”时,请设置该参数
+    public static String private_key = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMOVATfkq5JvFsIrQle+N9pjLQGakT0MizCeOQXLFIzyhJzsqD24dy/L7oX8CXd1pVGLIqYnbkuxo781qn6wzbkoDFUFkKlc8Df0THFhSvGAeaGFDjarweteXIRJ1RjE0q0M+e9D6zCDqmOvj/TenQn9pqH2DaqHURt6JVlYLHHvAgMBAAECgYANYbCHpnmmtzsTZepQHo+rvYViyrSNPMJ5PRohr1dknWM9aWPJdUmSV52mRSxQpBf/kEl6nNALFchiWMWljWtF1TUd/CHW5lH4c822O42EIdYvNxvxdKyGQNeMVkZefiexR5CY9xrgCS6GslEkokfvlF+HnXCdx2qO83eDS1zqoQJBAOoHO48hRyDgT2mrpPaVdrfvNa/eBacyWMGu97ckc0UKkdT6T1+IgebR/6M4tqGlfAokNCtMnEH6+hGZS6aVwDUCQQDV8bv9LpUmxjc6HoNEW4VTQYMNaiohrcdJcwUMBuzywQ8oXMStITCM8Q+7ggH7ZJuit94X7dxBqc5lNZKq9DYTAkA4V5ltMhPPxHEZ/arverhkPADu4EL4J9TafGdC/lGKE6tcXQ7y7whnK7Oh9itx60dboa+1pPIRqHy/8+oUpwTpAkBpoPlEzov7YeAAhPIgfOM9sNmodOMqT6dWH0C9qGmyjRkTv4GnTPywiZBP7qdV3F1vIEK6I8kcbl8l3yZz2zEbAkEAvVaFpuubgSEjlRPIAPO9tOphMfcJvtFUZBsW1wU4n6QVieiXiIF6HqVVTZvK/9Kn1zGsIILdGYQmdKy0f7C0zQ==";
+
+    // 支付宝的公钥  手机网页支付使用的公钥
+    // 如果签名方式设置为“0001”时,请设置该参数
+    public static String ali_public_key = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCNM1NWgpwmkJG6rJGR7QYMO/OI2LwxKN/dB+PPUXyIOdBfO0e+IDDX2swVYzds5d89mV9ymRNcx/0YNBDOXHJm8SlBM4IyZ/Y7zTjRso/vcWmv9ZbX84IIgJqKl5gTCdBhsbmRzkPrhCWePYCqauesIdJqtrJWwVP1wTmUTS278wIDAQAB";
+
+    //↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
+
+    //页面跳转同步通知页面路径
+    static public String return_url = "http://member.oltop.cn/order/success";
+
+    //服务器异步通知页面路径
+    static public String notify_url = "http://member.oltop.cn/notify/alipay/mobile";
+
+    //操作中断返回地址
+    public static String merchant_url = "http://member.oltop.cn";
+    //用户付款中途退出返回商户的地址。需http://格式的完整路径,不允许加?id=123这类自定义参数
+
+    /**
+     * 支付宝 直接到帐 交易状态:交易成功
+     */
+    public static final String TRADE_STATUS_TRADE_SUCCESS = "TRADE_SUCCESS";
+
+    // 订单名称
+    static public String name = "托普在线";
+
+    // 调试用,创建TXT日志文件夹路径
+    public static String log_path = "D:\\";
+
+    // 字符编码格式 目前支持  utf-8
+    public static String input_charset = "utf-8";
+
+    // 签名方式,选择项:0001(RSA)、MD5
+    public static String sign_type = "0001";
+    // 无线的产品中,签名方式为rsa时,sign_type需赋值为0001而不是RSA
+
+}

+ 279 - 0
top-core/src/main/java/com/alipay/sign/Base64.java

@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2010 The MobileSecurePay Project
+ * All right reserved.
+ * author: shiqun.shi@alipay.com
+ */
+
+package com.alipay.sign;
+
+public final class Base64 {
+
+    static private final int     BASELENGTH           = 128;
+    static private final int     LOOKUPLENGTH         = 64;
+    static private final int     TWENTYFOURBITGROUP   = 24;
+    static private final int     EIGHTBIT             = 8;
+    static private final int     SIXTEENBIT           = 16;
+    static private final int     FOURBYTE             = 4;
+    static private final int     SIGN                 = -128;
+    static private final char    PAD                  = '=';
+    static private final boolean fDebug               = false;
+    static final private byte[]  base64Alphabet       = new byte[BASELENGTH];
+    static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];
+
+    static {
+        for (int i = 0; i < BASELENGTH; ++i) {
+            base64Alphabet[i] = -1;
+        }
+        for (int i = 'Z'; i >= 'A'; i--) {
+            base64Alphabet[i] = (byte) (i - 'A');
+        }
+        for (int i = 'z'; i >= 'a'; i--) {
+            base64Alphabet[i] = (byte) (i - 'a' + 26);
+        }
+
+        for (int i = '9'; i >= '0'; i--) {
+            base64Alphabet[i] = (byte) (i - '0' + 52);
+        }
+
+        base64Alphabet['+'] = 62;
+        base64Alphabet['/'] = 63;
+
+        for (int i = 0; i <= 25; i++) {
+            lookUpBase64Alphabet[i] = (char) ('A' + i);
+        }
+
+        for (int i = 26, j = 0; i <= 51; i++, j++) {
+            lookUpBase64Alphabet[i] = (char) ('a' + j);
+        }
+
+        for (int i = 52, j = 0; i <= 61; i++, j++) {
+            lookUpBase64Alphabet[i] = (char) ('0' + j);
+        }
+        lookUpBase64Alphabet[62] = (char) '+';
+        lookUpBase64Alphabet[63] = (char) '/';
+
+    }
+
+    private static boolean isWhiteSpace(char octect) {
+        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
+    }
+
+    private static boolean isPad(char octect) {
+        return (octect == PAD);
+    }
+
+    private static boolean isData(char octect) {
+        return (octect < BASELENGTH && base64Alphabet[octect] != -1);
+    }
+
+    /**
+     * Encodes hex octects into Base64
+     *
+     * @param binaryData Array containing binaryData
+     * @return Encoded Base64 array
+     */
+    public static String encode(byte[] binaryData) {
+
+        if (binaryData == null) {
+            return null;
+        }
+
+        int lengthDataBits = binaryData.length * EIGHTBIT;
+        if (lengthDataBits == 0) {
+            return "";
+        }
+
+        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
+        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
+        int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
+        char encodedData[] = null;
+
+        encodedData = new char[numberQuartet * 4];
+
+        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
+
+        int encodedIndex = 0;
+        int dataIndex = 0;
+        if (fDebug) {
+            System.out.println("number of triplets = " + numberTriplets);
+        }
+
+        for (int i = 0; i < numberTriplets; i++) {
+            b1 = binaryData[dataIndex++];
+            b2 = binaryData[dataIndex++];
+            b3 = binaryData[dataIndex++];
+
+            if (fDebug) {
+                System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
+            }
+
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+            byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
+
+            if (fDebug) {
+                System.out.println("val2 = " + val2);
+                System.out.println("k4   = " + (k << 4));
+                System.out.println("vak  = " + (val2 | (k << 4)));
+            }
+
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
+        }
+
+        // form integral number of 6-bit groups
+        if (fewerThan24bits == EIGHTBIT) {
+            b1 = binaryData[dataIndex];
+            k = (byte) (b1 & 0x03);
+            if (fDebug) {
+                System.out.println("b1=" + b1);
+                System.out.println("b1<<2 = " + (b1 >> 2));
+            }
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
+            encodedData[encodedIndex++] = PAD;
+            encodedData[encodedIndex++] = PAD;
+        } else if (fewerThan24bits == SIXTEENBIT) {
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex + 1];
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
+            encodedData[encodedIndex++] = PAD;
+        }
+
+        return new String(encodedData);
+    }
+
+    /**
+     * Decodes Base64 data into octects
+     *
+     * @param encoded string containing Base64 data
+     * @return Array containind decoded data.
+     */
+    public static byte[] decode(String encoded) {
+
+        if (encoded == null) {
+            return null;
+        }
+
+        char[] base64Data = encoded.toCharArray();
+        // remove white spaces
+        int len = removeWhiteSpace(base64Data);
+
+        if (len % FOURBYTE != 0) {
+            return null;//should be divisible by four
+        }
+
+        int numberQuadruple = (len / FOURBYTE);
+
+        if (numberQuadruple == 0) {
+            return new byte[0];
+        }
+
+        byte decodedData[] = null;
+        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+        char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
+
+        int i = 0;
+        int encodedIndex = 0;
+        int dataIndex = 0;
+        decodedData = new byte[(numberQuadruple) * 3];
+
+        for (; i < numberQuadruple - 1; i++) {
+
+            if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
+                || !isData((d3 = base64Data[dataIndex++]))
+                || !isData((d4 = base64Data[dataIndex++]))) {
+                return null;
+            }//if found "no data" just return null
+
+            b1 = base64Alphabet[d1];
+            b2 = base64Alphabet[d2];
+            b3 = base64Alphabet[d3];
+            b4 = base64Alphabet[d4];
+
+            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+        }
+
+        if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
+            return null;//if found "no data" just return null
+        }
+
+        b1 = base64Alphabet[d1];
+        b2 = base64Alphabet[d2];
+
+        d3 = base64Data[dataIndex++];
+        d4 = base64Data[dataIndex++];
+        if (!isData((d3)) || !isData((d4))) {//Check if they are PAD characters
+            if (isPad(d3) && isPad(d4)) {
+                if ((b2 & 0xf) != 0)//last 4 bits should be zero
+                {
+                    return null;
+                }
+                byte[] tmp = new byte[i * 3 + 1];
+                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+                tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+                return tmp;
+            } else if (!isPad(d3) && isPad(d4)) {
+                b3 = base64Alphabet[d3];
+                if ((b3 & 0x3) != 0)//last 2 bits should be zero
+                {
+                    return null;
+                }
+                byte[] tmp = new byte[i * 3 + 2];
+                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+                tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+                tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+                return tmp;
+            } else {
+                return null;
+            }
+        } else { //No PAD e.g 3cQl
+            b3 = base64Alphabet[d3];
+            b4 = base64Alphabet[d4];
+            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+
+        }
+
+        return decodedData;
+    }
+
+    /**
+     * remove WhiteSpace from MIME containing encoded Base64 data.
+     *
+     * @param data  the byte array of base64 data (with WS)
+     * @return      the new length
+     */
+    private static int removeWhiteSpace(char[] data) {
+        if (data == null) {
+            return 0;
+        }
+
+        // count characters that's not whitespace
+        int newSize = 0;
+        int len = data.length;
+        for (int i = 0; i < len; i++) {
+            if (!isWhiteSpace(data[i])) {
+                data[newSize++] = data[i];
+            }
+        }
+        return newSize;
+    }
+}

+ 67 - 0
top-core/src/main/java/com/alipay/sign/MD5.java

@@ -0,0 +1,67 @@
+package com.alipay.sign;
+
+import org.apache.commons.codec.digest.DigestUtils;
+
+import java.io.UnsupportedEncodingException;
+
+/** 
+* 功能:支付宝MD5签名处理核心文件,不需要修改
+* 版本:3.3
+* 修改日期:2012-08-17
+* 说明:
+* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+* 该代码仅供学习和研究支付宝接口使用,只是提供一个
+* */
+
+public class MD5 {
+
+    /**
+     * 签名字符串
+     * @param text 需要签名的字符串
+     * @param key 密钥
+     * @param input_charset 编码格式
+     * @return 签名结果
+     */
+    public static String sign(String text, String key, String input_charset) {
+    	text = text + key;
+        return DigestUtils.md5Hex(getContentBytes(text, input_charset));
+    }
+    
+    /**
+     * 签名字符串
+     * @param text 需要签名的字符串
+     * @param sign 签名结果
+     * @param key 密钥
+     * @param input_charset 编码格式
+     * @return 签名结果
+     */
+    public static boolean verify(String text, String sign, String key, String input_charset) {
+    	text = text + key;
+    	String mysign = DigestUtils.md5Hex(getContentBytes(text, input_charset));
+    	if(mysign.equals(sign)) {
+    		return true;
+    	}
+    	else {
+    		return false;
+    	}
+    }
+
+    /**
+     * @param content
+     * @param charset
+     * @return
+     * @throws java.security.SignatureException
+     * @throws UnsupportedEncodingException
+     */
+    private static byte[] getContentBytes(String content, String charset) {
+        if (charset == null || "".equals(charset)) {
+            return content.getBytes();
+        }
+        try {
+            return content.getBytes(charset);
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
+        }
+    }
+
+}

+ 143 - 0
top-core/src/main/java/com/alipay/sign/RSA.java

@@ -0,0 +1,143 @@
+
+package com.alipay.sign;
+
+import javax.crypto.Cipher;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+public class RSA{
+	
+	public static final String  SIGN_ALGORITHMS = "SHA1WithRSA";
+	
+	/**
+	* RSA签名
+	* @param content 待签名数据
+	* @param privateKey 商户私钥
+	* @param input_charset 编码格式
+	* @return 签名值
+	*/
+	public static String sign(String content, String privateKey, String input_charset)
+	{
+        try 
+        {
+        	PKCS8EncodedKeySpec priPKCS8 	= new PKCS8EncodedKeySpec( Base64.decode(privateKey) ); 
+        	KeyFactory keyf 				= KeyFactory.getInstance("RSA");
+        	PrivateKey priKey 				= keyf.generatePrivate(priPKCS8);
+
+            java.security.Signature signature = java.security.Signature
+                .getInstance(SIGN_ALGORITHMS);
+
+            signature.initSign(priKey);
+            signature.update( content.getBytes(input_charset) );
+
+            byte[] signed = signature.sign();
+            
+            return Base64.encode(signed);
+        }
+        catch (Exception e) 
+        {
+        	e.printStackTrace();
+        }
+        
+        return null;
+    }
+	
+	/**
+	* RSA验签名检查
+	* @param content 待签名数据
+	* @param sign 签名值
+	* @param ali_public_key 支付宝公钥
+	* @param input_charset 编码格式
+	* @return 布尔值
+	*/
+	public static boolean verify(String content, String sign, String ali_public_key, String input_charset)
+	{
+		try 
+		{
+			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+	        byte[] encodedKey = Base64.decode(ali_public_key);
+	        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
+
+		
+			java.security.Signature signature = java.security.Signature
+			.getInstance(SIGN_ALGORITHMS);
+		
+			signature.initVerify(pubKey);
+			signature.update( content.getBytes(input_charset) );
+		
+			boolean bverify = signature.verify( Base64.decode(sign) );
+			return bverify;
+			
+		} 
+		catch (Exception e) 
+		{
+			e.printStackTrace();
+		}
+		
+		return false;
+	}
+	
+	/**
+	* 解密
+	* @param content 密文
+	* @param private_key 商户私钥
+	* @param input_charset 编码格式
+	* @return 解密后的字符串
+	*/
+	public static String decrypt(String content, String private_key, String input_charset) throws Exception {
+        PrivateKey prikey = getPrivateKey(private_key);
+
+        Cipher cipher = Cipher.getInstance("RSA");
+        cipher.init(Cipher.DECRYPT_MODE, prikey);
+
+        InputStream ins = new ByteArrayInputStream(Base64.decode(content));
+        ByteArrayOutputStream writer = new ByteArrayOutputStream();
+        //rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密
+        byte[] buf = new byte[128];
+        int bufl;
+
+        while ((bufl = ins.read(buf)) != -1) {
+            byte[] block = null;
+
+            if (buf.length == bufl) {
+                block = buf;
+            } else {
+                block = new byte[bufl];
+                for (int i = 0; i < bufl; i++) {
+                    block[i] = buf[i];
+                }
+            }
+
+            writer.write(cipher.doFinal(block));
+        }
+
+        return new String(writer.toByteArray(), input_charset);
+    }
+
+	
+	/**
+	* 得到私钥
+	* @param key 密钥字符串(经过base64编码)
+	* @throws Exception
+	*/
+	public static PrivateKey getPrivateKey(String key) throws Exception {
+
+		byte[] keyBytes;
+		
+		keyBytes = Base64.decode(key);
+		
+		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+		
+		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+		
+		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
+		
+		return privateKey;
+	}
+}

+ 134 - 0
top-core/src/main/java/com/alipay/util/AlipayCore.java

@@ -0,0 +1,134 @@
+package com.alipay.util;
+
+import com.alipay.config.AlipayConfig;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.httpclient.methods.multipart.FilePartSource;
+import org.apache.commons.httpclient.methods.multipart.PartSource;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.*;
+
+/* *
+ *类名:AlipayFunction
+ *功能:支付宝接口公用函数类
+ *详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改
+ *版本:3.3
+ *日期:2012-08-14
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
+ */
+
+public class AlipayCore {
+
+    /** 
+     * 除去数组中的空值和签名参数
+     * @param sArray 签名参数组
+     * @return 去掉空值与签名参数后的新签名参数组
+     */
+    public static Map<String, String> paraFilter(Map<String, String> sArray) {
+
+        Map<String, String> result = new HashMap<String, String>();
+
+        if (sArray == null || sArray.size() <= 0) {
+            return result;
+        }
+
+        for (String key : sArray.keySet()) {
+            String value = sArray.get(key);
+            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
+                || key.equalsIgnoreCase("sign_type")) {
+                continue;
+            }
+            result.put(key, value);
+        }
+
+        return result;
+    }
+
+    /** 
+     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
+     * @param params 需要排序并参与字符拼接的参数组
+     * @return 拼接后字符串
+     */
+    public static String createLinkString(Map<String, String> params) {
+
+        List<String> keys = new ArrayList<String>(params.keySet());
+        Collections.sort(keys);
+
+        String prestr = "";
+
+        for (int i = 0; i < keys.size(); i++) {
+            String key = keys.get(i);
+            String value = params.get(key);
+
+            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
+                prestr = prestr + key + "=" + value;
+            } else {
+                prestr = prestr + key + "=" + value + "&";
+            }
+        }
+
+        return prestr;
+    }
+    
+    /** 
+     * 把数组所有元素按照固定参数排序,以“参数=参数值”的模式用“&”字符拼接成字符串
+     * @param params 需要参与字符拼接的参数组
+     * @return 拼接后字符串
+     */
+    public static String createLinkStringNoSort(Map<String, String> params) {
+    	
+    	//手机网站支付MD5签名固定参数排序,顺序参照文档说明
+    	StringBuilder gotoSign_params = new StringBuilder();
+    	gotoSign_params.append("service="+params.get("service"));
+    	gotoSign_params.append("&v="+params.get("v"));
+    	gotoSign_params.append("&sec_id="+params.get("sec_id"));
+    	gotoSign_params.append("&notify_data="+params.get("notify_data"));
+    	
+    	return gotoSign_params.toString();
+    }
+
+    /** 
+     * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
+     * @param sWord 要写入日志里的文本内容
+     */
+    public static void logResult(String sWord) {
+        FileWriter writer = null;
+        try {
+            writer = new FileWriter(AlipayConfig.log_path + "alipay_log_" + System.currentTimeMillis()+".txt");
+            writer.write(sWord);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /** 
+     * 生成文件摘要
+     * @param strFilePath 文件路径
+     * @param file_digest_type 摘要算法
+     * @return 文件摘要结果
+     */
+    public static String getAbstract(String strFilePath, String file_digest_type) throws IOException {
+        PartSource file = new FilePartSource(new File(strFilePath));
+    	if(file_digest_type.equals("MD5")){
+    		return DigestUtils.md5Hex(file.createInputStream());
+    	}
+    	else if(file_digest_type.equals("SHA")) {
+    		return DigestUtils.sha256Hex(file.createInputStream());
+    	}
+    	else {
+    		return "";
+    	}
+    }
+}

+ 178 - 0
top-core/src/main/java/com/alipay/util/AlipayNotify.java

@@ -0,0 +1,178 @@
+package com.alipay.util;
+
+import com.alipay.config.AlipayConfig;
+import com.alipay.sign.MD5;
+import com.alipay.sign.RSA;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Map;
+
+/* *
+ *类名:AlipayNotify
+ *功能:支付宝通知处理类
+ *详细:处理支付宝各接口通知返回
+ *版本:3.3
+ *日期:2012-08-17
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考
+
+ *************************注意*************************
+ *调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常
+ */
+public class AlipayNotify {
+
+    /**
+     * 支付宝消息验证地址
+     */
+    private static final String HTTPS_VERIFY_URL = "https://mapi.alipay.com/gateway.do?service=notify_verify&";
+    
+    /**
+     * 验证消息是否是支付宝发出的合法消息,验证callback
+     * @param params 通知返回来的参数数组
+     * @return 验证结果
+     */
+    public static boolean verifyReturn(Map<String, String> params) {
+	    String sign = "";
+	    //获取返回时的签名验证结果
+	    if(params.get("sign") != null) {sign = params.get("sign");}
+	    //验证签名
+	    boolean isSign = getSignVeryfy(params, sign, true);
+
+        //写日志记录(若要调试,请取消下面两行注释)
+        //String sWord = "isSign=" + isSign + "\n 返回回来的参数:" + AlipayCore.createLinkString(params);
+	    //AlipayCore.logResult(sWord);
+
+        //判断isSign是否为true
+        //isSign不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
+        if (isSign) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * 验证消息是否是支付宝发出的合法消息,验证服务器异步通知
+     * @param params 通知返回来的参数数组
+     * @return 验证结果
+     */
+    public static boolean verifyNotify(Map<String, String> params) throws Exception {
+    	
+    	//获取是否是支付宝服务器发来的请求的验证结果
+    	String responseTxt = "true";
+    	try {
+        	//XML解析notify_data数据,获取notify_id
+	    	Document document = DocumentHelper.parseText(params.get("notify_data"));
+	    	String notify_id = document.selectSingleNode( "//notify/notify_id" ).getText();
+			responseTxt = verifyResponse(notify_id);
+    	} catch(Exception e) {
+    		responseTxt = e.toString();
+    	}
+    	
+    	//获取返回时的签名验证结果
+	    String sign = "";
+	    if(params.get("sign") != null) {sign = params.get("sign");}
+	    boolean isSign = getSignVeryfy(params, sign,false);
+
+        //写日志记录(若要调试,请取消下面两行注释)
+        //String sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign + "\n 返回回来的参数:" + AlipayCore.createLinkString(params);
+	    //AlipayCore.logResult(sWord);
+
+        //判断responsetTxt是否为true,isSign是否为true
+        //responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
+        //isSign不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
+        if (isSign && responseTxt.equals("true")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+    
+    /**
+     * 解密
+     * @param inputPara 要解密数据
+     * @return 解密后结果
+     */
+    public static Map<String, String> decrypt(Map<String, String> inputPara) throws Exception {
+    	inputPara.put("notify_data", RSA.decrypt(inputPara.get("notify_data"), AlipayConfig.private_key, AlipayConfig.input_charset));
+    	return inputPara;
+    }
+
+    /**
+     * 根据反馈回来的信息,生成签名结果
+     * @param Params 通知返回来的参数数组
+     * @param sign 比对的签名结果
+     * @param isSort 是否排序
+     * @return 生成的签名结果
+     */
+	private static boolean getSignVeryfy(Map<String, String> Params, String sign, boolean isSort) {
+    	//过滤空值、sign与sign_type参数
+    	Map<String, String> sParaNew = com.alipay.util.AlipayCore.paraFilter(Params);
+        //获取待签名字符串
+    	String preSignStr = "";
+    	if(isSort) {
+    		preSignStr = com.alipay.util.AlipayCore.createLinkString(sParaNew);
+    	} else {
+    		preSignStr = AlipayCore.createLinkStringNoSort(sParaNew);
+    	}
+        //获得签名验证结果
+        boolean isSign = false;
+        if(AlipayConfig.sign_type.equals("MD5") ) {
+        	isSign = MD5.verify(preSignStr, sign, AlipayConfig.key, AlipayConfig.input_charset);
+        }
+        if(AlipayConfig.sign_type.equals("0001")){
+        	isSign = RSA.verify(preSignStr, sign, AlipayConfig.ali_public_key, AlipayConfig.input_charset);
+        }
+        return isSign;
+    }
+
+    /**
+    * 获取远程服务器ATN结果,验证返回URL
+    * @param notify_id 通知校验ID
+    * @return 服务器ATN结果
+    * 验证结果集:
+    * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空 
+    * true 返回正确信息
+    * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
+    */
+    private static String verifyResponse(String notify_id) {
+        //获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
+
+        String partner = AlipayConfig.partner;
+        String veryfy_url = HTTPS_VERIFY_URL + "partner=" + partner + "&notify_id=" + notify_id;
+
+        return checkUrl(veryfy_url);
+    }
+
+    /**
+    * 获取远程服务器ATN结果
+    * @param urlvalue 指定URL路径地址
+    * @return 服务器ATN结果
+    * 验证结果集:
+    * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空 
+    * true 返回正确信息
+    * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
+    */
+    private static String checkUrl(String urlvalue) {
+        String inputLine = "";
+
+        try {
+            URL url = new URL(urlvalue);
+            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+            BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection
+                .getInputStream()));
+            inputLine = in.readLine().toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+            inputLine = "";
+        }
+
+        return inputLine;
+    }
+}

+ 335 - 0
top-core/src/main/java/com/alipay/util/AlipaySubmit.java

@@ -0,0 +1,335 @@
+package com.alipay.util;
+
+import com.alipay.config.AlipayConfig;
+import com.alipay.sign.MD5;
+import com.alipay.sign.RSA;
+import com.alipay.util.httpClient.HttpProtocolHandler;
+import com.alipay.util.httpClient.HttpRequest;
+import com.alipay.util.httpClient.HttpResponse;
+import com.alipay.util.httpClient.HttpResultType;
+import org.apache.commons.httpclient.NameValuePair;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Node;
+import org.dom4j.io.SAXReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/* *
+ *类名:AlipaySubmit
+ *功能:支付宝各接口请求提交类
+ *详细:构造支付宝各接口表单HTML文本,获取远程HTTP数据
+ *版本:3.3
+ *日期:2012-08-13
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
+ */
+
+public class AlipaySubmit {
+    public static Logger log = LoggerFactory.getLogger(AlipaySubmit.class);
+
+    //支付宝网关地址
+    static private final String ALIPAY_GATEWAY_NEW = "http://wappaygw.alipay.com/service/rest.htm?";
+
+    //创建支付宝form
+    static public String createHtmlContent(String sessionId, String orderId, String price, String description) {
+
+        //请求业务参数详细
+        String req_dataToken = "<direct_trade_create_req><notify_url>" + AlipayConfig.notify_url +
+                "</notify_url><call_back_url>" + AlipayConfig.return_url + "</call_back_url><seller_account_name>" +
+                AlipayConfig.seller_email + "</seller_account_name><out_trade_no>"
+                + orderId + "</out_trade_no><subject>" + description + "</subject><total_fee>" + price +
+                "</total_fee><merchant_url>" + AlipayConfig.merchant_url + "</merchant_url></direct_trade_create_req>";
+        //必填
+
+        //////////////////////////////////////////////////////////////////////////////////
+
+        //把请求参数打包成数组
+        Map<String, String> sParaTempToken = new HashMap<String, String>();
+        sParaTempToken.put("service", "alipay.wap.trade.create.direct");
+        sParaTempToken.put("partner", AlipayConfig.partner);
+        sParaTempToken.put("_input_charset", AlipayConfig.input_charset);
+        sParaTempToken.put("sec_id", AlipayConfig.sign_type);
+        sParaTempToken.put("format", "xml");
+        sParaTempToken.put("v", "2.0");
+        sParaTempToken.put("req_id", orderId);
+        sParaTempToken.put("req_data", req_dataToken);
+        String request_token = "";
+        try {
+            //建立请求
+            String sHtmlTextToken = AlipaySubmit.buildRequest(ALIPAY_GATEWAY_NEW, "", "", sParaTempToken);
+            //URLDECODE返回的信息
+            sHtmlTextToken = URLDecoder.decode(sHtmlTextToken, AlipayConfig.input_charset);
+            //获取token
+            request_token = AlipaySubmit.getRequestToken(sHtmlTextToken);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("request error,like request_token get failed");
+        }
+        ////////////////////////////////////根据授权码token调用交易接口alipay.wap.auth.authAndExecute//////////////////////////////////////
+
+        //业务详细
+        String req_data = "<auth_and_execute_req><request_token>" + request_token + "</request_token></auth_and_execute_req>";
+        //必填
+
+        //把请求参数打包成数组
+        Map<String, String> sParaTemp = new HashMap<String, String>();
+        sParaTemp.put("service", "alipay.wap.auth.authAndExecute");
+        sParaTemp.put("partner", AlipayConfig.partner);
+        sParaTemp.put("_input_charset", AlipayConfig.input_charset);
+        sParaTemp.put("sec_id", AlipayConfig.sign_type);
+        sParaTemp.put("format", "xml");
+        sParaTemp.put("v", "2.0");
+        sParaTemp.put("req_data", req_data);
+
+        //建立请求
+        return AlipaySubmit.buildRequest(ALIPAY_GATEWAY_NEW, sParaTemp, "get", "确认");
+    }
+
+    /**
+     * 生成签名结果
+     *
+     * @param sPara 要签名的数组
+     * @return 签名结果字符串
+     */
+    public static String buildRequestMysign(Map<String, String> sPara) {
+        String prestr = AlipayCore.createLinkString(sPara); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
+        String mysign = "";
+        if (AlipayConfig.sign_type.equals("MD5")) {
+            mysign = MD5.sign(prestr, AlipayConfig.key, AlipayConfig.input_charset);
+        }
+        if (AlipayConfig.sign_type.equals("0001")) {
+            mysign = RSA.sign(prestr, AlipayConfig.private_key, AlipayConfig.input_charset);
+        }
+        return mysign;
+    }
+
+    /**
+     * 生成要请求给支付宝的参数数组
+     *
+     * @param sParaTemp 请求前的参数数组
+     * @return 要请求的参数数组
+     */
+    private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {
+        //除去数组中的空值和签名参数
+        Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp);
+        //生成签名结果
+        String mysign = buildRequestMysign(sPara);
+
+        //签名结果与签名方式加入请求提交参数组中
+        sPara.put("sign", mysign);
+        if (!sPara.get("service").equals("alipay.wap.trade.create.direct") && !sPara.get("service").equals("alipay.wap.auth.authAndExecute")) {
+            sPara.put("sign_type", AlipayConfig.sign_type);
+        }
+
+        return sPara;
+    }
+
+    /**
+     * 建立请求,以表单HTML形式构造(默认)
+     *
+     * @param sParaTemp     请求参数数组
+     * @param strMethod     提交方式。两个值可选:post、get
+     * @param strButtonName 确认按钮显示文字
+     * @return 提交表单HTML文本
+     * @paramALIPAY_GATEWAY_NEW 支付宝网关地址
+     */
+    public static String buildRequest(String ALIPAY_GATEWAY_NEW, Map<String, String> sParaTemp, String strMethod, String strButtonName) {
+        //待请求参数数组
+        Map<String, String> sPara = buildRequestPara(sParaTemp);
+        List<String> keys = new ArrayList<String>(sPara.keySet());
+
+        StringBuffer sbHtml = new StringBuffer();
+
+        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + ALIPAY_GATEWAY_NEW
+                + "_input_charset=" + AlipayConfig.input_charset + "\" method=\"" + strMethod
+                + "\">");
+
+        for (int i = 0; i < keys.size(); i++) {
+            String name = (String) keys.get(i);
+            String value = (String) sPara.get(name);
+
+            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
+        }
+
+        //submit按钮控件请不要含有name属性
+        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
+        sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");
+
+        return sbHtml.toString();
+    }
+
+    /**
+     * 建立请求,以表单HTML形式构造,带文件上传功能
+     *
+     * @param sParaTemp       请求参数数组
+     * @param strMethod       提交方式。两个值可选:post、get
+     * @param strButtonName   确认按钮显示文字
+     * @param strParaFileName 文件上传的参数名
+     * @return 提交表单HTML文本
+     * @paramALIPAY_GATEWAY_NEW 支付宝网关地址
+     */
+    public static String buildRequest(String ALIPAY_GATEWAY_NEW, Map<String, String> sParaTemp, String strMethod, String strButtonName, String strParaFileName) {
+        //待请求参数数组
+        Map<String, String> sPara = buildRequestPara(sParaTemp);
+        List<String> keys = new ArrayList<String>(sPara.keySet());
+
+        StringBuffer sbHtml = new StringBuffer();
+
+        sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\"  enctype=\"multipart/form-data\" action=\"" + ALIPAY_GATEWAY_NEW
+                + "_input_charset=" + AlipayConfig.input_charset + "\" method=\"" + strMethod
+                + "\">");
+
+        for (int i = 0; i < keys.size(); i++) {
+            String name = (String) keys.get(i);
+            String value = (String) sPara.get(name);
+
+            sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");
+        }
+
+        sbHtml.append("<input type=\"file\" name=\"" + strParaFileName + "\" />");
+
+        //submit按钮控件请不要含有name属性
+        sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");
+
+        return sbHtml.toString();
+    }
+
+    /**
+     * 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
+     * 如果接口中没有上传文件参数,那么strParaFileName与strFilePath设置为空值
+     * 如:buildRequest("", "",sParaTemp)
+     *
+     * @param strParaFileName 文件类型的参数名
+     * @param strFilePath     文件路径
+     * @param sParaTemp       请求参数数组
+     * @return 支付宝处理结果
+     * @throws Exception
+     * @paramALIPAY_GATEWAY_NEW 支付宝网关地址
+     */
+    public static String buildRequest(String ALIPAY_GATEWAY_NEW, String strParaFileName, String strFilePath, Map<String, String> sParaTemp) throws Exception {
+        //待请求参数数组
+        Map<String, String> sPara = buildRequestPara(sParaTemp);
+
+        HttpProtocolHandler httpProtocolHandler = HttpProtocolHandler.getInstance();
+
+        HttpRequest request = new HttpRequest(HttpResultType.BYTES);
+        //设置编码集
+        request.setCharset(AlipayConfig.input_charset);
+
+        request.setParameters(generatNameValuePair(sPara));
+        request.setUrl(ALIPAY_GATEWAY_NEW + "_input_charset=" + AlipayConfig.input_charset);
+
+        HttpResponse response = httpProtocolHandler.execute(request, strParaFileName, strFilePath);
+        if (response == null) {
+            return null;
+        }
+
+        String strResult = response.getStringResult();
+
+        return strResult;
+    }
+
+    /**
+     * MAP类型数组转换成NameValuePair类型
+     *
+     * @param properties MAP类型数组
+     * @return NameValuePair类型数组
+     */
+    private static NameValuePair[] generatNameValuePair(Map<String, String> properties) {
+        NameValuePair[] nameValuePair = new NameValuePair[properties.size()];
+        int i = 0;
+        for (Map.Entry<String, String> entry : properties.entrySet()) {
+            nameValuePair[i++] = new NameValuePair(entry.getKey(), entry.getValue());
+        }
+
+        return nameValuePair;
+    }
+
+    /**
+     * 解析远程模拟提交后返回的信息,获得token
+     *
+     * @param text 要解析的字符串
+     * @return 解析结果
+     * @throws Exception
+     */
+    public static String getRequestToken(String text) throws Exception {
+        String request_token = "";
+        //以“&”字符切割字符串
+        String[] strSplitText = text.split("&");
+        //把切割后的字符串数组变成变量与数值组合的字典数组
+        Map<String, String> paraText = new HashMap<String, String>();
+        for (int i = 0; i < strSplitText.length; i++) {
+
+            //获得第一个=字符的位置
+            int nPos = strSplitText[i].indexOf("=");
+            //获得字符串长度
+            int nLen = strSplitText[i].length();
+            //获得变量名
+            String strKey = strSplitText[i].substring(0, nPos);
+            //获得数值
+            String strValue = strSplitText[i].substring(nPos + 1, nLen);
+            //放入MAP类中
+            paraText.put(strKey, strValue);
+        }
+
+        if (paraText.get("res_data") != null) {
+            String res_data = paraText.get("res_data");
+            //解析加密部分字符串(RSA与MD5区别仅此一句)
+            if (AlipayConfig.sign_type.equals("0001")) {
+                res_data = RSA.decrypt(res_data, AlipayConfig.private_key, AlipayConfig.input_charset);
+            }
+
+            //token从res_data中解析出来(也就是说res_data中已经包含token的内容)
+            Document document = DocumentHelper.parseText(res_data);
+            request_token = document.selectSingleNode("//direct_trade_create_res/request_token").getText();
+        }
+        return request_token;
+    }
+
+    /**
+     * 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
+     * 注意:远程解析XML出错,与服务器是否支持SSL等配置有关
+     *
+     * @return 时间戳字符串
+     * @throws IOException
+     * @throws DocumentException
+     * @throws MalformedURLException
+     */
+    public static String query_timestamp() throws MalformedURLException,
+            DocumentException, IOException {
+
+        //构造访问query_timestamp接口的URL串
+        String strUrl = "https://mapi.alipay.com/gateway.do?service=query_timestamp&partner=" + AlipayConfig.partner;
+        StringBuffer result = new StringBuffer();
+
+        SAXReader reader = new SAXReader();
+        Document doc = reader.read(new URL(strUrl).openStream());
+
+        List<Node> nodeList = doc.selectNodes("//alipay/*");
+
+        for (Node node : nodeList) {
+            // 截取部分不需要解析的信息
+            if (node.getName().equals("is_success") && node.getText().equals("T")) {
+                // 判断是否有成功标示
+                List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");
+                for (Node node1 : nodeList1) {
+                    result.append(node1.getText());
+                }
+            }
+        }
+
+        return result.toString();
+    }
+}

+ 111 - 0
top-core/src/main/java/com/alipay/util/UtilDate.java

@@ -0,0 +1,111 @@
+
+package com.alipay.util;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Random;
+
+/* *
+ *类名:UtilDate
+ *功能:自定义订单类
+ *详细:工具类,可以用作获取系统日期、订单编号等
+ *版本:3.3
+ *日期:2012-08-17
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
+ */
+public class UtilDate {
+
+    /**
+     * 年月日时分秒(无下划线) yyyyMMddHHmmss
+     */
+    public static final String dtLong = "yyyyMMddHHmmss";
+
+    /**
+     * 完整时间 yyyy-MM-dd HH:mm:ss
+     */
+    public static final String simple = "yyyy-MM-dd HH:mm:ss";
+
+    /**
+     * 年月日(无下划线) yyyyMMdd
+     */
+    public static final String dtShort = "yyyyMMdd";
+
+
+    /**
+     * 返回系统当前时间(精确到毫秒),作为一个唯一的订单编号
+     *
+     * @return 以yyyyMMddHHmmss为格式的当前系统时间
+     */
+    public static String getOrderNum() {
+        Date date = new Date();
+        DateFormat df = new SimpleDateFormat(dtLong);
+        return df.format(date) + getThree();
+    }
+
+    /**
+     * 获取系统当前日期(精确到毫秒),格式:yyyy-MM-dd HH:mm:ss
+     *
+     * @return
+     */
+    public static String getDateFormatter() {
+        Date date = new Date();
+        DateFormat df = new SimpleDateFormat(simple);
+        return df.format(date);
+    }
+
+    /**
+     * 获取系统当期年月日(精确到天),格式:yyyyMMdd
+     *
+     * @return
+     */
+    public static String getDate() {
+        Date date = new Date();
+        DateFormat df = new SimpleDateFormat(dtShort);
+        return df.format(date);
+    }
+
+    /**
+     * 产生随机的三位数
+     *
+     * @return
+     */
+    public static String getThree() {
+        Random rad = new Random();
+        return rad.nextInt(1000) + "";
+    }
+
+
+    /**
+     * 返回系统当前时间(精确到毫秒)
+     *
+     * @return 以yyyyMMddHHmmss为格式的当前系统时间
+     */
+    public static String getTodayFullTime() {
+        Date date = new Date();
+        DateFormat df = new SimpleDateFormat(dtLong);
+        return df.format(date);
+    }
+
+    /**
+     * 返回系统当前时间(精确到毫秒)
+     *
+     * @return 以yyyyMMddHHmmss为格式的当前系统时间
+     */
+    public static String getTomorrowFullTime() {
+        Date date = new Date();
+        DateFormat df = new SimpleDateFormat(dtLong);
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        cal.add(Calendar.DAY_OF_YEAR, +1);
+        return df.format(cal.getTime());
+    }
+
+    public static void main(String[] args) {
+        System.out.print(getTomorrowFullTime());
+    }
+
+}

+ 39 - 0
top-core/src/main/java/com/alipay/util/UtilDistance.java

@@ -0,0 +1,39 @@
+package com.alipay.util;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: MaYewei
+ * Date: 2015/2/4 0004
+ * Time: 10:28
+ * To change this template use File | Settings | File Templates.
+ */
+public class UtilDistance {
+
+    private static final double EARTH_RADIUS = 6378137;
+       private static double rad(double d)
+        {
+               return d * Math.PI / 180.0;
+            }
+
+        /**
+          * 根据两点间经纬度坐标(double值),计算两点间距离,单位为米
+          * @param lng1
+          * @param lat1
+          * @param lng2
+          * @param lat2
+          * @return
+          */
+        public static double GetDistance(double lng1, double lat1, double lng2, double lat2)
+        {
+               double radLat1 = rad(lat1);
+               double radLat2 = rad(lat2);
+               double a = radLat1 - radLat2;
+               double b = rad(lng1) - rad(lng2);
+               double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
+                        Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
+               s = s * EARTH_RADIUS;
+               s = Math.round(s * 10000) / 10000;
+               return s;
+            }
+
+}

+ 191 - 0
top-core/src/main/java/com/alipay/util/httpClient/HttpProtocolHandler.java

@@ -0,0 +1,191 @@
+package com.alipay.util.httpClient;
+
+import org.apache.commons.httpclient.*;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.multipart.*;
+import org.apache.commons.httpclient.params.HttpMethodParams;
+import org.apache.commons.httpclient.util.IdleConnectionTimeoutThread;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+/* *
+ *类名:HttpProtocolHandler
+ *功能:HttpClient方式访问
+ *详细:获取远程HTTP数据
+ *版本:3.3
+ *日期:2012-08-17
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
+ */
+
+public class HttpProtocolHandler {
+
+    private static String              DEFAULT_CHARSET                     = "GBK";
+
+    /** 连接超时时间,由bean factory设置,缺省为8秒钟 */
+    private int                        defaultConnectionTimeout            = 8000;
+
+    /** 回应超时时间, 由bean factory设置,缺省为30秒钟 */
+    private int                        defaultSoTimeout                    = 30000;
+
+    /** 闲置连接超时时间, 由bean factory设置,缺省为60秒钟 */
+    private int                        defaultIdleConnTimeout              = 60000;
+
+    private int                        defaultMaxConnPerHost               = 30;
+
+    private int                        defaultMaxTotalConn                 = 80;
+
+    /** 默认等待HttpConnectionManager返回连接超时(只有在达到最大连接数时起作用):1秒*/
+    private static final long          defaultHttpConnectionManagerTimeout = 3 * 1000;
+
+    /**
+     * HTTP连接管理器,该连接管理器必须是线程安全的.
+     */
+    private HttpConnectionManager      connectionManager;
+
+    private static HttpProtocolHandler httpProtocolHandler                 = new HttpProtocolHandler();
+
+    /**
+     * 工厂方法
+     * 
+     * @return
+     */
+    public static HttpProtocolHandler getInstance() {
+        return httpProtocolHandler;
+    }
+
+    /**
+     * 私有的构造方法
+     */
+    private HttpProtocolHandler() {
+        // 创建一个线程安全的HTTP连接池
+        connectionManager = new MultiThreadedHttpConnectionManager();
+        connectionManager.getParams().setDefaultMaxConnectionsPerHost(defaultMaxConnPerHost);
+        connectionManager.getParams().setMaxTotalConnections(defaultMaxTotalConn);
+
+        IdleConnectionTimeoutThread ict = new IdleConnectionTimeoutThread();
+        ict.addConnectionManager(connectionManager);
+        ict.setConnectionTimeout(defaultIdleConnTimeout);
+
+        ict.start();
+    }
+
+    /**
+     * 执行Http请求
+     * 
+     * @param request 请求数据
+     * @param strParaFileName 文件类型的参数名
+     * @param strFilePath 文件路径
+     * @return 
+     * @throws HttpException, IOException 
+     */
+    public HttpResponse execute(HttpRequest request, String strParaFileName, String strFilePath) throws HttpException, IOException {
+        HttpClient httpclient = new HttpClient(connectionManager);
+
+        // 设置连接超时
+        int connectionTimeout = defaultConnectionTimeout;
+        if (request.getConnectionTimeout() > 0) {
+            connectionTimeout = request.getConnectionTimeout();
+        }
+        httpclient.getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
+
+        // 设置回应超时
+        int soTimeout = defaultSoTimeout;
+        if (request.getTimeout() > 0) {
+            soTimeout = request.getTimeout();
+        }
+        httpclient.getHttpConnectionManager().getParams().setSoTimeout(soTimeout);
+
+        // 设置等待ConnectionManager释放connection的时间
+        httpclient.getParams().setConnectionManagerTimeout(defaultHttpConnectionManagerTimeout);
+
+        String charset = request.getCharset();
+        charset = charset == null ? DEFAULT_CHARSET : charset;
+        HttpMethod method = null;
+
+        //get模式且不带上传文件
+        if (request.getMethod().equals(HttpRequest.METHOD_GET)) {
+            method = new GetMethod(request.getUrl());
+            method.getParams().setCredentialCharset(charset);
+
+            // parseNotifyConfig会保证使用GET方法时,request一定使用QueryString
+            method.setQueryString(request.getQueryString());
+        } else if(strParaFileName.equals("") && strFilePath.equals("")) {
+        	//post模式且不带上传文件
+            method = new PostMethod(request.getUrl());
+            ((PostMethod) method).addParameters(request.getParameters());
+            method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded; text/html; charset=" + charset);
+        }
+        else {
+        	//post模式且带上传文件
+            method = new PostMethod(request.getUrl());
+            List<Part> parts = new ArrayList<Part>();
+            for (int i = 0; i < request.getParameters().length; i++) {
+            	parts.add(new StringPart(request.getParameters()[i].getName(), request.getParameters()[i].getValue(), charset));
+            }
+            //增加文件参数,strParaFileName是参数名,使用本地文件
+            parts.add(new FilePart(strParaFileName, new FilePartSource(new File(strFilePath))));
+            
+            // 设置请求体
+            ((PostMethod) method).setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[0]), new HttpMethodParams()));
+        }
+
+        // 设置Http Header中的User-Agent属性
+        method.addRequestHeader("User-Agent", "Mozilla/4.0");
+        HttpResponse response = new HttpResponse();
+
+        try {
+            httpclient.executeMethod(method);
+            if (request.getResultType().equals(HttpResultType.STRING)) {
+                response.setStringResult(method.getResponseBodyAsString());
+            } else if (request.getResultType().equals(HttpResultType.BYTES)) {
+                response.setByteResult(method.getResponseBody());
+            }
+            response.setResponseHeaders(method.getResponseHeaders());
+        } catch (UnknownHostException ex) {
+
+            return null;
+        } catch (IOException ex) {
+
+            return null;
+        } catch (Exception ex) {
+
+            return null;
+        } finally {
+            method.releaseConnection();
+        }
+        return response;
+    }
+
+    /**
+     * 将NameValuePairs数组转变为字符串
+     * 
+     * @param nameValues
+     * @return
+     */
+    protected String toString(NameValuePair[] nameValues) {
+        if (nameValues == null || nameValues.length == 0) {
+            return "null";
+        }
+
+        StringBuffer buffer = new StringBuffer();
+
+        for (int i = 0; i < nameValues.length; i++) {
+            NameValuePair nameValue = nameValues[i];
+
+            if (i == 0) {
+                buffer.append(nameValue.getName() + "=" + nameValue.getValue());
+            } else {
+                buffer.append("&" + nameValue.getName() + "=" + nameValue.getValue());
+            }
+        }
+
+        return buffer.toString();
+    }
+}

+ 152 - 0
top-core/src/main/java/com/alipay/util/httpClient/HttpRequest.java

@@ -0,0 +1,152 @@
+package com.alipay.util.httpClient;
+
+import org.apache.commons.httpclient.NameValuePair;
+
+/* *
+ *类名:HttpRequest
+ *功能:Http请求对象的封装
+ *详细:封装Http请求
+ *版本:3.3
+ *日期:2011-08-17
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
+ */
+
+public class HttpRequest {
+
+    /** HTTP GET method */
+    public static final String METHOD_GET        = "GET";
+
+    /** HTTP POST method */
+    public static final String METHOD_POST       = "POST";
+
+    /**
+     * 待请求的url
+     */
+    private String             url               = null;
+
+    /**
+     * 默认的请求方式
+     */
+    private String             method            = METHOD_POST;
+
+    private int                timeout           = 0;
+
+    private int                connectionTimeout = 0;
+
+    /**
+     * Post方式请求时组装好的参数值对
+     */
+    private NameValuePair[]    parameters        = null;
+
+    /**
+     * Get方式请求时对应的参数
+     */
+    private String             queryString       = null;
+
+    /**
+     * 默认的请求编码方式
+     */
+    private String             charset           = "GBK";
+
+    /**
+     * 请求发起方的ip地址
+     */
+    private String             clientIp;
+
+    /**
+     * 请求返回的方式
+     */
+    private HttpResultType     resultType        = HttpResultType.BYTES;
+
+    public HttpRequest(HttpResultType resultType) {
+        super();
+        this.resultType = resultType;
+    }
+
+    /**
+     * @return Returns the clientIp.
+     */
+    public String getClientIp() {
+        return clientIp;
+    }
+
+    /**
+     * @param clientIp The clientIp to set.
+     */
+    public void setClientIp(String clientIp) {
+        this.clientIp = clientIp;
+    }
+
+    public NameValuePair[] getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(NameValuePair[] parameters) {
+        this.parameters = parameters;
+    }
+
+    public String getQueryString() {
+        return queryString;
+    }
+
+    public void setQueryString(String queryString) {
+        this.queryString = queryString;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public void setMethod(String method) {
+        this.method = method;
+    }
+
+    public int getConnectionTimeout() {
+        return connectionTimeout;
+    }
+
+    public void setConnectionTimeout(int connectionTimeout) {
+        this.connectionTimeout = connectionTimeout;
+    }
+
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    /**
+     * @return Returns the charset.
+     */
+    public String getCharset() {
+        return charset;
+    }
+
+    /**
+     * @param charset The charset to set.
+     */
+    public void setCharset(String charset) {
+        this.charset = charset;
+    }
+
+    public HttpResultType getResultType() {
+        return resultType;
+    }
+
+    public void setResultType(HttpResultType resultType) {
+        this.resultType = resultType;
+    }
+
+}

+ 72 - 0
top-core/src/main/java/com/alipay/util/httpClient/HttpResponse.java

@@ -0,0 +1,72 @@
+package com.alipay.util.httpClient;
+
+import com.alipay.config.AlipayConfig;
+import org.apache.commons.httpclient.Header;
+
+import java.io.UnsupportedEncodingException;
+
+/* *
+ *类名:HttpResponse
+ *功能:Http返回对象的封装
+ *详细:封装Http返回信息
+ *版本:3.3
+ *日期:2011-08-17
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
+ */
+
+public class HttpResponse {
+
+    /**
+     * 返回中的Header信息
+     */
+    private Header[] responseHeaders;
+
+    /**
+     * String类型的result
+     */
+    private String   stringResult;
+
+    /**
+     * btye类型的result
+     */
+    private byte[]   byteResult;
+
+    public Header[] getResponseHeaders() {
+        return responseHeaders;
+    }
+
+    public void setResponseHeaders(Header[] responseHeaders) {
+        this.responseHeaders = responseHeaders;
+    }
+
+    public byte[] getByteResult() {
+        if (byteResult != null) {
+            return byteResult;
+        }
+        if (stringResult != null) {
+            return stringResult.getBytes();
+        }
+        return null;
+    }
+
+    public void setByteResult(byte[] byteResult) {
+        this.byteResult = byteResult;
+    }
+
+    public String getStringResult() throws UnsupportedEncodingException {
+        if (stringResult != null) {
+            return stringResult;
+        }
+        if (byteResult != null) {
+            return new String(byteResult, AlipayConfig.input_charset);
+        }
+        return null;
+    }
+
+    public void setStringResult(String stringResult) {
+        this.stringResult = stringResult;
+    }
+
+}

+ 27 - 0
top-core/src/main/java/com/alipay/util/httpClient/HttpResultType.java

@@ -0,0 +1,27 @@
+/*
+ * Alipay.com Inc.
+ * Copyright (c) 2004-2005 All Rights Reserved.
+ */
+package com.alipay.util.httpClient;
+
+/* *
+ *类名:HttpResultType
+ *功能:表示Http返回的结果字符方式
+ *详细:表示Http返回的结果字符方式
+ *版本:3.3
+ *日期:2012-08-17
+ *说明:
+ *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
+ *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
+ */
+public enum HttpResultType {
+    /**
+     * 字符串方式
+     */
+    STRING,
+
+    /**
+     * 字节数组方式
+     */
+    BYTES
+}

+ 64 - 0
top-core/src/main/java/com/tencent/Main.java

@@ -0,0 +1,64 @@
+package com.tencent;
+
+import com.tencent.common.Util;
+
+public class Main {
+
+    public static void main(String[] args) {
+
+        try {
+
+            //--------------------------------------------------------------------
+            //温馨提示,第一次使用该SDK时请到com.tencent.common.Configure类里面进行配置
+            //--------------------------------------------------------------------
+
+
+
+            //--------------------------------------------------------------------
+            //PART One:基础组件测试
+            //--------------------------------------------------------------------
+
+            //1)https请求可用性测试
+            //HTTPSPostRquestWithCert.test();
+
+            //2)测试项目用到的XStream组件,本项目利用这个组件将Java对象转换成XML数据Post给API
+            //XStreamTest.test();
+
+
+            //--------------------------------------------------------------------
+            //PART Two:基础服务测试
+            //--------------------------------------------------------------------
+
+            //1)测试被扫支付API
+            //PayServiceTest.test();
+
+            //2)测试被扫订单查询API
+            //PayQueryServiceTest.test();
+
+            //3)测试撤销API
+            //温馨提示,测试支付API成功扣到钱之后,可以通过调用PayQueryServiceTest.test(),将支付成功返回的transaction_id和out_trade_no数据贴进去,完成撤销工作,把钱退回来 ^_^v
+            //ReverseServiceTest.test();
+
+            //4)测试退款申请API
+            //RefundServiceTest.test();
+
+            //5)测试退款查询API
+            //RefundQueryServiceTest.test();
+
+            //6)测试对账单API
+            //DownloadBillServiceTest.test();
+
+
+            //本地通过xml进行API数据模拟的时候,先按需手动修改xml各个节点的值,然后通过以下方法对这个新的xml数据进行签名得到一串合法的签名,最后把这串签名放到这个xml里面的sign字段里,这样进行模拟的时候就可以通过签名验证了
+           // Util.log(Signature.getSignFromResponseString(Util.getLocalXMLString("/test/com/tencent/business/refundqueryserviceresponsedata/refundquerysuccess2.xml")));
+
+            //Util.log(new Date().getTime());
+            //Util.log(System.currentTimeMillis());
+
+        } catch (Exception e){
+            Util.log(e.getMessage());
+        }
+
+    }
+
+}

+ 153 - 0
top-core/src/main/java/com/tencent/WXPay.java

@@ -0,0 +1,153 @@
+package com.tencent;
+
+import com.tencent.business.DownloadBillBusiness;
+import com.tencent.business.RefundBusiness;
+import com.tencent.business.RefundQueryBusiness;
+import com.tencent.business.ScanPayBusiness;
+import com.tencent.common.Configure;
+import com.tencent.protocol.downloadbill_protocol.DownloadBillReqData;
+import com.tencent.protocol.pay_protocol.JSPayReqData;
+import com.tencent.protocol.pay_protocol.ScanPayReqData;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryReqData;
+import com.tencent.protocol.refund_protocol.RefundReqData;
+import com.tencent.protocol.refund_query_protocol.RefundQueryReqData;
+import com.tencent.protocol.reverse_protocol.ReverseReqData;
+import com.tencent.service.*;
+
+/**
+ * SDK总入口
+ */
+public class WXPay {
+
+    /**
+     * 初始化SDK依赖的几个关键配置
+     * @param key 签名算法需要用到的秘钥
+     * @param appID 公众账号ID
+     * @param mchID 商户ID
+     * @param sdbMchID 子商户ID,受理模式必填
+     * @param certLocalPath HTTP证书在服务器中的路径,用来加载证书用
+     * @param certPassword HTTP证书的密码,默认等于MCHID
+     */
+    public static void initSDKConfiguration(String key,String appID,String mchID,String sdbMchID,String certLocalPath,String certPassword){
+        Configure.setKey(key);
+        Configure.setAppID(appID);
+        Configure.setMchID(mchID);
+        Configure.setSubMchID(sdbMchID);
+        Configure.setCertLocalPath(certLocalPath);
+        Configure.setCertPassword(certPassword);
+    }
+
+
+    /**
+     * 请求支付服务
+     * @param jsPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public static String requestPayService(JSPayReqData jsPayReqData) throws Exception{
+        return new UnifiedOrderPayService().request(jsPayReqData);
+    }
+
+    /**
+     * 请求被扫支付服务
+     * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public static String requestScanPayService(ScanPayReqData scanPayReqData) throws Exception{
+        return new ScanPayService().request(scanPayReqData);
+    }
+
+    /**
+     * 请求支付查询服务
+     * @param scanPayQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+	public static String requestScanPayQueryService(ScanPayQueryReqData scanPayQueryReqData) throws Exception{
+		return new ScanPayQueryService().request(scanPayQueryReqData);
+	}
+
+    /**
+     * 请求退款服务
+     * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public static String requestRefundService(RefundReqData refundReqData) throws Exception{
+        return new RefundService().request(refundReqData);
+    }
+
+    /**
+     * 请求退款查询服务
+     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+	public static String requestRefundQueryService(RefundQueryReqData refundQueryReqData) throws Exception{
+		return new RefundQueryService().request(refundQueryReqData);
+	}
+
+    /**
+     * 请求撤销服务
+     * @param reverseReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+	public static String requestReverseService(ReverseReqData reverseReqData) throws Exception{
+		return new ReverseService().request(reverseReqData);
+	}
+
+    /**
+     * 请求对账单下载服务
+     * @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public static String requestDownloadBillService(DownloadBillReqData downloadBillReqData) throws Exception{
+        return new DownloadBillService().request(downloadBillReqData);
+    }
+
+    /**
+     * 直接执行被扫支付业务逻辑(包含最佳实践流程)
+     * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public static void doScanPayBusiness(ScanPayReqData scanPayReqData, ScanPayBusiness.ResultListener resultListener) throws Exception {
+        new ScanPayBusiness().run(scanPayReqData, resultListener);
+    }
+
+    /**
+     * 调用退款业务逻辑
+     * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 业务逻辑可能走到的结果分支,需要商户处理
+     * @throws Exception
+     */
+    public static void doRefundBusiness(RefundReqData refundReqData, RefundBusiness.ResultListener resultListener) throws Exception {
+        new RefundBusiness().run(refundReqData,resultListener);
+    }
+
+    /**
+     * 运行退款查询的业务逻辑
+     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public static void doRefundQueryBusiness(RefundQueryReqData refundQueryReqData,RefundQueryBusiness.ResultListener resultListener) throws Exception {
+        new RefundQueryBusiness().run(refundQueryReqData,resultListener);
+    }
+
+    /**
+     * 请求对账单下载服务
+     * @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public static void doDownloadBillBusiness(DownloadBillReqData downloadBillReqData,DownloadBillBusiness.ResultListener resultListener) throws Exception {
+        new DownloadBillBusiness().run(downloadBillReqData,resultListener);
+    }
+
+
+}

+ 125 - 0
top-core/src/main/java/com/tencent/bridge/IBridge.java

@@ -0,0 +1,125 @@
+package com.tencent.bridge;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/1
+ * Time: 17:11
+ */
+public interface IBridge {
+
+    /**
+     * 获取auth_code,这个是扫码终端设备从用户手机上扫取到的支付授权号,这个号是跟用户用来支付的银行卡绑定的,有效期是1分钟
+     * @return 授权码
+     */
+    public String getAuthCode();
+
+    /**
+     * 获取out_trade_no,这个是商户系统内自己可以用来唯一标识该笔订单的字符串,可以包含字母和数字,不超过32位
+     * @return 订单号
+     */
+    public String getOutTradeNo();
+
+    /**
+     * 获取body:要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+     * @return 描述信息
+     */
+    public String getBody();
+
+
+    /**
+     * 获取attach:支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回,有助于商户自己可以注明该笔消费的具体内容,方便后续的运营和记录
+     * @return 附加数据
+     */
+    public String getAttach();
+
+    /**
+     * 获取订单总额
+     * @return 订单总额
+     */
+    public int getTotalFee();
+
+    /**
+     * 获取device_info:商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+     * @return 支付终端设备号
+     */
+    public String getDeviceInfo();
+
+    /**
+     * 获取机器的ip地址
+     * @return 机器设备的ip地址
+     */
+    public String getUserIp();
+
+    /**
+     * 获取spBillCreateIP:订单生成的机器IP
+     * @return 订单生成的机器IP
+     */
+    public String getSpBillCreateIP();
+
+    /**
+     * 获取time_start:订单生成时间
+     * @return 订单生成时间
+     */
+    public String getTimeStart();
+
+    /**
+     * 获取time_end:订单生成时间
+     * @return 订单失效时间
+     */
+    public String getTimeExpire();
+
+    /**
+     * 获取goods_tag:商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+     * @return 商品标记
+     */
+    public String getGoodsTag();
+
+    /**
+     * 获取transaction_id:微信平台支付成功时给分配的唯一交易号,一般只要有这个tracnsacion_id,后续的查询、撤销、退款都建议优先用这个,而不是商户自己的那个out_trade_no
+     * @return 微信平台官方分配的交易号
+     */
+    public String getTransactionID();
+
+    /**
+     * 获取out_refund_no:商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+     * @return 商户系统内部的退款单号
+     */
+    public String getOutRefundNo();
+
+    /**
+     * 获取refund_fee:获取本次退款请求所要退的具体金额,这个金额不能比这个订单的total_fee(总金额)还大
+     * @return 本次退款请求所要退的具体金额
+     */
+    public int getRefundFee();
+
+    /**
+     * 获取refund_id:微信平台退款成功时给分配的唯一退款号,一般只要有这个refund_id,后续的查询建议优先用这个
+     * @return 微信平台官方分配的退款号
+     */
+    public String getRefundID();
+
+    /**
+     * 获取bill_date:获取对账单API需要的日期,格式是yyyyMMdd
+     * @return 要查询对账单的日期
+     */
+    public String getBillDate();
+
+    /**
+     * 获取bill_type:获取对账单API需要的数据类型,这些类型在DownloadBillService里面有定义
+     * @return 要查询对账单的类型
+     */
+    public String getBillType();
+
+    /**
+     * 获取操作员的ID,默认等于商户号
+     * @return 返回操作员的ID
+     */
+    public String getOpUserID();
+
+    /**
+     * 获取退款货币类型,符合ISO 4217标准的三位字母代码,默认为CNY(人民币)
+     * @return 获取退款货币类型
+     */
+    public String getRefundFeeType();
+
+}

+ 156 - 0
top-core/src/main/java/com/tencent/business/DownloadBillBusiness.java

@@ -0,0 +1,156 @@
+package com.tencent.business;
+
+import com.tencent.common.Configure;
+import com.tencent.common.Log;
+import com.tencent.common.Util;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.downloadbill_protocol.DownloadBillReqData;
+import com.tencent.protocol.downloadbill_protocol.DownloadBillResData;
+import com.tencent.service.DownloadBillService;
+import com.thoughtworks.xstream.io.StreamException;
+import org.slf4j.LoggerFactory;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/3
+ * Time: 10:45
+ */
+public class DownloadBillBusiness {
+
+    public DownloadBillBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        downloadBillService = new DownloadBillService();
+    }
+
+    public interface ResultListener{
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(DownloadBillResData downloadBillResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(DownloadBillResData downloadBillResData);
+
+        //下载对账单失败
+        void onDownloadBillFail(String response);
+
+        //下载对账单成功
+        void onDownloadBillSuccess(String response);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(DownloadBillBusiness.class));
+
+    //执行结果
+    private static String result = "";
+
+    private DownloadBillService downloadBillService;
+
+    /**
+     * 请求对账单下载服务
+     * @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+
+    public void run(DownloadBillReqData downloadBillReqData,ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“对账单API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        //API返回的数据
+        String downloadBillServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+        //支持加载本地测试数据进行调试
+
+        log.i("对账单API返回的数据如下:");
+        downloadBillServiceResponseString = downloadBillService.request(downloadBillReqData);
+
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        log.i(downloadBillServiceResponseString);
+
+        DownloadBillResData downloadBillResData;
+
+        String returnCode = "";
+        String returnMsg = "";
+
+        try {
+            //注意,这里失败的时候是返回xml数据,成功的时候反而返回非xml数据
+            downloadBillResData = (DownloadBillResData) Util.getObjectFromXML(downloadBillServiceResponseString, DownloadBillResData.class);
+
+            if (downloadBillResData == null || downloadBillResData.getReturn_code() == null) {
+                setResult("Case1:对账单API请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问",Log.LOG_TYPE_ERROR);
+                resultListener.onFailByReturnCodeError(downloadBillResData);
+                return;
+            }
+            if (downloadBillResData.getReturn_code().equals("FAIL")) {
+                ///注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+                setResult("Case2:对账单API系统返回失败,请检测Post给API的数据是否规范合法",Log.LOG_TYPE_ERROR);
+                resultListener.onFailByReturnCodeFail(downloadBillResData);
+                returnCode = "FAIL";
+                returnMsg = downloadBillResData.getReturn_msg();
+            }
+        } catch (StreamException e) {
+            //注意,这里成功的时候是直接返回纯文本的对账单文本数据,非XML格式
+            if (downloadBillServiceResponseString.equals(null) || downloadBillServiceResponseString.equals("")) {
+                setResult("Case4:对账单API系统返回数据为空",Log.LOG_TYPE_ERROR);
+                resultListener.onDownloadBillFail(downloadBillServiceResponseString);
+            } else {
+                setResult("Case3:对账单API系统成功返回数据",Log.LOG_TYPE_INFO);
+                resultListener.onDownloadBillSuccess(downloadBillServiceResponseString);
+            }
+            returnCode = "SUCCESS";
+        } finally {
+
+            ReportReqData reportReqData = new ReportReqData(
+                    downloadBillReqData.getDevice_info(),
+                    Configure.DOWNLOAD_BILL_API,
+                    (int) (totalTimeCost),//本次请求耗时
+                    returnCode,
+                    returnMsg,
+                    "",
+                    "",
+                    "",
+                    "",
+                    Configure.getIP()
+            );
+
+            long timeAfterReport;
+            if(Configure.isUseThreadToDoReport()){
+                ReporterFactory.getReporter(reportReqData).run();
+                timeAfterReport = System.currentTimeMillis();
+                Util.log("pay+report总耗时(异步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+            }else{
+                ReportService.request(reportReqData);
+                timeAfterReport = System.currentTimeMillis();
+                Util.log("pay+report总耗时(同步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+            }
+        }
+    }
+
+    public void setDownloadBillService(DownloadBillService service) {
+        downloadBillService = service;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        DownloadBillBusiness.result = result;
+    }
+
+    public void setResult(String result,String type){
+        setResult(result);
+        log.log(type,result);
+    }
+
+}

+ 162 - 0
top-core/src/main/java/com/tencent/business/RefundBusiness.java

@@ -0,0 +1,162 @@
+package com.tencent.business;
+
+import com.tencent.common.Configure;
+import com.tencent.common.Log;
+import com.tencent.common.Signature;
+import com.tencent.common.Util;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.refund_protocol.RefundReqData;
+import com.tencent.protocol.refund_protocol.RefundResData;
+import com.tencent.service.RefundService;
+import org.slf4j.LoggerFactory;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/2
+ * Time: 17:51
+ */
+public class RefundBusiness {
+
+    public RefundBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        refundService = new RefundService();
+    }
+
+    public interface ResultListener{
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(RefundResData refundResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(RefundResData refundResData);
+
+        //支付请求API返回的数据签名验证失败,有可能数据被篡改了
+        void onFailBySignInvalid(RefundResData refundResData);
+
+        //退款失败
+        void onRefundFail(RefundResData refundResData);
+
+        //退款成功
+        void onRefundSuccess(RefundResData refundResData);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(RefundBusiness.class));
+
+    //执行结果
+    private static String result = "";
+
+    private RefundService refundService;
+
+    /**
+     * 调用退款业务逻辑
+     * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 业务逻辑可能走到的结果分支,需要商户处理
+     * @throws Exception
+     */
+    public void run(RefundReqData refundReqData,ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“退款API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        //API返回的数据
+        String refundServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+
+        log.i("退款查询API返回的数据如下:");
+        refundServiceResponseString = refundService.request(refundReqData);
+
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        log.i(refundServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        RefundResData refundResData = (RefundResData) Util.getObjectFromXML(refundServiceResponseString, RefundResData.class);
+
+
+        ReportReqData reportReqData = new ReportReqData(
+                refundResData.getDevice_info(),
+                Configure.REFUND_API,
+                (int) (totalTimeCost),//本次请求耗时
+                refundResData.getReturn_code(),
+                refundResData.getReturn_msg(),
+                refundResData.getResult_code(),
+                refundResData.getErr_code(),
+                refundResData.getErr_code_des(),
+                refundResData.getOut_trade_no(),
+                Configure.getIP()
+        );
+
+        long timeAfterReport;
+        if(Configure.isUseThreadToDoReport()){
+            ReporterFactory.getReporter(reportReqData).run();
+            timeAfterReport = System.currentTimeMillis();
+            Util.log("pay+report总耗时(异步方式上报):" + (timeAfterReport - costTimeStart) + "ms");
+        }else{
+            ReportService.request(reportReqData);
+            timeAfterReport = System.currentTimeMillis();
+            Util.log("pay+report总耗时(同步方式上报):" + (timeAfterReport - costTimeStart) + "ms");
+        }
+
+        if (refundResData == null || refundResData.getReturn_code() == null) {
+            setResult("Case1:退款API请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问",Log.LOG_TYPE_ERROR);
+            resultListener.onFailByReturnCodeError(refundResData);
+            return;
+        }
+
+        //Debug:查看数据是否正常被填充到scanPayResponseData这个对象中
+        //Util.reflect(refundResData);
+
+        if (refundResData.getReturn_code().equals("FAIL")) {
+            ///注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            setResult("Case2:退款API系统返回失败,请检测Post给API的数据是否规范合法",Log.LOG_TYPE_ERROR);
+            resultListener.onFailByReturnCodeFail(refundResData);
+        } else {
+            log.i("退款API系统成功返回数据");
+            //--------------------------------------------------------------------
+            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改,确保安全
+            //--------------------------------------------------------------------
+
+            if (!Signature.checkIsSignValidFromResponseString(refundServiceResponseString)) {
+                setResult("Case3:退款请求API返回的数据签名验证失败,有可能数据被篡改了",Log.LOG_TYPE_ERROR);
+                resultListener.onFailBySignInvalid(refundResData);
+                return;
+            }
+
+            if (refundResData.getResult_code().equals("FAIL")) {
+                log.i("出错,错误码:" + refundResData.getErr_code() + "     错误信息:" + refundResData.getErr_code_des());
+                setResult("Case4:【退款失败】",Log.LOG_TYPE_ERROR);
+                //退款失败时再怎么延时查询退款状态都没有意义,这个时间建议要么再手动重试一次,依然失败的话请走投诉渠道进行投诉
+                resultListener.onRefundFail(refundResData);
+            } else {
+                //退款成功
+                setResult("Case5:【退款成功】",Log.LOG_TYPE_INFO);
+                resultListener.onRefundSuccess(refundResData);
+            }
+        }
+    }
+
+    public void setRefundService(RefundService service) {
+        refundService = service;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        RefundBusiness.result = result;
+    }
+
+    public void setResult(String result,String type){
+        setResult(result);
+        log.log(type,result);
+    }
+}

+ 197 - 0
top-core/src/main/java/com/tencent/business/RefundQueryBusiness.java

@@ -0,0 +1,197 @@
+package com.tencent.business;
+
+import com.tencent.common.*;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.refund_query_protocol.RefundOrderData;
+import com.tencent.protocol.refund_query_protocol.RefundQueryReqData;
+import com.tencent.protocol.refund_query_protocol.RefundQueryResData;
+import com.tencent.service.RefundQueryService;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/2
+ * Time: 18:51
+ */
+public class RefundQueryBusiness {
+
+    public RefundQueryBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        refundQueryService = new RefundQueryService();
+    }
+
+    public interface ResultListener{
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(RefundQueryResData refundQueryResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(RefundQueryResData refundQueryResData);
+
+        //支付请求API返回的数据签名验证失败,有可能数据被篡改了
+        void onFailBySignInvalid(RefundQueryResData refundQueryResData);
+
+        //退款查询失败
+        void onRefundQueryFail(RefundQueryResData refundQueryResData);
+
+        //退款查询成功
+        void onRefundQuerySuccess(RefundQueryResData refundQueryResData);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(RefundQueryBusiness.class));
+
+    //执行结果
+    private static String result = "";
+
+    //查询到的结果
+    private static String orderListResult = "";
+
+    private RefundQueryService refundQueryService;
+
+    public String getOrderListResult() {
+        return orderListResult;
+    }
+
+    public void setOrderListResult(String orderListResult) {
+        RefundQueryBusiness.orderListResult = orderListResult;
+    }
+
+    /**
+     * 运行退款查询的业务逻辑
+     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public void run(RefundQueryReqData refundQueryReqData,ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“退款查询API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        //接受API返回
+        String refundQueryServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+        //表示是本地测试数据
+        log.i("退款查询API返回的数据如下:");
+        refundQueryServiceResponseString = refundQueryService.request(refundQueryReqData);
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        log.i(refundQueryServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        RefundQueryResData refundQueryResData = (RefundQueryResData) Util.getObjectFromXML(refundQueryServiceResponseString, RefundQueryResData.class);
+
+        ReportReqData reportReqData = new ReportReqData(
+                refundQueryReqData.getDevice_info(),
+                Configure.REFUND_QUERY_API,
+                (int) (totalTimeCost),//本次请求耗时
+                refundQueryResData.getReturn_code(),
+                refundQueryResData.getReturn_msg(),
+                refundQueryResData.getResult_code(),
+                refundQueryResData.getErr_code(),
+                refundQueryResData.getErr_code_des(),
+                refundQueryResData.getOut_trade_no(),
+                Configure.getIP()
+        );
+
+        long timeAfterReport;
+        if(Configure.isUseThreadToDoReport()){
+            ReporterFactory.getReporter(reportReqData).run();
+            timeAfterReport = System.currentTimeMillis();
+            Util.log("pay+report总耗时(异步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+        }else{
+            ReportService.request(reportReqData);
+            timeAfterReport = System.currentTimeMillis();
+            Util.log("pay+report总耗时(同步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+        }
+
+
+        if (refundQueryResData == null || refundQueryResData.getReturn_code() == null) {
+            setResult("Case1:退款查询API请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问",Log.LOG_TYPE_ERROR);
+            resultListener.onFailByReturnCodeError(refundQueryResData);
+            return;
+        }
+
+        //Debug:查看数据是否正常被填充到scanPayResponseData这个对象中
+        //Util.reflect(refundQueryResData);
+
+        if (refundQueryResData.getReturn_code().equals("FAIL")) {
+            ///注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            setResult("Case2:退款查询API系统返回失败,请检测Post给API的数据是否规范合法",Log.LOG_TYPE_ERROR);
+            resultListener.onFailByReturnCodeFail(refundQueryResData);
+        } else {
+            log.i("退款查询API系统成功返回数据");
+            //--------------------------------------------------------------------
+            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改,确保安全
+            //--------------------------------------------------------------------
+
+            if (!Signature.checkIsSignValidFromResponseString(refundQueryServiceResponseString)) {
+                setResult("Case3:退款查询API返回的数据签名验证失败,有可能数据被篡改了",Log.LOG_TYPE_ERROR);
+                resultListener.onFailBySignInvalid(refundQueryResData);
+                return;
+            }
+
+            if (refundQueryResData.getResult_code().equals("FAIL")) {
+                Util.log("出错,错误码:" + refundQueryResData.getErr_code() + "     错误信息:" + refundQueryResData.getErr_code_des());
+                setResult("Case4:【退款查询失败】",Log.LOG_TYPE_ERROR);
+                resultListener.onRefundQueryFail(refundQueryResData);
+                //退款失败时再怎么延时查询退款状态都没有意义,这个时间建议要么再手动重试一次,依然失败的话请走投诉渠道进行投诉
+            } else {
+                //退款成功
+                getRefundOrderListResult(refundQueryServiceResponseString);
+                setResult("Case5:【退款查询成功】",Log.LOG_TYPE_INFO);
+                resultListener.onRefundQuerySuccess(refundQueryResData);
+            }
+        }
+    }
+
+    /**
+     * 打印出服务器返回的订单查询结果
+     * @param refundQueryResponseString 退款查询返回API返回的数据
+     * @throws ParserConfigurationException
+     * @throws SAXException
+     * @throws IOException
+     */
+    private void getRefundOrderListResult(String refundQueryResponseString) throws ParserConfigurationException, SAXException, IOException {
+        List<RefundOrderData> refundOrderList = XMLParser.getRefundOrderList(refundQueryResponseString);
+        int count = 1;
+        for(RefundOrderData refundOrderData : refundOrderList){
+            Util.log("退款订单数据NO" + count + ":");
+            Util.log(refundOrderData.toMap());
+            orderListResult += refundOrderData.toMap().toString();
+            count++;
+        }
+        log.i("查询到的结果如下:");
+        log.i(orderListResult);
+    }
+
+    public void setRefundQueryService(RefundQueryService service) {
+        refundQueryService = service;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        RefundQueryBusiness.result = result;
+    }
+
+    public void setResult(String result,String type){
+        setResult(result);
+        log.log(type,result);
+    }
+
+}

+ 422 - 0
top-core/src/main/java/com/tencent/business/ScanPayBusiness.java

@@ -0,0 +1,422 @@
+package com.tencent.business;
+
+import com.tencent.common.Configure;
+import com.tencent.common.Log;
+import com.tencent.common.Signature;
+import com.tencent.common.Util;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.pay_protocol.ScanPayReqData;
+import com.tencent.protocol.pay_protocol.UnifiedPayResData;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryReqData;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryResData;
+import com.tencent.protocol.reverse_protocol.ReverseReqData;
+import com.tencent.protocol.reverse_protocol.ReverseResData;
+import com.tencent.service.ReverseService;
+import com.tencent.service.ScanPayQueryService;
+import com.tencent.service.ScanPayService;
+import org.slf4j.LoggerFactory;
+
+import static java.lang.Thread.sleep;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/1
+ * Time: 17:05
+ */
+public class ScanPayBusiness {
+
+    public ScanPayBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        scanPayService = new ScanPayService();
+        scanPayQueryService = new ScanPayQueryService();
+        reverseService = new ReverseService();
+    }
+
+    public interface ResultListener {
+
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(UnifiedPayResData scanPayResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(UnifiedPayResData scanPayResData);
+
+        //支付请求API返回的数据签名验证失败,有可能数据被篡改了
+        void onFailBySignInvalid(UnifiedPayResData scanPayResData);
+
+
+        //用户用来支付的二维码已经过期,提示收银员重新扫一下用户微信“刷卡”里面的二维码
+        void onFailByAuthCodeExpire(UnifiedPayResData scanPayResData);
+
+        //授权码无效,提示用户刷新一维码/二维码,之后重新扫码支付"
+        void onFailByAuthCodeInvalid(UnifiedPayResData scanPayResData);
+
+        //用户余额不足,换其他卡支付或是用现金支付
+        void onFailByMoneyNotEnough(UnifiedPayResData scanPayResData);
+
+        //支付失败
+        void onFail(UnifiedPayResData scanPayResData);
+
+        //支付成功
+        void onSuccess(UnifiedPayResData scanPayResData);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(ScanPayBusiness.class));
+
+    //每次调用订单查询API时的等待时间,因为当出现支付失败的时候,如果马上发起查询不一定就能查到结果,所以这里建议先等待一定时间再发起查询
+
+    private int waitingTimeBeforePayQueryServiceInvoked = 5000;
+
+    //循环调用订单查询API的次数
+    private int payQueryLoopInvokedCount = 3;
+
+    //每次调用撤销API的等待时间
+    private int waitingTimeBeforeReverseServiceInvoked = 5000;
+
+    private ScanPayService scanPayService;
+
+    private ScanPayQueryService scanPayQueryService;
+
+    private ReverseService reverseService;
+
+    /**
+     * 直接执行被扫支付业务逻辑(包含最佳实践流程)
+     *
+     * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public void run(ScanPayReqData scanPayReqData, ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“被扫支付API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        String outTradeNo = scanPayReqData.getOut_trade_no();
+
+        //接受API返回
+        String payServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+
+        log.i("支付API返回的数据如下:");
+        payServiceResponseString = scanPayService.request(scanPayReqData);
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        //打印回包数据
+        log.i(payServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        UnifiedPayResData scanPayResData = (UnifiedPayResData) Util.getObjectFromXML(payServiceResponseString, UnifiedPayResData.class);
+
+        //异步发送统计请求
+        //*
+
+        ReportReqData reportReqData = new ReportReqData(
+                scanPayReqData.getDevice_info(),
+                Configure.PAY_API,
+                (int) (totalTimeCost),//本次请求耗时
+                scanPayResData.getReturn_code(),
+                scanPayResData.getReturn_msg(),
+                scanPayResData.getResult_code(),
+                scanPayResData.getErr_code(),
+                scanPayResData.getErr_code_des(),
+                scanPayResData.getOut_trade_no(),
+                scanPayReqData.getSpbill_create_ip()
+        );
+        long timeAfterReport;
+        if (Configure.isUseThreadToDoReport()) {
+            ReporterFactory.getReporter(reportReqData).run();
+            timeAfterReport = System.currentTimeMillis();
+            log.i("pay+report总耗时(异步方式上报):" + (timeAfterReport - costTimeStart) + "ms");
+        } else {
+            ReportService.request(reportReqData);
+            timeAfterReport = System.currentTimeMillis();
+            log.i("pay+report总耗时(同步方式上报):" + (timeAfterReport - costTimeStart) + "ms");
+        }
+
+        if (scanPayResData == null || scanPayResData.getReturn_code() == null) {
+            log.e("【支付失败】支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问");
+            resultListener.onFailByReturnCodeError(scanPayResData);
+            return;
+        }
+
+        if (scanPayResData.getReturn_code().equals("FAIL")) {
+            //注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            log.e("【支付失败】支付API系统返回失败,请检测Post给API的数据是否规范合法");
+            resultListener.onFailByReturnCodeFail(scanPayResData);
+            return;
+        } else {
+            log.i("支付API系统成功返回数据");
+            //--------------------------------------------------------------------
+            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改,确保安全
+            //--------------------------------------------------------------------
+            if (!Signature.checkIsSignValidFromResponseString(payServiceResponseString)) {
+                log.e("【支付失败】支付请求API返回的数据签名验证失败,有可能数据被篡改了");
+                resultListener.onFailBySignInvalid(scanPayResData);
+                return;
+            }
+
+            //获取错误码
+            String errorCode = scanPayResData.getErr_code();
+            //获取错误描述
+            String errorCodeDes = scanPayResData.getErr_code_des();
+
+            if (scanPayResData.getResult_code().equals("SUCCESS")) {
+
+                //--------------------------------------------------------------------
+                //1)直接扣款成功
+                //--------------------------------------------------------------------
+
+                log.i("【一次性支付成功】");
+                resultListener.onSuccess(scanPayResData);
+            }else{
+
+                //出现业务错误
+                log.i("业务返回失败");
+                log.i("err_code:" + errorCode);
+                log.i("err_code_des:" + errorCodeDes);
+
+                //业务错误时错误码有好几种,商户重点提示以下几种
+                if (errorCode.equals("AUTHCODEEXPIRE") || errorCode.equals("AUTH_CODE_INVALID") || errorCode.equals("NOTENOUGH")) {
+
+                    //--------------------------------------------------------------------
+                    //2)扣款明确失败
+                    //--------------------------------------------------------------------
+
+                    //对于扣款明确失败的情况直接走撤销逻辑
+                    doReverseLoop(outTradeNo);
+
+                    //以下几种情况建议明确提示用户,指导接下来的工作
+                    if (errorCode.equals("AUTHCODEEXPIRE")) {
+                        //表示用户用来支付的二维码已经过期,提示收银员重新扫一下用户微信“刷卡”里面的二维码
+                        log.w("【支付扣款明确失败】原因是:" + errorCodeDes);
+                        resultListener.onFailByAuthCodeExpire(scanPayResData);
+                    } else if (errorCode.equals("AUTH_CODE_INVALID")) {
+                        //授权码无效,提示用户刷新一维码/二维码,之后重新扫码支付
+                        log.w("【支付扣款明确失败】原因是:" + errorCodeDes);
+                        resultListener.onFailByAuthCodeInvalid(scanPayResData);
+                    } else if (errorCode.equals("NOTENOUGH")) {
+                        //提示用户余额不足,换其他卡支付或是用现金支付
+                        log.w("【支付扣款明确失败】原因是:" + errorCodeDes);
+                        resultListener.onFailByMoneyNotEnough(scanPayResData);
+                    }
+                } else if (errorCode.equals("USERPAYING")) {
+
+                    //--------------------------------------------------------------------
+                    //3)需要输入密码
+                    //--------------------------------------------------------------------
+
+                    //表示有可能单次消费超过300元,或是免输密码消费次数已经超过当天的最大限制,这个时候提示用户输入密码,商户自己隔一段时间去查单,查询一定次数,看用户是否已经输入了密码
+                    if (doPayQueryLoop(payQueryLoopInvokedCount, outTradeNo)) {
+                        log.i("【需要用户输入密码、查询到支付成功】");
+                        resultListener.onSuccess(scanPayResData);
+                    } else {
+                        log.i("【需要用户输入密码、在一定时间内没有查询到支付成功、走撤销流程】");
+                        doReverseLoop(outTradeNo);
+                        resultListener.onFail(scanPayResData);
+                    }
+                } else {
+
+                    //--------------------------------------------------------------------
+                    //4)扣款未知失败
+                    //--------------------------------------------------------------------
+
+                    if (doPayQueryLoop(payQueryLoopInvokedCount, outTradeNo)) {
+                        log.i("【支付扣款未知失败、查询到支付成功】");
+                        resultListener.onSuccess(scanPayResData);
+                    } else {
+                        log.i("【支付扣款未知失败、在一定时间内没有查询到支付成功、走撤销流程】");
+                        doReverseLoop(outTradeNo);
+                        resultListener.onFail(scanPayResData);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 进行一次支付订单查询操作
+     *
+     * @param outTradeNo    商户系统内部的订单号,32个字符内可包含字母, [确保在商户系统唯一]
+     * @return 该订单是否支付成功
+     * @throws Exception
+     */
+    private boolean doOnePayQuery(String outTradeNo) throws Exception {
+
+        sleep(waitingTimeBeforePayQueryServiceInvoked);//等待一定时间再进行查询,避免状态还没来得及被更新
+
+        String payQueryServiceResponseString;
+
+        ScanPayQueryReqData scanPayQueryReqData = new ScanPayQueryReqData("",outTradeNo);
+        payQueryServiceResponseString = scanPayQueryService.request(scanPayQueryReqData);
+
+        log.i("支付订单查询API返回的数据如下:");
+        log.i(payQueryServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        ScanPayQueryResData scanPayQueryResData = (ScanPayQueryResData) Util.getObjectFromXML(payQueryServiceResponseString, ScanPayQueryResData.class);
+        if (scanPayQueryResData == null || scanPayQueryResData.getReturn_code() == null) {
+            log.i("支付订单查询请求逻辑错误,请仔细检测传过去的每一个参数是否合法");
+            return false;
+        }
+
+        if (scanPayQueryResData.getReturn_code().equals("FAIL")) {
+            //注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            log.i("支付订单查询API系统返回失败,失败信息为:" + scanPayQueryResData.getReturn_msg());
+            return false;
+        } else {
+            if (scanPayQueryResData.getResult_code().equals("SUCCESS")) {//业务层成功
+                if (scanPayQueryResData.getTrade_state().equals("SUCCESS")) {
+                    //表示查单结果为“支付成功”
+                    log.i("查询到订单支付成功");
+                    return true;
+                } else {
+                    //支付不成功
+                    log.i("查询到订单支付不成功");
+                    return false;
+                }
+            } else {
+                log.i("查询出错,错误码:" + scanPayQueryResData.getErr_code() + "     错误信息:" + scanPayQueryResData.getErr_code_des());
+                return false;
+            }
+        }
+    }
+
+    /**
+     * 由于有的时候是因为服务延时,所以需要商户每隔一段时间(建议5秒)后再进行查询操作,多试几次(建议3次)
+     *
+     * @param loopCount     循环次数,至少一次
+     * @param outTradeNo    商户系统内部的订单号,32个字符内可包含字母, [确保在商户系统唯一]
+     * @return 该订单是否支付成功
+     * @throws InterruptedException
+     */
+    private boolean doPayQueryLoop(int loopCount, String outTradeNo) throws Exception {
+        //至少查询一次
+        if (loopCount == 0) {
+            loopCount = 1;
+        }
+        //进行循环查询
+        for (int i = 0; i < loopCount; i++) {
+            if (doOnePayQuery(outTradeNo)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    //是否需要再调一次撤销,这个值由撤销API回包的recall字段决定
+    private boolean needRecallReverse = false;
+
+    /**
+     * 进行一次撤销操作
+     *
+     * @param outTradeNo    商户系统内部的订单号,32个字符内可包含字母, [确保在商户系统唯一]
+     * @return 该订单是否支付成功
+     * @throws Exception
+     */
+    private boolean doOneReverse(String outTradeNo) throws Exception {
+
+        sleep(waitingTimeBeforeReverseServiceInvoked);//等待一定时间再进行查询,避免状态还没来得及被更新
+
+        String reverseResponseString;
+
+        ReverseReqData reverseReqData = new ReverseReqData("",outTradeNo);
+        reverseResponseString = reverseService.request(reverseReqData);
+
+        log.i("撤销API返回的数据如下:");
+        log.i(reverseResponseString);
+        //将从API返回的XML数据映射到Java对象
+        ReverseResData reverseResData = (ReverseResData) Util.getObjectFromXML(reverseResponseString, ReverseResData.class);
+        if (reverseResData == null) {
+            log.i("支付订单撤销请求逻辑错误,请仔细检测传过去的每一个参数是否合法");
+            return false;
+        }
+        if (reverseResData.getReturn_code().equals("FAIL")) {
+            //注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            log.i("支付订单撤销API系统返回失败,失败信息为:" + reverseResData.getReturn_msg());
+            return false;
+        } else {
+            if (reverseResData.getResult_code().equals("FAIL")) {
+                log.i("撤销出错,错误码:" + reverseResData.getErr_code() + "     错误信息:" + reverseResData.getErr_code_des());
+                if (reverseResData.getRecall().equals("Y")) {
+                    //表示需要重试
+                    needRecallReverse = true;
+                    return false;
+                } else {
+                    //表示不需要重试,也可以当作是撤销成功
+                    needRecallReverse = false;
+                    return true;
+                }
+            } else {
+                //查询成功,打印交易状态
+                log.i("支付订单撤销成功");
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * 由于有的时候是因为服务延时,所以需要商户每隔一段时间(建议5秒)后再进行查询操作,是否需要继续循环调用撤销API由撤销API回包里面的recall字段决定。
+     *
+     * @param outTradeNo    商户系统内部的订单号,32个字符内可包含字母, [确保在商户系统唯一]
+     * @throws InterruptedException
+     */
+    private void doReverseLoop(String outTradeNo) throws Exception {
+        //初始化这个标记
+        needRecallReverse = true;
+        //进行循环撤销,直到撤销成功,或是API返回recall字段为"Y"
+        while (needRecallReverse) {
+            if (doOneReverse(outTradeNo)) {
+                return;
+            }
+        }
+    }
+
+    /**
+     * 设置循环多次调用订单查询API的时间间隔
+     *
+     * @param duration 时间间隔,默认为10秒
+     */
+    public void setWaitingTimeBeforePayQueryServiceInvoked(int duration) {
+        waitingTimeBeforePayQueryServiceInvoked = duration;
+    }
+
+    /**
+     * 设置循环多次调用订单查询API的次数
+     *
+     * @param count 调用次数,默认为三次
+     */
+    public void setPayQueryLoopInvokedCount(int count) {
+        payQueryLoopInvokedCount = count;
+    }
+
+    /**
+     * 设置循环多次调用撤销API的时间间隔
+     *
+     * @param duration 时间间隔,默认为5秒
+     */
+    public void setWaitingTimeBeforeReverseServiceInvoked(int duration) {
+        waitingTimeBeforeReverseServiceInvoked = duration;
+    }
+
+    public void setScanPayService(ScanPayService service) {
+        scanPayService = service;
+    }
+
+    public void setScanPayQueryService(ScanPayQueryService service) {
+        scanPayQueryService = service;
+    }
+
+    public void setReverseService(ReverseService service) {
+        reverseService = service;
+    }
+
+}

+ 164 - 0
top-core/src/main/java/com/tencent/common/Configure.java

@@ -0,0 +1,164 @@
+package com.tencent.common;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 14:40
+ * 这里放置各种配置数据
+ */
+public class Configure {
+//这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中)
+    // 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证
+    // 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改
+
+    private static String key = "1qaz2wsx3edcvfr45tgbnhy67ujmkitr";
+
+    //微信分配的公众号ID(开通公众号之后可以获取到)
+    private static String appID = "wx47d745fcf21e7c4a";
+
+    //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+    private static String mchID = "1247566901";
+
+    //受理模式下给子商户分配的子商户号
+    private static String subMchID = "";
+
+    //HTTPS证书的本地路径
+    private static String certLocalPath = "/home/ymwy/wx_cert/apiclient_cert.p12";
+//    private static String certLocalPath = "H:/wx_cert/apiclient_cert.p12";
+
+    //HTTPS证书密码,默认密码等于商户号MCHID
+    private static String certPassword = "1247566901";
+
+    //是否使用异步线程的方式来上报API测速,默认为异步模式
+    private static boolean useThreadToDoReport = true;
+
+    private static String Appsecret = "17a1b3bc78c367b79d6ffd4babea78b4";
+
+    //机器IP
+    private static String ip = "";
+
+    public final static String scope_snsapi_base = "snsapi_base";
+
+    public final static String scope_snsapi_userinfo = "snsapi_userinfo";
+
+    public final static String NOTIFY_URL = "http://member.oltop.cn/notify/wxpay";
+
+    public final static String STATE_WX_JS_PAY = "1";
+
+    public final static String STATE_DEFAULT = "2";
+
+    //重定向url获取accesstoken
+    private static String redirect_uri = "http://member.oltop.cn/weChat/getOpenId";
+
+    //以下是几个API的路径:
+
+    //0)通用支付下单支付API
+    public static String PAY_UNIFIED_ORDER_API = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+
+    //1)被扫支付API
+    public static String PAY_API = "https://api.mch.weixin.qq.com/pay/micropay";
+
+    //2)被扫支付查询API
+    public static String PAY_QUERY_API = "https://api.mch.weixin.qq.com/pay/orderquery";
+
+    //3)退款API
+    public static String REFUND_API = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+
+    //4)退款查询API
+    public static String REFUND_QUERY_API = "https://api.mch.weixin.qq.com/pay/refundquery";
+
+    //5)撤销API
+    public static String REVERSE_API = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
+
+    //6)下载对账单API
+    public static String DOWNLOAD_BILL_API = "https://api.mch.weixin.qq.com/pay/downloadbill";
+
+    //7) 统计上报API
+    public static String REPORT_API = "https://api.mch.weixin.qq.com/payitil/report";
+
+    public static boolean isUseThreadToDoReport() {
+        return useThreadToDoReport;
+    }
+
+    public static void setUseThreadToDoReport(boolean useThreadToDoReport) {
+        Configure.useThreadToDoReport = useThreadToDoReport;
+    }
+
+    public static String HttpsRequestClassName = "com.tencent.common.HttpsRequest";
+
+    public static void setKey(String key) {
+        Configure.key = key;
+    }
+
+    public static void setAppID(String appID) {
+        Configure.appID = appID;
+    }
+
+    public static void setMchID(String mchID) {
+        Configure.mchID = mchID;
+    }
+
+    public static void setSubMchID(String subMchID) {
+        Configure.subMchID = subMchID;
+    }
+
+    public static void setCertLocalPath(String certLocalPath) {
+        Configure.certLocalPath = certLocalPath;
+    }
+
+    public static void setCertPassword(String certPassword) {
+        Configure.certPassword = certPassword;
+    }
+
+    public static void setIp(String ip) {
+        Configure.ip = ip;
+    }
+
+    public static String getKey() {
+        return key;
+    }
+
+    public static String getAppid() {
+        return appID;
+    }
+
+    public static String getMchid() {
+        return mchID;
+    }
+
+    public static String getSubMchid() {
+        return subMchID;
+    }
+
+    public static String getCertLocalPath() {
+        return certLocalPath;
+    }
+
+    public static String getCertPassword() {
+        return certPassword;
+    }
+
+    public static String getIP() {
+        return ip;
+    }
+
+    public static void setHttpsRequestClassName(String name) {
+        HttpsRequestClassName = name;
+    }
+
+    public static String getAppsecret() {
+        return Appsecret;
+    }
+
+    public static void setAppsecret(String appsecret) {
+        Appsecret = appsecret;
+    }
+
+    public static String getRedirect_uri() {
+        return redirect_uri;
+    }
+
+    public static void setRedirect_uri(String redirect_uri) {
+        Configure.redirect_uri = redirect_uri;
+    }
+}

+ 200 - 0
top-core/src/main/java/com/tencent/common/HttpRequest.java

@@ -0,0 +1,200 @@
+package com.tencent.common;
+
+import com.tencent.service.IServiceRequest;
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLContexts;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLContext;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.security.*;
+import java.security.cert.CertificateException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 14:36
+ * 无需整数的request
+ */
+public class HttpRequest implements IServiceRequest {
+
+    public interface ResultListener {
+
+
+        public void onConnectionPoolTimeoutError();
+
+    }
+
+    private static Log log = new Log(LoggerFactory.getLogger(HttpRequest.class));
+
+    //表示请求器是否已经做了初始化工作
+    private boolean hasInit = false;
+
+    //连接超时时间,默认10秒
+    private int socketTimeout = 10000;
+
+    //传输超时时间,默认30秒
+    private int connectTimeout = 30000;
+
+    //请求器的配置
+    private RequestConfig requestConfig;
+
+    //HTTP请求器
+    private CloseableHttpClient httpClient;
+
+    public HttpRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException {
+        init();
+    }
+
+    private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
+
+        KeyStore keyStore = KeyStore.getInstance("PKCS12");
+        FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));//加载本地的证书进行https加密传输
+        try {
+            keyStore.load(instream, Configure.getCertPassword().toCharArray());//设置证书密码
+        } catch (CertificateException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } finally {
+            instream.close();
+        }
+
+        // Trust own CA and all self-signed certs
+        SSLContext sslcontext = SSLContexts.custom()
+                .loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray())
+                .build();
+        // Allow TLSv1 protocol only
+        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
+                sslcontext,
+                new String[]{"TLSv1"},
+                null,
+                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+
+        httpClient = HttpClients.custom()
+                .setSSLSocketFactory(sslsf)
+                .build();
+
+        //根据默认超时限制初始化requestConfig
+        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
+
+        hasInit = true;
+    }
+
+    /**
+     * 通过Https往API post xml数据
+     *
+     * @param url    API地址
+     * @param xmlObj 要提交的XML数据对象
+     * @return API回包的实际数据
+     * @throws IOException
+     * @throws KeyStoreException
+     * @throws UnrecoverableKeyException
+     * @throws NoSuchAlgorithmException
+     * @throws KeyManagementException
+     */
+
+    public String sendPost(String url, Object xmlObj) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
+
+        if (!hasInit) {
+            init();
+        }
+
+        String result = null;
+
+        HttpPost httpPost = new HttpPost(url);
+
+        //解决XStream对出现双下划线的bug
+        XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
+
+        //将要提交给API的数据对象转换成XML格式数据Post给API
+        String postDataXML = xStreamForRequestPostData.toXML(xmlObj);
+
+        Util.log("API,POST过去的数据是:");
+        Util.log(postDataXML);
+
+        //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
+        StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
+        httpPost.addHeader("Content-Type", "text/xml");
+        httpPost.setEntity(postEntity);
+
+        //设置请求器的配置
+        httpPost.setConfig(requestConfig);
+
+        Util.log("executing request" + httpPost.getRequestLine());
+
+        try {
+            HttpResponse response = httpClient.execute(httpPost);
+
+            HttpEntity entity = response.getEntity();
+
+            result = EntityUtils.toString(entity, "UTF-8");
+
+        } catch (ConnectionPoolTimeoutException e) {
+            log.e("http get throw ConnectionPoolTimeoutException(wait time out)");
+
+        } catch (ConnectTimeoutException e) {
+            log.e("http get throw ConnectTimeoutException");
+
+        } catch (SocketTimeoutException e) {
+            log.e("http get throw SocketTimeoutException");
+
+        } catch (Exception e) {
+            log.e("http get throw Exception");
+
+        } finally {
+            httpPost.abort();
+        }
+
+        return result;
+    }
+
+    /**
+     * 设置连接超时时间
+     *
+     * @param socketTimeout 连接时长,默认10秒
+     */
+    public void setSocketTimeout(int socketTimeout) {
+        socketTimeout = socketTimeout;
+        resetRequestConfig();
+    }
+
+    /**
+     * 设置传输超时时间
+     *
+     * @param connectTimeout 传输时长,默认30秒
+     */
+    public void setConnectTimeout(int connectTimeout) {
+        connectTimeout = connectTimeout;
+        resetRequestConfig();
+    }
+
+    private void resetRequestConfig() {
+        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
+    }
+
+    /**
+     * 允许商户自己做更高级更复杂的请求器配置
+     *
+     * @param requestConfig 设置HttpsRequest的请求器配置
+     */
+    public void setRequestConfig(RequestConfig requestConfig) {
+        requestConfig = requestConfig;
+    }
+}

+ 199 - 0
top-core/src/main/java/com/tencent/common/HttpsRequest.java

@@ -0,0 +1,199 @@
+package com.tencent.common;
+
+import com.tencent.service.IServiceRequest;
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLContexts;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLContext;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.security.*;
+import java.security.cert.CertificateException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 14:36
+ */
+public class HttpsRequest implements IServiceRequest {
+
+    public interface ResultListener {
+
+
+        public void onConnectionPoolTimeoutError();
+
+    }
+
+    private static Log log = new Log(LoggerFactory.getLogger(HttpRequest.class));
+
+    //表示请求器是否已经做了初始化工作
+    private boolean hasInit = false;
+
+    //连接超时时间,默认10秒
+    private int socketTimeout = 10000;
+
+    //传输超时时间,默认30秒
+    private int connectTimeout = 30000;
+
+    //请求器的配置
+    private RequestConfig requestConfig;
+
+    //HTTP请求器
+    private CloseableHttpClient httpClient;
+
+    public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException {
+        init();
+    }
+
+    private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
+
+        KeyStore keyStore = KeyStore.getInstance("PKCS12");
+        FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));//加载本地的证书进行https加密传输
+        try {
+            keyStore.load(instream, Configure.getCertPassword().toCharArray());//设置证书密码
+        } catch (CertificateException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } finally {
+            instream.close();
+        }
+
+        // Trust own CA and all self-signed certs
+        SSLContext sslcontext = SSLContexts.custom()
+                .loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray())
+                .build();
+        // Allow TLSv1 protocol only
+        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
+                sslcontext,
+                new String[]{"TLSv1"},
+                null,
+                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+
+        httpClient = HttpClients.custom()
+                .setSSLSocketFactory(sslsf)
+                .build();
+
+        //根据默认超时限制初始化requestConfig
+        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
+
+        hasInit = true;
+    }
+
+    /**
+     * 通过Https往API post xml数据
+     *
+     * @param url    API地址
+     * @param xmlObj 要提交的XML数据对象
+     * @return API回包的实际数据
+     * @throws IOException
+     * @throws KeyStoreException
+     * @throws UnrecoverableKeyException
+     * @throws NoSuchAlgorithmException
+     * @throws KeyManagementException
+     */
+
+    public String sendPost(String url, Object xmlObj) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
+
+        if (!hasInit) {
+            init();
+        }
+
+        String result = null;
+
+        HttpPost httpPost = new HttpPost(url);
+
+        //解决XStream对出现双下划线的bug
+        XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
+
+        //将要提交给API的数据对象转换成XML格式数据Post给API
+        String postDataXML = xStreamForRequestPostData.toXML(xmlObj);
+
+        Util.log("API,POST过去的数据是:");
+        Util.log(postDataXML);
+
+        //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
+        StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
+        httpPost.addHeader("Content-Type", "text/xml");
+        httpPost.setEntity(postEntity);
+
+        //设置请求器的配置
+        httpPost.setConfig(requestConfig);
+
+        Util.log("executing request" + httpPost.getRequestLine());
+
+        try {
+            HttpResponse response = httpClient.execute(httpPost);
+
+            HttpEntity entity = response.getEntity();
+
+            result = EntityUtils.toString(entity, "UTF-8");
+
+        } catch (ConnectionPoolTimeoutException e) {
+            log.e("http get throw ConnectionPoolTimeoutException(wait time out)");
+
+        } catch (ConnectTimeoutException e) {
+            log.e("http get throw ConnectTimeoutException");
+
+        } catch (SocketTimeoutException e) {
+            log.e("http get throw SocketTimeoutException");
+
+        } catch (Exception e) {
+            log.e("http get throw Exception");
+
+        } finally {
+            httpPost.abort();
+        }
+
+        return result;
+    }
+
+    /**
+     * 设置连接超时时间
+     *
+     * @param socketTimeout 连接时长,默认10秒
+     */
+    public void setSocketTimeout(int socketTimeout) {
+        socketTimeout = socketTimeout;
+        resetRequestConfig();
+    }
+
+    /**
+     * 设置传输超时时间
+     *
+     * @param connectTimeout 传输时长,默认30秒
+     */
+    public void setConnectTimeout(int connectTimeout) {
+        connectTimeout = connectTimeout;
+        resetRequestConfig();
+    }
+
+    private void resetRequestConfig() {
+        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
+    }
+
+    /**
+     * 允许商户自己做更高级更复杂的请求器配置
+     *
+     * @param requestConfig 设置HttpsRequest的请求器配置
+     */
+    public void setRequestConfig(RequestConfig requestConfig) {
+        requestConfig = requestConfig;
+    }
+}

+ 59 - 0
top-core/src/main/java/com/tencent/common/Log.java

@@ -0,0 +1,59 @@
+package com.tencent.common;
+
+import org.slf4j.Logger;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/12
+ * Time: 14:32
+ */
+public class Log {
+
+    public static final String LOG_TYPE_TRACE = "logTypeTrace";
+    public static final String LOG_TYPE_DEBUG = "logTypeDebug";
+    public static final String LOG_TYPE_INFO = "logTypeInfo";
+    public static final String LOG_TYPE_WARN = "logTypeWarn";
+    public static final String LOG_TYPE_ERROR = "logTypeError";
+
+    //打印日志
+    private Logger logger;
+
+    public Log(Logger log){
+        logger = log;
+    }
+
+    public void t(String s){
+        logger.trace(s);
+    }
+
+    public void d(String s){
+        logger.debug(s);
+    }
+
+    public void i(String s){
+        logger.info(s);
+    }
+
+    public void w(String s){
+        logger.warn(s);
+    }
+
+    public void e(String s){
+        logger.error(s);
+    }
+
+    public void log(String type,String s){
+        if(type.equals(Log.LOG_TYPE_TRACE)){
+            t(s);
+        }else if(type.equals(Log.LOG_TYPE_DEBUG)){
+            d(s);
+        }else if(type.equals(Log.LOG_TYPE_INFO)){
+            i(s);
+        }else if(type.equals(Log.LOG_TYPE_WARN)){
+            w(s);
+        }else if(type.equals(Log.LOG_TYPE_ERROR)){
+            e(s);
+        }
+    }
+
+}

+ 59 - 0
top-core/src/main/java/com/tencent/common/MD5.java

@@ -0,0 +1,59 @@
+package com.tencent.common;
+
+import java.security.MessageDigest;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/23
+ * Time: 15:43
+ */
+public class MD5 {
+    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
+            "8", "9", "a", "b", "c", "d", "e", "f"};
+
+    /**
+     * 转换字节数组为16进制字串
+     * @param b 字节数组
+     * @return 16进制字串
+     */
+    public static String byteArrayToHexString(byte[] b) {
+        StringBuilder resultSb = new StringBuilder();
+        for (byte aB : b) {
+            resultSb.append(byteToHexString(aB));
+        }
+        return resultSb.toString();
+    }
+
+    /**
+     * 转换byte到16进制
+     * @param b 要转换的byte
+     * @return 16进制格式
+     */
+    private static String byteToHexString(byte b) {
+        int n = b;
+        if (n < 0) {
+            n = 256 + n;
+        }
+        int d1 = n / 16;
+        int d2 = n % 16;
+        return hexDigits[d1] + hexDigits[d2];
+    }
+
+    /**
+     * MD5编码
+     * @param origin 原始字符串
+     * @return 经过MD5加密之后的结果
+     */
+    public static String MD5Encode(String origin) {
+        String resultString = null;
+        try {
+            resultString = origin;
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return resultString;
+    }
+
+}

+ 28 - 0
top-core/src/main/java/com/tencent/common/RandomStringGenerator.java

@@ -0,0 +1,28 @@
+package com.tencent.common;
+
+import java.util.Random;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 14:18
+ */
+public class RandomStringGenerator {
+
+    /**
+     * 获取一定长度的随机字符串
+     * @param length 指定字符串长度
+     * @return 一定长度的字符串
+     */
+    public static String getRandomStringByLength(int length) {
+        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
+        Random random = new Random();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < length; i++) {
+            int number = random.nextInt(base.length());
+            sb.append(base.charAt(number));
+        }
+        return sb.toString();
+    }
+
+}

+ 78 - 0
top-core/src/main/java/com/tencent/common/Sign.java

@@ -0,0 +1,78 @@
+package com.tencent.common;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 微信js api
+ */
+public class Sign {
+    public static void main(String[] args) {
+        String jsapi_ticket = "jsapi_ticket";
+
+        // 注意 URL 一定要动态获取,不能 hardcode
+        String url = "http://example.com";
+        Map<String, String> ret = sign(jsapi_ticket, url);
+        for (Map.Entry entry : ret.entrySet()) {
+            System.out.println(entry.getKey() + ", " + entry.getValue());
+        }
+    }
+
+
+    public static Map<String, String> sign(String jsapi_ticket, String url) {
+        Map<String, String> ret = new HashMap<String, String>();
+        String nonce_str = create_nonce_str();
+        String timestamp = create_timestamp();
+        String string1;
+        String signature = "";
+
+        //注意这里参数名必须全部小写,且必须有序
+        string1 = "jsapi_ticket=" + jsapi_ticket +
+                "&noncestr=" + nonce_str +
+                "&timestamp=" + timestamp +
+                "&url=" + url;
+        System.out.println(string1);
+
+        try {
+            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
+            crypt.reset();
+            crypt.update(string1.getBytes("UTF-8"));
+            signature = byteToHex(crypt.digest());
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+
+        ret.put("url", url);
+        ret.put("jsapi_ticket", jsapi_ticket);
+        ret.put("nonceStr", nonce_str);
+        ret.put("timestamp", timestamp);
+        ret.put("signature", signature);
+
+        return ret;
+    }
+
+    private static String byteToHex(final byte[] hash) {
+        Formatter formatter = new Formatter();
+        for (byte b : hash) {
+            formatter.format("%02x", b);
+        }
+        String result = formatter.toString();
+        formatter.close();
+        return result;
+    }
+
+    private static String create_nonce_str() {
+        return UUID.randomUUID().toString();
+    }
+
+    public static String create_timestamp() {
+        return Long.toString(System.currentTimeMillis() / 1000);
+    }
+}

+ 120 - 0
top-core/src/main/java/com/tencent/common/Signature.java

@@ -0,0 +1,120 @@
+package com.tencent.common;
+
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 15:23
+ */
+public class Signature {
+    /**
+     * 签名算法
+     * @param o 要参与签名的数据对象
+     * @return 签名
+     * @throws IllegalAccessException
+     */
+    public static String getSign(Object o) throws IllegalAccessException {
+        ArrayList<String> list = new ArrayList<String>();
+        Class cls = o.getClass();
+        Field[] fields = cls.getDeclaredFields();
+        for (Field f : fields) {
+            f.setAccessible(true);
+            if (f.get(o) != null && f.get(o) != "") {
+                list.add(f.getName() + "=" + f.get(o) + "&");
+            }
+        }
+        int size = list.size();
+        String [] arrayToSort = list.toArray(new String[size]);
+        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
+        StringBuilder sb = new StringBuilder();
+        for(int i = 0; i < size; i ++) {
+            sb.append(arrayToSort[i]);
+        }
+        String result = sb.toString();
+        result += "key=" + Configure.getKey();
+        Util.log("Sign Before MD5:" + result);
+        result = MD5.MD5Encode(result).toUpperCase();
+        Util.log("Sign Result:" + result);
+        return result;
+    }
+
+    public static String getSign(Map<String,Object> map){
+        ArrayList<String> list = new ArrayList<String>();
+        for(Map.Entry<String,Object> entry:map.entrySet()){
+            if(entry.getValue()!=""){
+                list.add(entry.getKey() + "=" + entry.getValue() + "&");
+            }
+        }
+        int size = list.size();
+        String [] arrayToSort = list.toArray(new String[size]);
+        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
+        StringBuilder sb = new StringBuilder();
+        for(int i = 0; i < size; i ++) {
+            sb.append(arrayToSort[i]);
+        }
+        String result = sb.toString();
+        result += "key=" + Configure.getKey();
+        //Util.log("Sign Before MD5:" + result);
+        result = MD5.MD5Encode(result).toUpperCase();
+        //Util.log("Sign Result:" + result);
+        return result;
+    }
+
+    /**
+     * 从API返回的XML数据里面重新计算一次签名
+     * @param responseString API返回的XML数据
+     * @return 新鲜出炉的签名
+     * @throws ParserConfigurationException
+     * @throws IOException
+     * @throws SAXException
+     */
+    public static String getSignFromResponseString(String responseString) throws IOException, SAXException, ParserConfigurationException {
+        Map<String,Object> map = XMLParser.getMapFromXML(responseString);
+        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
+        map.put("sign","");
+        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
+        return Signature.getSign(map);
+    }
+
+    /**
+     * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改
+     * @param responseString API返回的XML数据字符串
+     * @return API签名是否合法
+     * @throws ParserConfigurationException
+     * @throws IOException
+     * @throws SAXException
+     */
+    public static boolean checkIsSignValidFromResponseString(String responseString) throws ParserConfigurationException, IOException, SAXException {
+
+        Map<String,Object> map = XMLParser.getMapFromXML(responseString);
+        Util.log(map.toString());
+
+        String signFromAPIResponse = map.get("sign").toString();
+        if(signFromAPIResponse=="" || signFromAPIResponse == null){
+            Util.log("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
+            return false;
+        }
+        Util.log("服务器回包里面的签名是:" + signFromAPIResponse);
+        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
+        map.put("sign","");
+        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
+        String signForAPIResponse = Signature.getSign(map);
+
+        if(!signForAPIResponse.equals(signFromAPIResponse)){
+            //签名验不过,表示这个API返回的数据有可能已经被篡改了
+            Util.log("API返回的数据签名验证不通过,有可能被第三方篡改!!!");
+            return false;
+        }
+        Util.log("恭喜,API返回的数据签名验证通过!!!");
+        return true;
+    }
+
+}

+ 120 - 0
top-core/src/main/java/com/tencent/common/Util.java

@@ -0,0 +1,120 @@
+package com.tencent.common;
+
+import com.thoughtworks.xstream.XStream;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/23
+ * Time: 14:59
+ */
+public class Util {
+
+    //打log用
+    private static Log logger = new Log(LoggerFactory.getLogger(Util.class));
+
+    /**
+     * 通过反射的方式遍历对象的属性和属性值,方便调试
+     *
+     * @param o 要遍历的对象
+     * @throws Exception
+     */
+    public static void reflect(Object o) throws Exception {
+        Class cls = o.getClass();
+        Field[] fields = cls.getDeclaredFields();
+        for (int i = 0; i < fields.length; i++) {
+            Field f = fields[i];
+            f.setAccessible(true);
+            Util.log(f.getName() + " -> " + f.get(o));
+        }
+    }
+
+    public static byte[] readInput(InputStream in) throws IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int len = 0;
+        byte[] buffer = new byte[1024];
+        while ((len = in.read(buffer)) > 0) {
+            out.write(buffer, 0, len);
+        }
+        out.close();
+        in.close();
+        return out.toByteArray();
+    }
+
+    public static String inputStreamToString(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        int i;
+        while ((i = is.read()) != -1) {
+            baos.write(i);
+        }
+        return baos.toString();
+    }
+
+
+    public static InputStream getStringStream(String sInputString) {
+        ByteArrayInputStream tInputStringStream = null;
+        if (sInputString != null && !sInputString.trim().equals("")) {
+            tInputStringStream = new ByteArrayInputStream(sInputString.getBytes());
+        }
+        return tInputStringStream;
+    }
+
+    public static Object getObjectFromXML(String xml, Class tClass) {
+        //将从API返回的XML数据映射到Java对象
+        XStream xStreamForResponseData = new XStream();
+        xStreamForResponseData.alias("xml", tClass);
+        xStreamForResponseData.ignoreUnknownElements();//暂时忽略掉一些新增的字段
+        return xStreamForResponseData.fromXML(xml);
+    }
+
+    public static String getStringFromMap(Map<String, Object> map, String key, String defaultValue) {
+        if (key == "" || key == null) {
+            return defaultValue;
+        }
+        String result = (String) map.get(key);
+        if (result == null) {
+            return defaultValue;
+        } else {
+            return result;
+        }
+    }
+
+    public static int getIntFromMap(Map<String, Object> map, String key) {
+        if (key == "" || key == null) {
+            return 0;
+        }
+        if (map.get(key) == null) {
+            return 0;
+        }
+        return Integer.parseInt((String) map.get(key));
+    }
+
+    /**
+     * 打log接口
+     * @param log 要打印的log字符串
+     * @return 返回log
+     */
+    public static String log(Object log){
+        logger.i(log.toString());
+        //System.out.println(log);
+        return log.toString();
+    }
+
+    /**
+     * 读取本地的xml数据,一般用来自测用
+     * @param localPath 本地xml文件路径
+     * @return 读到的xml字符串
+     */
+    public static String getLocalXMLString(String localPath) throws IOException {
+        return Util.inputStreamToString(Util.class.getResourceAsStream(localPath));
+    }
+
+}
+

+ 166 - 0
top-core/src/main/java/com/tencent/common/XMLParser.java

@@ -0,0 +1,166 @@
+package com.tencent.common;
+
+import com.tencent.protocol.refund_query_protocol.RefundOrderData;
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.core.util.QuickWriter;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
+import com.thoughtworks.xstream.io.xml.XppDriver;
+import org.dom4j.io.SAXReader;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/1
+ * Time: 14:06
+ */
+public class XMLParser {
+
+    /**
+     * 从RefunQueryResponseString里面解析出退款订单数据
+     *
+     * @param refundQueryResponseString RefundQuery API返回的数据
+     * @return 因为订单数据有可能是多个,所以返回一个列表
+     */
+    public static List<RefundOrderData> getRefundOrderList(String refundQueryResponseString) throws IOException, SAXException, ParserConfigurationException {
+        List list = new ArrayList();
+
+        Map<String, Object> map = XMLParser.getMapFromXML(refundQueryResponseString);
+
+        int count = Integer.parseInt((String) map.get("refund_count"));
+        Util.log("count:" + count);
+
+        if (count < 1) {
+            return list;
+        }
+
+        RefundOrderData refundOrderData;
+
+        for (int i = 0; i < count; i++) {
+            refundOrderData = new RefundOrderData();
+
+            refundOrderData.setOutRefundNo(Util.getStringFromMap(map, "out_refund_no_" + i, ""));
+            refundOrderData.setRefundID(Util.getStringFromMap(map, "refund_id_" + i, ""));
+            refundOrderData.setRefundChannel(Util.getStringFromMap(map, "refund_channel_" + i, ""));
+            refundOrderData.setRefundFee(Util.getIntFromMap(map, "refund_fee_" + i));
+            refundOrderData.setCouponRefundFee(Util.getIntFromMap(map, "coupon_refund_fee_" + i));
+            refundOrderData.setRefundStatus(Util.getStringFromMap(map, "refund_status_" + i, ""));
+            list.add(refundOrderData);
+        }
+
+        return list;
+    }
+
+    public static Map<String, Object> getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException {
+
+        //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        InputStream is = Util.getStringStream(xmlString);
+        Document document = builder.parse(is);
+
+        //获取到document里面的全部结点
+        NodeList allNodes = document.getFirstChild().getChildNodes();
+        Node node;
+        Map<String, Object> map = new HashMap<String, Object>();
+        int i = 0;
+        while (i < allNodes.getLength()) {
+            node = allNodes.item(i);
+            if (node instanceof Element) {
+                map.put(node.getNodeName(), node.getTextContent());
+            }
+            i++;
+        }
+        return map;
+
+    }
+
+
+    /**
+     * 解析微信发来的请求(XML)
+     *
+     * @param request
+     * @return
+     * @throws Exception
+     */
+    @SuppressWarnings("unchecked")
+    public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
+        // 将解析结果存储在HashMap中
+        Map<String, String> map = new HashMap<String, String>();
+
+        // 从request中取得输入流
+        InputStream inputStream = request.getInputStream();
+        // 读取输入流
+        SAXReader reader = new SAXReader();
+        org.dom4j.Document document = reader.read(inputStream);
+        // 得到xml根元素
+        org.dom4j.Element root = document.getRootElement();
+        // 得到根元素的所有子节点
+        List<org.dom4j.Element> elementList = root.elements();
+
+        // 遍历所有子节点
+        for (org.dom4j.Element e : elementList)
+            if (e.elements().size() == 0) {
+                map.put(e.getName(), e.getText());
+            } else {
+                List<org.dom4j.Element> childElementList = e.elements();
+                for (org.dom4j.Element child : childElementList)
+                    map.put(child.getName(), child.getText());
+            }
+        // 释放资源
+        inputStream.close();
+        inputStream = null;
+
+        return map;
+    }
+
+    /**
+     * 扩展xstream,使其支持CDATA块
+     *
+     * @date 2013-05-19
+     */
+    private static XStream xstream = new XStream(new XppDriver() {
+        public HierarchicalStreamWriter createWriter(Writer out) {
+            return new PrettyPrintWriter(out) {
+                // 对所有xml节点的转换都增加CDATA标记
+                boolean cdata = true;
+
+                @SuppressWarnings("unchecked")
+                public void startNode(String name, Class clazz) {
+                    super.startNode(name, clazz);
+                    if (name.equals("CreateTime")) {
+                        cdata = false;
+                    }
+                }
+
+                protected void writeText(QuickWriter writer, String text) {
+                    if (cdata) {
+                        writer.write("<![CDATA[");
+                        writer.write(text);
+                        writer.write("]]>");
+                    } else {
+                        writer.write(text);
+                    }
+                }
+            };
+        }
+    });
+
+
+}

+ 40 - 0
top-core/src/main/java/com/tencent/common/report/ReportRunable.java

@@ -0,0 +1,40 @@
+package com.tencent.common.report;
+
+import com.tencent.common.report.service.ReportService;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/3
+ * Time: 16:34
+ */
+public class ReportRunable implements Runnable {
+
+    private ReportService reportService ;
+
+    ReportRunable(ReportService rs){
+        reportService = rs;
+    }
+
+    @Override
+    public void run() {
+        try {
+            reportService.request();
+        } catch (UnrecoverableKeyException e) {
+            e.printStackTrace();
+        } catch (KeyManagementException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } catch (KeyStoreException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 31 - 0
top-core/src/main/java/com/tencent/common/report/Reporter.java

@@ -0,0 +1,31 @@
+package com.tencent.common.report;
+
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/3
+ * Time: 11:42
+ */
+public class Reporter {
+
+    private ReportRunable r;
+    private Thread t;
+    private ReportService rs;
+
+    /**
+     * 请求统计上报API
+     * @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     */
+    public Reporter(ReportReqData reportReqData){
+        rs = new ReportService(reportReqData);
+    }
+
+    public void run(){
+        r = new ReportRunable(rs);
+        t = new Thread(r);
+        t.setDaemon(true);  //后台线程
+        t.start();
+    }
+}

+ 21 - 0
top-core/src/main/java/com/tencent/common/report/ReporterFactory.java

@@ -0,0 +1,21 @@
+package com.tencent.common.report;
+
+import com.tencent.common.report.protocol.ReportReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/3
+ * Time: 17:44
+ */
+public class ReporterFactory {
+
+    /**
+     * 请求统计上报API
+     * @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return 返回一个Reporter
+     */
+    public static Reporter getReporter(ReportReqData reportReqData){
+        return new Reporter(reportReqData);
+    }
+
+}

+ 232 - 0
top-core/src/main/java/com/tencent/common/report/protocol/ReportReqData.java

@@ -0,0 +1,232 @@
+package com.tencent.common.report.protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/12
+ * Time: 17:05
+ */
+public class ReportReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid;
+    private String mch_id;
+    private String sub_mch_id;
+    private String device_info;
+    private String nonce_str;
+    private String sign;
+
+    //上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder
+    private String interface_url;
+    //接口耗时情况,单位为毫秒
+    private int execute_time_cost;
+    //发起接口调用时的机器IP
+    private String user_ip;
+    //上报该统计请求时的系统时间,格式为yyyyMMddHHmmss
+    private String time;
+
+    //以下是API接口返回的对应数据
+    private String return_code;
+    private String return_msg;
+    private String result_code;
+    private String err_code;
+    private String err_code_des;
+    private String out_trade_no;
+
+    /**
+     * 请求统计上报API
+     * @param deviceInfo 微信支付分配的终端设备号,商户自定义
+     * @param interfaceUrl 上报对应的接口的完整URL,类似: https://api.mch.weixin.qq.com/pay/unifiedorder
+     * @param executeTimeCost 接口耗时情况,单位为毫秒
+     * @param returnCode API返回的对应字段
+     * @param returnMsg API返回的对应字段
+     * @param resultCode API返回的对应字段
+     * @param errCode API返回的对应字段
+     * @param errCodeDes API返回的对应字段
+     * @param outTradeNo API返回的对应字段
+     * @param userIp 发起接口调用时的机器IP
+     */
+    public ReportReqData(String deviceInfo, String interfaceUrl,int executeTimeCost, String returnCode,String returnMsg,String resultCode,String errCode,String errCodeDes, String outTradeNo,String userIp){
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+        setSub_mch_id(Configure.getSubMchid());
+        setDevice_info(deviceInfo);
+        setInterface_url(interfaceUrl);
+        setExecute_time_cost(executeTimeCost);
+        setReturn_code(returnCode);
+        setReturn_msg(returnMsg);
+        setResult_code(resultCode);
+        setErr_code(errCode);
+        setErr_code_des(errCodeDes);
+        setUser_ip(userIp);
+        setTime(getTime());
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getSub_mch_id() {
+        return sub_mch_id;
+    }
+
+    public void setSub_mch_id(String sub_mch_id) {
+        this.sub_mch_id = sub_mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getInterface_url() {
+        return interface_url;
+    }
+
+    public void setInterface_url(String interface_url) {
+        this.interface_url = interface_url;
+    }
+
+    public int getExecute_time_cost() {
+        return execute_time_cost;
+    }
+
+    public void setExecute_time_cost(int execute_time) {
+        this.execute_time_cost = execute_time;
+    }
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getUser_ip() {
+        return user_ip;
+    }
+
+    public void setUser_ip(String user_ip) {
+        this.user_ip = user_ip;
+    }
+
+    public String getTime() {
+        return time;
+    }
+
+    public void setTime(String time) {
+        this.time = time;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 38 - 0
top-core/src/main/java/com/tencent/common/report/protocol/ReportResData.java

@@ -0,0 +1,38 @@
+package com.tencent.common.report.protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/12
+ * Time: 17:06
+ */
+public class ReportResData {
+
+    //以下是API接口返回的对应数据
+    private String return_code;
+    private String return_msg;
+    private String result_code;
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+}

+ 69 - 0
top-core/src/main/java/com/tencent/common/report/service/ReportService.java

@@ -0,0 +1,69 @@
+package com.tencent.common.report.service;
+
+import com.tencent.common.Configure;
+import com.tencent.common.HttpsRequest;
+import com.tencent.common.Util;
+import com.tencent.common.report.protocol.ReportReqData;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/12
+ * Time: 17:07
+ */
+public class ReportService {
+
+    private ReportReqData reqData ;
+
+    /**
+     * 请求统计上报API
+     * @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     */
+    public ReportService(ReportReqData reportReqData){
+        reqData = reportReqData;
+    }
+
+    public String request() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException {
+        String responseString = new HttpsRequest().sendPost(Configure.REPORT_API, reqData);
+
+        Util.log("   report返回的数据:" + responseString);
+
+        return responseString;
+    }
+
+    /**
+     * 请求统计上报API
+     * @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public static String request(ReportReqData reportReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = new HttpsRequest().sendPost(Configure.REPORT_API, reportReqData);
+
+        Util.log("report返回的数据:" + responseString);
+
+        return responseString;
+    }
+
+    /**
+     * 获取time:统计发送时间,格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。
+     * @return 订单生成时间
+     */
+    private static String getTime(){
+        //订单生成时间自然就是当前服务器系统时间咯
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+        return simpleDateFormat.format(new Date());
+    }
+
+}

+ 137 - 0
top-core/src/main/java/com/tencent/protocol/downloadbill_protocol/DownloadBillReqData.java

@@ -0,0 +1,137 @@
+package com.tencent.protocol.downloadbill_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:48
+ */
+public class DownloadBillReqData {
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String bill_date = "";
+    private String bill_type = "";
+
+    /**
+     * 请求对账单下载服务
+     * @param deviceInfo 商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+     * @param billDate 下载对账单的日期,格式:yyyyMMdd 例如:20140603
+     * @param billType 账单类型
+     *                 ALL,返回当日所有订单信息,默认值
+    SUCCESS,返回当日成功支付的订单
+    REFUND,返回当日退款订单
+    REVOKED,已撤销的订单
+     */
+    public DownloadBillReqData(String deviceInfo,String billDate,String billType){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+        setDevice_info(deviceInfo);
+
+        setBill_date(billDate);
+
+        setBill_type(billType);
+
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getBill_date() {
+        return bill_date;
+    }
+
+    public void setBill_date(String bill_date) {
+        this.bill_date = bill_date;
+    }
+
+    public String getBill_type() {
+        return bill_type;
+    }
+
+    public void setBill_type(String bill_type) {
+        this.bill_type = bill_type;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 29 - 0
top-core/src/main/java/com/tencent/protocol/downloadbill_protocol/DownloadBillResData.java

@@ -0,0 +1,29 @@
+package com.tencent.protocol.downloadbill_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:48
+ */
+public class DownloadBillResData {
+
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+}

+ 406 - 0
top-core/src/main/java/com/tencent/protocol/pay_protocol/JSPayReqData.java

@@ -0,0 +1,406 @@
+package com.tencent.protocol.pay_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/22
+ * Time: 21:29
+ */
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 请求JS支付API需要提交的数据
+ */
+public class JSPayReqData {
+
+
+    /**
+     * 公众账号ID
+     * appid
+     * 是
+     * String(32)
+     * wx8888888888888888
+     * 微信分配的公众账号ID
+     * 商户号
+     * mch_id
+     * 是
+     * String(32)
+     * 1900000109
+     * 微信支付分配的商户号
+     * 设备号
+     * device_info
+     * 否
+     * String(32)
+     * 013467007045764
+     * 终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB"
+     * 随机字符串
+     * nonce_str
+     * 是
+     * String(32)
+     * 5K8264ILTKCH16CQ2502SI8ZNMTM67VS
+     * 随机字符串,不长于32位。推荐随机数生成算法
+     * 签名
+     * sign
+     * 是
+     * String(32)
+     * C380BEC2BFD727A4B6845133519F3AD6
+     * 签名,详见签名生成算法
+     * 商品描述
+     * body
+     * 是
+     * String(32)
+     * Ipad mini  16G  白色
+     * 商品或支付单简要描述
+     * 商品详情
+     * detail
+     * 否
+     * String(8192)
+     * Ipad mini  16G  白色
+     * 商品名称明细列表
+     * 附加数据
+     * attach
+     * 否
+     * String(127)
+     * 说明
+     * 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
+     * 商户订单号
+     * out_trade_no
+     * 是
+     * String(32)
+     * 1217752501201407033233368018
+     * 商户系统内部的订单号,32个字符内、可包含字母, 其他说明见商户订单号
+     * 货币类型
+     * fee_type
+     * 否
+     * String(16)
+     * CNY
+     * 符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
+     * 总金额
+     * total_fee
+     * 是
+     * Int
+     * 888
+     * 订单总金额,只能为整数,详见支付金额
+     * 终端IP
+     * spbill_create_ip
+     * 是
+     * String(16)
+     * 8.8.8.8
+     * APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
+     * 交易起始时间
+     * time_start
+     * 否
+     * String(14)
+     * 20091225091010
+     * 订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
+     * 交易结束时间
+     * time_expire
+     * 否
+     * String(14)
+     * 20091227091010
+     * 订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。其他详见时间规则
+     * 商品标记
+     * goods_tag
+     * 否
+     * String(32)
+     * WXG
+     * 商品标记,代金券或立减优惠功能的参数,说明详见代金券或立减优惠
+     * 通知地址
+     * notify_url
+     * 是
+     * String(256)
+     * http://www.baidu.com/
+     * 接收微信支付异步通知回调地址
+     * 交易类型
+     * trade_type
+     * 是
+     * String(16)
+     * JSAPI
+     * 取值如下:JSAPI,NATIVE,APP,WAP,详细说明见参数规定
+     * 商品ID
+     * product_id
+     * 否
+     * String(32)
+     * 12235413214070356458058
+     * trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。
+     * 用户标识
+     * openid
+     * 否
+     * String(128)
+     * oUpF8uMuAJO_M2pxb1Q9zNjWeS6o
+     * trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。
+     */
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String body = "";
+    private String detail = "";
+    private String attach = "";
+    private String out_trade_no = "";
+    private String fee_type = "CNY";
+    private int total_fee = 0;
+    private String spbill_create_ip = "";
+    private String time_start = "";
+    private String time_expire = "";
+    private String goods_tag = "";
+    private String notify_url = "";
+    private String trade_type = "";
+    private String product_id = "";
+    private String openid = "";
+
+    /**
+     * @param body           要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+     * @param attach         支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回
+     * @param outTradeNo     商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
+     * @param totalFee       订单总金额,单位为“分”,只能整数
+     * @param spBillCreateIP 订单生成的机器IP
+     * @param timeStart      订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
+     * @param timeExpire     订单失效时间,格式同上
+     * @param goodsTag       商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+     */
+    public JSPayReqData(String body, String attach, String outTradeNo, int totalFee, String spBillCreateIP,
+                        String timeStart, String timeExpire, String goodsTag,String openId) {
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB"
+        setDevice_info("WEB");
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+        setBody(body);
+
+        //商品名称明细列表
+        setDetail(body);
+
+        //支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回,有助于商户自己可以注明该笔消费的具体内容,方便后续的运营和记录
+        setAttach(attach);
+
+        //商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
+        setOut_trade_no(outTradeNo);
+
+        //符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
+        setFee_type("CNY");
+
+        //订单总金额,单位为“分”,只能整数
+        setTotal_fee(totalFee);
+
+        //订单生成的机器IP
+        setSpbill_create_ip(spBillCreateIP);
+
+        //订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
+        setTime_start(timeStart);
+
+        //订单失效时间,格式同上
+        setTime_expire(timeExpire);
+
+        //商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+        setGoods_tag(goodsTag);
+
+        //接收微信支付异步通知回调地址
+        //TODO
+        setNotify_url(Configure.NOTIFY_URL);
+
+        //取值如下:JSAPI,NATIVE,APP,WAP,详细说明见参数规定
+        setTrade_type("JSAPI");
+
+        //trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。
+        setProduct_id("");
+
+        //trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。下单前需要调用【网页授权获取用户信息】接口获取到用户的Openid。
+        setOpenid(openId);
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public int getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(int total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getSpbill_create_ip() {
+        return spbill_create_ip;
+    }
+
+    public void setSpbill_create_ip(String spbill_create_ip) {
+        this.spbill_create_ip = spbill_create_ip;
+    }
+
+    public String getTime_start() {
+        return time_start;
+    }
+
+    public void setTime_start(String time_start) {
+        this.time_start = time_start;
+    }
+
+    public String getTime_expire() {
+        return time_expire;
+    }
+
+    public void setTime_expire(String time_expire) {
+        this.time_expire = time_expire;
+    }
+
+    public String getGoods_tag() {
+        return goods_tag;
+    }
+
+    public void setGoods_tag(String goods_tag) {
+        this.goods_tag = goods_tag;
+    }
+
+    public String getDetail() {
+        return detail;
+    }
+
+    public void setDetail(String detail) {
+        this.detail = detail;
+    }
+
+    public String getFee_type() {
+        return fee_type;
+    }
+
+    public void setFee_type(String fee_type) {
+        this.fee_type = fee_type;
+    }
+
+    public String getNotify_url() {
+        return notify_url;
+    }
+
+    public void setNotify_url(String notify_url) {
+        this.notify_url = notify_url;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getProduct_id() {
+        return product_id;
+    }
+
+    public void setProduct_id(String product_id) {
+        this.product_id = product_id;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type) {
+        this.trade_type = trade_type;
+    }
+
+    public Map<String, Object> toMap() {
+        Map<String, Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if (obj != null) {
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 230 - 0
top-core/src/main/java/com/tencent/protocol/pay_protocol/ScanPayReqData.java

@@ -0,0 +1,230 @@
+package com.tencent.protocol.pay_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/22
+ * Time: 21:29
+ */
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 请求被扫支付API需要提交的数据
+ */
+public class ScanPayReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String body = "";
+    private String attach = "";
+    private String out_trade_no = "";
+    private int total_fee = 0;
+    private String spbill_create_ip = "";
+    private String time_start = "";
+    private String time_expire = "";
+    private String goods_tag = "";
+    private String auth_code = "";
+
+    /**
+     * @param authCode 这个是扫码终端设备从用户手机上扫取到的支付授权号,这个号是跟用户用来支付的银行卡绑定的,有效期是1分钟
+     * @param body 要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+     * @param attach 支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回
+     * @param outTradeNo 商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
+     * @param totalFee 订单总金额,单位为“分”,只能整数
+     * @param deviceInfo 商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+     * @param spBillCreateIP 订单生成的机器IP
+     * @param timeStart 订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
+     * @param timeExpire 订单失效时间,格式同上
+     * @param goodsTag 商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+     */
+    public ScanPayReqData(String authCode,String body,String attach,String outTradeNo,int totalFee,String deviceInfo,String spBillCreateIP,String timeStart,String timeExpire,String goodsTag){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //这个是扫码终端设备从用户手机上扫取到的支付授权号,这个号是跟用户用来支付的银行卡绑定的,有效期是1分钟
+        //调试的时候可以在微信上打开“钱包”里面的“刷卡”,将扫码页面里的那一串14位的数字输入到这里来,进行提交验证
+        //记住out_trade_no这个订单号可以将这一笔支付进行退款
+        setAuth_code(authCode);
+
+        //要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+        setBody(body);
+
+        //支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回,有助于商户自己可以注明该笔消费的具体内容,方便后续的运营和记录
+        setAttach(attach);
+
+        //商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
+        setOut_trade_no(outTradeNo);
+
+        //订单总金额,单位为“分”,只能整数
+        setTotal_fee(totalFee);
+
+        //商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+        setDevice_info(deviceInfo);
+
+        //订单生成的机器IP
+        setSpbill_create_ip(spBillCreateIP);
+
+        //订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
+        setTime_start(timeStart);
+
+        //订单失效时间,格式同上
+        setTime_expire(timeExpire);
+
+        //商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+        setGoods_tag(goodsTag);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public int getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(int total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getSpbill_create_ip() {
+        return spbill_create_ip;
+    }
+
+    public void setSpbill_create_ip(String spbill_create_ip) {
+        this.spbill_create_ip = spbill_create_ip;
+    }
+
+    public String getTime_start() {
+        return time_start;
+    }
+
+    public void setTime_start(String time_start) {
+        this.time_start = time_start;
+    }
+
+    public String getTime_expire() {
+        return time_expire;
+    }
+
+    public void setTime_expire(String time_expire) {
+        this.time_expire = time_expire;
+    }
+
+    public String getGoods_tag() {
+        return goods_tag;
+    }
+
+    public void setGoods_tag(String goods_tag) {
+        this.goods_tag = goods_tag;
+    }
+
+    public String getAuth_code() {
+        return auth_code;
+    }
+
+    public void setAuth_code(String auth_code) {
+        this.auth_code = auth_code;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 208 - 0
top-core/src/main/java/com/tencent/protocol/pay_protocol/UnifiedPayResData.java

@@ -0,0 +1,208 @@
+package com.tencent.protocol.pay_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/22
+ * Time: 16:42
+ */
+
+/**
+ * 被扫支付提交Post数据给到API之后,API会返回XML格式的数据,这个类用来装这些数据
+ */
+public class UnifiedPayResData {
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String appid = "";
+    private String mch_id = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+    private String device_info = "";
+
+    //业务返回的具体数据(以下字段在return_code 和result_code 都为SUCCESS 的时候有返回)
+    private String openid = "";
+    private String is_subscribe = "";
+    private String trade_type = "";
+    private String bank_type = "";
+    private String total_fee = "";
+    private String coupon_fee = "";
+    private String fee_type = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String attach = "";
+    private String time_end = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getIs_subscribe() {
+        return is_subscribe;
+    }
+
+    public void setIs_subscribe(String is_subscribe) {
+        this.is_subscribe = is_subscribe;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type) {
+        this.trade_type = trade_type;
+    }
+
+    public String getBank_type() {
+        return bank_type;
+    }
+
+    public void setBank_type(String bank_type) {
+        this.bank_type = bank_type;
+    }
+
+    public String getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(String total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getCoupon_fee() {
+        return coupon_fee;
+    }
+
+    public void setCoupon_fee(String coupon_fee) {
+        this.coupon_fee = coupon_fee;
+    }
+
+    public String getFee_type() {
+        return fee_type;
+    }
+
+    public void setFee_type(String fee_type) {
+        this.fee_type = fee_type;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getTime_end() {
+        return time_end;
+    }
+
+    public void setTime_end(String time_end) {
+        this.time_end = time_end;
+    }
+
+}

+ 127 - 0
top-core/src/main/java/com/tencent/protocol/pay_query_protocol/ScanPayQueryReqData.java

@@ -0,0 +1,127 @@
+package com.tencent.protocol.pay_query_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 13:54
+ */
+public class ScanPayQueryReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String nonce_str = "";
+    private String sign = "";
+
+    /**
+     * 请求支付查询服务
+     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
+     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public ScanPayQueryReqData(String transactionID, String outTradeNo){
+
+        //--------------------------------------------------------------------
+        //以下是测试数据,请商户按照自己的实际情况填写具体的值进去
+        //--------------------------------------------------------------------
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
+        setTransaction_id(transactionID);
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+}

+ 236 - 0
top-core/src/main/java/com/tencent/protocol/pay_query_protocol/ScanPayQueryResData.java

@@ -0,0 +1,236 @@
+package com.tencent.protocol.pay_query_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 13:54
+ */
+public class ScanPayQueryResData {
+
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String appid = "";
+    private String mch_id = "";
+    private String sub_mch_id = "";//新增
+    private String nonce_str = "";
+    private String sign = "";
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+
+    //以下字段在return_code 和result_code 都为SUCCESS 的时候有返回
+    private String trade_state = "";
+
+    //trade_state的几种可能取值:
+    //    SUCCESS--支付成功
+    //    REFUND--转入退款
+    //    NOTPAY--未支付
+    //    CLOSED--已关闭
+    //    REVOKED--已撤销
+    //    USERPAYING--用户支付中
+    //    NOPAY--未支付(确认支付超时)
+    //    PAYERROR--支付失败(其他原因,
+    //            如银行返回失败)
+
+    //以下字段在trade_state 为SUCCESS 或者REFUND 的时候有返回
+    private String device_info = "";
+    private String openid = "";
+    private String is_subscribe = "";
+    private String trade_type = "";
+    private String bank_type = "";
+    private String total_fee = "";
+    private String coupon_fee = "";
+    private String fee_type = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String attach = "";
+    private String time_end = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getSub_mch_id() {
+        return sub_mch_id;
+    }
+
+    public void setSub_mch_id(String sub_mch_id) {
+        this.sub_mch_id = sub_mch_id;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getTrade_state() {
+        return trade_state;
+    }
+
+    public void setTrade_state(String trade_state) {
+        this.trade_state = trade_state;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getIs_subscribe() {
+        return is_subscribe;
+    }
+
+    public void setIs_subscribe(String is_subscribe) {
+        this.is_subscribe = is_subscribe;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type) {
+        this.trade_type = trade_type;
+    }
+
+    public String getBank_type() {
+        return bank_type;
+    }
+
+    public void setBank_type(String bank_type) {
+        this.bank_type = bank_type;
+    }
+
+    public String getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(String total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getCoupon_fee() {
+        return coupon_fee;
+    }
+
+    public void setCoupon_fee(String coupon_fee) {
+        this.coupon_fee = coupon_fee;
+    }
+
+    public String getFee_type() {
+        return fee_type;
+    }
+
+    public void setFee_type(String fee_type) {
+        this.fee_type = fee_type;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getTime_end() {
+        return time_end;
+    }
+
+    public void setTime_end(String time_end) {
+        this.time_end = time_end;
+    }
+
+}

+ 192 - 0
top-core/src/main/java/com/tencent/protocol/refund_protocol/RefundReqData.java

@@ -0,0 +1,192 @@
+package com.tencent.protocol.refund_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:12
+ */
+public class RefundReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String out_refund_no = "";
+    private int total_fee = 0;
+    private int refund_fee = 0;
+    private String refund_fee_type = "CNY";
+    private String op_user_id = "";
+
+    /**
+     * 请求退款服务
+     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
+     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
+     * @param deviceInfo 微信支付分配的终端设备号,与下单一致
+     * @param outRefundNo 商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+     * @param totalFee 订单总金额,单位为分
+     * @param refundFee 退款总金额,单位为分,可以做部分退款
+     * @param opUserID 操作员帐号, 默认为商户号
+     * @param refundFeeType 货币类型,符合ISO 4217标准的三位字母代码,默认为CNY(人民币)
+     */
+    public RefundReqData(String transactionID,String outTradeNo,String deviceInfo,String outRefundNo,int totalFee,int refundFee,String opUserID,String refundFeeType){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
+        setTransaction_id(transactionID);
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //微信支付分配的终端设备号,与下单一致
+        setDevice_info(deviceInfo);
+
+        setOut_refund_no(outRefundNo);
+
+        setTotal_fee(totalFee);
+
+        setRefund_fee(refundFee);
+
+        setOp_user_id(opUserID);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public int getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(int total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public int getRefund_fee() {
+        return refund_fee;
+    }
+
+    public void setRefund_fee(int refund_fee) {
+        this.refund_fee = refund_fee;
+    }
+
+    public String getOp_user_id() {
+        return op_user_id;
+    }
+
+    public void setOp_user_id(String op_user_id) {
+        this.op_user_id = op_user_id;
+    }
+
+    public String getRefund_fee_type() {
+        return refund_fee_type;
+    }
+
+    public void setRefund_fee_type(String refund_fee_type) {
+        this.refund_fee_type = refund_fee_type;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 168 - 0
top-core/src/main/java/com/tencent/protocol/refund_protocol/RefundResData.java

@@ -0,0 +1,168 @@
+package com.tencent.protocol.refund_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:12
+ */
+public class RefundResData {
+
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String appid = "";
+    private String mch_id = "";
+    private String sub_mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+
+
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String out_refund_no = "";
+    private String refund_id = "";
+    private String refund_fee = "";
+    private String coupon_refund_fee = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getSub_mch_id() {
+        return sub_mch_id;
+    }
+
+    public void setSub_mch_id(String sub_mch_id) {
+        this.sub_mch_id = sub_mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public String getRefund_id() {
+        return refund_id;
+    }
+
+    public void setRefund_id(String refund_id) {
+        this.refund_id = refund_id;
+    }
+
+    public String getRefund_fee() {
+        return refund_fee;
+    }
+
+    public void setRefund_fee(String refund_fee) {
+        this.refund_fee = refund_fee;
+    }
+
+    public String getCoupon_refund_fee() {
+        return coupon_refund_fee;
+    }
+
+    public void setCoupon_refund_fee(String coupon_refund_fee) {
+        this.coupon_refund_fee = coupon_refund_fee;
+    }
+}

+ 100 - 0
top-core/src/main/java/com/tencent/protocol/refund_query_protocol/RefundOrderData.java

@@ -0,0 +1,100 @@
+package com.tencent.protocol.refund_query_protocol;
+
+import java.lang.reflect.Field;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/1
+ * Time: 14:09
+ * 用来存放退款订单数据
+ */
+public class RefundOrderData {
+
+    private String outRefundNo = "";//商户退款单号
+    private String refundID = "";//微信退款单号
+    private String refundChannel = "";//退款渠道
+    //    IGINAL--原路退款
+//    BALANCE--退回到余额
+    private int refundFee = 0;//退款金额
+    private int couponRefundFee = 0;//企业红包退款金额
+    private String refundStatus = "";//退款状态
+
+    public String getOutRefundNo() {
+        return outRefundNo;
+    }
+
+    public void setOutRefundNo(String outRefundNo) {
+        this.outRefundNo = outRefundNo;
+    }
+
+    public String getRefundID() {
+        return refundID;
+    }
+
+    public void setRefundID(String refundID) {
+        this.refundID = refundID;
+    }
+
+    public String getRefundChannel() {
+        return refundChannel;
+    }
+
+    public void setRefundChannel(String refundChannel) {
+        this.refundChannel = refundChannel;
+    }
+
+    public int getRefundFee() {
+        return refundFee;
+    }
+
+    public void setRefundFee(int refundFee) {
+        this.refundFee = refundFee;
+    }
+
+    public int getCouponRefundFee() {
+        return couponRefundFee;
+    }
+
+    public void setCouponRefundFee(int couponRefundFee) {
+        this.couponRefundFee = couponRefundFee;
+    }
+
+    public String getRefundStatus() {
+        return refundStatus;
+    }
+
+    public void setRefundStatus(String refundStatus) {
+        this.refundStatus = refundStatus;
+    }
+
+    public String toMap(){
+        Map<String,Object> map = new LinkedHashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        StringBuilder s=new StringBuilder("{");
+
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    if(s.length()>0){
+                        s.append(" ");
+                    }
+                    s.append(field.getName());
+                    s.append("=");
+                    s.append(obj.toString());
+//                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        s.append("}");
+        return s.toString();
+    }
+
+}

+ 160 - 0
top-core/src/main/java/com/tencent/protocol/refund_query_protocol/RefundQueryReqData.java

@@ -0,0 +1,160 @@
+package com.tencent.protocol.refund_query_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:35
+ */
+public class RefundQueryReqData {
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+
+    /**
+     * 请求退款查询服务
+     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
+     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
+     * @param deviceInfo 微信支付分配的终端设备号,与下单一致
+     * @param outRefundNo 商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+     * @param refundID 来自退款API的成功返回,微信退款单号refund_id、out_refund_no、out_trade_no 、transaction_id 四个参数必填一个,如果同事存在优先级为:refund_id>out_refund_no>transaction_id>out_trade_no
+     */
+
+    public RefundQueryReqData(String transactionID,String outTradeNo,String deviceInfo,String outRefundNo,String refundID){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
+        setTransaction_id(transactionID);
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //微信支付分配的终端设备号,与下单一致
+        setDevice_info(deviceInfo);
+
+        setOut_refund_no(outRefundNo);
+
+        //商户系统自己管理的退款号,商户自身必须保证这个号在系统内唯一
+        setRefund_id(refundID);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public String getRefund_id() {
+        return refund_id;
+    }
+
+    public void setRefund_id(String refund_id) {
+        this.refund_id = refund_id;
+    }
+
+    private String out_refund_no;
+    private String refund_id;
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 187 - 0
top-core/src/main/java/com/tencent/protocol/refund_query_protocol/RefundQueryResData.java

@@ -0,0 +1,187 @@
+package com.tencent.protocol.refund_query_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:36
+ */
+public class RefundQueryResData {
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+    private String appid = "";
+    private String mch_id = "";
+    private String nonce_str = "";
+    private String sign = "";
+
+
+    private String device_info = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private int refund_count = 0;
+
+    //TODO 这里要用对象来装,因为有可能出现多个数据
+    private String out_refund_no = "";
+    private String refund_id = "";
+    private String refund_channel = "";
+    private String refund_fee = "";
+    private String coupon_refund_fee = "";
+    private String refund_status = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public int getRefund_count() {
+        return refund_count;
+    }
+
+    public void setRefund_count(int refund_count) {
+        this.refund_count = refund_count;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public String getRefund_id() {
+        return refund_id;
+    }
+
+    public void setRefund_id(String refund_id) {
+        this.refund_id = refund_id;
+    }
+
+    public String getRefund_channel() {
+        return refund_channel;
+    }
+
+    public void setRefund_channel(String refund_channel) {
+        this.refund_channel = refund_channel;
+    }
+
+    public String getRefund_fee() {
+        return refund_fee;
+    }
+
+    public void setRefund_fee(String refund_fee) {
+        this.refund_fee = refund_fee;
+    }
+
+    public String getCoupon_refund_fee() {
+        return coupon_refund_fee;
+    }
+
+    public void setCoupon_refund_fee(String coupon_refund_fee) {
+        this.coupon_refund_fee = coupon_refund_fee;
+    }
+
+    public String getRefund_status() {
+        return refund_status;
+    }
+
+    public void setRefund_status(String refund_status) {
+        this.refund_status = refund_status;
+    }
+}

+ 127 - 0
top-core/src/main/java/com/tencent/protocol/reverse_protocol/ReverseReqData.java

@@ -0,0 +1,127 @@
+package com.tencent.protocol.reverse_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:42
+ */
+public class ReverseReqData {
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String nonce_str = "";
+    private String sign = "";
+
+    /**
+     * 请求撤销服务
+     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
+     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+
+    public ReverseReqData(String transactionID,String outTradeNo){
+
+        //--------------------------------------------------------------------
+        //以下是测试数据,请商户按照自己的实际情况填写具体的值进去
+        //--------------------------------------------------------------------
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
+        setTransaction_id(transactionID);
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 104 - 0
top-core/src/main/java/com/tencent/protocol/reverse_protocol/ReverseResData.java

@@ -0,0 +1,104 @@
+package com.tencent.protocol.reverse_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:43
+ */
+public class ReverseResData {
+
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+    private String sign = "";
+    private String appid = "";
+    private String mch_id = "";
+    private String nonce_str = "";
+
+    private String recall = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getRecall() {
+        return recall;
+    }
+
+    public void setRecall(String recall) {
+        this.recall = recall;
+    }
+}

+ 42 - 0
top-core/src/main/java/com/tencent/service/BaseService.java

@@ -0,0 +1,42 @@
+package com.tencent.service;
+
+import com.tencent.common.Configure;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/10
+ * Time: 15:44
+ * 服务的基类
+ */
+public class BaseService{
+
+    //API的地址
+    private String apiURL;
+
+    //发请求的HTTPS请求器
+    private IServiceRequest serviceRequest;
+
+    public BaseService(String api) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        apiURL = api;
+        Class c = Class.forName(Configure.HttpsRequestClassName);
+        serviceRequest = (IServiceRequest) c.newInstance();
+    }
+
+    protected String sendPost(Object xmlObj) throws UnrecoverableKeyException, IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+        return serviceRequest.sendPost(apiURL,xmlObj);
+    }
+
+    /**
+     * 供商户想自定义自己的HTTP请求器用
+     * @param request 实现了IserviceRequest接口的HttpsRequest
+     */
+    public void setServiceRequest(IServiceRequest request){
+        serviceRequest = request;
+    }
+}

+ 46 - 0
top-core/src/main/java/com/tencent/service/DownloadBillService.java

@@ -0,0 +1,46 @@
+package com.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.downloadbill_protocol.DownloadBillReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class DownloadBillService extends BaseService {
+
+    public DownloadBillService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.DOWNLOAD_BILL_API);
+    }
+
+    //ALL,返回当日所有订单信息,默认值
+    public static final String BILL_TYPE_ALL = "ALL";
+
+    //SUCCESS,返回当日成功支付的订单
+    public static final String BILL_TYPE_SUCCESS = "SUCCESS";
+
+    //REFUND,返回当日退款订单
+    public static final String BILL_TYPE_REFUND = "REFUND";
+
+    //REVOKED,已撤销的订单
+    public static final String BILL_TYPE_REVOKE = "REVOKE";
+
+
+    /**
+     * 请求对账单下载服务
+     * @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(DownloadBillReqData downloadBillReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(downloadBillReqData);
+
+        return responseString;
+    }
+
+}

+ 20 - 0
top-core/src/main/java/com/tencent/service/IServiceRequest.java

@@ -0,0 +1,20 @@
+package com.tencent.service;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/10
+ * Time: 15:16
+ * 这里定义服务层需要请求器标准接口
+ */
+public interface IServiceRequest {
+
+    //Service依赖的底层https请求器必须实现这么一个接口
+    public String sendPost(String api_url, Object xmlObj) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException;
+
+}

+ 36 - 0
top-core/src/main/java/com/tencent/service/RefundQueryService.java

@@ -0,0 +1,36 @@
+package com.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.refund_query_protocol.RefundQueryReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class RefundQueryService extends BaseService {
+
+    public RefundQueryService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.REFUND_QUERY_API);
+    }
+
+    /**
+     * 请求退款查询服务
+     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(RefundQueryReqData refundQueryReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(refundQueryReqData);
+
+        return responseString;
+    }
+
+
+
+
+}

+ 33 - 0
top-core/src/main/java/com/tencent/service/RefundService.java

@@ -0,0 +1,33 @@
+package com.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.refund_protocol.RefundReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class RefundService extends BaseService {
+
+    public RefundService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.REFUND_API);
+    }
+
+    /**
+     * 请求退款服务
+     * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(RefundReqData refundReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(refundReqData);
+
+        return responseString;
+    }
+
+}

+ 33 - 0
top-core/src/main/java/com/tencent/service/ReverseService.java

@@ -0,0 +1,33 @@
+package com.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.reverse_protocol.ReverseReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class ReverseService extends BaseService {
+
+    public ReverseService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.REVERSE_API);
+    }
+
+    /**
+     * 请求撤销服务
+     * @param reverseReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(ReverseReqData reverseReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(reverseReqData);
+
+        return responseString;
+    }
+
+}

+ 34 - 0
top-core/src/main/java/com/tencent/service/ScanPayQueryService.java

@@ -0,0 +1,34 @@
+package com.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class ScanPayQueryService extends BaseService {
+
+    public ScanPayQueryService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.PAY_QUERY_API);
+    }
+
+    /**
+     * 请求支付查询服务
+     * @param scanPayQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(ScanPayQueryReqData scanPayQueryReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(scanPayQueryReqData);
+
+        return responseString;
+    }
+
+
+}

+ 32 - 0
top-core/src/main/java/com/tencent/service/ScanPayService.java

@@ -0,0 +1,32 @@
+package com.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.pay_protocol.ScanPayReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:03
+ */
+public class ScanPayService extends BaseService {
+
+    public ScanPayService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.PAY_API);
+    }
+
+    /**
+     * 请求支付服务
+     * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public String request(ScanPayReqData scanPayReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(scanPayReqData);
+
+        return responseString;
+    }
+}

+ 37 - 0
top-core/src/main/java/com/tencent/service/UnifiedOrderPayService.java

@@ -0,0 +1,37 @@
+package com.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.pay_protocol.JSPayReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:03
+ * 统一支付接口,可接叐JSAPI/NATIVE/APP 下预支付订单,返回预支付订单号。
+ * NATIVE 支付返回二维码 code_url。
+ * 注意:JSAPI 下单前需要调用登录授权接口(详细调用说明请点击打开链接)获叏到用户
+ * 的 Openid。
+ */
+public class UnifiedOrderPayService extends BaseService {
+
+    public UnifiedOrderPayService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.PAY_UNIFIED_ORDER_API);
+    }
+
+    /**
+     * 请求支付服务
+     *
+     * @param jsPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public String request(JSPayReqData jsPayReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(jsPayReqData);
+
+        return responseString;
+    }
+}

+ 41 - 0
top-core/src/main/java/com/top/core/AbstractSpringBean.java

@@ -0,0 +1,41 @@
+package com.top.core;
+
+import com.github.sd4324530.fastweixin.api.OauthAPI;
+import com.github.sd4324530.fastweixin.api.config.ApiConfig;
+import com.tencent.common.Configure;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * @author Tian MA
+ */
+public class AbstractSpringBean {
+
+    protected Logger log;
+
+    @PostConstruct
+    void postConstruct() {
+
+        log = LoggerFactory.getLogger(this.getClass().getCanonicalName());
+    }
+
+    protected static OauthAPI oauthAPI;
+    protected static ApiConfig config;
+
+    public static ApiConfig getApiConfig() {
+        if (config == null) {
+            config = new ApiConfig(Configure.getAppid(), Configure.getAppsecret(), true);
+        }
+        return config;
+    }
+
+    public static OauthAPI getOauthApi() {
+        if (oauthAPI == null) {
+            oauthAPI = new OauthAPI(getApiConfig());
+        }
+        return oauthAPI;
+    }
+
+}

+ 30 - 0
top-core/src/main/java/com/top/core/base/GeoLocation.java

@@ -0,0 +1,30 @@
+package com.top.core.base;
+
+/**
+ * Immutable geolocation coordinates
+ *
+ * @author Sebastian MA
+ */
+public class GeoLocation {
+
+	double latitude;
+
+	double longitude;
+
+	public GeoLocation(double latitude, double longitude) {
+
+		this.latitude = latitude;
+		this.longitude = longitude;
+	}
+
+	public double getLongitude() {
+
+		return longitude;
+	}
+
+	public double getLatitude() {
+
+		return latitude;
+	}
+
+}

+ 37 - 0
top-core/src/main/java/com/top/core/controller/AbstractController.java

@@ -0,0 +1,37 @@
+package com.top.core.controller;
+
+import com.top.core.AbstractSpringBean;
+import com.top.core.service.*;
+
+import javax.annotation.Resource;
+
+public abstract class AbstractController extends AbstractSpringBean {
+
+	@Resource
+	ObjectMapper objectMapper;
+
+	@Resource
+	protected UserService userService;
+
+	@Resource
+	protected CategoryService categoryService;
+
+	@Resource
+	protected OrderService orderService;
+
+	@Resource
+	protected TradeRecordService tradeRecordService;
+
+	@Resource
+	protected ProjectService projectService;
+
+	@Resource
+	protected SchoolService schoolService;
+
+	@Resource
+	protected SpecialtyService specialtyService;
+
+	@Resource
+	protected IntegralRecordService integralRecordService;
+
+}

+ 31 - 0
top-core/src/main/java/com/top/core/controller/ModelController.java

@@ -0,0 +1,31 @@
+package com.top.core.controller;
+
+import org.springframework.util.MultiValueMap;
+import org.triiskelion.tinyspring.viewmodel.Page;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Sebastian MA
+ * Date: December 21, 2014
+ * Time: 15:27
+ * <p></p>
+ * ModelController通过和前端交换view model对象完成CRUD操作
+ */
+public interface ModelController<T> {
+
+	public static String PAGE = "page";
+
+	public static String MAX = "max";
+
+	public String add(HttpSession session, T model);
+
+	public String remove(HttpSession session, T model);
+
+	public String update(HttpSession session, T model);
+
+	public Page<T> query(HttpSession session, MultiValueMap<String, String> criteria);
+
+
+}

+ 21 - 0
top-core/src/main/java/com/top/core/dao/CategoryDao.java

@@ -0,0 +1,21 @@
+package com.top.core.dao;
+
+import com.top.core.domain.CategoryEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 9:42
+ * <p>
+ * TODO
+ */
+@Repository
+public class CategoryDao extends AbstractDao<CategoryEntity> {
+    @Override
+    protected Class<CategoryEntity> getEntityClass() {
+        return CategoryEntity.class;
+    }
+}

+ 21 - 0
top-core/src/main/java/com/top/core/dao/IntegralRecordDao.java

@@ -0,0 +1,21 @@
+package com.top.core.dao;
+
+import com.top.core.domain.IntegralRecordEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/15
+ * Time: 13:42
+ * <p>
+ * TODO
+ */
+@Repository
+public class IntegralRecordDao extends AbstractDao<IntegralRecordEntity>{
+    @Override
+    protected Class<IntegralRecordEntity> getEntityClass() {
+        return IntegralRecordEntity.class;
+    }
+}

+ 21 - 0
top-core/src/main/java/com/top/core/dao/LevelDao.java

@@ -0,0 +1,21 @@
+package com.top.core.dao;
+
+import com.top.core.domain.LevelEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/12
+ * Time: 11:11
+ * <p>
+ * TODO
+ */
+@Repository
+public class LevelDao extends AbstractDao<LevelEntity> {
+    @Override
+    protected Class<LevelEntity> getEntityClass() {
+        return LevelEntity.class;
+    }
+}

+ 21 - 0
top-core/src/main/java/com/top/core/dao/OrderDao.java

@@ -0,0 +1,21 @@
+package com.top.core.dao;
+
+import com.top.core.domain.OrderEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 9:41
+ * <p>
+ * TODO
+ */
+@Repository
+public class OrderDao extends AbstractDao<OrderEntity> {
+    @Override
+    protected Class<OrderEntity> getEntityClass() {
+        return OrderEntity.class;
+    }
+}

+ 51 - 0
top-core/src/main/java/com/top/core/dao/ProjectDao.java

@@ -0,0 +1,51 @@
+package com.top.core.dao;
+
+import com.google.common.base.Optional;
+import com.top.core.domain.ProjectEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+import java.util.List;
+
+import static org.triiskelion.tinyspring.dao.TinyPredicate.equal;
+
+/**
+ * @author Tian MA
+ */
+@Repository
+public class ProjectDao extends AbstractDao<ProjectEntity> {
+
+	@Override
+	protected Class<ProjectEntity> getEntityClass() {
+
+		return ProjectEntity.class;
+	}
+
+	/**
+	 * 根据参数查找学历提升项目
+	 *
+	 * @param levelId
+	 * @param majorId
+	 * @param schoolId
+	 *
+	 * @return
+	 */
+	public Optional<ProjectEntity> find(int levelId, int majorId, int schoolId) {
+
+		return beginQuery().select()
+		                   .where(equal("type", 1))
+		                   .and(equal("levelId", levelId))
+		                   .and(equal("majorId", majorId))
+		                   .and(equal("schoolId", schoolId))
+		                   .and(equal("deleted", ProjectEntity.DEL_NORMAL))
+		                   .getFirstResult();
+	}
+
+	public List<ProjectEntity> findByCategoryId(int categoryId) {
+
+		return beginQuery().select()
+		                   .where(equal("type", categoryId))
+		                   .and(equal("deleted", ProjectEntity.DEL_NORMAL))
+		                   .getResultList();
+	}
+}

+ 21 - 0
top-core/src/main/java/com/top/core/dao/SchoolDao.java

@@ -0,0 +1,21 @@
+package com.top.core.dao;
+
+import com.top.core.domain.SchoolEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/12
+ * Time: 11:11
+ * <p>
+ * TODO
+ */
+@Repository
+public class SchoolDao extends AbstractDao<SchoolEntity> {
+    @Override
+    protected Class<SchoolEntity> getEntityClass() {
+        return SchoolEntity.class;
+    }
+}

+ 21 - 0
top-core/src/main/java/com/top/core/dao/SpecialtyDao.java

@@ -0,0 +1,21 @@
+package com.top.core.dao;
+
+import com.top.core.domain.SpecialtyEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/12
+ * Time: 11:11
+ * <p>
+ * TODO
+ */
+@Repository
+public class SpecialtyDao extends AbstractDao<SpecialtyEntity> {
+    @Override
+    protected Class<SpecialtyEntity> getEntityClass() {
+        return SpecialtyEntity.class;
+    }
+}

+ 19 - 0
top-core/src/main/java/com/top/core/dao/TradeRecordDAO.java

@@ -0,0 +1,19 @@
+package com.top.core.dao;
+
+import com.top.core.domain.TradeRecordEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+/**
+ * Created by Wang Lei.
+ * Date on 2015/2/2
+ * Time 17:25
+ * TODO
+ */
+@Repository
+public class TradeRecordDAO extends AbstractDao<TradeRecordEntity> {
+    @Override
+    protected Class<TradeRecordEntity> getEntityClass() {
+        return TradeRecordEntity.class;
+    }
+}

+ 30 - 0
top-core/src/main/java/com/top/core/dao/UserDao.java

@@ -0,0 +1,30 @@
+package com.top.core.dao;
+
+import com.google.common.base.Optional;
+import com.top.core.domain.UserInfoEntity;
+import org.springframework.stereotype.Repository;
+import org.triiskelion.tinyspring.dao.AbstractDao;
+
+import static org.triiskelion.tinyspring.dao.TinyPredicate.equal;
+
+/**
+ * @author Sebastian MA
+ */
+@Repository
+public class UserDao extends AbstractDao<UserInfoEntity> {
+
+	@Override
+	protected Class<UserInfoEntity> getEntityClass() {
+
+		return UserInfoEntity.class;
+	}
+
+	public Optional<UserInfoEntity> findByMobile(String mobile) {
+
+		return beginQuery().ignoreNull(false)
+		                   .select()
+		                   .where(equal("mobile", mobile))
+		                   .getFirstResult();
+	}
+
+}

+ 31 - 0
top-core/src/main/java/com/top/core/domain/AbstractEntity.java

@@ -0,0 +1,31 @@
+package com.top.core.domain;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.MappedSuperclass;
+import java.io.Serializable;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/9
+ * Time: 16:53
+ * <p/>
+ * TODO
+ */
+@MappedSuperclass
+public abstract class AbstractEntity implements Serializable {
+
+    private Long id;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+}

+ 314 - 0
top-core/src/main/java/com/top/core/domain/CategoryEntity.java

@@ -0,0 +1,314 @@
+package com.top.core.domain;
+
+import com.top.core.utils.TimestampConverter;
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 9:34
+ * <p>
+ * TODO
+ */
+@Entity
+@Table(name = "category")
+@Deprecated
+public class CategoryEntity {
+
+    private int id;
+    private Integer parentId;
+    private String name;
+    private Integer type;
+    private Float studyHours;
+    private Integer studyUnit;
+
+    private String classDescr;
+    private String majorDescr;
+    private String subject;
+    private BigDecimal entryFee;
+    private BigDecimal examFee;
+    private BigDecimal tuitionFee;
+    private BigDecimal bookFee;
+    private BigDecimal price;
+
+    private Integer payMethod;
+    private Integer integralVal;
+    private Integer integralSwitch;
+    private DateTime startDate;
+    private DateTime endDate;
+    private DateTime createTime;
+    private DateTime updateTime;
+    private Integer deleted;
+    private Integer studyMethod;
+    private Integer leaf;
+
+
+    @Id
+    @Column(name = "id")
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    @Basic
+    @Column(name = "parent_id")
+    public Integer getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Integer parentId) {
+        this.parentId = parentId;
+    }
+
+
+    @Basic
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Basic
+    @Column(name = "type")
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+
+    @Basic
+    @Column(name = "study_hours")
+    public Float getStudyHours() {
+        return studyHours;
+    }
+
+    public void setStudyHours(Float studyHours) {
+        this.studyHours = studyHours;
+    }
+
+
+    @Basic
+    @Column(name = "study_unit")
+    public Integer getStudyUnit() {
+        return studyUnit;
+    }
+
+    public void setStudyUnit(Integer studyUnit) {
+        this.studyUnit = studyUnit;
+    }
+
+
+    @Basic
+    @Column(name = "price")
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
+
+    @Basic
+    @Column(name = "class_descr")
+    public String getClassDescr() {
+        return classDescr;
+    }
+
+    public void setClassDescr(String classDescr) {
+        this.classDescr = classDescr;
+    }
+
+
+    @Basic
+    @Column(name = "major_descr")
+    public String getMajorDescr() {
+        return majorDescr;
+    }
+
+    public void setMajorDescr(String majorDescr) {
+        this.majorDescr = majorDescr;
+    }
+
+
+    @Basic
+    @Column(name = "subject")
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    @Basic
+    @Column(name = "entry_fee")
+    public BigDecimal getEntryFee() {
+        return entryFee;
+    }
+
+    public void setEntryFee(BigDecimal entryFee) {
+        this.entryFee = entryFee;
+    }
+
+    @Basic
+    @Column(name = "exam_fee")
+    public BigDecimal getExamFee() {
+        return examFee;
+    }
+
+    public void setExamFee(BigDecimal examFee) {
+        this.examFee = examFee;
+    }
+
+
+    @Basic
+    @Column(name = "tuition_fee")
+    public BigDecimal getTuitionFee() {
+        return tuitionFee;
+    }
+
+    public void setTuitionFee(BigDecimal tuitionFee) {
+        this.tuitionFee = tuitionFee;
+    }
+
+
+    @Basic
+    @Column(name = "book_fee")
+    public BigDecimal getBookFee() {
+        return bookFee;
+    }
+
+    public void setBookFee(BigDecimal bookFee) {
+        this.bookFee = bookFee;
+    }
+
+
+    @Basic
+    @Column(name = "pay_method")
+    public Integer getPayMethod() {
+        return payMethod;
+    }
+
+    public void setPayMethod(Integer payMethod) {
+        this.payMethod = payMethod;
+    }
+
+
+    @Basic
+    @Column(name = "integral_val")
+    public Integer getIntegralVal() {
+        return integralVal;
+    }
+
+    public void setIntegralVal(Integer integralVal) {
+        this.integralVal = integralVal;
+    }
+
+
+    @Basic
+    @Column(name = "integral_switch")
+    public Integer getIntegralSwitch() {
+        return integralSwitch;
+    }
+
+    public void setIntegralSwitch(Integer integralSwitch) {
+        this.integralSwitch = integralSwitch;
+    }
+
+
+    @Basic
+    @Column(name = "start_date")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(DateTime startDate) {
+        this.startDate = startDate;
+    }
+
+
+    @Basic
+    @Column(name = "end_date")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(DateTime endDate) {
+        this.endDate = endDate;
+    }
+
+
+    @Basic
+    @Column(name = "create_time")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(DateTime createTime) {
+        this.createTime = createTime;
+    }
+
+
+    @Basic
+    @Column(name = "update_time")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(DateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+
+
+    @Basic
+    @Column(name = "deleted")
+    public Integer getDeleted() {
+        return deleted;
+    }
+
+    public void setDeleted(Integer deleted) {
+        this.deleted = deleted;
+    }
+
+
+    @Basic
+    @Column(name = "study_method")
+    public Integer getStudyMethod() {
+        return studyMethod;
+    }
+
+    public void setStudyMethod(Integer studyMethod) {
+        this.studyMethod = studyMethod;
+    }
+
+
+    @Basic
+    @Column(name = "leaf")
+    public Integer getLeaf() {
+        return leaf;
+    }
+
+    public void setLeaf(Integer leaf) {
+        this.leaf = leaf;
+    }
+
+}

+ 116 - 0
top-core/src/main/java/com/top/core/domain/IntegralRecordEntity.java

@@ -0,0 +1,116 @@
+package com.top.core.domain;
+
+import com.top.core.utils.TimestampConverter;
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/15
+ * Time: 13:36
+ * <p>
+ * TODO
+ */
+@Entity
+@Table(name = "integral_record")
+public class IntegralRecordEntity {
+
+    private Integer id;
+    private Integer tradingCapacity;
+    private String outTradeNo;
+    private Integer integralBefore;
+    private Integer integralBehind;
+    private String description;
+    private int userId;
+    private DateTime createTime;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Basic
+    @Column(name = "trading_capacity")
+    public Integer getTradingCapacity() {
+        return tradingCapacity;
+    }
+
+    public void setTradingCapacity(Integer tradingCapacity) {
+        this.tradingCapacity = tradingCapacity;
+    }
+
+
+    @Basic
+    @Column(name = "out_trade_no")
+    public String getOutTradeNo() {
+        return outTradeNo;
+    }
+
+    public void setOutTradeNo(String outTradeNo) {
+        this.outTradeNo = outTradeNo;
+    }
+
+
+    @Basic
+    @Column(name = "integral_before")
+    public Integer getIntegralBefore() {
+        return integralBefore;
+    }
+
+    public void setIntegralBefore(Integer integralBefore) {
+        this.integralBefore = integralBefore;
+    }
+
+
+    @Basic
+    @Column(name = "integral_behind")
+    public Integer getIntegralBehind() {
+        return integralBehind;
+    }
+
+    public void setIntegralBehind(Integer integralBehind) {
+        this.integralBehind = integralBehind;
+    }
+
+    @Basic
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+    @Basic
+    @Column(name = "createTime")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(DateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Basic
+    @Column(name = "userId")
+    public int getUserId() {
+        return userId;
+    }
+
+    public void setUserId(int userId) {
+        this.userId = userId;
+    }
+
+}

+ 101 - 0
top-core/src/main/java/com/top/core/domain/LevelEntity.java

@@ -0,0 +1,101 @@
+package com.top.core.domain;
+
+import com.top.core.utils.TimestampConverter;
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/12
+ * Time: 10:59
+ * <p>
+ * TODO
+ */
+@Entity
+@Table(name = "tb_level")
+public class LevelEntity {
+    private int id;
+    private Integer parentId;
+    private String name;
+    private DateTime createTime;
+    private DateTime updateTime;
+    private Integer type;
+    private String description;
+
+    @Id
+    @Column(name = "id")
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    @Basic
+    @Column(name = "parent_id")
+    public Integer getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Integer parentId) {
+        this.parentId = parentId;
+    }
+
+    @Basic
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Basic
+    @Column(name = "create_time")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(DateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Basic
+    @Column(name = "update_time")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(DateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Basic
+    @Column(name = "type")
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+    @Basic
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+
+}

+ 262 - 0
top-core/src/main/java/com/top/core/domain/OrderEntity.java

@@ -0,0 +1,262 @@
+package com.top.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.top.core.utils.TimestampConverter;
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 9:28
+ * <p>
+ * TODO
+ */
+@Entity
+@Table(name = "tb_order")
+public class OrderEntity {
+
+    /**
+     * 已取消
+     */
+    public final static int STATUS_CANCEL = -1;
+
+    /**
+     * 已创建(待支付)
+     */
+    public final static int STATUS_CREATE = 0;
+
+    /**
+     * 支付成功
+     */
+    public final static int STATUS_PAY_OK = 1;
+
+    /**
+     * 线下支付
+     */
+    public final static int STATUS_OFFLINE_PAY = 2;
+
+    /**
+     * 已退款
+     */
+    public final static int STATUS_REFUND = 3;
+
+
+    private String orderNumber;
+    private Integer userId;
+    private Integer projectId;
+    private String category;
+    private String buyerId;
+    private DateTime createTime;
+    private DateTime notifyTime;
+    private String description;
+    private String payId;
+    private Integer payType;
+    private BigDecimal price;
+    private BigDecimal totalPrice;
+    private String referrer;
+    private String proxyIdcard;
+    private String proxyMobile;
+    private String proxyName;
+    private Integer pay_full;
+    private BigDecimal integral;
+    private Integer status;
+
+    @Id
+    @Column(name = "order_number")
+    public String getOrderNumber() {
+        return orderNumber;
+    }
+
+    public void setOrderNumber(String orderNumber) {
+        this.orderNumber = orderNumber;
+    }
+
+    @Basic
+    @Column
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    @Basic
+    @Column
+    public Integer getProjectId() {
+        return projectId;
+    }
+
+    public void setProjectId(Integer projectId) {
+        this.projectId = projectId;
+    }
+
+    @Basic
+    @Column
+    @Lob
+    public String getCategory() {
+        return category;
+    }
+
+    public void setCategory(String category) {
+        this.category = category;
+    }
+
+    @Basic
+    @Column(name = "buyerId")
+    public String getBuyerId() {
+        return buyerId;
+    }
+
+    public void setBuyerId(String buyerId) {
+        this.buyerId = buyerId;
+    }
+
+    @Basic
+    @Column(name = "create_time")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(DateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Basic
+    @Column(name = "notify_time")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getNotifyTime() {
+        return notifyTime;
+    }
+
+    public void setNotifyTime(DateTime notifyTime) {
+        this.notifyTime = notifyTime;
+    }
+
+    @Basic
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Basic
+    @Column(name = "payId")
+    public String getPayId() {
+        return payId;
+    }
+
+    public void setPayId(String payId) {
+        this.payId = payId;
+    }
+
+    @Basic
+    @Column(name = "pay_type")
+    public Integer getPayType() {
+        return payType;
+    }
+
+    public void setPayType(Integer payType) {
+        this.payType = payType;
+    }
+
+    @Basic
+    @Column(name = "price")
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
+    @Basic
+    @Column(name = "totalPrice")
+    public BigDecimal getTotalPrice() {
+        return totalPrice;
+    }
+
+    public void setTotalPrice(BigDecimal totalPrice) {
+        this.totalPrice = totalPrice;
+    }
+
+    @Basic
+    @Column
+    public String getReferrer() {
+        return referrer;
+    }
+
+    public void setReferrer(String referrer) {
+        this.referrer = referrer;
+    }
+
+    @Basic
+    @Column(name = "proxy_idcard")
+    public String getProxyIdcard() {
+        return proxyIdcard;
+    }
+
+    public void setProxyIdcard(String proxyIdcard) {
+        this.proxyIdcard = proxyIdcard;
+    }
+
+    @Basic
+    @Column(name = "proxy_mobile")
+    public String getProxyMobile() {
+        return proxyMobile;
+    }
+
+    public void setProxyMobile(String proxyMobile) {
+        this.proxyMobile = proxyMobile;
+    }
+
+    @Basic
+    @Column(name = "proxy_name")
+    public String getProxyName() {
+        return proxyName;
+    }
+
+    public void setProxyName(String proxyName) {
+        this.proxyName = proxyName;
+    }
+
+
+    @Basic
+    @Column(name = "pay_full")
+    public Integer getPay_full() {
+        return pay_full;
+    }
+
+    public void setPay_full(Integer pay_full) {
+        this.pay_full = pay_full;
+    }
+
+    @Basic
+    @Column(name = "integral")
+    public BigDecimal getIntegral() {
+        return integral;
+    }
+
+    public void setIntegral(BigDecimal integral) {
+        this.integral = integral;
+    }
+
+    @Basic
+    @Column(name = "status")
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+}

+ 356 - 0
top-core/src/main/java/com/top/core/domain/ProjectEntity.java

@@ -0,0 +1,356 @@
+package com.top.core.domain;
+
+import com.top.core.utils.TimestampConverter;
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/12
+ * Time: 10:59
+ * <p>
+ */
+@Entity
+@Table(name = "tb_project")
+public class ProjectEntity {
+
+	/** 学历提升 */
+	public static final int cat_xlts = 1;
+
+	/** 会计培训 */
+	public static final int cat_kjpx = 2;
+
+	/** 技能培训 */
+	public static final int cat_jnpx = 3;
+
+	/** 会计培训 */
+	public static final int cat_sypx = 4;
+
+	/** 银行证书 */
+	public static final int cat_yhzs = 5;
+
+	/** 期货证书 */
+	public static final int cat_qhzs = 6;
+
+	/** 证券证书 */
+	public static final int cat_zqzs = 7;
+
+	/** 少儿培训 */
+	public static final int cat_sepx = 8;
+
+	public static final int DEL_DELETED =2;
+
+	public static final int DEL_NORMAL =1;
+
+
+	private int id;
+
+	@Column
+	private String name;
+
+	private int type;
+
+	private Integer studyUnit;
+
+	private BigDecimal studyDuration;
+
+	private String majorDesc;
+
+	private BigDecimal entryFee;
+
+	private BigDecimal examFee;
+
+	private BigDecimal tuitionFee;
+
+	private BigDecimal bookFee;
+
+	private BigDecimal totalFee;
+
+	private Integer payMethod;
+
+	private DateTime startDate;
+
+	private String enrolment;
+
+	private DateTime endDate;
+
+	private DateTime createTime;
+
+	private DateTime updateTime;
+
+	private Integer deleted;
+
+	private Integer studyMethod;
+
+	Integer levelId;
+
+	Integer schoolId;
+
+	Integer majorId;
+
+	public String getName() {
+
+		return name;
+	}
+
+	public void setName(String name) {
+
+		this.name = name;
+	}
+
+	@Column(name = "level_id")
+	public Integer getLevelId() {
+
+		return levelId;
+	}
+
+	public void setLevelId(Integer levelId) {
+
+		this.levelId = levelId;
+	}
+
+	@Column(name = "school_id")
+	public Integer getSchoolId() {
+
+		return schoolId;
+	}
+
+	public void setSchoolId(Integer schoolId) {
+
+		this.schoolId = schoolId;
+	}
+
+	@Column(name = "specialty_id")
+	public Integer getMajorId() {
+
+		return majorId;
+	}
+
+	public void setMajorId(Integer majorId) {
+
+		this.majorId = majorId;
+	}
+
+	@Id
+	@Column(name = "id")
+	public int getId() {
+
+		return id;
+	}
+
+	public void setId(int id) {
+
+		this.id = id;
+	}
+
+	@Column(name = "type")
+	public int getType() {
+
+		return type;
+	}
+
+	public void setType(int type) {
+
+		this.type = type;
+	}
+
+	@Basic
+	@Column(name = "study_unit")
+	public Integer getStudyUnit() {
+
+		return studyUnit;
+	}
+
+	public void setStudyUnit(Integer studyUnit) {
+
+		this.studyUnit = studyUnit;
+	}
+
+	@Basic
+	@Column(name = "study_duration")
+	public BigDecimal getStudyDuration() {
+
+		return studyDuration;
+	}
+
+	public void setStudyDuration(BigDecimal studyDuration) {
+
+		this.studyDuration = studyDuration;
+	}
+
+	@Basic
+	@Column(name = "major_desc")
+	public String getMajorDesc() {
+
+		return majorDesc;
+	}
+
+	public void setMajorDesc(String majorDescr) {
+
+		this.majorDesc = majorDescr;
+	}
+
+	@Basic
+	@Column(name = "entry_fee")
+	public BigDecimal getEntryFee() {
+
+		return entryFee;
+	}
+
+	public void setEntryFee(BigDecimal entryFee) {
+
+		this.entryFee = entryFee;
+	}
+
+	@Basic
+	@Column(name = "exam_fee")
+	public BigDecimal getExamFee() {
+
+		return examFee;
+	}
+
+	public void setExamFee(BigDecimal examFee) {
+
+		this.examFee = examFee;
+	}
+
+	@Basic
+	@Column(name = "tuition_fee")
+	public BigDecimal getTuitionFee() {
+
+		return tuitionFee;
+	}
+
+	public void setTuitionFee(BigDecimal tuitionFee) {
+
+		this.tuitionFee = tuitionFee;
+	}
+
+	@Basic
+	@Column(name = "book_fee")
+	public BigDecimal getBookFee() {
+
+		return bookFee;
+	}
+
+	public void setBookFee(BigDecimal bookFee) {
+
+		this.bookFee = bookFee;
+	}
+
+	@Basic
+	@Column(name = "total_fee")
+	public BigDecimal getTotalFee() {
+
+		return totalFee;
+	}
+
+	public void setTotalFee(BigDecimal totalFee) {
+
+		this.totalFee = totalFee;
+	}
+
+
+	@Basic
+	@Column(name = "pay_method")
+	public Integer getPayMethod() {
+
+		return payMethod;
+	}
+
+	public void setPayMethod(Integer payMethod) {
+
+		this.payMethod = payMethod;
+	}
+
+	@Column(name = "start_date")
+	@Convert(converter = TimestampConverter.class)
+	public DateTime getStartDate() {
+
+		return startDate;
+	}
+
+	public void setStartDate(DateTime startDate) {
+
+		this.startDate = startDate;
+	}
+
+	@Basic
+	@Column(name = "enrolment")
+	public String getEnrolment() {
+
+		return enrolment;
+	}
+
+	public void setEnrolment(String enrolment) {
+
+		this.enrolment = enrolment;
+	}
+
+	@Basic
+	@Column(name = "end_date")
+	@Convert(converter = TimestampConverter.class)
+	public DateTime getEndDate() {
+
+		return endDate;
+	}
+
+	public void setEndDate(DateTime endDate) {
+
+		this.endDate = endDate;
+	}
+
+	@Basic
+	@Column(name = "create_time")
+	@Convert(converter = TimestampConverter.class)
+	public DateTime getCreateTime() {
+
+		return createTime;
+	}
+
+	public void setCreateTime(DateTime createTime) {
+
+		this.createTime = createTime;
+	}
+
+	@Basic
+	@Column(name = "update_time")
+	@Convert(converter = TimestampConverter.class)
+	public DateTime getUpdateTime() {
+
+		return updateTime;
+	}
+
+	public void setUpdateTime(DateTime updateTime) {
+
+		this.updateTime = updateTime;
+	}
+
+	@Basic
+	@Column(name = "deleted")
+	public Integer getDeleted() {
+
+		return deleted;
+	}
+
+	public void setDeleted(Integer deleted) {
+
+		this.deleted = deleted;
+	}
+
+	@Basic
+	@Column(name = "study_method")
+	public Integer getStudyMethod() {
+
+		return studyMethod;
+	}
+
+	public void setStudyMethod(Integer studyMethod) {
+
+		this.studyMethod = studyMethod;
+	}
+
+}

+ 91 - 0
top-core/src/main/java/com/top/core/domain/SchoolEntity.java

@@ -0,0 +1,91 @@
+package com.top.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.top.core.utils.TimestampConverter;
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/12
+ * Time: 10:59
+ * <p>
+ * TODO
+ */
+@Entity
+@Table(name = "tb_school")
+public class SchoolEntity {
+    private int id;
+    private String name;
+    private DateTime createTime;
+    private DateTime updateTime;
+    private Integer status;
+    private String description;
+
+    @Id
+    @Column(name = "id")
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    @Basic
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Basic
+    @Column(name = "create_time")
+    @Convert(converter = TimestampConverter.class)
+    @JsonIgnore
+    public DateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(DateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Basic
+    @Column(name = "update_time")
+    @Convert(converter = TimestampConverter.class)
+    @JsonIgnore
+    public DateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(DateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Basic
+    @Column(name = "status")
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    @Basic
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}

+ 103 - 0
top-core/src/main/java/com/top/core/domain/SpecialtyEntity.java

@@ -0,0 +1,103 @@
+package com.top.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.top.core.utils.TimestampConverter;
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+import java.sql.Timestamp;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/12
+ * Time: 10:59
+ * <p>
+ * TODO
+ */
+@Entity
+@Table(name = "tb_specialty")
+public class SpecialtyEntity {
+    private int id;
+    private String name;
+    private DateTime createTime;
+    private DateTime updateTime;
+    private Integer status;
+    private String description;
+    private Integer levelId;
+
+
+    @Id
+    @Column(name = "id")
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    @Basic
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Basic
+    @Column(name = "create_time")
+    @JsonIgnore
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(DateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Basic
+    @Column(name = "update_time")
+    @Convert(converter = TimestampConverter.class)
+    @JsonIgnore
+    public DateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(DateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Basic
+    @Column(name = "status")
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    @Basic
+    @Column(name = "description")
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Basic
+    @Column(name = "level_id")
+    public Integer getLevelId() {
+        return levelId;
+    }
+
+    public void setLevelId(Integer levelId) {
+        this.levelId = levelId;
+    }
+}

+ 123 - 0
top-core/src/main/java/com/top/core/domain/TradeRecordEntity.java

@@ -0,0 +1,123 @@
+package com.top.core.domain;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+
+/**
+ * Created by Wang Lei.
+ * Date on 2015/2/2
+ * Time 17:22
+ * TODO
+ */
+@Entity
+@Table(name = "trade_record")
+public class TradeRecordEntity {
+
+    @Id
+    private String id;
+
+    @Column(name = "trade_number", nullable = false, insertable = true, updatable = true, length = 255)
+    private String tradeNumber;
+
+    @Basic
+    @Column(name = "out_trade_no", nullable = true, insertable = true, updatable = true, length = 255)
+    private String outTradeNo;
+
+    @Basic
+    @Column(name = "notifyTime", nullable = true, insertable = true, updatable = true)
+    private Timestamp notifyTime;
+
+    @Basic
+    @Column(name = "createTime", nullable = true, insertable = true, updatable = true)
+    private Timestamp createTime;
+
+    @Basic
+    @Column(name = "total_fee", nullable = true, insertable = true, updatable = true, precision = 2)
+    private BigDecimal totalFee;
+
+    @Basic
+    @Column(name = "result", nullable = true, insertable = true, updatable = true, length = 255)
+    private String result;
+
+    @Basic
+    @Column(name = "buyer_id", nullable = true, insertable = true, updatable = true, length = 255)
+    private String buyerId;
+
+    @Basic
+    @Column(name = "subject", nullable = true, insertable = true, updatable = true, length = 255)
+    private String subject;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getTradeNumber() {
+        return tradeNumber;
+    }
+
+    public void setTradeNumber(String tradeNumber) {
+        this.tradeNumber = tradeNumber;
+    }
+
+    public String getOutTradeNo() {
+        return outTradeNo;
+    }
+
+    public void setOutTradeNo(String outTradeNo) {
+        this.outTradeNo = outTradeNo;
+    }
+
+    public Timestamp getNotifyTime() {
+        return notifyTime;
+    }
+
+    public void setNotifyTime(Timestamp notifyTime) {
+        this.notifyTime = notifyTime;
+    }
+
+    public BigDecimal getTotalFee() {
+        return totalFee;
+    }
+
+    public void setTotalFee(BigDecimal totalFee) {
+        this.totalFee = totalFee;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        this.result = result;
+    }
+
+
+    public String getBuyerId() {
+        return buyerId;
+    }
+
+    public void setBuyerId(String buyerId) {
+        this.buyerId = buyerId;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    public Timestamp getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Timestamp createTime) {
+        this.createTime = createTime;
+    }
+}

+ 163 - 0
top-core/src/main/java/com/top/core/domain/UserInfoEntity.java

@@ -0,0 +1,163 @@
+package com.top.core.domain;
+
+import com.top.core.utils.TimestampConverter;
+import org.joda.time.DateTime;
+
+import javax.persistence.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/9
+ * Time: 11:45
+ * <p>
+ * TODO
+ */
+@Entity
+@Table(name = "user")
+public class UserInfoEntity {
+    private Integer id;
+    private String mobile;
+    private String password;
+    private String name;
+    private char gender;
+    private String idCard;
+    private String referrerMobile;
+    private String industry;
+    private Integer availableCredits;
+    private Integer freezeCredits;
+    private DateTime registerDate;
+    private String proxy;
+    private String weChat;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    @Column(name = "id")
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Column(name = "mobile")
+    public String getMobile() {
+        return mobile;
+    }
+
+    public void setMobile(String mobile) {
+        this.mobile = mobile;
+    }
+
+    @Basic
+    @Column(name = "password")
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    @Basic
+    @Column(name = "name")
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Basic
+    @Column(name = "gender")
+    public char getGender() {
+        return gender;
+    }
+
+    public void setGender(char gender) {
+        this.gender = gender;
+    }
+
+    @Basic
+    @Column(name = "id_card")
+    public String getIdCard() {
+        return idCard;
+    }
+
+    public void setIdCard(String idCard) {
+        this.idCard = idCard;
+    }
+
+    @Basic
+    @Column(name = "referrer_mobile")
+    public String getReferrerMobile() {
+        return referrerMobile;
+    }
+
+    public void setReferrerMobile(String referrerMobile) {
+        this.referrerMobile = referrerMobile;
+    }
+
+    @Basic
+    @Column(name = "industry")
+    public String getIndustry() {
+        return industry;
+    }
+
+    public void setIndustry(String industry) {
+        this.industry = industry;
+    }
+
+    @Basic
+    @Column(name = "available_credits")
+    public Integer getAvailableCredits() {
+        return availableCredits;
+    }
+
+    public void setAvailableCredits(Integer availableCredits) {
+        this.availableCredits = availableCredits;
+    }
+
+    @Basic
+    @Column(name = "freeze_credits")
+    public Integer getFreezeCredits() {
+        return freezeCredits;
+    }
+
+    public void setFreezeCredits(Integer freezeCredits) {
+        this.freezeCredits = freezeCredits;
+    }
+
+    @Basic
+    @Column(name = "register_date")
+    @Convert(converter = TimestampConverter.class)
+    public DateTime getRegisterDate() {
+        return registerDate;
+    }
+
+    public void setRegisterDate(DateTime registerDate) {
+        this.registerDate = registerDate;
+    }
+
+    @Basic
+    @Column(name = "proxy")
+    public String getProxy() {
+        return proxy;
+    }
+
+    public void setProxy(String proxy) {
+        this.proxy = proxy;
+    }
+
+    @Basic
+    @Column(name = "wechat")
+    public String getWeChat() {
+        return weChat;
+    }
+
+    public void setWeChat(String weChat) {
+        this.weChat = weChat;
+    }
+}

+ 50 - 0
top-core/src/main/java/com/top/core/service/CategoryService.java

@@ -0,0 +1,50 @@
+package com.top.core.service;
+
+import com.google.common.base.Optional;
+import com.top.core.domain.CategoryEntity;
+import com.top.core.service.impl.AbstractService;
+import org.springframework.stereotype.Service;
+import org.triiskelion.tinyspring.dao.TinyPredicate;
+
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 10:04
+ * <p>
+ * TODO
+ */
+@Service
+@Deprecated
+public class CategoryService extends AbstractService {
+
+    /**
+     * 通过id查询 {@link CategoryEntity}
+     *
+     * @param id
+     * @return
+     */
+    public CategoryEntity findById(Integer id) {
+        Optional<CategoryEntity> optional = categoryDao.findById(id);
+        if (optional.isPresent()) {
+            return optional.get();
+        }
+        return null;
+    }
+
+    /**
+     * 通过prentId查询 {@link CategoryEntity}
+     *
+     * @param parentId
+     * @return
+     */
+    public List<CategoryEntity> findByParentId(Integer parentId) {
+
+        return categoryDao.beginQuery()
+                .select()
+                .where(TinyPredicate.equal("parentId", parentId))
+                .getResultList();
+    }
+}

+ 68 - 0
top-core/src/main/java/com/top/core/service/IntegralRecordService.java

@@ -0,0 +1,68 @@
+package com.top.core.service;
+
+import com.google.common.base.Optional;
+import com.top.core.domain.IntegralRecordEntity;
+import com.top.core.domain.SchoolEntity;
+import com.top.core.domain.UserInfoEntity;
+import com.top.core.service.impl.AbstractService;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.triiskelion.tinyspring.dao.TinyPredicate;
+import org.triiskelion.tinyspring.viewmodel.Page;
+
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 10:04
+ * <p>
+ * TODO
+ */
+@Service
+public class IntegralRecordService extends AbstractService {
+
+    /**
+     * 通过id查询 page{@link IntegralRecordEntity}
+     *
+     * @param userId
+     * @return
+     */
+    public Page<IntegralRecordEntity> findByUserId(Integer userId, Integer page, Integer max) {
+        return integralRecordDao.beginQuery()
+                .select()
+                .where(TinyPredicate.equal("userId", userId))
+                .page(page, max)
+                .getPagedResult();
+    }
+
+    /**
+     * 添加积分变动记录
+     *
+     * @param userId
+     * @param tradingCapacity
+     * @param description
+     * @param outTradeNo
+     */
+    @Transactional
+    public void add(@NotNull Integer userId, @NotNull Integer tradingCapacity,
+                    String description, String outTradeNo) {
+        Optional<UserInfoEntity> optional = userDao.findById(userId);
+        if (optional.isPresent()) {
+            UserInfoEntity user = optional.get();
+            IntegralRecordEntity entity = new IntegralRecordEntity();
+            entity.setUserId(user.getId());
+            entity.setTradingCapacity(tradingCapacity);
+            entity.setIntegralBefore(user.getAvailableCredits());
+            entity.setIntegralBehind(user.getAvailableCredits() + tradingCapacity);
+            entity.setDescription(description);
+            entity.setOutTradeNo(outTradeNo);
+            integralRecordDao.persist(entity);
+        }
+
+
+    }
+
+}

+ 107 - 0
top-core/src/main/java/com/top/core/service/ObjectMapper.java

@@ -0,0 +1,107 @@
+package com.top.core.service;
+
+import com.top.core.domain.CategoryEntity;
+import com.top.core.domain.OrderEntity;
+import com.top.core.domain.UserInfoEntity;
+import com.top.core.utils.DateUtils;
+import com.top.core.viewmodel.CategoryViewModel;
+import com.top.core.viewmodel.OrderViewModel;
+import com.top.core.viewmodel.UserViewModel;
+import com.top.core.service.impl.AbstractService;
+import ma.glasnost.orika.MapperFacade;
+import ma.glasnost.orika.impl.DefaultMapperFactory;
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * Object mapping service
+ *
+ * @author Sebastian MA
+ */
+@Service
+public class ObjectMapper extends AbstractService implements ApplicationContextAware {
+
+    private MapperFacade mapper;
+
+    /**
+     * for i18n
+     */
+    private ApplicationContext appContext;
+
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext)
+            throws BeansException {
+
+        this.appContext = applicationContext;
+    }
+
+    @PostConstruct
+    public void init() {
+
+        DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
+
+        // map user
+        //        mapperFactory.classMap(AdEntity.class, AdViewModel.class)
+        //                     .byDefault()
+        //                     .register();
+
+        mapper = mapperFactory.getMapperFacade();
+    }
+
+    public MapperFacade mapper() {
+
+        return mapper;
+    }
+
+    /**
+     * 用户view
+     *
+     * @return
+     */
+    public UserViewModel map(UserInfoEntity entity) {
+        UserViewModel model = mapper.map(entity, UserViewModel.class);
+
+        model.setRegisterDate(entity.getRegisterDate().toString(DateUtils.DEFAULT_FORMAT1));
+        return model;
+
+    }
+
+
+    public OrderViewModel map(OrderEntity entity) {
+        OrderViewModel model = mapper.map(entity, OrderViewModel.class);
+        model.setCreateTime(entity.getCreateTime().toString(DateUtils.DEFAULT_FORMAT1));
+
+        if (entity.getNotifyTime() != null) {
+            model.setNotifyTime(entity.getNotifyTime().toString(DateUtils.DEFAULT_FORMAT1));
+        }
+
+        return model;
+    }
+
+    public CategoryViewModel map(CategoryEntity entity) {
+        CategoryViewModel model = mapper.map(entity, CategoryViewModel.class);
+
+        if (entity.getStartDate() != null) {
+            model.setStartDate(entity.getStartDate().toString(DateUtils.DEFAULT_FORMAT1));
+        }
+        if (entity.getEndDate() != null) {
+            model.setEndDate(entity.getEndDate().toString(DateUtils.DEFAULT_FORMAT1));
+        }
+        if (entity.getCreateTime() != null) {
+            model.setCreateTime(entity.getCreateTime().toString(DateUtils.DEFAULT_FORMAT1));
+        }
+        if (entity.getUpdateTime() != null) {
+            model.setUpdateTime(entity.getUpdateTime().toString(DateUtils.DEFAULT_FORMAT1));
+        }
+
+
+        return model;
+    }
+}

+ 182 - 0
top-core/src/main/java/com/top/core/service/OrderService.java

@@ -0,0 +1,182 @@
+package com.top.core.service;
+
+import com.alibaba.fastjson.JSON;
+import com.alipay.config.AlipayConfig;
+import com.alipay.util.UtilDate;
+import com.google.common.base.Optional;
+import com.top.core.domain.OrderEntity;
+import com.top.core.domain.ProjectEntity;
+import com.top.core.domain.UserInfoEntity;
+import com.top.core.service.impl.AbstractService;
+import com.top.core.utils.ResultValues;
+import com.top.core.viewmodel.OrderViewModel;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.joda.time.DateTime;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.triiskelion.tinyspring.dao.TinyPredicate;
+import org.triiskelion.tinyspring.viewmodel.Page;
+
+import java.math.BigDecimal;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 9:51
+ * <p>
+ * TODO
+ */
+@Service
+public class OrderService extends AbstractService {
+
+    /**
+     * 创建订单
+     *
+     * @param userId
+     * @param projectId
+     * @param payFull
+     * @param integral
+     * @param actual_fee
+     * @return
+     */
+    @Transactional
+    public String create(Integer userId, Integer projectId, boolean payFull,
+                         double integral, double actual_fee) {
+
+        try {
+            Optional<UserInfoEntity> up = userDao.findById(userId);
+            if (!up.isPresent()) {
+                return ResultValues.USER_NOT_FOUND;
+            }
+            UserInfoEntity user = up.get();
+
+            Optional<ProjectEntity> optional = projectDao.findById(projectId);
+            if (!optional.isPresent()) {
+                return ResultValues.CATEGORY_NOT_FOUND;
+            }
+
+            ProjectEntity projectEntity = optional.get();
+
+            OrderEntity entity = new OrderEntity();
+            entity.setOrderNumber(UtilDate.getOrderNum());
+            entity.setUserId(up.get().getId());
+            entity.setProjectId(projectEntity.getId());
+            entity.setDescription(projectEntity.getName());
+            entity.setCategory(JSON.toJSONString(projectEntity));
+            entity.setCreateTime(DateTime.now());
+            entity.setReferrer(up.get().getReferrerMobile());
+            entity.setStatus(OrderEntity.STATUS_CREATE);
+            entity.setPay_full(payFull ? 1 : 0);
+            entity.setPrice(new BigDecimal(actual_fee));
+            entity.setTotalPrice(projectEntity.getTotalFee());
+            orderDao.persist(entity);
+
+            //todo 扣除积分
+            if (integral > 0) {
+                entity.setIntegral(new BigDecimal(integral));
+                user.setAvailableCredits(user.getAvailableCredits() - ((int) integral * 10));
+                integralRecordService.add(user.getId(), -((int) integral * 10), "消费积分", entity.getOrderNumber());
+            }
+            if (StringUtils.isNotBlank(user.getReferrerMobile())) {
+                Optional<UserInfoEntity> referrerUp = userDao.findByMobile(user.getReferrerMobile());
+                if (referrerUp.isPresent() && StringUtils.isNoneBlank(user.getReferrerMobile())) {
+                    UserInfoEntity referrer = referrerUp.get();
+                    referrer.setAvailableCredits(referrer.getAvailableCredits() + ((int) integral * 10));
+                    integralRecordService.add(referrer.getId(), UserService.RegisterPoints, "被推荐人" + user.getMobile() + "消费,赠送积分", entity.getOrderNumber());
+                }
+            }
+
+            return entity.getOrderNumber();
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("create order error,msg:" + e.getMessage());
+            return ResultValues.FAILURE;
+        }
+    }
+
+
+    /**
+     * 查询订单根据用户id和订单号
+     *
+     * @param userId
+     * @param orderNo
+     * @return
+     */
+    public OrderViewModel getOrderInfo(Integer userId, @NotNull String orderNo) {
+
+        if (StringUtils.isBlank(orderNo)) {
+            throw new IllegalArgumentException(ResultValues.PARAM_INVALID);
+        }
+        Optional<UserInfoEntity> up = userDao.findById(userId);
+        if (!up.isPresent()) {
+            throw new IllegalArgumentException(ResultValues.USER_NOT_FOUND);
+        }
+        Optional<OrderEntity> optional = orderDao.beginQuery()
+                .select()
+                .where(TinyPredicate.equal("orderNumber",
+                        orderNo))
+                .and(TinyPredicate.equal("userId", userId))
+                .getFirstResult();
+
+        if (!optional.isPresent()) {
+            throw new IllegalArgumentException(ResultValues.ORDER_NOT_FOUND);
+        }
+
+        return objectMapper.map(optional.get());
+    }
+
+    /**
+     * 根据用户id查询订单列表
+     *
+     * @param userId
+     * @param page
+     * @param max
+     * @return
+     */
+    public Page<OrderViewModel> getOrderList(Integer userId, Integer page, Integer max) {
+
+        Optional<UserInfoEntity> up = userDao.findById(userId);
+        if (!up.isPresent()) {
+            throw new IllegalArgumentException(ResultValues.USER_NOT_FOUND);
+        }
+        Page<OrderEntity> result = orderDao.beginQuery()
+                .select()
+                .and(TinyPredicate.equal("userId", userId))
+                .page(page, max)
+                .getPagedResult();
+        return result.map(OrderViewModel.class, objectMapper::map);
+    }
+
+    /**
+     * 缴费通知确认
+     *
+     * @param out_trade_no
+     * @param price
+     * @return
+     */
+    @Transactional
+    public boolean onConfirmPayment(String out_trade_no, BigDecimal price) {
+
+        Optional<OrderEntity> opt = orderDao.findById(out_trade_no);
+
+        if (!opt.isPresent()) {
+            return false;
+        }
+
+        OrderEntity entity = opt.get();
+        if (entity.getStatus() == OrderEntity.STATUS_CREATE && price.compareTo(entity.getPrice())
+                == 0) {
+            entity.setNotifyTime(DateTime.now());
+            entity.setStatus(OrderEntity.STATUS_PAY_OK);
+        } else {
+            log.error("onConfirmPayment failed. Order is not on right status. no={},amount={}",
+                    out_trade_no, price);
+            return false;
+
+        }
+        return true;
+    }
+
+}

+ 53 - 0
top-core/src/main/java/com/top/core/service/ProjectService.java

@@ -0,0 +1,53 @@
+package com.top.core.service;
+
+import com.google.common.base.Optional;
+import com.top.core.dao.ProjectDao;
+import com.top.core.domain.ProjectEntity;
+import com.top.core.service.impl.AbstractService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 报名项目
+ *
+ * @author Tian MA
+ */
+@Service
+public class ProjectService extends AbstractService {
+
+	@Resource
+	protected ProjectDao projectDao;
+
+	/**
+	 * 根据项目id查找
+	 *
+	 * @param projectId
+	 * 		项目id
+	 */
+	public Optional<ProjectEntity> findById(int projectId) {
+
+		return projectDao.findById(projectId);
+	}
+
+	/**
+	 * 根据选择器查找专业
+	 *
+	 * @param levelId
+	 * 		层次id
+	 * @param majorId
+	 * 		专业id
+	 * @param schoolId
+	 * 		学校id
+	 */
+	public Optional<ProjectEntity> find(int levelId, int majorId, int schoolId) {
+
+		return projectDao.find(levelId, majorId, schoolId);
+	}
+
+	public List<ProjectEntity> list(int categoryId) {
+
+		return projectDao.findByCategoryId(categoryId);
+	}
+}

+ 53 - 0
top-core/src/main/java/com/top/core/service/SchoolService.java

@@ -0,0 +1,53 @@
+package com.top.core.service;
+
+import com.google.common.base.Optional;
+import com.top.core.domain.SchoolEntity;
+import com.top.core.service.impl.AbstractService;
+import org.springframework.stereotype.Service;
+import org.triiskelion.tinyspring.dao.TinyPredicate;
+
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 10:04
+ * <p>
+ * TODO
+ */
+@Service
+public class SchoolService extends AbstractService {
+
+    /**
+     * 通过id查询 {@link com.top.core.domain.SchoolEntity}
+     *
+     * @param id
+     * @return
+     */
+    public SchoolEntity findById(Integer id) {
+        Optional<SchoolEntity> optional = schoolDao.findById(id);
+        if (optional.isPresent()) {
+            return optional.get();
+        }
+        return null;
+    }
+
+    public List<SchoolEntity> findAll() {
+        return schoolDao.findAll();
+    }
+
+    /**
+     * 查询学校根据层次,专业
+     *
+     * @param levelId
+     * @param specialtyId
+     * @return
+     */
+    public List<SchoolEntity> find(Integer levelId, Integer specialtyId) {
+        String jpql = "SELECT s from SchoolEntity s,ProjectEntity p WHERE s.id=p.schoolId AND " +
+                "p.levelId =" + levelId + " AND p.majorId = " + specialtyId + " GROUP BY s.id";
+
+        return projectDao.beginQuery().query(jpql).getUntypedResultList();
+    }
+}

+ 91 - 0
top-core/src/main/java/com/top/core/service/SecurityManager.java

@@ -0,0 +1,91 @@
+package com.top.core.service;
+
+import com.google.common.base.Optional;
+import com.top.core.dao.UserDao;
+import com.top.core.domain.UserInfoEntity;
+import com.top.core.utils.MD5Utils;
+import com.top.core.utils.ServletUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.triiskelion.tinyspring.security.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Objects;
+
+/**
+ * @author Sebastian MA
+ */
+@Service
+public class SecurityManager extends TinySecurityManager {
+
+    private static Logger log = LoggerFactory.getLogger(SecurityManager.class);
+
+    @Resource
+    private UserDao userDao;
+
+    @Override
+    public AuthenticationResult doAuthenticate(HttpSession session,
+                                               String login, String password) {
+
+        Optional<UserInfoEntity> userOpt = userDao.findByMobile(login);
+
+        if (userOpt.isPresent()) {
+            TinyUser user = new TinyUser(login, new ArrayList<>(), userOpt.get().getId());
+            if (Objects.equals(userOpt.get().getPassword(), MD5Utils.encrypt(password, 16))) {
+                session.setAttribute(SESSION_NAME_USER, user);
+                return AuthenticationResult.of(user);
+            }
+        }
+        return AuthenticationResult.denied();
+    }
+
+    @Override
+    protected boolean doAuthenticateStatelessly(HttpServletRequest request,
+                                                HttpServletResponse response) {
+
+        return false;
+    }
+
+    @Override
+    protected void onNotLogin(HttpServletRequest request, HttpServletResponse
+            response) {
+
+        try {
+            ServletUtils.redirect(request, response, "/home/login");
+        } catch (IOException e) {
+            log.error("Could not redirect to: {}", "/home/login");
+        }
+    }
+
+
+    @Override
+    protected void onRequireAllPrivilegesFail(HttpServletRequest request, HttpServletResponse
+            response, TinyUser tinyUser, String[] strings) {
+
+    }
+
+    @Override
+    protected void onRequireAnyPrivilegeFail(HttpServletRequest request, HttpServletResponse
+            response, TinyUser tinyUser, String[] strings) {
+
+    }
+
+    @Override
+    public void onRequireRolesFail(HttpServletRequest request, HttpServletResponse
+            response, TinyUser user, String[] roles) {
+
+        try {
+            response.getWriter().write("NOT_ALLOWED");
+        } catch (IOException ignored) {
+        }
+
+    }
+
+
+}

+ 54 - 0
top-core/src/main/java/com/top/core/service/SpecialtyService.java

@@ -0,0 +1,54 @@
+package com.top.core.service;
+
+import com.google.common.base.Optional;
+import com.top.core.domain.SpecialtyEntity;
+import com.top.core.service.impl.AbstractService;
+import org.springframework.stereotype.Service;
+import org.triiskelion.tinyspring.dao.TinyPredicate;
+
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: Wang Lei
+ * Date: 2015/6/11
+ * Time: 10:04
+ * <p>
+ * TODO
+ */
+@Service
+public class SpecialtyService extends AbstractService {
+
+    /**
+     * 通过id查询 {@link SpecialtyEntity}
+     *
+     * @param id
+     * @return
+     */
+    public SpecialtyEntity findById(Integer id) {
+        Optional<SpecialtyEntity> optional = specialtyDao.findById(id);
+
+        if (optional.isPresent()) {
+            return optional.get();
+        }
+        return null;
+    }
+
+    /**
+     * 通过levelId查询 {@link SpecialtyEntity}
+     *
+     * @param levelId
+     * @return
+     */
+    public List<SpecialtyEntity> findByLevelId(Integer levelId) {
+
+        return specialtyDao.beginQuery()
+                .select()
+                .where(TinyPredicate.equal("levelId", levelId))
+                .getResultList();
+    }
+
+    public List<SpecialtyEntity> findAll() {
+        return specialtyDao.findAll();
+    }
+}

+ 57 - 0
top-core/src/main/java/com/top/core/service/TradeRecordService.java

@@ -0,0 +1,57 @@
+package com.top.core.service;
+
+import com.top.core.domain.TradeRecordEntity;
+import com.top.core.service.impl.AbstractService;
+import com.top.core.utils.ResultValues;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.triiskelion.tinyutils.datetime.JodaDateTimeFactory;
+
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.util.UUID;
+
+/**
+ * Created by Wang Lei.
+ * Date on 2015/2/3
+ * Time 15:48
+ * TODO
+ */
+@Service
+public class TradeRecordService extends AbstractService {
+
+    /**
+     * 支付通知记录*
+     *
+     * @param tradeNumber 支付宝交易号
+     * @param outTradeNo  订单号
+     * @param notifyTime  通知时间
+     * @param totalFee    交易 金额
+     * @param result      交易状态
+     * @param buyerId     卖家支付宝id
+     * @param subject     交易账目名称
+     * @return
+     */
+    @Transactional
+    public String add(String tradeNumber, String outTradeNo, Timestamp notifyTime, String totalFee,
+                      String result, String buyerId, String subject) {
+        try {
+            TradeRecordEntity entity = new TradeRecordEntity();
+            entity.setId(UUID.randomUUID().toString());
+            entity.setTradeNumber(tradeNumber);
+            entity.setOutTradeNo(outTradeNo);
+            entity.setNotifyTime(notifyTime);
+            entity.setTotalFee(new BigDecimal(totalFee));
+            entity.setResult(result);
+            entity.setBuyerId(buyerId);
+            entity.setSubject(subject);
+            entity.setCreateTime(JodaDateTimeFactory.Timestamp.now());
+            tradeRecordDAO.persist(entity);
+            return ResultValues.SUCCESS;
+        } catch (Exception e) {
+            log.error("save alipay data fail,like had deal:" + e.getMessage());
+            return ResultValues.FAILURE;
+        }
+
+    }
+}

+ 160 - 0
top-core/src/main/java/com/top/core/service/UserService.java

@@ -0,0 +1,160 @@
+package com.top.core.service;
+
+
+import com.google.common.base.Optional;
+import com.top.core.domain.UserInfoEntity;
+import com.top.core.service.impl.AbstractService;
+import com.top.core.utils.MD5Utils;
+import com.top.core.utils.ResultValues;
+import org.apache.commons.lang3.StringUtils;
+import org.joda.time.DateTime;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.triiskelion.tinyutils.Validator;
+
+@Service
+public class UserService extends AbstractService {
+
+    public static final int RegisterPoints = 100;
+    /**
+     * 检查手机号是否存在
+     *
+     * @param mobile
+     * @return 存在 true 不存在 false
+     */
+    public boolean checkMobile(String mobile) {
+        Optional<UserInfoEntity> optional = userDao.findByMobile(mobile);
+        if (optional.isPresent()) {
+            return true;
+        }
+        return false;
+    }
+
+    @Transactional
+    public String createUserByMobile(String mobile, String password) {
+        try {
+            if (checkMobile(mobile)) {
+                return ResultValues.MOBILE_ALREADY_EXISTS;
+            }
+            if (Validator.isStrictMobileNumber(mobile) && StringUtils.isNotBlank(password)) {
+                UserInfoEntity entity = new UserInfoEntity();
+                entity.setMobile(mobile);
+                entity.setPassword(MD5Utils.encrypt(password, 16));
+                entity.setRegisterDate(DateTime.now());
+                userDao.persist(entity);
+                return ResultValues.SUCCESS;
+            }
+            return ResultValues.PARAM_INVALID;
+        } catch (Exception e) {
+            return ResultValues.FAILURE;
+        }
+    }
+
+    /**
+     * 创建用户,并且为推荐人添加积分
+     * @param mobile
+     * @param password
+     * @param refereeMobile
+     * @return
+     */
+    @Transactional
+    public String createUserByMobile(String mobile, String password, String refereeMobile) {
+        try {
+            UserInfoEntity referee = null;
+            if (checkMobile(mobile)) {
+                return ResultValues.MOBILE_ALREADY_EXISTS;
+            }
+            if (refereeMobile != null && refereeMobile.length() > 0) {
+                if (!checkMobile(refereeMobile)) {
+                    return ResultValues.REFEREE_NOT_FOUND;
+                } else {
+                    referee = userDao.findByMobile(refereeMobile).get();
+                }
+            }
+            if (Validator.isStrictMobileNumber(mobile) && StringUtils.isNotBlank(password)) {
+                UserInfoEntity entity = new UserInfoEntity();
+                entity.setMobile(mobile);
+                entity.setPassword(MD5Utils.encrypt(password, 16));
+                entity.setRegisterDate(DateTime.now());
+                entity.setAvailableCredits(RegisterPoints);
+                entity.setReferrerMobile(refereeMobile);
+                userDao.persist(entity);
+                integralRecordService.add(entity.getId(), RegisterPoints, "注册赠送积分", null);
+                if (referee != null) {
+                    referee.setAvailableCredits(RegisterPoints + referee.getAvailableCredits());
+                    integralRecordService.add(referee.getId(),RegisterPoints,"推荐"+mobile+"注册赠送积分",null);
+
+                    userDao.merge(referee);
+                }
+                return ResultValues.SUCCESS;
+            }
+            return ResultValues.PARAM_INVALID;
+        } catch (Exception e) {
+            return ResultValues.FAILURE;
+        }
+    }
+
+    public Optional<UserInfoEntity> getUserInfoById(Integer id) {
+        return userDao.findById(id);
+//        Optional<UserInfoEntity> optional = userDao.findById(id);
+//        if (optional.isPresent()) {
+//            return optional.get();
+//        }
+//        return null;
+    }
+
+    /**
+     * 用户修改密码或者忘记密码
+     *
+     * @param mobile
+     * @param newPassword
+     * @return
+     */
+    @Transactional
+    public String changePassword(String mobile, String newPassword) {
+        Optional<UserInfoEntity> optional = userDao.findByMobile(mobile);
+        if (optional.isPresent()) {
+            UserInfoEntity user = optional.get();
+            user.setPassword(MD5Utils.encrypt(newPassword, 16));
+            return ResultValues.SUCCESS;
+        } else {
+            return ResultValues.USER_NOT_FOUND;
+        }
+    }
+
+    /**
+     * 绑定用户微信openid
+     *
+     * @param id
+     * @param openId
+     */
+    @Transactional
+    public void bindingWeChat(Integer id, String openId) {
+        Optional<UserInfoEntity> optional = getUserInfoById(id);
+        if (optional.isPresent()) {
+            optional.get().setWeChat(openId);
+            userDao.merge(optional.get());
+        }
+    }
+
+    /**
+     * 用户修改真实姓名
+     * @param id
+     * @param name
+     */
+    @Transactional
+    public void modifyName(Integer id, String name) {
+        Optional<UserInfoEntity> optional = getUserInfoById(id);
+        if (optional.isPresent()) {
+            optional.get().setName(name);
+        }
+    }
+
+    @Transactional
+    public void modifyIdCardNum(Integer id, String idCardNum) {
+        Optional<UserInfoEntity> optional = getUserInfoById(id);
+        if (optional.isPresent()) {
+            optional.get().setIdCard(idCardNum);
+        }
+    }
+}

+ 46 - 0
top-core/src/main/java/com/top/core/service/impl/AbstractService.java

@@ -0,0 +1,46 @@
+package com.top.core.service.impl;
+
+import com.top.core.dao.*;
+import com.top.core.AbstractSpringBean;
+import com.top.core.service.IntegralRecordService;
+import com.top.core.service.ObjectMapper;
+
+import javax.annotation.Resource;
+
+public abstract class AbstractService extends AbstractSpringBean {
+
+    @Resource
+    protected ObjectMapper objectMapper;
+
+    @Resource
+    protected UserDao userDao;
+
+    @Resource
+    protected OrderDao orderDao;
+
+    @Resource
+    protected CategoryDao categoryDao;
+
+    @Resource
+    protected TradeRecordDAO tradeRecordDAO;
+
+    @Resource
+    protected SpecialtyDao specialtyDao;
+
+    @Resource
+    protected SchoolDao schoolDao;
+
+    @Resource
+    protected LevelDao levelDao;
+
+    @Resource
+    protected ProjectDao projectDao;
+
+    @Resource
+    protected IntegralRecordDao integralRecordDao;
+
+    @Resource
+    protected IntegralRecordService integralRecordService;
+
+
+}

+ 29 - 0
top-core/src/main/java/com/top/core/service/impl/FileService.java

@@ -0,0 +1,29 @@
+package com.top.core.service.impl;
+
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @author Sebastian MA
+ */
+public interface FileService {
+
+
+	String prefix = "http://www.eggcharge.com/images/";
+
+	public String put(String path, String filename, byte[] bytes);
+
+	public String upload(MultipartFile file);
+
+	/**
+	 * 获取完整的url
+	 *
+	 * @param relativeUrl
+	 * 		没有域名的相对路径
+	 *
+	 * @return 完整的url
+	 */
+	default public String getAbsoluteUrl(String relativeUrl) {
+
+		return prefix + relativeUrl;
+	}
+}

+ 22 - 0
top-core/src/main/java/com/top/core/service/impl/GeoLocationService.java

@@ -0,0 +1,22 @@
+package com.top.core.service.impl;
+
+
+import com.top.core.base.GeoLocation;
+
+import java.util.Optional;
+
+/**
+ * @author Sebastian MA
+ */
+public interface GeoLocationService {
+
+	/**
+	 * 根据地址获取坐标
+	 *
+	 * @param address
+	 * 		详细地址
+	 *
+	 * @return 经纬度坐标
+	 */
+	Optional<GeoLocation> resolveGeolocation(String address);
+}

+ 25 - 0
top-core/src/main/java/com/top/core/service/impl/SystemPropertyService.java

@@ -0,0 +1,25 @@
+package com.top.core.service.impl;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * @author Sebastian MA
+ */
+public interface SystemPropertyService {
+
+
+	Optional<String> getString(String key);
+
+	Optional<Integer> getInt(String key);
+
+	Optional<Double> getDouble(String key);
+
+	<T> Optional<T> getObject(String key, Class<T> clazz);
+
+	<T> List<T> getArray(String key, Class<T> clazz);
+
+	<T> Map<String, T> getMap(String key, Class<T> clazz);
+
+}

+ 28 - 0
top-core/src/main/java/com/top/core/utils/DateConverter.java

@@ -0,0 +1,28 @@
+package com.top.core.utils;
+
+import org.joda.time.DateTime;
+
+import javax.persistence.AttributeConverter;
+import javax.persistence.Converter;
+import java.sql.Date;
+
+/**
+ * @author Sebastian MA
+ */
+@Converter
+public class DateConverter implements AttributeConverter<DateTime, Date> {
+
+
+	@Override
+	public Date convertToDatabaseColumn(DateTime attribute) {
+
+
+		return new Date(attribute.getMillis());
+	}
+
+	@Override
+	public DateTime convertToEntityAttribute(Date dbData) {
+
+		return new DateTime(dbData.getYear() + 1900, dbData.getMonth() + 1, dbData.getDate(), 0, 0);
+	}
+}

Some files were not shown because too many files changed in this diff