diff --git a/pom.xml b/pom.xml index 245d771b2e33c769ea8d80d6330e1731d99e3a3c..6d593ec03787653000ad22421331170bb654f991 100644 --- a/pom.xml +++ b/pom.xml @@ -153,6 +153,12 @@ beanstalkc 2.3.0 + + com.tencentcloudapi + tencentcloud-sdk-java + 3.1.322 + + spring-boot-seckill diff --git a/src/main/java/com/itstyle/seckill/queue/kafka/KafkaConsumer.java b/src/main/java/com/itstyle/seckill/queue/kafka/KafkaConsumer.java index f8b23a398d10c99b411d880d7ef4494b5324e83d..d8ac98d0e631c9b9cb1b772a66708638590b0c89 100644 --- a/src/main/java/com/itstyle/seckill/queue/kafka/KafkaConsumer.java +++ b/src/main/java/com/itstyle/seckill/queue/kafka/KafkaConsumer.java @@ -9,6 +9,9 @@ import com.itstyle.seckill.common.entity.Result; import com.itstyle.seckill.common.redis.RedisUtil; import com.itstyle.seckill.common.webSocket.WebSocketServer; import com.itstyle.seckill.service.ISeckillService; + +import javax.annotation.Resource; + /** * 消费者 spring-kafka 2.0 + 依赖JDK8 * @author 科帮网 By https://blog.52itstyle.com @@ -17,8 +20,9 @@ import com.itstyle.seckill.service.ISeckillService; public class KafkaConsumer { @Autowired private ISeckillService seckillService; - - private static RedisUtil redisUtil = new RedisUtil(); + + @Autowired + private RedisUtil redisUtil; /** * 监听seckill主题,有消息就读取 * @param message @@ -32,9 +36,9 @@ public class KafkaConsumer { if(redisUtil.getValue(array[0])==null){ Result result = seckillService.startSeckilAopLock(Long.parseLong(array[0]), Long.parseLong(array[1])); if(result.equals(Result.ok(SeckillStatEnum.SUCCESS))){ - WebSocketServer.sendInfo(array[0], "秒杀成功"); + WebSocketServer.sendInfo("秒杀成功", array[0]); }else{ - WebSocketServer.sendInfo(array[0], "秒杀失败"); + WebSocketServer.sendInfo("秒杀失败", array[0]); redisUtil.cacheValue(array[0], "ok"); } }else{ diff --git a/src/main/java/com/itstyle/seckill/web/SeckillDistributedController.java b/src/main/java/com/itstyle/seckill/web/SeckillDistributedController.java index f2500d762d0ca376bd4188c561790182e7312d91..1ca3740b4972728e8ad6237dd59fb9511ceee929 100644 --- a/src/main/java/com/itstyle/seckill/web/SeckillDistributedController.java +++ b/src/main/java/com/itstyle/seckill/web/SeckillDistributedController.java @@ -142,7 +142,7 @@ public class SeckillDistributedController { executor.execute(task); } try { - Thread.sleep(10000); + Thread.sleep(30000); redisUtil.cacheValue(killId+"", null); Long seckillCount = seckillService.getSeckillCount(seckillId); LOGGER.info("一共秒杀出{}件商品",seckillCount); diff --git a/src/main/java/com/itstyle/seckill/web/SeckillPageController.java b/src/main/java/com/itstyle/seckill/web/SeckillPageController.java index a5391adfda7d3563348f534811b15fba210c469b..3623f63617121c33b30c49aafdd12c327b5b6edf 100644 --- a/src/main/java/com/itstyle/seckill/web/SeckillPageController.java +++ b/src/main/java/com/itstyle/seckill/web/SeckillPageController.java @@ -1,6 +1,14 @@ package com.itstyle.seckill.web; import com.itstyle.seckill.common.redis.RedisUtil; +import com.itstyle.seckill.queue.kafka.KafkaSender; +import com.tencentcloudapi.captcha.v20190722.CaptchaClient; +import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultRequest; +import com.tencentcloudapi.captcha.v20190722.models.DescribeCaptchaResultResponse; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -42,13 +50,18 @@ public class SeckillPageController { @Autowired private ActiveMQSender activeMQSender; + @Autowired + private KafkaSender kafkaSender; + @Autowired private RedisUtil redisUtil; - - @Autowired - private HttpClient httpClient; - @Value("${qq.captcha.url}") - private String url; + + @Value("${qq.captcha.endPoint}") + private String endPoint; + @Value("${qq.captcha.SecretId}") + private String secretId; + @Value("${qq.captcha.SecretKey}") + private String secretKey; @Value("${qq.captcha.aid}") private String aid; @Value("${qq.captcha.AppSecretKey}") @@ -65,29 +78,40 @@ public class SeckillPageController { @PostMapping("/startSeckill") public Result startSeckill(String ticket,String randstr,HttpServletRequest request) { - HttpMethod method =HttpMethod.POST; - MultiValueMap params= new LinkedMultiValueMap(); - params.add("aid", aid); - params.add("AppSecretKey", appSecretKey); - params.add("Ticket", ticket); - params.add("Randstr", randstr); - params.add("UserIP", IPUtils.getIpAddr()); - String msg = httpClient.client(url,method,params); - /** - * response: 1:验证成功,0:验证失败,100:AppSecretKey参数校验错误[required] - * evil_level:[0,100],恶意等级[optional] - * err_msg:验证错误信息[optional] - */ - //{"response":"1","evil_level":"0","err_msg":"OK"} - JSONObject json = JSONObject.parseObject(msg); - String response = (String) json.get("response"); - if("1".equals(response)){ - //进入队列、假数据而已 - Destination destination = new ActiveMQQueue("seckill.queue"); - activeMQSender.sendChannelMess(destination,1000+";"+1); - return Result.ok(); - }else{ - return Result.error("验证失败"); + try { + Credential cred = new Credential(secretId, secretKey); + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint(endPoint); + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + CaptchaClient client = new CaptchaClient(cred, "", clientProfile); + DescribeCaptchaResultRequest req = new DescribeCaptchaResultRequest(); + req.setCaptchaType(9L); + req.setTicket(ticket); + req.setUserIp(IPUtils.getIpAddr()); + req.setRandstr(randstr); + req.setCaptchaAppId(Long.valueOf(aid)); + req.setAppSecretKey(appSecretKey); + DescribeCaptchaResultResponse resp = client.DescribeCaptchaResult(req); +// {"CaptchaCode":1,"CaptchaMsg":"OK","EvilLevel":0,"GetCaptchaTime":0,"RequestId":"8f11aabf-d319-4884-b6d3-8fa6fa561418"} + /** + * CaptchaCode: 1:验证成功,0:验证失败,100:AppSecretKey参数校验错误[required] + * EvilLevel:[0,100],恶意等级[optional] + * CaptchaMsg:验证错误信息[optional] + */ + JSONObject json = JSONObject.parseObject(DescribeCaptchaResultResponse.toJsonString(resp)); + Integer response = (Integer) json.get("CaptchaCode"); + if(1 == response) { + //进入队列、假数据而已 + kafkaSender.sendChannelMess("seckill", 1000+";"+2); +// Destination destination = new ActiveMQQueue("seckill.queue"); +// activeMQSender.sendChannelMess(destination,1000+";"+1); + return Result.ok(); + }else{ + return Result.error("验证失败"); + } + } catch (TencentCloudSDKException e) { + return Result.error("验证失败"); } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3a37c1372614d09e50d716a5ad74c3115f4027cd..ab5622c22e03569b0f48a73f3adfb8973d068923 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,15 +1,15 @@ -# 项目contextPath 科帮网https://blog.52itstyle.vip +# \u9879\u76EEcontextPath \u79D1\u5E2E\u7F51https://blog.52itstyle.vip server.context-path=/seckill -# 服务端口 +# \u670D\u52A1\u7AEF\u53E3 server.port=8080 -# session最大超时时间(分钟),默认为30 +# session\u6700\u5927\u8D85\u65F6\u65F6\u95F4(\u5206\u949F)\uFF0C\u9ED8\u8BA4\u4E3A30 server.session-timeout=60 -# tomcat最大线程数,默认为200 +# tomcat\u6700\u5927\u7EBF\u7A0B\u6570\uFF0C\u9ED8\u8BA4\u4E3A200 server.tomcat.max-threads=100 -# tomcat的URI编码 +# tomcat\u7684URI\u7F16\u7801 server.tomcat.uri-encoding=UTF-8 -#spring boot从控制台打印出来的日志级别只有ERROR, WARN 还有INFO,如果你想要打印debug级别的日志 +#spring boot\u4ECE\u63A7\u5236\u53F0\u6253\u5370\u51FA\u6765\u7684\u65E5\u5FD7\u7EA7\u522B\u53EA\u6709ERROR, WARN \u8FD8\u6709INFO\uFF0C\u5982\u679C\u4F60\u60F3\u8981\u6253\u5370debug\u7EA7\u522B\u7684\u65E5\u5FD7 #debug=true logging.level.root=INFO @@ -19,10 +19,10 @@ spring.devtools.livereload.enabled=true spring.thymeleaf.cache=false spring.thymeleaf.cache-period=0 spring.thymeleaf.template.cache=false -# 静态文件请求匹配方式 +# \u9759\u6001\u6587\u4EF6\u8BF7\u6C42\u5339\u914D\u65B9\u5F0F spring.mvc.static-path-pattern=/** -#注意中文乱码 +#\u6CE8\u610F\u4E2D\u6587\u4E71\u7801 spring.datasource.url=jdbc:mysql://localhost:3306/seckill?characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=root @@ -39,23 +39,23 @@ spring.jpa.hibernate.naming.strategy = org.hibernate.cfg.ImprovedNamingStrategy spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect # Redis -# 数据库索引(默认为0) +# \u6570\u636E\u5E93\u7D22\u5F15\uFF08\u9ED8\u8BA4\u4E3A0\uFF09 spring.redis.database=0 -# 服务器地址 变更为自己的 +# \u670D\u52A1\u5668\u5730\u5740 \u53D8\u66F4\u4E3A\u81EA\u5DF1\u7684 spring.redis.host=127.0.0.1 -# 服务器连接端口 +# \u670D\u52A1\u5668\u8FDE\u63A5\u7AEF\u53E3 spring.redis.port=6379 -# 服务器连接密码(默认为空)如果有变更为自己的 -spring.redis.password=123456 -# 连接池最大连接数(使用负值表示没有限制) +# \u670D\u52A1\u5668\u8FDE\u63A5\u5BC6\u7801\uFF08\u9ED8\u8BA4\u4E3A\u7A7A\uFF09\u5982\u679C\u6709\u53D8\u66F4\u4E3A\u81EA\u5DF1\u7684 +#spring.redis.password=123456 +# \u8FDE\u63A5\u6C60\u6700\u5927\u8FDE\u63A5\u6570\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 spring.redis.pool.max-active=8 -# 连接池最大阻塞等待时间(使用负值表示没有限制) +# \u8FDE\u63A5\u6C60\u6700\u5927\u963B\u585E\u7B49\u5F85\u65F6\u95F4\uFF08\u4F7F\u7528\u8D1F\u503C\u8868\u793A\u6CA1\u6709\u9650\u5236\uFF09 spring.redis.pool.max-wait=-1 -# 连接池中的最大空闲连接 +# \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5927\u7A7A\u95F2\u8FDE\u63A5 spring.redis.pool.max-idle=8 -# 连接池中的最小空闲连接 +# \u8FDE\u63A5\u6C60\u4E2D\u7684\u6700\u5C0F\u7A7A\u95F2\u8FDE\u63A5 spring.redis.pool.min-idle=0 -# 连接超时时间(毫秒) +# \u8FDE\u63A5\u8D85\u65F6\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09 spring.redis.timeout=30000 spring.session.store-type=redis @@ -63,18 +63,18 @@ spring.session.store-type=redis # redisson lock redisson.address=redis://127.0.0.1:6379 -redisson.password=123456 +#redisson.password=123456 -#kafka相关配置 参考:https://blog.52itstyle.vip/archives/2868/ +#kafka\u76F8\u5173\u914D\u7F6E \u53C2\u8003\uFF1Ahttps://blog.52itstyle.vip/archives/2868/ spring.kafka.bootstrap-servers=192.168.1.180:9092 -#设置一个默认组 +#\u8BBE\u7F6E\u4E00\u4E2A\u9ED8\u8BA4\u7EC4 spring.kafka.consumer.group-id=0 -#key-value序列化反序列化 +#key-value\u5E8F\u5217\u5316\u53CD\u5E8F\u5217\u5316 spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer -#每次批量发送消息的数量 +#\u6BCF\u6B21\u6279\u91CF\u53D1\u9001\u6D88\u606F\u7684\u6570\u91CF spring.kafka.producer.batch-size=65536 spring.kafka.producer.buffer-memory=524288 @@ -82,7 +82,7 @@ spring.kafka.producer.buffer-memory=524288 #zookeeper.address zookeeper.address = 192.168.1.180:2181 -#freemarker(用于商品静态页生成简化版) +#freemarker(\u7528\u4E8E\u5546\u54C1\u9759\u6001\u9875\u751F\u6210\u7B80\u5316\u7248) spring.freemarker.template-loader-path=classpath:/static/template/ spring.freemarker.suffix=.flt spring.freemarker.enabled=true @@ -95,46 +95,48 @@ spring.freemarker.expose-request-attributes=false spring.freemarker.expose-session-attributes=false spring.freemarker.expose-spring-macro-helpers=false -#商品静态页(自定义映射路径) +#\u5546\u54C1\u9759\u6001\u9875(\u81EA\u5B9A\u4E49\u6620\u5C04\u8DEF\u5F84) spring.freemarker.html.path = D://file// -# 特别注意:我们通过添加 spring-boot-starter-activemq 依赖即可默认采用内嵌的activeMQ,在生产环境下个人认为尽量还是采用外部服务,提高扩展性和维护性。 -# activemq 基础配置 +# \u7279\u522B\u6CE8\u610F\uFF1A\u6211\u4EEC\u901A\u8FC7\u6DFB\u52A0 spring-boot-starter-activemq \u4F9D\u8D56\u5373\u53EF\u9ED8\u8BA4\u91C7\u7528\u5185\u5D4C\u7684activeMQ\uFF0C\u5728\u751F\u4EA7\u73AF\u5883\u4E0B\u4E2A\u4EBA\u8BA4\u4E3A\u5C3D\u91CF\u8FD8\u662F\u91C7\u7528\u5916\u90E8\u670D\u52A1\uFF0C\u63D0\u9AD8\u6269\u5C55\u6027\u548C\u7EF4\u62A4\u6027\u3002 +# activemq \u57FA\u7840\u914D\u7F6E #spring.activemq.broker-url=tcp://47.94.232.109:61616 -# 生产环境设置密码 +# \u751F\u4EA7\u73AF\u5883\u8BBE\u7F6E\u5BC6\u7801 #spring.activemq.user=admin #spring.activemq.password=123456 #spring.activemq.in-memory=true #spring.activemq.pool.enabled=false -# 验证码参数(自行替换) -qq.captcha.url= https://ssl.captcha.qq.com/ticket/verify -qq.captcha.aid= 20426*** -qq.captcha.AppSecretKey= 0OsIkPt****** +# \u9A8C\u8BC1\u7801\u53C2\u6570(\u81EA\u884C\u66FF\u6362) +qq.captcha.endPoint= captcha.tencentcloudapi.com +qq.captcha.SecretId= AKIDqW*********** +qq.captcha.SecretKey= JL6an******************** +qq.captcha.aid= 196****** +qq.captcha.AppSecretKey= 82q******** -# 监控的HTTP端口 +# \u76D1\u63A7\u7684HTTP\u7AEF\u53E3 management.port=28806 -# 忽略拦截 +# \u5FFD\u7565\u62E6\u622A management.security.enabled=false -# 当前应用信息 +# \u5F53\u524D\u5E94\u7528\u4FE1\u606F info.app.version=v1.0.0 -info.app.name=爪哇笔记 +info.app.name=\u722A\u54C7\u7B14\u8BB0 info.app.email=345849402@qq.com info.app.url=https://blog.52itstyle.vip -#开启shutdown远程关闭功能 +#\u5F00\u542Fshutdown\u8FDC\u7A0B\u5173\u95ED\u529F\u80FD endpoints.shutdown.enabled=true -#访问:http://localhost:28806/shutdown 关闭服务 -#关闭metrics功能 +#\u8BBF\u95EE\uFF1Ahttp://localhost:28806/shutdown \u5173\u95ED\u670D\u52A1 +#\u5173\u95EDmetrics\u529F\u80FD #endpoints.metrics.enabled=false -#设置beansId +#\u8BBE\u7F6EbeansId #endpoints.beans.id=mybean -#设置beans路径 +#\u8BBE\u7F6Ebeans\u8DEF\u5F84 #endpoints.beans.path=/bean -#关闭beans 功能 +#\u5173\u95EDbeans \u529F\u80FD #endpoints.beans.enabled=false -#关闭所有的 +#\u5173\u95ED\u6240\u6709\u7684 #endpoints.enabled=false -#开启单个beans功能 +#\u5F00\u542F\u5355\u4E2Abeans\u529F\u80FD #endpoints.beans.enabled=true -#所有访问添加根目录 +#\u6240\u6709\u8BBF\u95EE\u6DFB\u52A0\u6839\u76EE\u5F55 #management.context-path=/manage \ No newline at end of file diff --git a/src/main/resources/templates/1000.html b/src/main/resources/templates/1000.html index dd38ae90d5e04b74d19280c796b184ecd0402d7a..151561b692b59fa00d5e83267f966c502497f7e2 100644 --- a/src/main/resources/templates/1000.html +++ b/src/main/resources/templates/1000.html @@ -137,7 +137,7 @@ A.info:hover {color:green;background:transparent;text-decoration:underline}

尺码:

-

立即购买加入购物车

+

立即购买加入购物车

服务承诺: