[
  {
    "path": ".github/workflows/maven.yml",
    "content": "# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time\n# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven\n\n# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and are governed by\n# separate terms of service, privacy policy, and support\n# documentation.\n\nname: Java CI with Maven\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n    - name: Set up JDK 17\n      uses: actions/setup-java@v3\n      with:\n        java-version: '17'\n        distribution: 'temurin'\n        cache: maven\n    - name: Build with Maven\n      run: mvn -B package --file pom.xml\n\n    # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive\n    - name: Update dependency graph\n      uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6\n"
  },
  {
    "path": ".gitignore",
    "content": "*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n*.idea\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 justinbaby\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# seckill（Java高并发秒杀API）\n一个spring入门项目,后续将更新spring中级项目 :)\n#### 所用技术点\n - spring\n - springMVC: MVC框架\n - Tomcat: web容器\n - mybatis: ORM框架\n - bootstrap: css/html框架\n - JQuery: JS框架\n - Redis: NOSQL数据库\n - MySQL: 关系型数据库\n - Logback: 日志框架\n - JUnit: 单元测试\n - CDN: 内容分发服务器\n - Procedure:数据库存储过程\n - Protostuff:Google开发的基于Java语言的序列化库\n - ZooKeeper:分布式应用程序协调服务 \n - DUBBO:分布式应用服务框架 \n\n## Java高并发秒杀系统API\n\n本项目参考慕课网视频(版权方),并在此基础上进行了模块划分,功能添加,欢迎去官网观看!!!!\n\n## 安装部署\n\n #### 软件环境：\n\n  - IDEA\n  - MySQL\n  - JDK1.8或以上\n  - tomcat 8.0\n  - Redis\n  - Maven\n #### 硬件环境(最小配置)：\n\n  - CPU：1核\n  - 内存：1G\n\n #### 说明\n - seckill-core：秒杀核心模块，部署tomcat启动\n - seckill-api：秒杀api模块\n - seckill-base：秒杀工具类模块\n - seckill-web：秒杀页面模块\n\n #### 步骤\n 1. 创建数据库，导入初始化脚本initDB.sql\n 2. 修改系统数据库连接seckill-core/src/main/resources/jdbc.properties\n 3. Tomcat运行\n\n## FAQ\n- Q:为什么我的maven下载依赖jar包这么慢\n- A:可以自己下载maven,使用自己的Maven,修改maven安装目录下的/conf/settings.xml,在IDEA或eclipse里配置为默认的设置\n```XML\n                           <mirror>\n                               <id>nexus-aliyun</id>\n                               <mirrorOf>central</mirrorOf>\n                               <name>Nexus aliyun</name>\n                               <url>http://maven.aliyun.com/nexus/content/groups/public</url>\n                           </mirror>\n```\n\n- Q:为什么我的数据库连不上\n- A:查看一下jdbc.properties，配置url为你的数据库地址,你的数据库用户名和密码\n\n- Q:为什控制台报Redis异常\n- A:查看一下Redis服务器是否启动，没下载的建议去官网下载window或linux版\n\n- Q:eclipse怎么导入\n- A:去掉.开头的文件就可以导入!!!\n"
  },
  {
    "path": "docs/script/initDB.sql",
    "content": "/*\n\nSource Server         : root\nSource Server Version : 50538\nSource Host           : localhost:3306\nSource Database       : seckill\n\nTarget Server Type    : MYSQL\nTarget Server Version : 50538\nFile Encoding         : 65001\n\nDate: 2017-02-17 12:05:42\n*/\n\nSET FOREIGN_KEY_CHECKS=0;\n\n-- ----------------------------\n-- Table structure for seckill\n-- ----------------------------\nDROP TABLE IF EXISTS `seckill`;\nCREATE TABLE `seckill` (\n  `seckill_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品库存ID',\n  `name` varchar(120) NOT NULL COMMENT '商品名称',\n  `number` int(11) NOT NULL COMMENT '库存数量',\n  `start_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '秒杀开始时间',\n  `end_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '秒杀结束时间',\n  `create_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',\n  PRIMARY KEY (`seckill_id`),\n  KEY `idx_start_time` (`start_time`),\n  KEY `idx_end_time` (`end_time`),\n  KEY `idx_create_time` (`create_time`)\n) ENGINE=InnoDB AUTO_INCREMENT=1006 DEFAULT CHARSET=utf8 COMMENT='秒杀库存表';\n\n-- ----------------------------\n-- Records of seckill\n-- ----------------------------\nINSERT INTO `seckill` VALUES ('1000', '100元秒杀诺基亚', '10000', '2017-02-17 12:02:05', '2019-12-21 00:00:00', '2016-12-21 00:00:00');\nINSERT INTO `seckill` VALUES ('1001', '5000元秒杀iphone7', '1700', '2017-02-17 11:47:36', '2016-04-11 00:00:00', '2016-04-11 00:00:00');\nINSERT INTO `seckill` VALUES ('1002', '1000元秒杀ipad1', '3500', '2017-02-17 11:47:41', '2016-05-12 00:00:00', '2016-05-12 00:00:00');\nINSERT INTO `seckill` VALUES ('1003', '1600元秒杀小米4', '1200', '2017-02-17 11:47:47', '2016-07-23 00:00:00', '2016-07-23 00:00:00');\nINSERT INTO `seckill` VALUES ('1004', '1400元秒杀魅族4', '1099', '2017-02-17 12:02:28', '2018-02-17 11:48:00', '2017-02-17 11:48:00');\nINSERT INTO `seckill` VALUES ('1005', '1400元秒杀小米3', '1100', '2017-02-17 11:48:23', '2016-01-21 00:00:00', '2016-01-21 00:00:00');\n\n-- ----------------------------\n-- Table structure for success_killed\n-- ----------------------------\nDROP TABLE IF EXISTS `success_killed`;\nCREATE TABLE `success_killed` (\n  `seckill_id` bigint(20) NOT NULL COMMENT '秒杀商品ID',\n  `user_phone` bigint(20) NOT NULL COMMENT '用户手机号',\n  `state` tinyint(4) NOT NULL DEFAULT '-1' COMMENT '状态标识:-1:无效 0:成功 1:已付款 2:已发货',\n  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',\n  PRIMARY KEY (`seckill_id`,`user_phone`),\n  KEY `idx_create_time` (`create_time`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='秒杀成功明细表';\n\n-- ----------------------------\n-- Records of success_killed\n-- ----------------------------\nINSERT INTO `success_killed` VALUES ('1004', '15643645806', '-1', '2017-02-17 12:02:27');\n\n-- ----------------------------\n-- View structure for v1\n-- ----------------------------\nDROP VIEW IF EXISTS `v1`;\nCREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost`  VIEW `v1` AS SELECT *FROM seckill ;\n\n-- ----------------------------\n-- Procedure structure for execute_seckill\n-- ----------------------------\nDROP PROCEDURE IF EXISTS `execute_seckill`;\nDELIMITER ;;\nCREATE DEFINER=`root`@`localhost` PROCEDURE `execute_seckill`(IN v_seckill_id bigint, IN v_phone BIGINT,\nIN v_kill_time TIMESTAMP, OUT r_result INT)\nBEGIN\n\t\tDECLARE insert_count INT DEFAULT 0;\n\t\tSTART TRANSACTION;\n\t\tINSERT ignore INTO success_killed (seckill_id, user_phone, create_time)\n\t\tVALUES(v_seckill_id, v_phone, v_kill_time);\n\t\tSELECT ROW_COUNT() INTO insert_count;\n\t\tIF (insert_count = 0) THEN\n\t\t\tROLLBACK;\n\t\t\tSET r_result = -1;\n\t\tELSEIF (insert_count < 0) THEN\n\t\t\tROLLBACK ;\n\t\t\tSET r_result = -2;\n\t\tELSE\n\t\t\tUPDATE seckill SET number = number - 1\n\t\t\tWHERE seckill_id = v_seckill_id AND end_time > v_kill_time\n\t\t\tAND start_time < v_kill_time AND number > 0;\n\t\t\tSELECT ROW_COUNT() INTO insert_count;\n\t\t\tIF (insert_count = 0) THEN\n\t\t\t\tROLLBACK;\n\t\t\t\tSET r_result = 0;\n\t\t\tELSEIF (insert_count < 0) THEN\n\t\t\t\tROLLBACK;\n\t\t\t\tSET r_result = -2;\n\t\t\tELSE\n\t\t\t\tCOMMIT;\n\t\t\tSET r_result = 1;\n\t\t\tEND IF;\n\t\tEND IF;\n\tEND\n;;\nDELIMITER ;\nSET FOREIGN_KEY_CHECKS=1;\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>com.imooc</groupId>\n    <artifactId>seckill</artifactId>\n    <packaging>pom</packaging>\n    <version>0.0.1-SNAPSHOT </version>\n    <modules>\n        <module>seckill-core</module>\n        <module>seckill-model</module>\n        <module>seckill-client</module>\n    </modules>\n    <name>seckill Maven Webapp</name>\n    <url>http://maven.apache.org</url>\n    <dependencies>\n        <!-- 单元测试 \t//test master add something -->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.1</version>\n        </dependency>\n\n        <!-- 1.日志 -->\n        <!-- 实现slf4j接口并整合 -->\n        <dependency>\n            <groupId>ch.qos.logback</groupId>\n            <artifactId>logback-classic</artifactId>\n            <version>1.2.0</version>\n        </dependency>\n\n        <!-- 2.数据库 -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n\t\t\t<version>8.0.16</version>\n            <scope>runtime</scope>\n        </dependency>\n        <dependency>\n            <groupId>c3p0</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.1.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid</artifactId>\n            <version>1.0.13</version>\n        </dependency>\n\n        <!-- DAO: MyBatis -->\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis</artifactId>\n            <version>3.5.6</version>\n        </dependency>\n        <dependency>\n            <groupId>org.mybatis</groupId>\n            <artifactId>mybatis-spring</artifactId>\n            <version>1.3.2</version>\n        </dependency>\n\n        <!-- 3.Servlet web -->\n        <dependency>\n            <groupId>taglibs</groupId>\n            <artifactId>standard</artifactId>\n            <version>1.1.2</version>\n        </dependency>\n        <dependency>\n            <groupId>jstl</groupId>\n            <artifactId>jstl</artifactId>\n            <version>1.2</version>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n            <version>2.9.10.7</version>\n        </dependency>\n        <dependency>\n            <groupId>javax.servlet</groupId>\n            <artifactId>javax.servlet-api</artifactId>\n            <version>3.1.0</version>\n        </dependency>\n\n        <!-- 4.Spring -->\n        <!-- 1)Spring核心 -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-core</artifactId>\n            <version>4.3.21.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-beans</artifactId>\n            <version>4.1.7.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n            <version>4.1.7.RELEASE</version>\n        </dependency>\n        <!-- 2)Spring DAO层 -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n            <version>4.1.7.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-tx</artifactId>\n            <version>4.1.7.RELEASE</version>\n        </dependency>\n        <!-- 3)Spring web -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-web</artifactId>\n            <version>4.1.7.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-webmvc</artifactId>\n            <version>4.1.7.RELEASE</version>\n        </dependency>\n        <!-- 4)Spring test -->\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-test</artifactId>\n            <version>4.1.7.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-aop</artifactId>\n            <version>4.1.7.RELEASE</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-aspects</artifactId>\n            <version>4.2.0.RELEASE</version>\n        </dependency>\n\n        <!-- redis客户端:Jedis -->\n        <dependency>\n            <groupId>redis.clients</groupId>\n            <artifactId>jedis</artifactId>\n            <version>2.7.3</version>\n        </dependency>\n        <dependency>\n            <groupId>com.dyuproject.protostuff</groupId>\n            <artifactId>protostuff-core</artifactId>\n            <version>1.0.8</version>\n        </dependency>\n        <dependency>\n            <groupId>javax</groupId>\n            <artifactId>javaee-api</artifactId>\n            <version>7.0</version>\n        </dependency>\n        <dependency>\n            <groupId>com.dyuproject.protostuff</groupId>\n            <artifactId>protostuff-runtime</artifactId>\n            <version>1.0.8</version>\n        </dependency>\n\n        <dependency>\n            <groupId>commons-collections</groupId>\n            <artifactId>commons-collections</artifactId>\n            <version>3.2.2</version>\n        </dependency>\n    </dependencies>\n    <build>\n        <finalName>seckill</finalName>\n    </build>\n</project>\n"
  },
  {
    "path": "seckill-client/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>seckill</artifactId>\n        <groupId>com.imooc</groupId>\n        <version>0.0.1-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>seckill-client</artifactId>\n    <dependencies>\n        <dependency>\n            <groupId>com.imooc</groupId>\n            <artifactId>seckill-model</artifactId>\n            <version>0.0.1-SNAPSHOT</version>\n        </dependency>\n    </dependencies>\n\n\n</project>"
  },
  {
    "path": "seckill-client/src/main/java/com/imooc/client/SeckillService.java",
    "content": "package com.imooc.client;\n\nimport com.imooc.dto.Exposer;\nimport com.imooc.dto.SeckillExecution;\nimport com.imooc.entity.Seckill;\nimport com.imooc.exception.RepeatKillException;\nimport com.imooc.exception.SeckillCloseException;\nimport com.imooc.exception.SeckillException;\n\nimport java.util.List;\n\n/**\n * 业务接口：站在\"使用者\"角度设计接口 三个方面：方法定义粒度，参数，返回类型（return 类型/异常）\n *\n * @author yan\n */\npublic interface SeckillService {\n\n    /**\n     * 查询所有秒杀记录\n     *\n     * @return\n     */\n    List<Seckill> getSeckillList();\n\n    /**\n     * 查询单个秒杀记录\n     *\n     * @param seckillId\n     * @return\n     */\n    Seckill getById(long seckillId);\n\n    /**\n     * 秒杀开启时输出秒杀接口地址，否则输出系统时间和秒杀时间\n     *\n     * @param seckillId\n     * @return\n     */\n    Exposer exportSeckillUrl(long seckillId);\n\n    /**\n     * 执行秒杀操作\n     *\n     * @param seckillId\n     * @param userPhone\n     * @param md5\n     * @return\n     * @throws SeckillException\n     * @throws RepeatKillException\n     * @throws SeckillCloseException\n     */\n    SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)\n            throws SeckillException, RepeatKillException, SeckillCloseException;\n\n    /**\n     * 执行秒杀操作by存储过程\n     *\n     * @param seckillId\n     * @param userPhone\n     * @param md5\n     * @return\n     * @throws SeckillException\n     * @throws RepeatKillException\n     * @throws SeckillCloseException\n     */\n    SeckillExecution executeSeckillProcedure(long seckillId, long userPhone, String md5)\n            throws SeckillException, RepeatKillException, SeckillCloseException;\n\n}"
  },
  {
    "path": "seckill-core/.gitignore",
    "content": "*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.ear\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\n"
  },
  {
    "path": "seckill-core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>seckill</artifactId>\n        <groupId>com.imooc</groupId>\n        <version>0.0.1-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>seckill-core</artifactId>\n    <packaging>war</packaging>\n    <name>seckill-dubbo-consumer Maven Webapp</name>\n    <url>http://maven.apache.org</url>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n    <dependencies>\n        <dependency>\n            <groupId>com.imooc</groupId>\n            <artifactId>seckill-model</artifactId>\n            <version>0.0.1-SNAPSHOT</version>\n        </dependency>\n        <dependency>\n            <groupId>com.imooc</groupId>\n            <artifactId>seckill-client</artifactId>\n            <version>0.0.1-SNAPSHOT</version>\n        </dependency>\n        <!-- Dubbo 依赖 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>dubbo</artifactId>\n            <version>2.5.7</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>spring</artifactId>\n                    <groupId>org.springframework</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!-- Zookeeper 依赖 -->\n        <dependency>\n            <groupId>org.apache.zookeeper</groupId>\n            <artifactId>zookeeper</artifactId>\n            <version>3.5.3-beta</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>log4j</artifactId>\n                    <groupId>log4j</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>com.101tec</groupId>\n            <artifactId>zkclient</artifactId>\n            <version>0.8</version>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "seckill-core/src/main/java/com/imooc/aop/LogAOP.java",
    "content": "package com.imooc.aop;\n\n\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\nimport org.springframework.validation.BindingResult;\n\n/**\n * @author yan\n *         <p>\n *         采用AOP的方式处理参数问题。\n */\n@Component\n@Aspect\npublic class LogAOP {\n\n    private final Logger LOG = LoggerFactory.getLogger(this.getClass());\n\n    @Pointcut(\"execution(* com.imooc.web.*.*(..))\")\n    public void aopMethod() {\n    }\n\n    @Around(\"aopMethod()\")\n    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {\n        String classType = joinPoint.getTarget().getClass().getName();\n        //运用反射的原理创建对象\n        Class<?> clazz = Class.forName(classType);\n        String clazzName = clazz.getName();\n        String clazzSimpleName = clazz.getSimpleName();\n        String methodName = joinPoint.getSignature().getName();\n        Logger logger = LoggerFactory.getLogger(clazzName);\n        logger.info(\"clazzName: \" + clazzName + \", methodName:\" + methodName);\n        long start = System.currentTimeMillis();\n        LOG.info(\"before method invoking!\");\n        BindingResult bindingResult = null;\n        System.out.println(\"---------------\");\n        System.out.println(\"调用类：\" + clazzSimpleName);\n        System.out.println(\"调用方法：\" + methodName);\n        return joinPoint.proceed();\n    }\n}"
  },
  {
    "path": "seckill-core/src/main/java/com/imooc/web/SeckillController.java",
    "content": "package com.imooc.web;\n\nimport com.imooc.dto.SeckillExecution;\nimport com.imooc.exception.SeckillCloseException;\nimport com.imooc.dto.Exposer;\nimport com.imooc.dto.SeckillResult;\nimport com.imooc.entity.Seckill;\nimport com.imooc.enums.SeckillStateEnum;\nimport com.imooc.exception.RepeatKillException;\nimport com.imooc.client.SeckillService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.util.Date;\nimport java.util.List;\n\n@Controller // @Service @Componet\n@RequestMapping(\"/seckill\") // url:/模块/资源/{id}/细分 /seckill/list\npublic class SeckillController {\n\n\t//sb\n\tprivate Logger logger = LoggerFactory.getLogger(this.getClass());\n\n\t@Autowired\n\tprivate SeckillService seckillService;\n\t//http://localhost:8080/seckill/seckill/list\n\t@RequestMapping(value = \"/list\", method = RequestMethod.GET)\n\tpublic String list(Model model) {\n\t\t// 获取列表页\n\t\tList<Seckill> list = seckillService.getSeckillList();\n\t\tmodel.addAttribute(\"list\", list);\n\t\t// list.jsp + model = ModelAndView\n\t\treturn \"list\";// WEB-INF/jsp/\"list\".jsp\n\t}\n\n\t@RequestMapping(value = \"/{seckillId}/detail\", method = RequestMethod.GET)\n\tpublic String detail(@PathVariable(\"seckillId\") Long seckillId, Model model) {\n\t\tif (seckillId == null) {\n\t\t\treturn \"redirect:/seckill/list\";\n\t\t}\n\t\tSeckill seckill = seckillService.getById(seckillId);\n\t\tif (seckill == null) {\n\t\t\treturn \"forward:/seckill/list\";\n\t\t}\n\t\tmodel.addAttribute(\"seckill\", seckill);\n\t\treturn \"detail\";\n\t}\n\n\t// ajax json\n\t@RequestMapping(value = \"/{seckillId}/exposer\", method = RequestMethod.POST, produces = {\n\t\t\t\"application/json; charset=utf-8\" })\n\t@ResponseBody\n\tpublic SeckillResult<Exposer> exposer(@PathVariable(\"seckillId\") Long seckillId) {\n\t\tSeckillResult<Exposer> result;\n\t\ttry {\n\t\t\tExposer exposer = seckillService.exportSeckillUrl(seckillId);\n\t\t\tresult = new SeckillResult<Exposer>(true, exposer);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\tresult = new SeckillResult<Exposer>(false, e.getMessage());\n\t\t}\n\t\treturn result;\n\t}\n\n\t@RequestMapping(value = \"/{seckillId}/{md5}/execution\", method = RequestMethod.POST, produces = {\n\t\t\t\"application/json; charset=utf-8\" })\n\t@ResponseBody\n\tpublic SeckillResult<SeckillExecution> execute(@PathVariable(\"seckillId\") Long seckillId,\n\t\t\t\t\t\t\t\t\t\t\t\t   @PathVariable(\"md5\") String md5, @CookieValue(value = \"killPhone\", required = false) Long phone) {\n\t\t// springmvc valid\n\t\tif (phone == null) {\n\t\t\treturn new SeckillResult<SeckillExecution>(false, \"未注册\");\n\t\t}\n\t\ttry {\n\t\t\t// 存储过程调用\n\t\t\tSeckillExecution execution = seckillService.executeSeckillProcedure(seckillId, phone, md5);\n\t\t\treturn new SeckillResult<SeckillExecution>(true, execution);\n\t\t} catch (RepeatKillException e) {\n\t\t\tSeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.REPEAT_KILL);\n\t\t\treturn new SeckillResult<SeckillExecution>(true, execution);\n\t\t} catch (SeckillCloseException e) {\n\t\t\tSeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.END);\n\t\t\treturn new SeckillResult<SeckillExecution>(true, execution);\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\tSeckillExecution execution = new SeckillExecution(seckillId, SeckillStateEnum.INNER_ERROR);\n\t\t\treturn new SeckillResult<SeckillExecution>(true, execution);\n\t\t}\n\t}\n\n\t@RequestMapping(value = \"/time/now\", method = RequestMethod.GET)\n\t@ResponseBody\n\tpublic SeckillResult<Long> time() {\n\t\tDate now = new Date();\n\t\treturn new SeckillResult<Long>(true, now.getTime());\n\t}\n\n}\n"
  },
  {
    "path": "seckill-core/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"true\">\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<!-- encoders are by default assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder -->\n\t\t<encoder>\n\t\t\t<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<root level=\"debug\">\n\t\t<appender-ref ref=\"STDOUT\" />\n\t</root>\n</configuration>"
  },
  {
    "path": "seckill-core/src/main/resources/spring/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n    <import resource=\"spring-*\"/>\n</beans>"
  },
  {
    "path": "seckill-core/src/main/resources/spring/spring-dubbo-config.xml",
    "content": "<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n    http://www.springframework.org/schema/beans/spring-beans.xsd\n    http://code.alibabatech.com/schema/dubbo\n    http://code.alibabatech.com/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"seckill-service-consumer\" owner=\"seckill\" organization=\"seckill-service-consumer\" logger=\"slf4j\"/>\n    <dubbo:registry address=\"zookeeper://127.0.0.1:2181\"/>\n    <dubbo:protocol name=\"dubbo\" port=\"20882\" host=\"127.0.0.1\"/>\n    <dubbo:provider timeout=\"15000\" retries=\"0\" delay=\"-1\"/>\n    <dubbo:consumer check=\"false\" timeout=\"15000\"/>\n</beans>"
  },
  {
    "path": "seckill-core/src/main/resources/spring/spring-dubbo-consumer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n    http://www.springframework.org/schema/beans/spring-beans.xsd\n    http://code.alibabatech.com/schema/dubbo\n    http://code.alibabatech.com/schema/dubbo/dubbo.xsd\">\n    <!-- 生成远程服务代理，可以和本地bean一样使用demoService -->\n    <dubbo:reference id=\"seckillService\" interface=\"com.imooc.client.SeckillService\" />\n</beans>"
  },
  {
    "path": "seckill-core/src/main/resources/spring/spring-web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\t   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t   xmlns:context=\"http://www.springframework.org/schema/context\"\n\t   xmlns:mvc=\"http://www.springframework.org/schema/mvc\"\n\t   xmlns:aop=\"http://www.springframework.org/schema/aop\"\n\t   xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n\thttp://www.springframework.org/schema/beans/spring-beans.xsd\n\thttp://www.springframework.org/schema/context\n\thttp://www.springframework.org/schema/context/spring-context.xsd\n\thttp://www.springframework.org/schema/mvc\n\thttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd\n\thttp://www.springframework.org/schema/aop\n\thttp://www.springframework.org/schema/aop/spring-aop.xsd\">\n\n\t<!-- 激活组件扫描功能,扫描aop的相关组件组件 -->\n\t<context:component-scan base-package=\"com.imooc.aop\"/>\n\t<!-- 启动对@AspectJ注解的支持 -->\n\t<aop:aspectj-autoproxy proxy-target-class=\"false\" />\n\n\t<!-- 配置SpringMVC -->\n\t<!-- 1.开启SpringMVC注解模式 -->\n\t<!-- 简化配置： \n\t\t(1)自动注册DefaultAnootationHandlerMapping,AnotationMethodHandlerAdapter \n\t\t(2)提供一些列：数据绑定，数字和日期的format @NumberFormat, @DateTimeFormat, xml,json默认读写支持 \n\t-->\n\t<mvc:annotation-driven />\n\t\n\t<!-- 2.静态资源默认servlet配置\n\t\t(1)加入对静态资源的处理：js,gif,png\n\t\t(2)允许使用\"/\"做整体映射\n\t -->\n\t <mvc:default-servlet-handler/>\n\t \n\t <!-- 3.配置jsp 显示ViewResolver -->\n\t <bean class=\"org.springframework.web.servlet.view.InternalResourceViewResolver\">\n\t \t<property name=\"viewClass\" value=\"org.springframework.web.servlet.view.JstlView\" />\n\t \t<property name=\"prefix\" value=\"/WEB-INF/jsp/\" />\n\t \t<property name=\"suffix\" value=\".jsp\" />\n\t </bean>\n\t \n\t <!-- 4.扫描web相关的bean -->\n\t <context:component-scan base-package=\"com.imooc.web\" />\n</beans>"
  },
  {
    "path": "seckill-core/src/main/webapp/WEB-INF/jsp/common/head.jsp",
    "content": "<%  \n    String path = request.getContextPath();  \n    String basePath = request.getScheme() + \"://\"  \n            + request.getServerName() + \":\" + request.getServerPort()  \n            + path + \"/\";  \n    pageContext.setAttribute(\"basePath\",basePath);    \n%>\n\n<meta charset=\"utf-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<!-- 上述3个meta标签*必须*放在最前面，任何其他内容都*必须*跟随其后！ -->\n\n<!-- 新 Bootstrap 核心 CSS 文件 -->\n<link rel=\"stylesheet\"\n\thref=\"//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css\">\n\t\n<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->\n<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->\n<!--[if lt IE 9]>\n      <script src=\"//cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js\"></script>\n      <script src=\"//cdn.bootcss.com/respond.js/1.4.2/respond.min.js\"></script>\n    <![endif]-->\n"
  },
  {
    "path": "seckill-core/src/main/webapp/WEB-INF/jsp/common/tag.jsp",
    "content": "<%@ taglib prefix=\"c\" uri=\"http://java.sun.com/jsp/jstl/core\" %>\n<%@ taglib prefix=\"fmt\" uri=\"http://java.sun.com/jsp/jstl/fmt\" %>"
  },
  {
    "path": "seckill-core/src/main/webapp/WEB-INF/jsp/detail.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n\tpageEncoding=\"UTF-8\"%>\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<%@include file=\"common/head.jsp\"%>\n<title>秒杀详情页</title>\n</head>\n<body>\n<input type=\"hidden\" id=\"basePath\" value=\"${basePath}\" />\n\t<div class=\"container\">\n\t\t<div class=\"panel panel-default text-center\">\n\t\t\t<div class=\"panel-heading\">\n\t\t\t\t<h1>${seckill.name}</h1>\n\t\t\t</div>\n\t\t\t<div class=\"panel-body\">\n\t\t\t\t<h2 class=\"text-danger\">\n\t\t\t\t\t<!-- 显示time图标 -->\n\t\t\t\t\t<span class=\"glyphicon glyphicon-time\"></span>\n\t\t\t\t\t<!-- 展示倒计时 -->\n\t\t\t\t\t<span class=\"glyphicon\" id=\"seckillBox\"></span>\n\t\t\t\t</h2>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- 登录弹出层，输入电话 -->\n\t<div id=\"killPhoneModal\" class=\"modal fade\">\n\t\t<div class=\"modal-dialog\">\n\t\t\t<div class=\"modal-content\">\n\t\t\t\t<div class=\"modal-header\">\n\t\t\t\t\t<h3 class=\"modal-title text-center\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-phone\"></span>秒杀电话：\n\t\t\t\t\t</h3>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"modal-body\">\n\t\t\t\t\t<div class=\"row\">\n\t\t\t\t\t\t<div class=\"col-xs-8 col-xs-offset-2\">\n\t\t\t\t\t\t\t<input type=\"text\" name=\"killphone\" id=\"killphoneKey\"\n\t\t\t\t\t\t\t\tplaceholder=\"填手机号^O^\" class=\"form-control\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"modal-footer\">\n\t\t\t\t\t<span id=\"killphoneMessage\" class=\"glyphicon\"></span>\n\t\t\t\t\t<button type=\"button\" id=\"killPhoneBtn\" class=\"btn btn-success\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-phone\"></span> Submit\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->\n\t<script src=\"//cdn.bootcss.com/jquery/1.11.3/jquery.min.js\"></script>\n\t<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->\n\t<script src=\"//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js\"></script>\n\t<!-- jQuery cookie操作插件 -->\n\t<script src=\"//cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js\"></script>\n\t<!-- jQery countDonw倒计时插件  -->\n\t<script src=\"//cdn.bootcss.com/jquery.countdown/2.1.0/jquery.countdown.min.js\"></script>\n\t<!-- 开始编写交互逻辑 -->\n\t<script src=\"${basePath}resources/js/seckill.js\"  type=\"text/javascript\"></script>\n\t<script type=\"text/javascript\">\n\t\t$(function(){\n\t\t\t//使用EL表达式传入参数\n\t\t\tseckill.detail.init({\n\t\t\t\tseckillId : ${seckill.seckillId},\n\t\t\t\tstartTime : ${seckill.startTime.time},//毫秒\n\t\t\t\tendTime : ${seckill.endTime.time}\n\t\t\t});\n\t\t});\n\t</script>\n</body>\n</html>"
  },
  {
    "path": "seckill-core/src/main/webapp/WEB-INF/jsp/list.jsp",
    "content": "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\"\n\tpageEncoding=\"UTF-8\"%>\n<!-- 引入jstl -->\n<%@include file=\"common/tag.jsp\" %>\n<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n<%@include file=\"common/head.jsp\"%>\n<title>秒杀列表页</title>\n</head>\n<body>\n\t<!-- 页面显示部分 -->\n\t<div class=\"container\">\n\t\t<div class=\"panel panel-default\">\n\t\t\t<div class=\"panel-heading text-center\">\n\t\t\t\t<h2>秒杀列表</h2>\n\t\t\t</div>\n\t\t\t<div class=\"panel-body\">\n\t\t\t\t<table class=\"table table-hover\">\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th>名称</th>\n\t\t\t\t\t\t\t<th>库存</th>\n\t\t\t\t\t\t\t<th>开始时间</th>\n\t\t\t\t\t\t\t<th>结束时间</th>\n\t\t\t\t\t\t\t<th>创建时间</th>\n\t\t\t\t\t\t\t<th>详情页</th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t<c:forEach var=\"sk\" items=\"${list}\">\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<td>${sk.name}</td>\n\t\t\t\t\t\t\t\t<td>${sk.number}</td>\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<fmt:formatDate value=\"${sk.startTime}\" pattern=\"yyy-MM-dd HH:mm:ss\"/>\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<fmt:formatDate value=\"${sk.endTime}\" pattern=\"yyy-MM-dd HH:mm:ss\"/>\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<fmt:formatDate value=\"${sk.createTime}\" pattern=\"yyy-MM-dd HH:mm:ss\"/>\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<a class=\"btn btn-info\" href=\"${basePath}seckill/${sk.seckillId}/detail\" target=\"_blank\">link</a>\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</c:forEach>\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\n\t<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->\n\t<script src=\"//cdn.bootcss.com/jquery/1.11.3/jquery.min.js\"></script>\n\t<!-- 最新的 Bootstrap 核心 JavaScript 文件 -->\n\t<script src=\"//cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "seckill-core/src/main/webapp/WEB-INF/web.xml",
    "content": "<web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee\n                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"\n\tversion=\"3.1\" metadata-complete=\"true\">\n\t<!-- 修改servlet版本为3.1 -->\n\t<!-- 配置DispatcherServlet -->\n\t<servlet>\n\t\t<servlet-name>seckill-dispatcher</servlet-name>\n\t\t<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>\n\t\t<!-- 配置springMVC需要加载的配置文件\n\t\t\tspring-dao.xml,spring-service.xml,spring-web.xml\n\t\t\tMybatis - > spring -> springmvc\n\t\t -->\n\t\t<init-param>\n\t\t\t<param-name>contextConfigLocation</param-name>\n\t\t\t<param-value>classpath:spring/applicationContext.xml</param-value>\n\t\t</init-param>\n\t</servlet>\n\t<servlet-mapping>\n\t\t\t<servlet-name>seckill-dispatcher</servlet-name>\n\t\t<!-- 默认匹配所有的请求 -->\n\t\t<url-pattern>/</url-pattern>\n\t</servlet-mapping>\n\t<context-param>\n\t\t<param-name>contextConfigLocation</param-name>\n\t\t<param-value>classpath:spring/applicationContext.xml</param-value>\n\t</context-param>\n\t<listener>\n\t\t<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n\t</listener>\n</web-app>\n"
  },
  {
    "path": "seckill-core/src/main/webapp/resources/js/seckill.js",
    "content": "// 存放主要交换逻辑js代码\n// javascript 模块化\nvar seckill = {\n\t// 封装秒杀相关ajax的url\n\tURL : {\n\t\tbasePath : function() {\n\t\t\treturn $('#basePath').val();\n\t\t},\n\t\tnow : function() {\n\t\t\treturn seckill.URL.basePath() + 'seckill/time/now';\n\t\t},\n\t\texposer : function(seckillId) {\n\t\t\treturn seckill.URL.basePath() + 'seckill/' + seckillId + '/exposer';\n\t\t},\n\t\texecution : function(seckillId, md5) {\n\t\t\treturn seckill.URL.basePath() + 'seckill/' + seckillId + '/' + md5 + '/execution';\n\t\t}\n\t},\n\t// 处理秒杀逻辑\n\thandleSeckill : function(seckillId, node) {\n\t\t// 获取秒杀地址，控制显示逻辑，执行秒杀\n\t\tnode.hide().html('<button class=\"btn btn-primary btn-lg\" id=\"killBtn\">开始秒杀</button>');\n\t\tconsole.log('exposerUrl=' + seckill.URL.exposer(seckillId));//TODO\n\t\t$.post(seckill.URL.exposer(seckillId), {}, function(result) {\n\t\t\t// 在回调函数中，执行交互流程\n\t\t\tif (result && result['success']) {\n\t\t\t\tvar exposer = result['data'];\n\t\t\t\tif (exposer['exposed']) {\n\t\t\t\t\t// 开启秒杀\n\t\t\t\t\tvar md5 = exposer['md5'];\n\t\t\t\t\tvar killUrl = seckill.URL.execution(seckillId, md5);\n\t\t\t\t\tconsole.log('killUrl=' + killUrl);//TODO\n\t\t\t\t\t$('#killBtn').one('click', function() {\n\t\t\t\t\t\t// 执行秒杀请求\n\t\t\t\t\t\t// 1.先禁用按钮\n\t\t\t\t\t\t$(this).addClass('disabled');\n\t\t\t\t\t\t// 2.发送秒杀请求\n\t\t\t\t\t\t$.post(killUrl, {}, function(result) {\n\t\t\t\t\t\t\tif (result && result['success']) {\n\t\t\t\t\t\t\t\tvar killResult = result['data'];\n\t\t\t\t\t\t\t\tvar state = killResult['state'];\n\t\t\t\t\t\t\t\tvar stateInfo = killResult['stateInfo'];\n\t\t\t\t\t\t\t\t// 3.显示秒杀结果\n\t\t\t\t\t\t\t\tnode.html('<span class=\"label label-success\">' + stateInfo + '</span>');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t\tnode.show();\n\t\t\t\t} else {\n\t\t\t\t\t// 未开启秒杀\n\t\t\t\t\tvar now = exposer['now'];\n\t\t\t\t\tvar start = exposer['start'];\n\t\t\t\t\tvar end = exposer['end'];\n\t\t\t\t\t// 重新计算计时逻辑\n\t\t\t\t\tseckill.countdown(seckillId, now, start, end);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconsole.log('result=' + result);\n\t\t\t}\n\t\t});\n\t},\n\t// 验证手机号\n\tvalidatePhone : function(phone) {\n\t\tif (phone && phone.length == 11 && !isNaN(phone)) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t},\n\t// 倒计时\n\tcountdown : function(seckillId, nowTime, startTime, endTime) {\n\t\t// 时间判断\n\t\tvar seckillBox = $('#seckillBox');\n\t\tif (nowTime > endTime) {\n\t\t\t// 秒杀结束\n\t\t\tseckillBox.html('秒杀结束!');\n\t\t} else if (nowTime < startTime) {\n\t\t\t// 秒杀未开始，计时事件绑定\n\t\t\tvar killTime = new Date(startTime + 1000);\n\t\t\tseckillBox.countdown(killTime, function(event) {\n\t\t\t\t// 时间格式\n\t\t\t\tvar format = event.strftime('秒杀倒计时：%D天 %H时 %M分 %S秒');\n\t\t\t\tseckillBox.html(format);\n\t\t\t\t// 时间完成后回调事件\n\t\t\t}).on('finish.countdown', function() {\n\t\t\t\t// 获取秒杀地址，控制显示逻辑，执行秒杀\n\t\t\t\tseckill.handleSeckill(seckillId, seckillBox);\n\t\t\t});\n\t\t} else {\n\t\t\t// 秒杀开始\n\t\t\tseckill.handleSeckill(seckillId ,seckillBox);\n\t\t}\n\t},\n\t// 详情页秒杀逻辑\n\tdetail : {\n\t\t// 详情页初始化\n\t\tinit : function(params) {\n\t\t\t// 用户手机验证和登录，计时交互\n\t\t\t// 规划我们的交互流程\n\t\t\t// 在cookie中查找手机号\n\t\t\tvar killPhone = $.cookie('killPhone');\n\t\t\tvar startTime = params['startTime'];\n\t\t\tvar endTime = params['endTime'];\n\t\t\tvar seckillId = params['seckillId'];\n\t\t\t// 验证手机号\n\t\t\tif (!seckill.validatePhone(killPhone)) {\n\t\t\t\t// 绑定phone\n\t\t\t\t// 控制输出\n\t\t\t\tvar killPhoneModal = $('#killPhoneModal');\n\t\t\t\tkillPhoneModal.modal({\n\t\t\t\t\tshow : true,// 显示弹出层\n\t\t\t\t\tbackdrop : 'static',// 禁止位置关闭\n\t\t\t\t\tkeyboard : false\n\t\t\t\t// 关闭键盘事件\n\t\t\t\t})\n\t\t\t\t$('#killPhoneBtn').click(function() {\n\t\t\t\t\tvar inputPhone = $('#killphoneKey').val();\n\t\t\t\t\tconsole.log('inputPhone='+inputPhone);//TODO\n\t\t\t\t\tif (seckill.validatePhone(inputPhone)) {\n\t\t\t\t\t\t// 电话写入cookie\n\t\t\t\t\t\t$.cookie('killPhone', inputPhone, {\n\t\t\t\t\t\t\texpires : 7,\n\t\t\t\t\t\t\tpath : '/seckill'\n\t\t\t\t\t\t});\n\t\t\t\t\t\t// 刷新页面\n\t\t\t\t\t\twindow.location.reload();\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$('#killphoneMessage').hide().html('<label class=\"label label-danger\">手机号错误!</label>').show(300);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\t// 已经登录\n\t\t\t// 计时交互\n\t\t\tvar startTime = params['startTime'];\n\t\t\tvar endTime = params['endTime'];\n\t\t\tvar seckillId = params['seckillId'];\n\t\t\t$.get(seckill.URL.now(), {}, function(result) {\n\t\t\t\tif (result && result['success']) {\n\t\t\t\t\tvar nowTime = result['data'];\n\t\t\t\t\t// 时间判断，计时交互\n\t\t\t\t\tseckill.countdown(seckillId, nowTime, startTime, endTime);\n\t\t\t\t} else {\n\t\t\t\t\tconsole.log(result['reult:'] + result);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "seckill-model/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>seckill</artifactId>\n        <groupId>com.imooc</groupId>\n        <version>0.0.1-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>seckill-model</artifactId>\n\n\n</project>"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/dto/Exposer.java",
    "content": "package com.imooc.dto;\n\nimport java.io.Serializable;\n\n/**\n * 暴露秒杀接口DTO\n * \n * @author yan\n */\npublic class Exposer implements Serializable {\n\n\t// 是否开启秒杀\n\tprivate boolean exposed;\n\n\t// 一种加密措施\n\tprivate String md5;\n\n\t// id\n\tprivate long seckillId;\n\n\t// 系统当前时间（毫秒）\n\tprivate long now;\n\n\t// 开启时间\n\tprivate long start;\n\n\t// 结束时间\n\tprivate long end;\n\n\tpublic Exposer(boolean exposed, String md5, long seckillId) {\n\t\tthis.exposed = exposed;\n\t\tthis.md5 = md5;\n\t\tthis.seckillId = seckillId;\n\t}\n\n\tpublic Exposer(boolean exposed, long seckillId, long now, long start, long end) {\n\t\tthis.exposed = exposed;\n\t\tthis.seckillId = seckillId;\n\t\tthis.now = now;\n\t\tthis.start = start;\n\t\tthis.end = end;\n\t}\n\n\tpublic Exposer(boolean exposed, long seckillId) {\n\t\tthis.exposed = exposed;\n\t\tthis.seckillId = seckillId;\n\t}\n\n\tpublic boolean isExposed() {\n\t\treturn exposed;\n\t}\n\n\tpublic void setExposed(boolean exposed) {\n\t\tthis.exposed = exposed;\n\t}\n\n\tpublic String getMd5() {\n\t\treturn md5;\n\t}\n\n\tpublic void setMd5(String md5) {\n\t\tthis.md5 = md5;\n\t}\n\n\tpublic long getSeckillId() {\n\t\treturn seckillId;\n\t}\n\n\tpublic void setSeckillId(long seckillId) {\n\t\tthis.seckillId = seckillId;\n\t}\n\n\tpublic long getNow() {\n\t\treturn now;\n\t}\n\n\tpublic void setNow(long now) {\n\t\tthis.now = now;\n\t}\n\n\tpublic long getStart() {\n\t\treturn start;\n\t}\n\n\tpublic void setStart(long start) {\n\t\tthis.start = start;\n\t}\n\n\tpublic long getEnd() {\n\t\treturn end;\n\t}\n\n\tpublic void setEnd(long end) {\n\t\tthis.end = end;\n\t}\n\t\t\n\t//重写toString方法\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Exposer [exposed=\" + exposed + \", md5=\" + md5 + \", seckillId=\" + seckillId + \", now=\" + now + \", start=\"\n\t\t\t\t+ start + \", end=\" + end + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/dto/SeckillExecution.java",
    "content": "package com.imooc.dto;\n\nimport com.imooc.entity.SuccessKilled;\nimport com.imooc.enums.SeckillStateEnum;\n\nimport java.io.Serializable;\n\n/**\n * 封装秒杀执行后结果\n * \n * @author yan\n */\npublic class SeckillExecution implements Serializable {\n\n\tprivate Long seckillId;\n\n\t// 秒杀执行结果状态\n\tprivate Integer state;\n\n\t// 状态标识\n\tprivate String stateInfo;\n\n\t// 秒杀成功对象\n\tprivate SuccessKilled successKilled;\n\n\tpublic SeckillExecution(Long seckillId, SeckillStateEnum stateEnum, SuccessKilled successKilled) {\n\t\tthis.seckillId = seckillId;\n\t\tthis.state = stateEnum.getState();\n\t\tthis.stateInfo = stateEnum.getStateInfo();\n\t\tthis.successKilled = successKilled;\n\t}\n\n\tpublic SeckillExecution(Long seckillId, SeckillStateEnum stateEnum) {\n\t\tthis.seckillId = seckillId;\n\t\tif(stateEnum!=null){\n\t\t\tthis.state = stateEnum.getState();\n\t\t\tthis.stateInfo = stateEnum.getStateInfo();\n\t\t}\n\t}\n\n\tpublic Long getSeckillId() {\n\t\treturn seckillId;\n\t}\n\n\tpublic void setSeckillId(Long seckillId) {\n\t\tthis.seckillId = seckillId;\n\t}\n\n\tpublic Integer getState() {\n\t\treturn state;\n\t}\n\n\tpublic void setState(Integer state) {\n\t\tthis.state = state;\n\t}\n\n\tpublic String getStateInfo() {\n\t\treturn stateInfo;\n\t}\n\n\tpublic void setStateInfo(String stateInfo) {\n\t\tthis.stateInfo = stateInfo;\n\t}\n\n\tpublic SuccessKilled getSuccessKilled() {\n\t\treturn successKilled;\n\t}\n\n\tpublic void setSuccessKilled(SuccessKilled successKilled) {\n\t\tthis.successKilled = successKilled;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"SeckillExecution [seckillId=\" + seckillId + \", state=\" + state + \", stateInfo=\" + stateInfo\n\t\t\t\t+ \", successKilled=\" + successKilled + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/dto/SeckillResult.java",
    "content": "package com.imooc.dto;\n\n//封装json结果\npublic class SeckillResult<T> {\n\n\tprivate boolean success;\n\n\tprivate T data;\n\n\tprivate String error;\n\n\tpublic SeckillResult(boolean success, String error) {\n\t\tthis.success = success;\n\t\tthis.error = error;\n\t}\n\n\tpublic SeckillResult(boolean success, T data) {\n\t\tthis.success = success;\n\t\tthis.data = data;\n\t}\n\n\tpublic boolean isSuccess() {\n\t\treturn success;\n\t}\n\n\tpublic void setSuccess(boolean success) {\n\t\tthis.success = success;\n\t}\n\n\tpublic T getData() {\n\t\treturn data;\n\t}\n\n\tpublic void setData(T data) {\n\t\tthis.data = data;\n\t}\n\n\tpublic String getError() {\n\t\treturn error;\n\t}\n\n\tpublic void setError(String error) {\n\t\tthis.error = error;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"SeckillResult [success=\" + success + \", data=\" + data + \", error=\" + error + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/entity/Seckill.java",
    "content": "package com.imooc.entity;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 秒杀库存实体\n * \n * @author yan\n */\npublic class Seckill implements Serializable {\n\tprivate long seckillId;\n\n\tprivate String name;\n\n\tprivate int number;\n\n\tprivate Date startTime;\n\n\tprivate Date endTime;\n\n\tprivate Date createTime;\n\n\tpublic long getSeckillId() {\n\t\treturn seckillId;\n\t}\n\n\tpublic void setSeckillId(long seckillId) {\n\t\tthis.seckillId = seckillId;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic int getNumber() {\n\t\treturn number;\n\t}\n\n\tpublic void setNumber(int number) {\n\t\tthis.number = number;\n\t}\n\n\tpublic Date getStartTime() {\n\t\treturn startTime;\n\t}\n\n\tpublic void setStartTime(Date startTime) {\n\t\tthis.startTime = startTime;\n\t}\n\n\tpublic Date getEndTime() {\n\t\treturn endTime;\n\t}\n\n\tpublic void setEndTime(Date endTime) {\n\t\tthis.endTime = endTime;\n\t}\n\n\tpublic Date getCreateTime() {\n\t\treturn createTime;\n\t}\n\n\tpublic void setCreateTime(Date createTime) {\n\t\tthis.createTime = createTime;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"Seckill [seckillId=\" + seckillId + \", name=\" + name + \", number=\" + number + \", startTime=\" + startTime\n\t\t\t\t+ \", endTime=\" + endTime + \", createTime=\" + createTime + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/entity/SuccessKilled.java",
    "content": "package com.imooc.entity;\n\nimport java.io.Serializable;\nimport java.util.Date;\n\n/**\n * 成功秒杀实体\n * \n * @author yan\n */\npublic class SuccessKilled implements Serializable {\n\n\tprivate long seckillId;\n\n\tprivate long userPhone;\n\n\tprivate short state;\n\n\tprivate Date creteTime;\n\n\t// 多对一的复合属性\n\tprivate Seckill seckill;\n\n\tpublic long getSeckillId() {\n\t\treturn seckillId;\n\t}\n\n\tpublic void setSeckillId(long seckillId) {\n\t\tthis.seckillId = seckillId;\n\t}\n\n\tpublic long getUserPhone() {\n\t\treturn userPhone;\n\t}\n\n\tpublic void setUserPhone(long userPhone) {\n\t\tthis.userPhone = userPhone;\n\t}\n\n\tpublic short getState() {\n\t\treturn state;\n\t}\n\n\tpublic void setState(short state) {\n\t\tthis.state = state;\n\t}\n\n\tpublic Date getCreteTime() {\n\t\treturn creteTime;\n\t}\n\n\tpublic void setCreteTime(Date creteTime) {\n\t\tthis.creteTime = creteTime;\n\t}\n\n\tpublic Seckill getSeckill() {\n\t\treturn seckill;\n\t}\n\n\tpublic void setSeckill(Seckill seckill) {\n\t\tthis.seckill = seckill;\n\t}\n\n\t@Override\n\tpublic String toString() {\n\t\treturn \"SuccessKilled [seckillId=\" + seckillId + \", userPhone=\" + userPhone + \", state=\" + state\n\t\t\t\t+ \", creteTime=\" + creteTime + \"]\";\n\t}\n\n}\n"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/enums/SeckillStateEnum.java",
    "content": "package com.imooc.enums;\n\n/**\n * 使用枚举表述常量数据字典\n *\n * @author yan\n */\npublic enum SeckillStateEnum {\n\n    SUCCESS(1, \"秒杀成功\"), END(0, \"秒杀结束\"),\n\n    REPEAT_KILL(-1, \"重复秒杀\"),\n\n    INNER_ERROR(-2, \"系统异常\"),\n\n    DATA_REWRITE(-3, \"数据篡改\");\n\n    private Integer state;\n\n    private String stateInfo;\n\n    private SeckillStateEnum(int state, String stateInfo) {\n        this.state = state;\n        this.stateInfo = stateInfo;\n    }\n\n    public Integer getState() {\n        return state;\n    }\n\n    public String getStateInfo() {\n        return stateInfo;\n    }\n\n    public static SeckillStateEnum stateOf(Integer index) {\n        for (SeckillStateEnum state : values()) {\n            if (state.getState().equals(index)) {\n                return state;\n            }\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/exception/RepeatKillException.java",
    "content": "package com.imooc.exception;\n\n/**\n * 重复秒杀异常（运行期异常）\n * \n * @author yan\n */\npublic class RepeatKillException extends SeckillException {\n\tpublic RepeatKillException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic RepeatKillException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/exception/SeckillCloseException.java",
    "content": "package com.imooc.exception;\n\n/**\n * 秒杀关闭异常\n * \n * @author yan\n */\npublic class SeckillCloseException extends SeckillException {\n\n\tpublic SeckillCloseException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic SeckillCloseException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "seckill-model/src/main/java/com/imooc/exception/SeckillException.java",
    "content": "package com.imooc.exception;\n\n/**\n * 秒杀相关业务异常\n * \n * @author yan\n */\npublic class SeckillException extends RuntimeException {\n\n\tpublic SeckillException(String message) {\n\t\tsuper(message);\n\t}\n\n\tpublic SeckillException(String message, Throwable cause) {\n\t\tsuper(message, cause);\n\t}\n\n}\n"
  },
  {
    "path": "seckill-service-provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>seckill</artifactId>\n        <groupId>com.imooc</groupId>\n        <version>0.0.1-SNAPSHOT</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>seckill-service</artifactId>\n    <packaging>war</packaging>\n    <name>seckill-dubbo-consumer Maven Webapp</name>\n    <url>http://maven.apache.org</url>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.6</source>\n                    <target>1.6</target>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n    <dependencies>\n        <dependency>\n            <groupId>com.imooc</groupId>\n            <artifactId>seckill-model</artifactId>\n            <version>0.0.1-SNAPSHOT</version>\n        </dependency>\n        <dependency>\n            <groupId>com.imooc</groupId>\n            <artifactId>seckill-client</artifactId>\n            <version>0.0.1-SNAPSHOT</version>\n        </dependency>\n        <!-- Dubbo 依赖 -->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>dubbo</artifactId>\n            <version>2.5.7</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>spring</artifactId>\n                    <groupId>org.springframework</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n\n        <!-- Zookeeper 依赖 -->\n        <dependency>\n            <groupId>org.apache.zookeeper</groupId>\n            <artifactId>zookeeper</artifactId>\n            <version>3.5.3-beta</version>\n            <exclusions>\n                <exclusion>\n                    <artifactId>log4j</artifactId>\n                    <groupId>log4j</groupId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>com.101tec</groupId>\n            <artifactId>zkclient</artifactId>\n            <version>0.8</version>\n        </dependency>\n    </dependencies>\n\n\n</project>"
  },
  {
    "path": "seckill-service-provider/src/main/java/com/imooc/dao/SeckillDao.java",
    "content": "package com.imooc.dao;\n\nimport com.imooc.entity.Seckill;\nimport org.apache.ibatis.annotations.Param;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 秒杀库存DAO接口\n * \n * @author yan\n */\npublic interface SeckillDao {\n\n\t/**\n\t * 减库存\n\t * \n\t * @param seckillId\n\t * @param killTime\n\t * @return 如果影响行数等于>1，表示更新的记录行数\n\t */\n\tint reduceNumber(@Param(\"seckillId\") long seckillId, @Param(\"killTime\") Date killTime);\n\n\t/**\n\t * 根据id查询秒杀对象\n\t * \n\t * @param seckillId\n\t * @return\n\t */\n\tSeckill queryById(long seckillId);\n\n\t/**\n\t * 根据偏移量查询秒杀商品列表\n\t * \n\t * @param offset\n\t * @param limit\n\t * @return\n\t */\n\tList<Seckill> queryAll(@Param(\"offset\") int offset, @Param(\"limit\") int limit);\n\n\t/**\n\t * 使用存储过程执行秒杀\n\t * \n\t * @param paramMap\n\t */\n\tvoid killByProcedure(Map<String, Object> paramMap);\n\n}\n"
  },
  {
    "path": "seckill-service-provider/src/main/java/com/imooc/dao/SuccessKilledDao.java",
    "content": "package com.imooc.dao;\n\nimport com.imooc.entity.SuccessKilled;\nimport org.apache.ibatis.annotations.Param;\n\npublic interface SuccessKilledDao {\n\n\t/**\n\t * 插入购买明细，可过滤重复\n\t * \n\t * @param seckillId\n\t * @param userPhone\n\t * @return 插入的行数\n\t */\n\tint insertSuccessKilled(@Param(\"seckillId\") long seckillId, @Param(\"userPhone\") long userPhone);\n\n\t/**\n\t * 根据id查询SuccessKilled并携带秒杀产品对象实体\n\t * \n\t * @param seckillId\n\t * @param userPhone\n\t * @return\n\t */\n\tSuccessKilled queryByIdWithSeckill(@Param(\"seckillId\") long seckillId, @Param(\"userPhone\") long userPhone);\n\n}\n"
  },
  {
    "path": "seckill-service-provider/src/main/java/com/imooc/dao/cache/RedisDao.java",
    "content": "package com.imooc.dao.cache;\n\nimport com.dyuproject.protostuff.LinkedBuffer;\nimport com.dyuproject.protostuff.ProtostuffIOUtil;\nimport com.dyuproject.protostuff.runtime.RuntimeSchema;\nimport com.imooc.entity.Seckill;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport redis.clients.jedis.Jedis;\nimport redis.clients.jedis.JedisPool;\n\npublic class RedisDao {\n\n\tprivate final Logger logger = LoggerFactory.getLogger(this.getClass());\n\n\tprivate final JedisPool jedisPool;\n\n\tprivate RuntimeSchema<Seckill> schema = RuntimeSchema.createFrom(Seckill.class);\n\n\tpublic RedisDao(String ip, int port) {\n\t\tjedisPool = new JedisPool(ip, port);\n\t}\n\n\tpublic Seckill getSeckill(long seckillId) {\n\t\t// redis操作逻辑\n\t\ttry {\n\t\t\tJedis jedis = jedisPool.getResource();\n\t\t\ttry {\n\t\t\t\tString key = \"seckill:\" + seckillId;\n\t\t\t\t// 并没有实现内部序列化操作\n\t\t\t\t// get -> byte[] -> 反序列化 -> object[Seckill]\n\t\t\t\t// 采用自定义序列化\n\t\t\t\t// protostuff : pojo.\n\t\t\t\tbyte[] bytes = jedis.get(key.getBytes());\n\t\t\t\tif (bytes != null) {\n\t\t\t\t\tSeckill seckill = schema.newMessage();\n\t\t\t\t\tProtostuffIOUtil.mergeFrom(bytes, seckill, schema);\n\t\t\t\t\t// seckill被反序列化\n\t\t\t\t\treturn seckill;\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tjedis.close();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic String putSeckill(Seckill seckill) {\n\t\t// set Object(Seckill) -> 序列号 -> byte[]\n\t\ttry {\n\t\t\tJedis jedis = jedisPool.getResource();\n\t\t\ttry {\n\t\t\t\tString key = \"seckill:\" + seckill.getSeckillId();\n\t\t\t\tbyte[] bytes = ProtostuffIOUtil.toByteArray(seckill, schema,\n\t\t\t\t\t\tLinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE));\n\t\t\t\t// 超时缓存\n\t\t\t\tint timeout = 60 * 60;\n\t\t\t\tString result = jedis.setex(key.getBytes(), timeout, bytes);\n\t\t\t\treturn result;\n\t\t\t} finally {\n\t\t\t\tjedis.close();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t\treturn null;\n\t}\n\n}\n"
  },
  {
    "path": "seckill-service-provider/src/main/java/com/imooc/service/impl/App.java",
    "content": "package com.imooc.service.impl;\n\nimport com.imooc.client.SeckillService;\nimport com.imooc.entity.Seckill;\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\nimport java.io.IOException;\nimport java.util.List;\n\npublic class App {\n    public static void main(String[] args) throws IOException {\n        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{\"spring/applicationContext.xml\"});\n        context.start();\n        SeckillService seckillService = context.getBean(\"seckillService\",SeckillService.class);\n        List<Seckill> getSeckillList = seckillService.getSeckillList();\n        System.out.println(getSeckillList);\n        System.out.println(\"press any key to exit.\");\n        System.in.read();\n    }\n}\n"
  },
  {
    "path": "seckill-service-provider/src/main/java/com/imooc/service/impl/SeckillServiceImpl.java",
    "content": "package com.imooc.service.impl;\n\nimport com.imooc.dao.SeckillDao;\nimport com.imooc.dao.SuccessKilledDao;\nimport com.imooc.dao.cache.RedisDao;\nimport com.imooc.dto.Exposer;\nimport com.imooc.dto.SeckillExecution;\nimport com.imooc.entity.Seckill;\nimport com.imooc.entity.SuccessKilled;\nimport com.imooc.enums.SeckillStateEnum;\nimport com.imooc.exception.RepeatKillException;\nimport com.imooc.exception.SeckillCloseException;\nimport com.imooc.exception.SeckillException;\nimport com.imooc.client.SeckillService;\nimport org.apache.commons.collections.MapUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.util.DigestUtils;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n//@Componet @Service @Dao @Controller\n@Service\npublic class SeckillServiceImpl implements SeckillService {\n\n\tprivate Logger logger = LoggerFactory.getLogger(this.getClass());\n\n\t// 注入Service依赖\n\t@Autowired\n\tprivate SeckillDao seckillDao;\n\n\t@Autowired\n\tprivate SuccessKilledDao successKilledDao;\n\n\t@Autowired\n\tprivate RedisDao redisDao;\n\n\t// md5盐值字符串，用于混淆MD5\n\tprivate final String slat = \"sdfsgsfjks;sf,lasmglksmg\";\n\n\t@Override\n\tpublic List<Seckill> getSeckillList() {\n\t\treturn seckillDao.queryAll(0, 6);\n\t}\n\n\t@Override\n\tpublic Seckill getById(long seckillId) {\n\t\treturn seckillDao.queryById(seckillId);\n\t}\n\n\tprivate String getMD5(long seckillId) {\n\t\tString base = seckillId + \"/\" + slat;\n\t\tString md5 = DigestUtils.md5DigestAsHex(base.getBytes());\n\t\treturn md5;\n\t}\n\n\t@Override\n\tpublic Exposer exportSeckillUrl(long seckillId) {\n\t\t// 优化点：缓存优化：超时的基础上维护一致性\n\t\t// 1.访问redis\n\t\tSeckill seckill = redisDao.getSeckill(seckillId);\n\t\tif (seckill == null) {\n\t\t\t// 2.访问数据库\n\t\t\tseckill = seckillDao.queryById(seckillId);\n\t\t\tif (seckill == null) {\n\t\t\t\treturn new Exposer(false, seckillId);\n\t\t\t} else {\n\t\t\t\t// 3.访问redis\n\t\t\t\tredisDao.putSeckill(seckill);\n\t\t\t}\n\t\t}\n\t\tif (seckill == null) {\n\t\t\treturn new Exposer(false, seckillId);\n\t\t}\n\t\tDate startTime = seckill.getStartTime();\n\t\tDate endTime = seckill.getEndTime();\n\t\t// 系统当前时间\n\t\tDate nowTime = new Date();\n\t\tif (nowTime.getTime() < startTime.getTime() || nowTime.getTime() > endTime.getTime()) {\n\t\t\treturn new Exposer(false, seckillId, nowTime.getTime(), startTime.getTime(), endTime.getTime());\n\t\t}\n\t\t// 转化特定字符串的过程，不可逆\n\t\tString md5 = getMD5(seckillId);\n\t\treturn new Exposer(true, md5, seckillId);\n\t}\n\n\t@Override\n\t@Transactional\n\t/**\n\t * 使用注解控制事务方法的优点： 1.开发团队达成一致约定，明确标注事务方法的编程风格\n\t * 2.保证事务方法的执行时间尽可能短，不要穿插其他网络操作，RPC/HTTP请求或者剥离到事务方法外部\n\t * 3.不是所有的方法都需要事务，如只有一条修改操作，只读操作不需要事务控制\n\t */\n\tpublic SeckillExecution executeSeckill(long seckillId, long userPhone, String md5)\n\t\t\tthrows SeckillException, RepeatKillException, SeckillCloseException {\n\t\tif (md5 == null || !md5.equals(getMD5(seckillId))) {\n\t\t\tthrow new SeckillException(\"seckill data rewrite\");\n\t\t}\n\t\t// 执行秒杀逻辑：减库存 + 记录购买行为\n\t\tDate now = new Date();\n\t\ttry {\n\t\t\t// 记录购买行为\n\t\t\tint insertCount = successKilledDao.insertSuccessKilled(seckillId, userPhone);\n\t\t\t// 唯一：seckillId,userPhone\n\t\t\tif (insertCount <= 0) {\n\t\t\t\t// 重复秒杀\n\t\t\t\tthrow new RepeatKillException(\"seckill repeated\");\n\t\t\t} else {\n\t\t\t\t// 减库存，热点商品竞争\n\t\t\t\tint updateCount = seckillDao.reduceNumber(seckillId, now);\n\t\t\t\tif (updateCount <= 0) {\n\t\t\t\t\t// 没有更新到记录 rollback\n\t\t\t\t\tthrow new SeckillCloseException(\"seckill is closed\");\n\t\t\t\t} else {\n\t\t\t\t\t// 秒杀成功 commit\n\t\t\t\t\tSuccessKilled successKilled = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);\n\t\t\t\t\treturn new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS, successKilled);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (SeckillCloseException e1) {\n\t\t\tthrow e1;\n\t\t} catch (RepeatKillException e2) {\n\t\t\tthrow e2;\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\t// 所有编译期异常转换为运行期异常\n\t\t\tthrow new SeckillException(\"seckill inner error:\" + e.getMessage());\n\t\t}\n\t}\n\n\t@Override\n\tpublic SeckillExecution executeSeckillProcedure(long seckillId, long userPhone, String md5) {\n\t\tif (md5 == null || !md5.equals(getMD5(seckillId))) {\n\t\t\treturn new SeckillExecution(seckillId, SeckillStateEnum.DATA_REWRITE);\n\t\t}\n\t\tDate killTime = new Date();\n\t\tMap<String, Object> map = new HashMap<String, Object>();\n\t\tmap.put(\"seckillId\", seckillId);\n\t\tmap.put(\"phone\", userPhone);\n\t\tmap.put(\"killTime\", killTime);\n\t\tmap.put(\"result\", null);\n\t\t// 执行存储过程，result被赋值\n\t\ttry {\n\t\t\tseckillDao.killByProcedure(map);\n\t\t\t// 获取result\n\t\t\tint result = MapUtils.getInteger(map, \"result\", -2);\n\t\t\tif (result == 1) {\n\t\t\t\tSuccessKilled sk = successKilledDao.queryByIdWithSeckill(seckillId, userPhone);\n\t\t\t\treturn new SeckillExecution(seckillId, SeckillStateEnum.SUCCESS, sk);\n\t\t\t} else {\n\t\t\t\treturn new SeckillExecution(seckillId, SeckillStateEnum.stateOf(result));\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t\treturn new SeckillExecution(seckillId, SeckillStateEnum.INNER_ERROR);\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "seckill-service-provider/src/main/resources/dubbo.proerpties",
    "content": "dubbo.application.name=seckill-service\ndubbo.registry.address=zookeeper://127.0.0.1:2181\ndubbo.registry.check=false\ndubbo.protocol.name=dubbo"
  },
  {
    "path": "seckill-service-provider/src/main/resources/jdbc.properties",
    "content": "jdbc.driver=com.mysql.cj.jdbc.Driver\njdbc.url=jdbc:mysql://127.0.0.1:3306/seckill?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8\njdbc.username=root\njdbc.password=root\n\n#ʼӴС\njdbc.initialSize=0\n#ӳ\njdbc.maxActive=20\n#ӳС\njdbc.minIdle=1\n#ȡȴʱ\njdbc.maxWait=60000"
  },
  {
    "path": "seckill-service-provider/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration debug=\"true\">\n\t<appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<!-- encoders are by default assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder -->\n\t\t<encoder>\n\t\t\t<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>\n\t\t</encoder>\n\t</appender>\n\n\t<root level=\"debug\">\n\t\t<appender-ref ref=\"STDOUT\" />\n\t</root>\n</configuration>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/mapper/SeckillDao.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\n    PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n    \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.imooc.dao.SeckillDao\">\n\t<!-- 目的：为dao接口方法提供sql语句配置 -->\n\t<update id=\"reduceNumber\">\n\t\t<!-- 具体的sql -->\n\t\tUPDATE seckill\n\t\tSET number = number - 1\n\t\tWHERE\n\t\t\tseckill_id = #{seckillId}\n\t\tAND start_time <![CDATA[ <= ]]> #{killTime}\n\t\tAND end_time >= #{killTime}\n\t\tAND number > 0\n\t</update>\n\t\n\t<select id=\"queryById\" resultType=\"Seckill\" parameterType=\"long\">\n\t\tSELECT\n\t\t\tseckill_id,\n\t\t\tNAME,\n\t\t\tnumber,\n\t\t\tstart_time,\n\t\t\tend_time,\n\t\t\tcreate_time\n\t\tFROM\n\t\t\tseckill\n\t\tWHERE\n\t\t\tseckill_id = #{seckillId}\n\t</select>\n\t\n\t<select id=\"queryAll\" resultType=\"Seckill\">\n\t\tSELECT\n\t\t\tseckill_id,\n\t\t\tNAME,\n\t\t\tnumber,\n\t\t\tstart_time,\n\t\t\tend_time,\n\t\t\tcreate_time\n\t\tFROM\n\t\t\tseckill\n\t\tORDER BY\n\t\t\tcreate_time DESC\n\t\tLIMIT #{offset},\n\t\t#{limit}\n\t</select>\n\t\n\t<select id=\"killByProcedure\" statementType=\"CALLABLE\">\n\t\tcall execute_seckill (\n\t\t\t#{seckillId, jdbcType = BIGINT, mode = IN },\n\t\t\t#{phone, jdbcType = BIGINT, mode = IN },\n\t\t\t#{killTime, jdbcType = TIMESTAMP, mode = IN },\n\t\t\t#{result, jdbcType = INTEGER, mode = OUT }\n\t\t)\n\t</select>\n</mapper>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/mapper/SuccessKilledDao.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE mapper\n    PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"\n    \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n<mapper namespace=\"com.imooc.dao.SuccessKilledDao\">\n\t<insert id=\"insertSuccessKilled\">\n\t\t<!-- 主键冲突，报错 -->\n\t\tINSERT ignore INTO success_killed (seckill_id, user_phone, state)\n\t\tVALUES (#{seckillId}, #{userPhone}, 0)\n\t</insert>\n\t\n\t<select id=\"queryByIdWithSeckill\" resultType=\"SuccessKilled\">\n\t\t<!-- 如何告诉MyBatis把结果映射到SuccessKilled同时映射seckill属性 -->\n\t\t<!-- 可以自由控制SQL -->\n\t\tSELECT\n\t\t\tsk.seckill_id,\n\t\t\tsk.user_phone,\n\t\t\tsk.create_time,\n\t\t\tsk.state,\n\t\t\ts.seckill_id \"seckill.seckill_id\",\n\t\t\ts.`name` \"seckill.name\",\n\t\t\ts.number \"seckill.number\",\n\t\t\ts.start_time \"seckill.start_time\",\n\t\t\ts.end_time \"seckill.end_time\",\n\t\t\ts.create_time \"seckill.create_time\"\n\t\tFROM\n\t\t\tsuccess_killed sk\n\t\tINNER JOIN seckill s ON sk.seckill_id = s.seckill_id\n\t\tWHERE\n\t\t\tsk.seckill_id = #{seckillId}\n\t\tAND sk.user_phone = #{userPhone}\n\t</select>\n</mapper>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/mybatis-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<!DOCTYPE configuration\n  PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\"\n  \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n<configuration>\n\t<!-- 配置全局属性 -->\n\t<settings>\n\t\t<!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 -->\n\t\t<setting name=\"useGeneratedKeys\" value=\"true\" />\n\n\t\t<!-- 使用列别名替换列名 默认:true -->\n\t\t<setting name=\"useColumnLabel\" value=\"true\" />\n\n\t\t<!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->\n\t\t<setting name=\"mapUnderscoreToCamelCase\" value=\"true\" />\n\t</settings>\n</configuration>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/spring/applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\">\n    <import resource=\"spring-*\"/>\n</beans>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/spring/spring-dao.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans\n\thttp://www.springframework.org/schema/beans/spring-beans.xsd\n\thttp://www.springframework.org/schema/context\n\thttp://www.springframework.org/schema/context/spring-context.xsd\">\n\t<!-- 配置整合mybatis过程 -->\n\t<!-- 1.配置数据库相关参数properties的属性：${url} -->\n\t<context:property-placeholder location=\"classpath:jdbc.properties\" />\n\n\t<!-- 2.数据库连接池 -->\n\t<bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\"\n\t\t  init-method=\"init\" destroy-method=\"clone\">\n\t\t<!-- 基本属性driverClassName、 url、user、password -->\n\t\t<property name=\"driverClassName\" value=\"${jdbc.driver}\" />\n\t\t<property name=\"url\" value=\"${jdbc.url}\" />\n\t\t<property name=\"username\" value=\"${jdbc.username}\" />\n\t\t<property name=\"password\" value=\"${jdbc.password}\" />\n\n\t\t<!-- 配置初始化大小、最小、最大 -->\n\t\t<!-- 通常来说，只需要修改initialSize、minIdle、maxActive -->\n\t\t<!-- 初始化时建立物理连接的个数，缺省值为0 -->\n\t\t<property name=\"initialSize\" value=\"${jdbc.initialSize}\" />\n\t\t<!-- 最小连接池数量 -->\n\t\t<property name=\"minIdle\" value=\"${jdbc.minIdle}\" />\n\t\t<!-- 最大连接池数量，缺省值为8 -->\n\t\t<property name=\"maxActive\" value=\"${jdbc.maxActive}\" />\n\n\t\t<!-- 获取连接时最大等待时间，单位毫秒。配置了maxWait之后，缺省启用公平锁，并发效率会有所下降，如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 -->\n\t\t<property name=\"maxWait\" value=\"${jdbc.maxWait}\" />\n\t</bean>\n\t<!--<bean id=\"dataSource\" class=\"com.mchange.v2.c3p0.ComboPooledDataSource\">-->\n\t\t<!--&lt;!&ndash; 配置连接池属性 &ndash;&gt;-->\n\t\t<!--<property name=\"driverClass\" value=\"${jdbc.driver}\" />-->\n\t\t<!--<property name=\"jdbcUrl\" value=\"${jdbc.url}\" />-->\n\t\t<!--<property name=\"user\" value=\"${jdbc.username}\" />-->\n\t\t<!--<property name=\"password\" value=\"${jdbc.password}\" />-->\n\n\t\t<!--&lt;!&ndash; c3p0连接池的私有属性 &ndash;&gt;-->\n\t\t<!--<property name=\"maxPoolSize\" value=\"30\" />-->\n\t\t<!--<property name=\"minPoolSize\" value=\"10\" />-->\n\t\t<!--&lt;!&ndash; 关闭连接后不自动commit &ndash;&gt;-->\n\t\t<!--<property name=\"autoCommitOnClose\" value=\"false\" />-->\n\t\t<!--&lt;!&ndash; 获取连接超时时间 &ndash;&gt;-->\n\t\t<!--<property name=\"checkoutTimeout\" value=\"10000\" />-->\n\t\t<!--&lt;!&ndash; 当获取连接失败重试次数 &ndash;&gt;-->\n\t\t<!--<property name=\"acquireRetryAttempts\" value=\"2\" />-->\n\t<!--</bean>-->\n\n\t<!-- 3.配置SqlSessionFactory对象 -->\n\t<bean id=\"sqlSessionFactory\" class=\"org.mybatis.spring.SqlSessionFactoryBean\">\n\t\t<!-- 注入数据库连接池 -->\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t\t<!-- 配置MyBaties全局配置文件:mybatis-config.xml -->\n\t\t<property name=\"configLocation\" value=\"classpath:mybatis-config.xml\" />\n\t\t<!-- 扫描entity包 使用别名 -->\n\t\t<property name=\"typeAliasesPackage\" value=\"com.imooc.entity\" />\n\t\t<!-- 扫描sql配置文件:mapper需要的xml文件 -->\n\t\t<property name=\"mapperLocations\" value=\"classpath:mapper/*.xml\" />\n\t</bean>\n\n\t<!-- 4.配置扫描Dao接口包，动态实现Dao接口，注入到soring容器中 -->\n\t<bean class=\"org.mybatis.spring.mapper.MapperScannerConfigurer\">\n\t\t<!-- 注入sqlSessionFactory -->\n\t\t<property name=\"sqlSessionFactoryBeanName\" value=\"sqlSessionFactory\" />\n\t\t<!-- 给出需要扫描Dao接口包 -->\n\t\t<property name=\"basePackage\" value=\"com.imooc.dao\" />\n\t</bean>\n\n\t<!-- RedisDao -->\n\t<bean id=\"redisDao\" class=\"com.imooc.dao.cache.RedisDao\">\n\t\t<constructor-arg index=\"0\" value=\"localhost\" />\n\t\t<constructor-arg index=\"1\" value=\"6379\" />\n\t</bean>\n\n</beans>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/spring/spring-dubbo-config.xml",
    "content": "<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n    http://www.springframework.org/schema/beans/spring-beans.xsd\n    http://code.alibabatech.com/schema/dubbo\n    http://code.alibabatech.com/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:application name=\"seckill-service\" owner=\"seckill\" organization=\"seckill-service\" logger=\"slf4j\"/>\n    <dubbo:registry address=\"zookeeper://127.0.0.1:2181\"/>\n    <dubbo:protocol name=\"dubbo\" port=\"20882\" host=\"127.0.0.1\"/>\n    <dubbo:provider timeout=\"15000\" retries=\"0\" delay=\"-1\"/>\n    <dubbo:consumer check=\"false\" timeout=\"15000\"/>\n</beans>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/spring/spring-dubbo-provider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xmlns:dubbo=\"http://code.alibabatech.com/schema/dubbo\"\n       xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n    http://www.springframework.org/schema/beans/spring-beans.xsd\n    http://code.alibabatech.com/schema/dubbo\n    http://code.alibabatech.com/schema/dubbo/dubbo.xsd\">\n\n    <dubbo:service interface=\"com.imooc.client.SeckillService\" ref=\"seckillService\"  timeout=\"10000\"/>\n    <!-- 和本地bean一样实现服务 -->\n    <bean id=\"seckillService\" class=\"com.imooc.service.impl.SeckillServiceImpl\" />\n</beans>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/spring/spring-service.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans\n\thttp://www.springframework.org/schema/beans/spring-beans.xsd\n\thttp://www.springframework.org/schema/context\n\thttp://www.springframework.org/schema/context/spring-context.xsd\n\thttp://www.springframework.org/schema/tx\n\thttp://www.springframework.org/schema/tx/spring-tx.xsd\">\n\t<!-- 扫描service包下所有使用注解的类型 -->\n\t<context:component-scan base-package=\"com.imooc.service\" />\n\n\t<!-- 配置事务管理器 -->\n\t<bean id=\"transactionManager\"\n\t\tclass=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\">\n\t\t<!-- 注入数据库连接池 -->\n\t\t<property name=\"dataSource\" ref=\"dataSource\" />\n\t</bean>\n\n\t<!-- 配置基于注解的声明式事务 -->\n\t<tx:annotation-driven transaction-manager=\"transactionManager\" />\n</beans>"
  },
  {
    "path": "seckill-service-provider/src/main/resources/spring/spring-web.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\t   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t   xmlns:context=\"http://www.springframework.org/schema/context\"\n\t   xmlns:mvc=\"http://www.springframework.org/schema/mvc\"\n\t   xmlns:aop=\"http://www.springframework.org/schema/aop\"\n\t   xsi:schemaLocation=\"http://www.springframework.org/schema/beans\n\thttp://www.springframework.org/schema/beans/spring-beans.xsd\n\thttp://www.springframework.org/schema/context\n\thttp://www.springframework.org/schema/context/spring-context.xsd\n\thttp://www.springframework.org/schema/mvc\n\thttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd\n\thttp://www.springframework.org/schema/aop\n\thttp://www.springframework.org/schema/aop/spring-aop.xsd\">\n\n\t<!-- 激活组件扫描功能,扫描aop的相关组件组件 -->\n\t<context:component-scan base-package=\"com.imooc.*\"/>\n\t<!-- 启动对@AspectJ注解的支持 -->\n\t<aop:aspectj-autoproxy proxy-target-class=\"false\" />\n\n\t<!-- 配置SpringMVC -->\n\t<!-- 1.开启SpringMVC注解模式 -->\n\t<!-- 简化配置： \n\t\t(1)自动注册DefaultAnootationHandlerMapping,AnotationMethodHandlerAdapter \n\t\t(2)提供一些列：数据绑定，数字和日期的format @NumberFormat, @DateTimeFormat, xml,json默认读写支持 \n\t-->\n\t<mvc:annotation-driven />\n\t\n\t<!-- 2.静态资源默认servlet配置\n\t\t(1)加入对静态资源的处理：js,gif,png\n\t\t(2)允许使用\"/\"做整体映射\n\t -->\n\t <mvc:default-servlet-handler/>\n\t \n\t <!-- 3.配置jsp 显示ViewResolver -->\n\t <bean class=\"org.springframework.web.servlet.view.InternalResourceViewResolver\">\n\t \t<property name=\"viewClass\" value=\"org.springframework.web.servlet.view.JstlView\" />\n\t \t<property name=\"prefix\" value=\"/WEB-INF/jsp/\" />\n\t \t<property name=\"suffix\" value=\".jsp\" />\n\t </bean>\n\n</beans>"
  },
  {
    "path": "seckill-service-provider/src/main/webapp/WEB-INF/web.xml",
    "content": "<web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n  xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee\n                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"\n  version=\"3.1\" metadata-complete=\"true\">\n  <!-- 配置DispatcherServlet -->\n  <servlet>\n    <servlet-name>seckill-dispatcher</servlet-name>\n    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>\n    <!-- 配置springMVC需要加载的配置文件 -->\n    <init-param>\n      <param-name>contextConfigLocation</param-name>\n      <param-value>classpath:spring/applicationContext.xml</param-value>\n    </init-param>\n  </servlet>\n\n  <servlet-mapping>\n    <servlet-name>seckill-dispatcher</servlet-name>\n    <!-- 默认匹配所有的请求 -->\n    <url-pattern>/</url-pattern>\n  </servlet-mapping>\n\n  <context-param>\n    <param-name>contextConfigLocation</param-name>\n    <param-value>classpath:spring/applicationContext.xml</param-value>\n  </context-param>\n  <listener>\n    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n  </listener>\n</web-app>"
  },
  {
    "path": "seckill-service-provider/src/main/webapp/index.jsp",
    "content": "<html>\n<body>\n<h2>Hello World!</h2>\n</body>\n</html>\n"
  }
]