基于Springboot+rabbitMQ+redis秒杀demo

目录

写在前面

可以使用的功能

模拟秒杀(UserUtils类)

1.生成用户(获取token)

2.查询mysql

3.查询redis

4.前端页面情况

5.开始模拟秒杀

秒杀流程

1.点击秒杀开始,获取秒杀路径path

2.消息队列操作

3.判断是否秒杀成功(轮询)

遇到的问题

改造工作

1.改造数据库表,创建秒杀实体类

2.创建秒杀三层架构(controller,service,dao)

2.创建redis业务

3.创建rabbitMQ业务

GITEE地址


写在前面

最近刚刚学习完rabbitMQ的概念以及使用,于是想找点项目练练手。找了许多发现要么缺失数据库Sql文件要么就是代码水土不服。想到自己之前刚学springboot时写过一个电商项目(简易版),于是想着将其改造改造,应该可以增加一个秒杀的业务。

老项目的问题挺多的,之前登录用的是session,这次我给改成token了,但是这么一改之前的很多按钮点击事件由于没有发送token,所以出现了点击不生效的现象。= = 又由于当时这个项目的前端部分,请求js都是分开写的,每个页面写各自的请求,冗余极大,一大堆请求我都分不清了。真要改我得干很久,所以我只是将秒杀的功能那一部分修改修改了。为求它能够跑通秒杀的接口。

现在项目可以跑通,代码完全开源,已放在gitee(含sql文件),欢迎感兴趣的兄弟下载。

如果你对本系统的设计有更好的建议,欢迎评论区讨论~

制作不易,还请多多点赞+stars~

可以使用的功能

首先浏览器访问localhost:80

 

第一步先登录

 

登录成功后会跳转到首页

 

点击秒杀(只能在这一页面点击,其它页面没有绑定点击事件)

 

这些商品都是可以秒杀的,其实我在后台就是查询了'笔记本'这一类的商品

 

点击秒杀即可。

模拟秒杀(UserUtils类)

1.生成用户(获取token)

//插入mysql
@Test
public void createUsers(){
    List<User> users = new ArrayList<User>();
    //生成用户
    for(int i=0;i<1000;i++) {
        User user = new User();
        user.setUid(0);
        user.setUsername("user"+i);
        user.setCreatedUser("admin");
        user.setPhone((1581333333l+i)+"");
        user.setCreatedTime(new Date());
        user.setSalt("9d5b364d");
        user.setPassword(DigestUtils.md5Hex(123456+""+ md5mm));
        users.add(user);
        userMapper.addUser(user);
        System.out.println("新增用户-->"+user.getUid());
    }
}

 在UserUtils这个类里面,要先有mysql用户,再模拟登录生成token至txt文件里,做完这两步就可以模拟秒杀了.

    public static void main(String[] args) throws Exception {
        //先模拟生成token
//        createUserToken(count);

        //模拟通过token发起秒杀
        run();

    }

以id为15的这款商品测试秒杀

2.查询mysql

 

3.查询redis

 

4.前端页面情况

 

5.开始模拟秒杀

开启800条用户线程,将模拟秒杀的商品类id写好

static final int goodid=10000015; //将模拟类的商品id改为15
static int count=800;//模拟用户数(线程数)

调用run方法即开始。

结束之后查看mysql,redis,mq(不到3秒钟)

mysql已经为0

 

redis出现了-2

 

mq的折线图

页面情况:

后台日志:

第一步获取path没有打印出日志

 

第二步日志最多

 

第三步日志

 

针对redis的情况查看数据库是否有超卖的现象

查看秒杀订单表

 

没有超卖.

后面我又测试了多款商品的秒杀,发现redis都会出现误判的情况,但是mysql那边没有问题

 

 

秒杀流程

 

 

1.点击秒杀开始,获取秒杀路径path

1.1检查是否登录 1.1.1先获取登录token,再发送token通过redis获取到登录信息user

1.2获取秒杀路径,创建秒杀路径 1.2.1 通过md5创建秒杀路径,再将秒杀路径存入redis

存入redis:
prefix: SeckillKey.getSeckillPath  --> new SeckillKey("mp");
key:   ""+user.getId() + "_"+ goodsId
value:  md5生成的path  -->MD5Util.md5(UUID.randomUUID()+"123456");
exTime:  Const.RedisCacheExtime.GOODS_ID  -->  int GOODS_ID = 60;//1分钟
​
最终的key: new SeckillKey("mp")+""+user.getId() + "_"+ goodsId
最终的value: md5生成的path

