package com.miaoshaproject.controller;
import com.miaoshaproject.error.BusinessException;
import com.miaoshaproject.error.EmBusinessError;
import com.miaoshaproject.model.UserModel;
import com.miaoshaproject.mq.MqProducer;
import com.miaoshaproject.respones.CommonReturnType;
import com.miaoshaproject.service.ItemService;
import com.miaoshaproject.service.OrderService;
import com.miaoshaproject.service.PromoService;
import com.miaoshaproject.util.CodeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.*;
/**
* Author: XiangL
* Date: 2019/6/15 12:14
* Version 1.0
* 注解@RequestParam(value = "promoId", required = false)中required代表可以不加参数
* 若不写,则使用@RequestParam后要求必须传入对应的参数
*/
@Controller("order")
@RequestMapping("/order")
@CrossOrigin(allowCredentials = "true", allowedHeaders = "*")
public class OrderController extends BaseController{
@Autowired
private OrderService orderService;
@Autowired
private HttpServletRequest httpServletRequest;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private MqProducer mqProducer;
@Autowired
private ItemService itemService;
@Autowired
private PromoService promoService;
//用于队列泄洪;利用了线程池实现
private ExecutorService executorService;
//要知道@PostConstruct的作用
@PostConstruct
public void init(){
//生成固定大小的线程池
executorService = Executors.newFixedThreadPool(20);
}
//生成验证码
@RequestMapping(path = {"/generateverifycode"}, method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
public void generateVerifyCode(HttpServletResponse response) throws BusinessException, IOException {
String token = httpServletRequest.getParameterMap().get("token")[0];
if(StringUtils.isEmpty(token)){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN,"用户还未登录,不能生成验证码");
}
UserModel userModel = (UserModel) redisTemplate.opsForValue().get(token);
if(userModel == null){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "请先登录用户");
}
Map<String, Object> map = CodeUtil.generateCodeAndPic();
//并将该验证码与用户做一个绑定
redisTemplate.opsForValue().set("verify_code_"+userModel.getId(), map.get("code"));
//设置验证码有效期
redisTemplate.expire("verify_code_"+userModel.getId(), 10, TimeUnit.MINUTES);
//将生成的图片写到httpServletResponse中,返回给前端
ImageIO.write((RenderedImage) map.get("codePic"), "jpeg", response.getOutputStream());
}
//生成秒杀令牌
@RequestMapping(path = {"/generatetoken"}, method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType generatetoken(@RequestParam("itemId") Integer itemId,
@RequestParam("promoId") Integer promoId,
@RequestParam("verifyCode") String verifyCode) throws BusinessException{
//根据token获取用户信息
String token = httpServletRequest.getParameterMap().get("token")[0];
if(StringUtils.isEmpty(token)){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "请先登录用户");
}
//获取用户登录信息也通过token去redis中寻找
UserModel userModel = (UserModel) redisTemplate.opsForValue().get(token);
if(userModel == null){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "请先登录用户");
}
//通过verifycode验证验证码的有效性
String redisVerifyCode = (String) redisTemplate.opsForValue().get("verify_code_"+userModel.getId());
if(StringUtils.isEmpty(redisVerifyCode)){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "请填写验证码");
}
//equalsIgnoreCase无视大小写区别
if(!redisVerifyCode.equalsIgnoreCase(verifyCode)){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "验证码错误");
}
//获取秒杀访问令牌
String promoToken = promoService.generateSecondKillToken(promoId, itemId, userModel.getId());
if(promoToken == null){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "生成令牌失败");
}
//返回对应的结果
return CommonReturnType.create(promoToken);
}
//封装下单请求
@RequestMapping(path = {"/createorder"}, method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType createOrder(@RequestParam("itemId") Integer itemId,
@RequestParam("amount") Integer amount,
@RequestParam(value = "promoId", required = false) Integer promoId,
@RequestParam(value = "promoToken", required = false) String promoToken) throws BusinessException {
//判断用户是否登录,使用token方法后注释
//Boolean isLogin = (Boolean)httpServletRequest.getSession().getAttribute("IS_LOGIN");
// if(isLogin == null || !isLogin.booleanValue()){
// throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "请先登录用户");
// }
//获取用户登录信息--注意需要强转类型---值是在用户登录存储在对应的request的session里的
//UserModel userModel = (UserModel) httpServletRequest.getSession().getAttribute("LOGIN_USER");
String token = httpServletRequest.getParameterMap().get("token")[0];
if(StringUtils.isEmpty(token)){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "请先登录用户");
}
//获取用户登录信息也通过token去redis中寻找
UserModel userModel = (UserModel) redisTemplate.opsForValue().get(token);
if(userModel == null){
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "请先登录用户");
}
//校验秒杀令牌是否正确
if(promoId != null){
String inRedisPromoToken = (String) redisTemplate.opsForValue().get("promo_token_"+promoId+"_userid_"+userModel.getId()+"_itemid_"+itemId);
if(inRedisPromoToken == null){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "秒杀令牌校验失败");
}
if(!org.apache.commons.lang3.StringUtils.equals(promoToken, inRedisPromoToken)){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR, "秒杀令牌校验失败");
}
}
//此时使用异步发送事务型消息,不通过下面的普通流程创建订单
//OrderModel orderModel = orderService.createOrder(userModel.getId(), itemId, amount, promoId);
//同步调用线程池的submit方法;使用实现Callable接口重写call方法的方式创建线程
//第三种方法创建的线程,存在返回值。必须使用Future进行包装
//拥塞窗口为20的等待队列,用来队列泄洪
Future<Object> future = executorService.submit(new Callable<Object>() {
没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
收起资源包目录
基于SpringBoot的秒杀系统.zip (67个子文件)
miaosha-master
pom.xml 8KB
src
main
resources
application.properties 930B
mybatis-generator.xml 4KB
mapping
SequenceDOMapper.xml 4KB
UserDOMapper.xml 6KB
StockLogDOMapper.xml 4KB
OrderDOMapper.xml 6KB
ItemStockDOMapper.xml 5KB
UserPasswordDOMapper.xml 4KB
PromoDOMapper.xml 6KB
ItemDOMapper.xml 6KB
java
com
miaoshaproject
mq
MqConsumer.java 2KB
MqProducer.java 7KB
serializer
JodaDateTimeJsonDeserializer.java 955B
JodaDateTimeJsonSerializer.java 688B
error
CommonError.java 246B
EmBusinessError.java 1KB
BusinessException.java 2KB
controller
UserController.java 8KB
GlobalExceptionHandler.java 2KB
OrderController.java 9KB
ItemController.java 6KB
BaseController.java 1KB
service
PromoService.java 479B
OrderService.java 816B
UserService.java 517B
CacheService.java 293B
ItemService.java 1KB
impl
UserServiceImpl.java 6KB
ItemServiceImpl.java 8KB
OrderServiceImpl.java 8KB
CacheServiceImpl.java 1KB
PromoServiceImpl.java 5KB
DAO
ItemDOMapper.java 2KB
StockLogDOMapper.java 2KB
UserDOMapper.java 2KB
PromoDOMapper.java 2KB
ItemStockDOMapper.java 2KB
UserPasswordDOMapper.java 2KB
OrderDOMapper.java 1KB
SequenceDOMapper.java 2KB
App.java 2KB
model
ItemModel.java 2KB
viewobject
ItemVO.java 3KB
UserVO.java 1KB
OrderModel.java 2KB
UserModel.java 2KB
PromoModel.java 2KB
respones
CommonReturnType.java 1KB
validator
ValidatorImpl.java 1KB
ValidationResult.java 979B
util
CodeUtil.java 4KB
DO
ItemDO.java 5KB
OrderDO.java 6KB
StockLogDO.java 4KB
ItemStockDO.java 3KB
SequenceDO.java 3KB
PromoDO.java 5KB
UserDO.java 6KB
UserPasswordDO.java 3KB
config
RedisConfig.java 2KB
WebServerConfiguration.java 2KB
.idea
vcs.xml 180B
misc.xml 513B
compiler.xml 694B
encodings.xml 288B
miaosha.iml 80B
共 67 条
- 1
资源评论
探索电平
- 粉丝: 674
- 资源: 1545
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功