电商-秒杀模块

SeckillStatus:

package com.kejin.seckill.bean;

import lombok.Data;

import java.io.Serializable;

@Data
public class SeckillStatus implements Serializable {

    //秒杀状态 1排队中 2秒杀等待支付 3支付超时 4支付失败 5支付完成
    private Integer status;

    //商品id
    private Long goodsId;

    //用户id
    private Long userId;

    //订单号
    private Long orderId;

}

User:

package com.kejin.seckill.bean;

import lombok.Data;

import java.io.Serializable;

@Data
public class User implements Serializable {
    private Long id;
    private String userName;
}

RedisCacheConfig:

package com.kejin.seckill.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;


@Component
public class RedisCacheConfig {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(redisTemplate.getKeySerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}


SeckillConstant:

package com.kejin.seckill.constant;

public class SeckillConstant {

    //商品库存信息
    public static String seckillStock ="goods:seckill:stock:";

    //保存秒杀队列记录,避免重复下单
    public static String seckillOrderCount ="goods:seckill:order:count:";

    //查看下单状态
    public static String seckillOrderStatus ="goods:seckill:order:status:";

    //查看秒杀订单信息
    public static String seckillOrderInfo ="goods:seckill:order:info:";

    //秒杀成功的订单
    public static String seckillOrderSuccess ="goods:seckill:order:success:";

}

SeckillController:

package com.kejin.seckill.controller;

import com.kejin.seckill.service.SeckillService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@ResponseBody
public class SeckillController {

    @Autowired
    private SeckillService seckillService;

    @GetMapping("/testSeckill")
    public Boolean findById(){
        return seckillService.placeOrder();
    }

}

RedisPreHeat:

package com.kejin.seckill.init;

import com.kejin.seckill.constant.SeckillConstant;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Component
public class RedisPreHeat  implements InitializingBean {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void afterPropertiesSet() throws Exception {

        Long goodsId=123456789L;redisTemplate.boundListOps(SeckillConstant.seckillStock+goodsId).leftPushAll(getAllIds(10,goodsId));

        System.out.println("开始数据预热");
    }

    //获取秒杀商品的队列集合
    public Long[] getAllIds(Integer num,Long id) {
        Long[] ids = new Long[num];
        for (int i = 0; i < ids.length; i++) {
            ids[i] = id;
        }
        return ids;
    }

}

SeckillService:

package com.kejin.seckill.service;

public interface SeckillService {
    //下单
    boolean placeOrder();
}

SeckillServiceImpl:

package com.kejin.seckill.service.impl;

import com.kejin.seckill.bean.SeckillStatus;
import com.kejin.seckill.bean.User;
import com.kejin.seckill.constant.SeckillConstant;
import com.kejin.seckill.service.SeckillService;
import com.kejin.seckill.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Random;

@Service
public class SeckillServiceImpl implements SeckillService {

    @Autowired
    private RedisTemplate redisTemplate;



    //下单操作
    @Override
    public boolean placeOrder() {
        Long goodsId=123456789L;

        User user=UserUtil.getCurrentUser();

        SeckillStatus seckillStatus=new SeckillStatus();
        seckillStatus.setStatus(1);
        seckillStatus.setGoodsId(goodsId);
        seckillStatus.setUserId(user.getId());

        //递增,判断是否排队
        Long queueCount=redisTemplate.boundHashOps(SeckillConstant.seckillOrderCount+goodsId).increment(seckillStatus.getUserId()+"",1);
        if(queueCount>1){
            //表示有重复抢单
            return false;
        }

        //创建队列,记录用户秒杀信息
        redisTemplate.boundListOps(SeckillConstant.seckillOrderInfo+goodsId).leftPush(seckillStatus);

        //存储秒杀状态信息
        redisTemplate.boundHashOps(SeckillConstant.seckillOrderStatus+goodsId).put(seckillStatus.getUserId()+"",seckillStatus);

        //异步处理订单
        createOrder(goodsId);

        return true;

     }

    //异步多线程创建订单
    @Async
    public void createOrder(Long goodsId){

        SeckillStatus seckillStatus= (SeckillStatus) redisTemplate.boundListOps(SeckillConstant.seckillOrderInfo+goodsId).rightPop();

        Object goodsIdObj = redisTemplate.boundListOps(SeckillConstant.seckillStock+goodsId).rightPop();

        if(null==goodsIdObj){

            //代表没有库存了
            System.out.println(seckillStatus.getGoodsId()+"没有库存了");

        }else{

            //开始下单
            //修改秒杀状态信息

            //创建订单后,将订单记录保存到redis中
            Random random = new Random();
            seckillStatus.setOrderId((long) random.nextInt(100));
            seckillStatus.setStatus(2);

            redisTemplate.boundHashOps(SeckillConstant.seckillOrderStatus+goodsId).put(seckillStatus.getUserId()+"",seckillStatus);

            redisTemplate.boundHashOps(SeckillConstant.seckillOrderSuccess+goodsId).put(seckillStatus.getUserId()+"",seckillStatus);

        }

    }


}

UserUtil:

package com.kejin.seckill.utils;

import com.kejin.seckill.bean.User;

import java.util.Random;

public class UserUtil {
    public static User getCurrentUser(){
        Random random = new Random();
        User user=new User();
        user.setId((long) random.nextInt(100));
        user.setUserName("张三"+random.nextInt(100));
        return user;
    }
}

application:

package com.kejin.seckill;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class SeckillApplication {

    public static void main(String[] args) {
        SpringApplication.run(SeckillApplication.class, args);
    }

}

ThreadPoolTaskConfig:


package com.kejin.seckill.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;


@Component
public class RedisCacheConfig {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}


application.properties:

# Redis数据库索引(默认为0)  
spring.redis.database=0  

# Redis服务器地址
spring.redis.host=127.0.0.1

# Redis服务器连接端口  
spring.redis.port=6379  

# Redis服务器连接密码(默认为空)
spring.redis.password=

项目结构:

猜你喜欢

转载自blog.csdn.net/u013008898/article/details/113376480