2.消息队列操作

2.1判断是否登录 2.2验证path,从redis进行验证

boolean check = seckillOrderService.checkPath(user, goodsId, path);
    public boolean checkPath(User user, long goodsId, String path) {
        if(user == null || path == null) {
            return false;
        }
        String pathOld = redisService.get(SeckillKey.getSeckillPath, ""+user.getId() + "_"+ goodsId, String.class);
        return path.equals(pathOld);
    }

2.3map标记(查看活动是否已经结束)

boolean over = localOverMap.get(goodsId);

2.4预减库存(redis)

此前应该在redis有过存储库存量,通过秒杀商品的key获取库存量并且-1

long stock = redisService.decr(GoodsKey.getSeckillGoodsStock, "" + goodsId);
getSeckillGoodsStock --> getSeckillGoodsStock= new GoodsKey( "gs");
​
​
public <T> Long decr(KeyPrefix prefix, String key) {
         Jedis jedis = null;
         try {
             jedis =  jedisPool.getResource();
            //生成真正的key
             String realKey  = prefix.getPrefix() + key;
            return  jedis.decr(realKey);
         }finally {
              returnToPool(jedis);
         }
    }

2.5判断是否已经秒杀到了(访问mapper)

SeckillOrder order = seckillOrderService.getSeckillOrderByUserIdGoodsId(user.getId(), goodsId);
//如果可以获取到订单则提示不能重复秒杀

2.6进入消息队列排队

SeckillMessage mm = new SeckillMessage();
mm.setUser(user);
mm.setGoodsId(goodsId);
mqSender.sendSeckillMessage(mm);//加入秒杀队列
return Result.success(0);//排队中

2.7秒杀队列消费者细节:

@RabbitListener(queues=MQConfig.MIAOSHA_QUEUE)
public void receive(String message) {
   log.info("receive message:"+message);
   SeckillMessage mm  = RedisService.stringToBean(message, SeckillMessage.class);
   User user = mm.getUser();
   long goodsId = mm.getGoodsId();
​
   GoodsBo goods = goodsService.getseckillGoodsBoByGoodsId(goodsId);
       int stock = goods.getStockCount();
       if(stock <= 0) {
          return;
       }
       //判断是否已经秒杀到了
       SeckillOrder order = seckillOrderService.getSeckillOrderByUserIdGoodsId(user.getId(), goodsId);
       if(order != null) {
          return;
       }
       //减库存 下订单 写入秒杀订单
   seckillOrderService.insert(user, goods);
}

1.从消息里面获取用户以及商品信息

2.通过redis查看商品库存量,做判断

3.通过mapper做判断是否已经秒杀到了

4.减库存,下订单,写入秒杀订单(事务)

@Transactional
@Override
public OrderInfo insert(User user, GoodsBo goods) {
    //秒杀商品库存减一
    int success = seckillGoodsService.reduceStock(goods.getId());
    if(success == 1) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setCreateDate(new Date());
        orderInfo.setAddrId(0L);
        orderInfo.setGoodsCount(1);
        orderInfo.setGoodsId(goods.getId());
        orderInfo.setGoodsName(goods.getGoodsName());
        orderInfo.setGoodsPrice(goods.getSeckillPrice());
        orderInfo.setOrderChannel(1);
        orderInfo.setStatus(0);
        orderInfo.setUserId((long)user.getId());
        //添加信息进订单
        long orderId = orderService.addOrder(orderInfo);
        log.info("orderId -->" +orderId+"");
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setGoodsId(goods.getId());
        seckillOrder.setOrderId(orderInfo.getId());
        seckillOrder.setUserId((long)user.getId());
        //插入秒杀表
        seckillOrderMapper.insertSelective(seckillOrder);
        return orderInfo;
    }else {
        setGoodsOver(goods.getId());
        return null;
    }
}

3.判断是否秒杀成功(轮询)

3.1判断是否登录(redis) 3.2查询秒杀结果

long result = seckillOrderService.getSeckillResult((long) user.getId(), goodsId);

    public long getSeckillResult(Long userId, long goodsId) {
        SeckillOrder order = getSeckillOrderByUserIdGoodsId(userId, goodsId);//访问mapper
        if(order != null) {//秒杀成功
            return order.getOrderId();
        }else {
            boolean isOver = getGoodsOver(goodsId);//这个redis主要用于判断秒杀活动是否已经结束
            if(isOver) {
                return -1;
            }else {
                return 0;
            }
        }
    }
    
    
    private boolean getGoodsOver(long goodsId) {
    //判断key是否存在
        return redisService.exists(SeckillKey.isGoodsOver, ""+goodsId);
    }

遇到的问题

1.修改登录逻辑为JWT签发token,登陆时发送到response里的headers。前端接收这个token之后访问页面时携带这个token在request的headers里面。在拦截器那里一直出现空指针异常,一开始以为是前端那边的token没有处理好,后来发现是拦截器里面注入的service为空。于是把拦截器注册为bean,再通过addInterceptor添加就解决了此问题。

    registry.addInterceptor(getLoginInterceptor())   //加载下面那个bean注解的拦截器
            .addPathPatterns("/**")
            .excludePathPatterns(patterns);
}
//使用bean提前加载,不然拦截器那边注入为空
@Bean
public HandlerInterceptor getLoginInterceptor(){
    return new LoginInterceptor();
}

前端的js代码:

var token = xhr.getResponseHeader('Authorization');//获取后端服务发过来的token
console.log("获取到的token==>"+token);
window.location.href="index.html?token="+token;//直接发送给下一个请求页面
$.ajax({
   headers:{
      "Authorization":token
   },
//后面有需要登录的页面就携带token发起请求即可

2.redis 出现ERR value is not an integer or out of range(increment(key

报错原理 使用的RedisTemplate,做读写操作时候,都是要经过序列化和反序列化。这时你使用redisTemplate.opsForValue().increment()【自增和自减操作】就可能报错redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range了。

解决

@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    // 1.创建 redisTemplate 模版 用以
    RedisTemplate<Object, Object> template = new RedisTemplate<>();
    // 2.关联 redisConnectionFactory
    template.setConnectionFactory(redisConnectionFactory);
    // 3.创建 序列化类
    GenericToStringSerializer genericToStringSerializer = new GenericToStringSerializer(Object.class);
    // 6.序列化类,对象映射设置
    // 7.设置 value 的转化格式和 key 的转化格式
    template.setValueSerializer(genericToStringSerializer);
    template.setKeySerializer(new StringRedisSerializer());
    template.afterPropertiesSet();
    return template;
}

3.模拟上千个用户发起请求时出现的问题

1.com.alibaba.fastjson.JSONException: syntax error, pos 1, line 1, column 2

这个错误是由于生成的token和用户信息没匹配上,导致登录验证过不去被拦截器重定向到登录界面导致.

重新生成一下token可以解决.

2.java.net.SocketException: Software caused connection abort: recv failed

主要是模拟用户发起请求时,服务端关闭太快导致客户端正在读的时候,服务端已经关闭了,导致报错。

解决:

模拟登录:在关闭请求后面阻塞线程0.5s

模拟抢单:设置多个线程进行模拟请求,每个用户应该是独立的一条线程

for(int i=2;i<count;i++) {
    //遍历map,取出token发起进攻
    String token = tokenMp.get(i);
    int id=i;
    new Thread(()->{
        try {
            //通过用户token和id进行模拟秒杀
            startMiaosha(token,id);
        } catch (IOException e) {
            e.printStackTrace();
        }
    },"->"+id).start();

}

改造工作

1.改造数据库表,创建秒杀实体类

原商品表:

 

增加属性:

1.秒杀库存数量(不能为0)

2.秒杀开始时间

3.秒杀结束时间

 

修改原先的商品实体类

 

2.创建秒杀三层架构(controller,service,dao)

2.1 MiaoshaController

package com.markyao.controller;

import com.markyao.dao.pojo.*;
import com.markyao.miaosha.Const;
import com.markyao.miaosha.GoodsKey;
import com.markyao.mq.MiaoshaMessage;
import com.markyao.mq.MqSender;
import com.markyao.service.*;
import com.markyao.service.impl.UserServiceImpl;
import com.markyao.vo.Result;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("miaosha")
public class MiaoshaController implements InitializingBean {

    private static HashMap<Integer,Boolean> isOverMap=new HashMap<>();
    @Autowired
    private MiaoshaGoodService miaoshaGoodService;
    @Autowired
    private RedisService redisService;
    @Autowired
    UserService userService;
    @Autowired
    MiaoshaService miaoshaService;
    @Autowired
    OrderService orderService;
    @Autowired
    MqSender mqSender;
    /*
     * 系统初始化 -->implements InitializingBean
     */
    public void afterPropertiesSet() throws Exception {
        List<Product> goodsList = miaoshaGoodService.getSeckillGoodsList();
        if (goodsList == null) {
            return;
        }
        for (Product goods : goodsList) {
            //对redis进行初始化
            redisService.set(GoodsKey.getSeckillGoodsStock,
                    "" + goods.getId(),
                    goods.getMiaoshaCount(),
                    Const.RedisCacheExtime.GOODS_LIST);
            //对是否结束进行初始化
            isOverMap.put(goods.getId(), false);
        }
    }

    /*
    NO.1,点击秒杀开始,获取秒杀路径path
    1.1检查是否登录
    1.1.1先获取登录token,再发送token通过redis获取到登录信息user
    1.2获取秒杀路径,创建秒杀路径
    1.2.1 通过md5创建秒杀路径,再将秒杀路径存入redis
     */
    @GetMapping("getpath/{id}")
    public Result getMiaoshaPath(@PathVariable long id,HttpServletRequest request
                                 ) {
        String token = request.getHeader("Authorization");
        User user = userService.checkT(token);
        if (user == null) {
            return Result.fail(-999,"未登录");
        }
        String path = miaoshaService.createMiaoshaPath(user, id);
        return Result.success(0,"获取秒杀资格成功",path);
    }

    /*
    N0.2 获取成功之后,将path作为请求路径进入到此,
    2.1判断是否登录,通过redis进行判断获取
    2.2验证path,通过第一步
    2.3map标记
    2.4预减库存(redis)
    2.5判断是否已经秒杀到了
    2.6进入消息队列排队
     */
    @PostMapping(value = "/{path}/seckill")
    public Result list(Model model,
                                @RequestParam("goodsId") Integer goodsId,
                                @PathVariable("path") String path,
                                HttpServletRequest request) {
        String loginToken = request.getHeader("Authorization");
        User user = userService.checkT(loginToken);
        if (user == null) {
            return Result.fail(-999,"未登录");
        }
        //验证path
        boolean check = miaoshaService.checkPath(user, goodsId, path);
        if (!check) {
            return Result.fail(-777,"path不正确!请检查你的账号是否登录正确");
        }
        //减少redis访问
        boolean over = isOverMap.get(goodsId);
        if (over) {
            return Result.fail(-555,"活动已经结束!");
        }/**/
        //预减库存
        long stock = redisService.decr(GoodsKey.getSeckillGoodsStock, "" + goodsId);//10
        if (stock < 0) {
            isOverMap.put( goodsId, true);
            return Result.fail(-555,"已经被抢光啦!活动已经结束!");
        }
        //判断是否已经秒杀到了 -->订单表
        MiaoshaOrder order = miaoshaService.findOrderByUidAndGoodId(user.getUid(),goodsId);
        if (order != null) {
            return Result.fail(-666,"不要重复抢单哦!");
        }
        //加入消息队列
        MiaoshaMessage mm = new MiaoshaMessage();
        mm.setUser(user);
        mm.setGoodsId(goodsId);
        mqSender.sendSeckillMessage(mm);
        return Result.success(123321,"排队中",null);//排队中
    }

    /*
    No.3 判断是否秒杀成功(客户端轮询)
    3.1判断是否登录
    3.2查询秒杀结果
     */
    @GetMapping(value = "/result/{gid}")
    public Result miaoshaResult(@PathVariable("gid") Integer gid, HttpServletRequest request) {
        String loginToken = request.getHeader("Authorization");
        User user = userService.checkT(loginToken);
        if (user == null) {
            return Result.fail(-999,"你还未登录!");
        }
        MiaoshaOrder order = miaoshaService.findOrderByUidAndGoodId(user.getUid(), gid);
        if (order!=null){
            return Result.success(111,"秒杀成功啦!",null);
        }
        if (isOverMap.get(gid)){
            return Result.fail(-555,"已经被抢光啦!活动已经结束!");
        }
        return Result.success(123321,"排队中",null);//排队中
    }

}

2.2 MiaoshaService

package com.markyao.service.impl;

import com.markyao.dao.mapper.MiaoshaMapper;
import com.markyao.dao.pojo.MiaoshaOrder;
import com.markyao.dao.pojo.User;
import com.markyao.miaosha.Const;
import com.markyao.miaosha.SeckillKey;
import com.markyao.service.MiaoshaService;
import com.markyao.service.OrderService;
import com.markyao.service.ProductService;
import com.markyao.service.RedisService;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MiaoshaServiceImpl implements MiaoshaService {
    private static final String  md5ForPath="123qaz@key!";
    @Autowired
    RedisService redisService;
    @Autowired
    MiaoshaMapper miaoshaMapper;
    @Autowired
    ProductService productService;
    @Autowired
    OrderService orderService;
    
    @Override
    public String createMiaoshaPath(User user, long goodsId) {
        //通过md5生成秒杀路径path
        if (user==null || goodsId<=0){
            return null;
        }
        String path=DigestUtils.md5Hex(user.getUid()+""+goodsId+""+md5ForPath);
        //以SeckillKey.getSeckillPath+user.getUid()+"-"+goodsId 为key
        //以path为值存入redis
        redisService.set(
                SeckillKey.getSeckillPath,
                user.getUid()+"-"+goodsId,
                path,
                Const.RedisCacheExtime.GOODS_ID);
        return path;
    }

    @Override
    public boolean checkPath(User user, long goodsId, String path) {
        String realPath=redisService.getPath(SeckillKey.getSeckillPath,user.getUid(),goodsId);

        return path.equals(realPath);
    }
    
    @Override
    public MiaoshaOrder findOrderByUidAndGoodId(Integer uid, Integer goodsId) {
        return miaoshaMapper.findByUidAndGoodId(uid,goodsId);
    }
    
    @Transactional  //开启事务
    @Override
    //生成订单
    public void insertMiaoshaOrder(User user, Integer goodsId) {
        int cnt=productService.reduceMiaoshaCnt(goodsId);//秒杀库存量减1
        if (cnt==1){
            //说明此时数据库中库存量大于等于0,秒杀成功了,生成对应订单-->order与orderItem表
            orderService.addMiaoshaOrder(user.getUid(),goodsId);
            //插入秒杀订单表
            miaoshaMapper.insert(user.getUid(),goodsId);
        }
    }
}

2.3 MiaoshaDao

package com.markyao.dao.mapper;

import com.markyao.dao.pojo.MiaoshaOrder;
import com.markyao.dao.pojo.Product;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import java.util.List;

@Mapper
public interface MiaoshaMapper {
    
    //通过uid和商品id查找秒杀订单
    MiaoshaOrder findByUidAndGoodId(@Param("uid") Integer uid, @Param("pid") Integer goodsId);
    
    //生成秒杀订单
    void insert(@Param("uid") Integer uid, @Param("pid")Integer goodsId);
    
    //查找秒杀商品列表,这里我选用了"笔记本类"的商品
    List<Product> findMiaoshaList();
}

2.创建redis业务

package com.markyao.service;

import com.alibaba.fastjson.JSON;
import com.markyao.miaosha.GoodsKey;
import com.markyao.miaosha.KeyPrefix;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

@Service
public class RedisService {

    @Autowired
    RedisTemplate redisTemplate;
    public <T> boolean set(KeyPrefix prefix, String key, T value , int exTime) {
        //存入redis(秒杀路径path以及商品的库存量)
        //key的规则: prefix +key
        String valueStr = beanToString(value);
        if (valueStr==null||valueStr.length()==0){
            return false;
        }
        //生成key
        String realKey=prefix.getPrefix()+key;
        if (exTime==0){
            //要是时间过期则活动已经结束
            redisTemplate.opsForValue().set(realKey,valueStr);
        }else{
            //设置过期时间
            redisTemplate.opsForValue().set(realKey,valueStr,exTime, TimeUnit.SECONDS);
        }
        return true;
    }
    //将实体类转化为string用以存入redis
    public static <T> String beanToString(T value) {
        if(value == null) {
            return null;
        }
        Class<?> clazz = value.getClass();
        if(clazz == int.class || clazz == Integer.class) {
            return ""+value;
        }else if(clazz == String.class) {
            return (String)value;
        }else if(clazz == long.class || clazz == Long.class) {
            return ""+value;
        }else {
            return JSON.toJSONString(value);
        }
    }

    //获取秒杀路径path
    public String getPath(KeyPrefix prefix, Integer uid, long goodsId) {
        String realKey=prefix.getPrefix()+uid+"-"+goodsId;
        ValueOperations<String,String> valueOperations = redisTemplate.opsForValue();
        String  realPath = valueOperations.get(realKey);
        return realPath;
    }
    
    //用以减少秒杀货品的库存
    public long decr(GoodsKey getSeckillGoodsStock, String s) {
        //key的规则: prefix +key
        String prefix = getSeckillGoodsStock.getPrefix();
        String key=prefix+s;
        //从redis减少库存
        Long decrement = redisTemplate.opsForValue().decrement(key);
        return decrement;
    }
}

3.创建rabbitMQ业务

消息队列初始化: 交换机选择"amq.direct",绑定好对应的秒杀队列即可

消息队列这块生产者比较简单,将秒杀信息存入秒杀队列即可,需要实现创建秒杀信息实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MiaoshaMessage {
    //秒杀队列实体类

    private User user;

    private Integer goodsId;
}
主要是消费者的编写

package com.markyao.mq;
import com.markyao.dao.pojo.MiaoshaOrder;
import com.markyao.dao.pojo.Product;
import com.markyao.dao.pojo.User;
import com.markyao.service.MiaoshaService;
import com.markyao.service.ProductService;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MqConsumer {
    @Autowired
    ProductService productService;
    @Autowired
    MiaoshaService miaoshaService;
    //mq消费端,主要用于插入秒杀订单,监听秒杀队列
    //注意将消息转化为json对象
    @RabbitListener(queues = MQConfig.MIAOSHA_QUEUE,
    messageConverter = "jacksonConverter")
    public void recevie(MiaoshaMessage message){
        User user = message.getUser();
        Integer goodsId = message.getGoodsId();
        //通过商品的id查询此商品此时库存量多少
        Product product=productService.getProductByid(goodsId);
        Integer miaoshaCount = product.getMiaoshaCount();
        if(miaoshaCount<=0){
            return;
        }
        MiaoshaOrder miaoshaOrder = miaoshaService.findOrderByUidAndGoodId(user.getUid(), goodsId);
        if(miaoshaOrder!=null){
            //已经秒杀到了
            return;
        }
        //插入订单之中,生成订单
        miaoshaService.insertMiaoshaOrder(user,goodsId);
    }
}

GITEE地址

点我

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot是一个非常流行的Java Web框架,它简化了Java应用程序的开发和部署过程。 RabbitMQ是一个开源的消息代理,它支持多种协议,包括AMQP、STOMP和MQTT等。TLS协议则是一种加密传输协议,它可以保证数据在传输过程中的安全性。 在Spring Boot应用程序中使用RabbitMQ需要引入相应的依赖,可以使用Maven或Gradle来进行管理。同时,为了保证消息的安全传输,我们可以使用TLS协议对消息进行加密传输。 以下是使用Spring BootRabbitMQ进行消息传输并加密的简单示例: 1. 引入依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-rsa</artifactId> </dependency> ``` 2. 配置RabbitMQ和TLS 在application.properties文件中添加以下配置: ```properties spring.rabbitmq.host=localhost spring.rabbitmq.port=5671 spring.rabbitmq.username=user spring.rabbitmq.password=password spring.rabbitmq.ssl.enabled=true spring.rabbitmq.ssl.key-store=file:/path/to/keystore spring.rabbitmq.ssl.key-store-password=changeit spring.rabbitmq.ssl.trust-store=file:/path/to/truststore spring.rabbitmq.ssl.trust-store-password=changeit ``` 其中,key-store和trust-store分别为用于TLS加密的密钥库和信任库文件路径,需要根据实际情况进行配置。 3. 发送和接收消息 在Spring Boot应用程序中使用RabbitTemplate来发送和接收消息,示例代码如下: ```java @Service public class RabbitMQService { @Autowired private RabbitTemplate rabbitTemplate; public void send(String message) { rabbitTemplate.convertAndSend("exchange", "routingKey", message); } @RabbitListener(queues = "queue") public void receive(String message) { System.out.println("Received message: " + message); } } ``` 其中,send方法用于发送消息,receive方法用于接收消息。在这个例子中,我们将消息发送到名为exchange的交换机,使用名为routingKey的路由键进行路由,然后将消息发送到名为queue的队列中进行消费。 以上就是在Spring Boot应用程序中使用RabbitMQ和TLS进行消息传输的简单示例。需要注意的是,这只是一个基本的示例,实际应用中还需要进行更多的配置和处理,以确保消息传输的安全和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值