网站建设哪家好 需要多少钱锦州做网站哪家好

张小明 2026/1/19 20:44:00
网站建设哪家好 需要多少钱,锦州做网站哪家好,破解网站后台,境外直播appps年 title: 优惠卷发布平台 author: John Doe date: 2024-10-03 20:22:30 categories: 后端实战ps 自己和同学写的个项目的开发日志#xff0c;算是回忆吧#xff0c;代码很青涩 优惠卷发布平台 1.提供登录注册 登录注册采用redis缓存 减缓mysql压力 2.登录验证 采用cookie …ps年title: 优惠卷发布平台author: John Doedate: 2024-10-03 20:22:30categories:后端实战ps自己和同学写的个项目的开发日志算是回忆吧代码很青涩优惠卷发布平台1.提供登录注册登录注册采用redis缓存 减缓mysql压力2.登录验证采用cookie 对ID进行aes加密拦截器解密3.异常捕获未知异常—全部补获—发送邮箱提醒开发者4.优惠卷定时发布采用xll—job5.优惠券发布mysql redis各一份6.抢优惠卷lua-redis-ecle7.优惠卷同步同步xxl—job 配合线程池异步同步8.使用优惠券redis 分布式锁 事务问题9.优惠券展示redis缓存问题—mysql索引优化设计思路-数据库 id 账号 密码逻辑 -判断账号密码-给与seioon-拦截器进行判断技术方案-redis// SpringCache下一个项目再使用MQCanal-同步数据库xxl-job预热缓存//cookie 加密登录逻辑调优方案jvm-查看堆-gc时间-查看高并发下运行时间ps:01案例-只需要搭建起查看时间不需要进行各类jvm调优1.环境搭建太久没搭建环境了创建的maven项目-导入的各类依赖1.创建数据库三个字段主键 id (雪花算法) 用户名String --去重 密码Stringcreate table user(id BigInt Primary key,account varchar(255) not null, password varchar(255) not null); Query OK, 0 rows affected (0.03 sec)2.配置环境1.配置maven 导入spring起步依赖 导入redis-导入knif34i 导入工具类2.编写启动类-编写knif4i配置3.导入mybutsplus-代码生成4.自动生成mvc三层架构模式5.插入数据库数据insert into user(id,account,password) values(1,2,3),(2,3,4);6.修改用户账号索引alter table user add constraint account_unique Unique(account);3.登录逻辑1.controllerRestControllerRequestMapping(/api)publicclassExampleController{AutowiredIUserServiceiUserService;GetMapping(/login)ApiOperation(value登录)publicRhello(ApiParam(value用户ID,requiredtrue)Stringaccount,ApiParam(value用户密码,requiredtrue)Stringpassword,HttpServletRequestreq){RriUserService.login(account,password);if(Objects.nonNull(r.getData())){//登录成功了的SessionwebUserDtodata(SessionwebUserDto)r.getData();HttpSessionsessionreq.getSession();session.setAttribute(session_account,data);}returnr;}}2.serviceServicepublicclassUserServiceImplextendsServiceImplUserMapper,UserimplementsIUserService{AutowiredRedisTemplateredisTemplate;OverridepublicRlogin(Stringaccount,Stringpassword){//查询redis缓存ObjectoredisTemplate.opsForValue().get(account);if(onull){//弹出验证码-或者其他策略 查mysql//mysql也为空LambdaQueryWrapperUserlambdaQueryWrappernewLambdaQueryWrapper();lambdaQueryWrapper.eq(User::getAccount,account);// 使用 Lambda 表达式引用字段 lambdaQueryWrapper.ge(User::getAge, 18);Useruserthis.baseMapper.selectOne(lambdaQueryWrapper);ouser;if(usernull){returnR.error(账号或密码错误);}//插入user缓存到redisredisTemplate.opsForValue().set(account,user);}//账号对了Useruser(User)o;if(!user.getPassword().equals(password)){returnR.error(账号或密码错误);}//登录成功给sessioSessionwebUserDtosessionwebUserDtonewSessionwebUserDto();sessionwebUserDto.setAccountId(user.getAccount());returnR.success(sessionwebUserDto);}}demo 登录注册抢单-核销lua-redis原子性主要是的redis进行操作-看看redis的延迟任务能不能加入进来加密token编写对明文seiion转json后加密非对称和对称加密解密都在服务器-选择对称加密采用base64编码需要手动解析data-赋值给对象ConfigurationDatapublicclassTokenEncryption{Value(${token.encryption.key})privateStringkey;Value(${token.encryption.iv})privateStringiv;Value(${token.encryption.algorithm})privateStringalgorithm;privateSecretKeySpecAES;privateIvParameterSpecivSpec;privateCiphercipher;publicStringgetKey(){returnkey;}publicStringgetIv(){returniv;}publicStringgetAlgorithm(){returnalgorithm;}publicStringgetTokenEncryption(Stringdata)throwsException{//用于包装密钥 --包装向量extracted();//指定加密//加密cipher.init(Cipher.ENCRYPT_MODE,AES,ivSpec);byte[]encryptedcipher.doFinal(data.getBytes());StringencryptedBase64Base64.getEncoder().encodeToString(encrypted);returnencryptedBase64;}privatevoidextracted()throwsException{if(AESnull){byte[]rawKeyadjustKeyLength(key,16);// 16字节128位AESnewSecretKeySpec(rawKey,algorithm);}if(ivSpecnull){byte[]ivBytesadjustKeyLength(iv,16);ivSpecnewIvParameterSpec(ivBytes);}if(ciphernull){cipherCipher.getInstance(AES/CBC/PKCS5Padding);}}privateSecretKeySpecsecretKey;publicStringretToken(Stringdata)throwsException{if(secretKeynull){byte[]rawKeyadjustKeyLength(key,16);// 16字节128位secretKeynewSecretKeySpec(rawKey,algorithm);}if(ivSpecnull){byte[]ivBytesadjustKeyLength(iv,16);ivSpecnewIvParameterSpec(ivBytes);}// 指定解密算法和模式CiphercipherCipher.getInstance(AES/CBC/PKCS5Padding);// 初始化解密器cipher.init(Cipher.DECRYPT_MODE,secretKey,ivSpec);// 解密Base64编码的加密数据byte[]decodedEncryptedDataBase64.getDecoder().decode(data);byte[]decryptedDatacipher.doFinal(decodedEncryptedData);// 返回解密后的原始字符串returnnewString(decryptedData,UTF-8);}privatebyte[]adjustKeyLength(Stringkey,intlength)throwsException{byte[]keyByteskey.getBytes(UTF-8);if(keyBytes.lengthlength){returnkeyBytes;}elseif(keyBytes.lengthlength){// 如果长度不足使用0填充byte[]paddedKeynewbyte[length];System.arraycopy(keyBytes,0,paddedKey,0,keyBytes.length);returnpaddedKey;}else{// 如果长度超出截取前面的部分byte[]shortenedKeynewbyte[length];System.arraycopy(keyBytes,0,shortenedKey,0,length);returnshortenedKey;}}}脑子一抽就写出来了本来准备套JWT的。。我脑子抽了-然后-关于过期就加入时间搓效验-我没有加-后续能人再加把-嘻嘻拦截器编写Configuration public class WebConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(new MyInterceptor()) .addPathPatterns(/**) // 拦截所有请求 .excludePathPatterns(/api/login, /error); // 排除某些路径不拦截 } }Component public class MyInterceptor implements HandlerInterceptor { Autowired TokenEncryption tokenEncryption; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { /* HttpSession session request.getSession(); String token (String) session.getAttribute(session_account);*/ if(tokenEncryptionnull) { tokenEncryptionnew TokenEncryption(); /* key: w7HqLJz3Kt0J3u6fYT3Ow iv: 77b07a672d57d64c algorithm: AES */ tokenEncryption.setKey(w7HqLJz3Kt0J3u6fYT3Ow); tokenEncryption.setIv(77b07a672d57d64c); tokenEncryption.setAlgorithm(AES); } Cookie[] cookies request.getCookies(); if (cookies null) { throw new BusinessException(用户错误); } for (Cookie cookie : cookies) { if (username.equals(cookie.getName())) { String username cookie.getValue(); String userid tokenEncryption.retToken(username); return true; } } throw new BusinessException(用户错误); } }全局异常编写我redis忘记启动了报错信息直接给我出了-redis地址-笑死我了RestControllerAdvice public class ExceptionHandler { org.springframework.web.bind.annotation.ExceptionHandler(value Exception.class) public R handleException(Exception e) { e.getMessage(); return R.error(对不起,操作失败,请联系管理员); } org.springframework.web.bind.annotation.ExceptionHandler(value BusinessException.class) public R handleException(BusinessException e) { return R.error( e.getMessage()); } }public class BusinessException extends RuntimeException { private ResponseCodeEnum codeEnum; private Integer code; private String message; public BusinessException(String message, Throwable e) { super(message, e); this.message message; } public BusinessException(String message) { super(message); this.message message; } public BusinessException(Throwable e) { super(e); } public BusinessException(ResponseCodeEnum codeEnum) { super(codeEnum.getMsg()); this.codeEnum codeEnum; this.code codeEnum.getCode(); this.message codeEnum.getMsg(); } public BusinessException(Integer code, String message) { super(message); this.code code; this.message message; } public ResponseCodeEnum getCodeEnum() { return codeEnum; } public Integer getCode() { return code; } Override public String getMessage() { return message; } /** * 重写fillInStackTrace 业务异常不需要堆栈信息提高效率. */ Override public Throwable fillInStackTrace() { return this; } }10/4号代码注册编写以后碰到异常我自己捕获了不能老是抛抛抛使用IdType.ASSIGN_ID雪花算法MyBatis-Plus 的内置雪花算法来生成一个Long类型的唯一 IDTableId(value id, type IdType.ASSIGN_UUID) private Long id;Override public R register(User user) { if(usernull||user.getAccount() null||user.getPassword()null) { return R.error(请补全参数); } //各类校验 Object o redisTemplate.opsForValue().get(user.getAccount()); if(o!null) { return R.error(账号已存在); } ///后续做xxl-job /* String keyRegister registeruser.getAccount(); redisTemplate.opsForValue().set(keyRegister,user.getPassword());*/ int insert this.baseMapper.insert(user); if(insert0) { return R.error(注册失败); } //即时缓存 redisTemplate.opsForValue().set(user.getAccount(),user.getPassword()); return R.success(注册成功); }设计出错redis设计结构出错-应该是id-配合整个类()不然拿不到id-主键搜索本身就是聚集索引快-而账户搜索就不是前端编写抢卷发布0-redis各类技术设计思路-我发布抢卷mysqlmysql-canlce—redis进行缓存–解决缓存不一致redis各类击穿问题reids-spring cacheredis原子性操作抢卷发布数据库设计抢卷ID -抢卷库存抢卷表Coupon抢卷记录表Coupon_Redemptioncreatetablecoupon(idBIGINTAUTO_INCREMENTPRIMARYKEY,coupon_codevarchar(255)notnullUNIQUE,total_stockint,available_stockintnotnull,start_timedatetimenotnull,end_timedatetimenotnull,statusTINYINTNOTNULLDEFAULT0COMMENT0: 未开始, 1: 进行中, 2: 已结束,indexidex_coupon_status(status));Query OK,0rowsaffected(0.03sec)createtableCoupon_Redemption(idbigintAUTO_INCREMENTprimarykey,user_idVarchar(255),coupon_idbigintnotnull,redemption_timeDATETIMEnotnull,statusTINYINTNOTNULLDEFAULT1COMMENT0: 失败, 1: 成功,foreignkey(coupon_id)referencescoupon(id)ONDELETECASCADE,uniquekeyuk_user_coupon(user_id,coupon_id));发卷思路reids抢卷结构1.redis抢卷表记录redisTemplate.opsForValue().set(coupon.getId(), coupon);id整个表-再次设计问题redis加上前缀-例如-登录账户-优惠卷id发卷serviceRestController RequestMapping(/coupon) public class CouponController { Autowired ICouponService iCouponService; PostMapping(/publish) ApiOperation(value 发卷) public R publish(RequestBody Coupon coupon) { return iCouponService.publish(coupon); } }Service public class CouponServiceImpl extends ServiceImplCouponMapper, Coupon implements ICouponService { Autowired RedisTemplate redisTemplate; Override public R publish(Coupon coupon) { //判断--太多硬编码了-懒得用常量-谁喜欢改谁改 coupon this.ifCoupon(coupon); //xxl-job每日扫描-防止错误 boolean isave(coupon); if(!i) { return R.error(发布失败); } redisTemplate.opsForValue().set(couponcoupon.getId().toString(), coupon); return R.success(coupon); } public Coupon ifCoupon(Coupon coupon) { if(coupon.getTotalStock()null) { coupon.setTotalStock(10); } if(coupon.getAvailableStock()null) { coupon.setAvailableStock(coupon.getTotalStock()); } if(coupon.getStartTime()null) { coupon.setStartTime(LocalDateTime.now()); } if(coupon.getEndTime()null) { coupon.setEndTime(LocalDateTime.now().plusDays(1));//默认一天后结束 } if(coupon.getCouponCode()null) { coupon.generateCouponCode(); } if(coupon.getStatus()null) { coupon.setStatus(0); } return coupon; } }xxl-job 定时发布优惠卷步骤 1.搭建调度中心-创建调度器-创建任务配置调度中心-添加任务执行调度代码Component public class issueJob { Autowired ICouponService iCouponService; /* 创建一个与 issueJob 类关联的日志记录器。 日志记录器用于输出日志信息以帮助开发者在运行时了解程序的执行状态或排查问题。 */ XxlJob(fajuan) public void testJob() { Coupon couponnew Coupon(); ///coupon iCouponService.publish(coupon); } }抢卷逻辑////判断请求参数Service public class CouponRedemptionServiceImpl extends ServiceImplCouponRedemptionMapper, CouponRedemption implements ICouponRedemptionService { Autowired RedisTemplate redisTemplate; Override public R qiangjuan(CouponRedemption coupon) { String userId (String) RequestContextHolder.getRequestAttributes().getAttribute(userId, RequestAttributes.SCOPE_REQUEST); if (coupon.getUserId() null) { return R.error(用户id不能为空); } if (coupon.getCouponId() null) { return R.error(活动查询失败); } //查询活动是否开始 ValueOperations valueOperations redisTemplate.opsForValue(); Object o valueOperations.get(coupon coupon.getCouponId()); Coupon coupon2 new Coupon(); coupon2 (Coupon) o; if (coupon2.getStatus() 0) { return R.error(活动未开始); } LocalDateTime now LocalDateTime.now(); if (now.isBefore(coupon2.getStartTime())) { System.out.println(活动尚未开始); } else if (now.isAfter(coupon2.getEndTime())) { System.out.println(活动已结束); } if (coupon2.getTotalStock() 0) { return R.error(库存不足); } //开始抢卷 return null; } }///执行抢卷脚本eval执行lua脚本-redistempplate替换 MULTL开始redis的事务lua脚本 --抢卷 --队列-抢卷成功队列 -设计库存-修改库存表的可用库存 --优惠卷是否抢过 local couponNumredis.call(HGET,KEYS[3],ARGV[2]) -- hget 获取不到数据返回false而不是nil if couponNum ~ false and tonumber(couponNum) 1 then return -1; end --库存是否充足 local stockNumredis.call(HGET,KEYS[1],ARGV[1]) if stockNum ~ false or tonumber(stockNum) 1 then return -2; end --减库存 --写入抢卷成功队列///返回抢卷结果-1 限领一张-2 已抢光-3 写入抢券成功队列失败返回给用户为抢券失败-4 已抢光-5 写入抢券同步队列失败返回给用户为抢券失败///线程池xxl-job进行抢卷结果同步崩溃一天做redis-给redis加了个序列化器-导致后续代码一直获取redis失败Service public class CouponRedemptionServiceImpl extends ServiceImplCouponRedemptionMapper, CouponRedemption implements ICouponRedemptionService { Autowired RedisTemplate redisTemplate; ///Resource(name Lua_test01) /// DefaultRedisScriptInteger seizeCouponScript; Override public R qiangjuan(CouponRedemption coupon) { String userId (String) RequestContextHolder.getRequestAttributes().getAttribute(userId, RequestAttributes.SCOPE_REQUEST); if (userId null) { return R.error(用户id不能为空); } coupon.setUserId(userId); if (coupon.getCouponId() null) { return R.error(活动查询失败); } //查询活动是否开始 // redisTemplate.opsForValue().set(couponcoupon.getCouponCode().toString(), coupon); Object o redisTemplate.opsForValue().get(couponcoupon.getCouponId().toString()); if(onull) { return R.error(活动查询失败); } Coupon coupon2 new Coupon(); coupon2 (Coupon) o; if (coupon2.getStatus() 0) { return R.error(活动未开始); } LocalDateTime now LocalDateTime.now(); if (now.isBefore(coupon2.getStartTime())) { System.out.println(活动尚未开始); } else if (now.isAfter(coupon2.getEndTime())) { System.out.println(活动已结束); } if (coupon2.getTotalStock() 0) { return R.error(库存不足); } // 同步队列redisKey // 资源库存redisKey int index (int) (UUID.randomUUID().hashCode() % 10); String resourceStockRedisKey String.format(coupon%s, index); String couponSeizeSyncRedisKey String.format(COUPON_SEIZE_SYNC_QUEUE_NAME%s, index); // 抢券成功列表 String couponSeizeListRedisKey String.format(COUPON_SEIZE%s%s,coupon.getCouponId(), index); /* ListString listnew ArrayList(); list.add(couponSeizeSyncRedisKey);// 同步队列redisKey list.add(resourceStockRedisKey); // 资源库存redisKey list.add(couponSeizeListRedisKey); // 抢券成功列表 用户id 优惠卷id */ ListString listnew ArrayList(); list.add(couponSeizeSyncRedisKey);// 同步队列redisKey list.add(resourceStockRedisKey); // 资源库存redisKey list.add(couponSeizeListRedisKey); // 抢券成功列表 //开始抢卷 // Object executeredisTemplate.execute(seizeCouponScript,list,userId,coupon.getCouponId()); return null; } }优惠卷库存同步ps:以前跟着别人写简简单单自己真的就老实了-逆天时间复杂度Configuration public class kcyure { Autowired RedisTemplate redisTemplate; XxlJob(value kcyure) public void kcyure() { try { //SetString couponKeys redisTemplate.keys(*); // 假设你的优惠券键以 coupon: 开头 //拿出同步库存表的-进行id过滤掉已经同步过的库存 //拿去同步表ids Cursorbyte[] couponKeys redisTemplate.getConnectionFactory().getConnection().scan(ScanOptions.scanOptions().match(*coupon*).count(100).build()); SetString couponKeyss new HashSet(); while (couponKeys.hasNext()) { byte[] key couponKeys.next(); String keyStr new String(key, StandardCharsets.UTF_8); // 转换为字符串 // 提取 coupon 后面的部分 if (keyStr.contains(coupon)) { String suffix keyStr.substring(keyStr.indexOf(coupon) coupon.length()); couponKeyss.add(suffix); } } //拿去库存表 SetString stocks new HashSet(); Cursorbyte[] stocksi redisTemplate.getConnectionFactory().getConnection() .scan(ScanOptions.scanOptions().match(stock*).count(100).build()); while (stocksi.hasNext()) { byte[] key stocksi.next(); String keyStr new String(key, StandardCharsets.UTF_8); // 转换为字符串 MapObject, Object hashEntries redisTemplate.opsForHash().entries(keyStr); for(Object key1 : hashEntries.keySet()) { stocks.add(keyStr); } } if (couponKeyss ! null) { for (String key : couponKeyss) { if(stocks.contains(key)) { continue; } Coupon coupon (Coupon) redisTemplate.opsForValue().get(couponkey.toString()); int index (int) (coupon.getId() % 10); String resourceStockRedisKey String.format(Stock:%s, index); redisTemplate.opsForHash().put(resourceStockRedisKey, key, coupon.getAvailableStock()); } } }catch (Exception e) { e.printStackTrace(); System.out.println(库存同步失败); //异常处理 }}}设计问题优惠卷id-我设置的String-用的uuid-一直有— 我设置了LOng的-后续抢卷脚本转long才能找到数据-设计序列化-哈希计算的问题redis序列化-更换日期类型-设置日期格式10/5 内容抢卷脚本--抢卷 --队列-抢卷成功队列 -设计库存-修改库存表的可用库存 ---- key: 抢券同步队列资源库存,抢券成功列表 -- argv活动id,用户id --优惠卷是否抢过--抢卷成功队列--key coupon local couponNum redis.call(HGET, KEYS[3], ARGV[2]) -- hget 获取不到数据返回false而不是nil if couponNum ~ false and tonumber(couponNum) 1 then return -1; end --库存是否充足 local stockNumredis.call(HGET,KEYS[2],ARGV[1]) if stockNum false or tonumber(stockNum) 1 then return -2; end --抢券列表 local listNum redis.call(HSET,KEYS[3], ARGV[2], 1) if listNum false or tonumber(listNum) 1 then return -3; end --减库存 stockNumredis.call(HINCRBY,KEYS[2],ARGV[1],-1) if tonumber(stockNum)0 then return -4; end --写入抢卷成功队列 local resultredis.call(HSETNX,KEYS[1],ARGV[2],ARGV[1]) if result0 then return ARGV[1].. end return -5抢卷开发Configuration public class kcyure { Autowired RedisTemplate redisTemplate; XxlJob(value kcyure) public void kcyure() { try { //SetString couponKeys redisTemplate.keys(*); // 假设你的优惠券键以 coupon: 开头 //拿出同步库存表的-进行id过滤掉已经同步过的库存 //拿去同步表ids Cursorbyte[] couponKeys redisTemplate.getConnectionFactory().getConnection().scan(ScanOptions.scanOptions().match(*coupon*).count(100).build()); SetString couponKeyss new HashSet(); while (couponKeys.hasNext()) { byte[] key couponKeys.next(); String keyStr new String(key, StandardCharsets.UTF_8); // 转换为字符串 // 提取 coupon 后面的部分 if (keyStr.contains(coupon)) { String suffix keyStr.substring(keyStr.indexOf(coupon) coupon.length()); couponKeyss.add(suffix); } } //拿去库存表 SetString stocks new HashSet(); Cursorbyte[] stocksi redisTemplate.getConnectionFactory().getConnection() .scan(ScanOptions.scanOptions().match(stock*).count(100).build()); while (stocksi.hasNext()) { byte[] key stocksi.next(); String keyStr new String(key, StandardCharsets.UTF_8); // 转换为字符串 MapObject, Object hashEntries redisTemplate.opsForHash().entries(keyStr); for(Object key1 : hashEntries.keySet()) { stocks.add(keyStr); } } if (couponKeyss ! null) { for (String key : couponKeyss) { if(stocks.contains(key)) { continue; } Coupon coupon (Coupon) redisTemplate.opsForValue().get(couponkey.toString()); int index (int) (coupon.getId() % 10); String resourceStockRedisKey String.format(Stock:%s, index); redisTemplate.opsForHash().put(resourceStockRedisKey, key, coupon.getAvailableStock()); } } }catch (Exception e) { e.printStackTrace(); System.out.println(库存同步失败); //异常处理 }}}库存同步线程池-配合xxl-jobConfiguration public class syncThreadPool { Bean(syncThreadPool) public ThreadPoolExecutor syncThreadPool(){ int corePoolSize 1; // 核心线程数 int maxPoolSize 10; // 最大线程数 long keepAliveTime 120; // 线程空闲时间 TimeUnit unit TimeUnit.SECONDS; // 时间单位 // 指定拒绝策略为 DiscardPolicy RejectedExecutionHandler rejectedHandler new ThreadPoolExecutor.DiscardPolicy(); // 任务队列使用SynchronousQueue容量为1在没有线程去消费时不会保存任务 ThreadPoolExecutor executor new ThreadPoolExecutor (corePoolSize, maxPoolSize, keepAliveTime, unit, new SynchronousQueue(),rejectedHandler); return executor; } }xxl-jobpublic class getData implements Runnable { private int index; public getData(int index){ this.index index; } Override public void run() { //读取任务-加锁-免得重复读取 //创建示例 RedissonClient redissonClient Redisson.create(); //获取锁 RLock locredissonClient.getLock(ying); try { boolean isLockloc.tryLock(3, -1, TimeUnit.SECONDS); if (isLock) { //锁内执行 最大等待时间 持锁时间 分钟数 //-2看门狗机制-只要执行完成后才会放锁 String queneString.format(ying:%s,index); jgtb(quene); } }catch (Exception e) { // 处理中断异常 }finally { if(lock!null ) } } public void jgtb(String quene) { } }库存同步代码XxlJob(value kctb) public void qjtb_syncThreadPool() { for (int i0;i10;i) { threadPool.execute(getData); } }ComponentpublicclassgetDataimplementsRunnable{AutowiredprivateRedisTemplateredisTemplate;AutowiredprivateICouponRedemptionServiceiCouponRedemptionService;Overridepublicvoidrun(){//读取任务-加锁-免得重复读取//创建示例RedissonClientredissonClientRedisson.create();//获取锁RLocklocredissonClient.getLock(ying);try{booleanisLockloc.tryLock(3,-1,TimeUnit.SECONDS);if(isLock){//锁内执行 最大等待时间 持锁时间 分钟数//-2看门狗机制-只要执行完成后才会放锁intindex(int)(Math.random()*10)1;StringqueneString.format(ying:%s,index);jgtb(quene);}}catch(Exceptione){// 处理中断异常}finally{if(loc!nullloc.isLocked()){loc.unlock();}}}publicvoidjgtb(Stringquene){/// Cursorbyte[] couponKeys redisTemplate.getConnectionFactory()// .getConnection().scan(// ScanOptions.scanOptions().match(*coupon*).count(100).build());//获取成功数据 -游标拿去try{ListStringstocksnewArrayList();Cursorbyte[]stocksiredisTemplate.getConnectionFactory().getConnection().scan(ScanOptions.scanOptions().match(quene).count(100).build());if(stocksinull){return;}while(stocksi.hasNext()){byte[]keystocksi.next();StringkeyStrnewString(key,StandardCharsets.UTF_8);// 转换为字符串-队列名字MapString,ObjecthashEntriesredisTemplate.opsForHash().entries(keyStr);//根据队列名字找key集合for(Stringkey1:hashEntries.keySet()){stocks.add(key1);}}if(stocks.size()0){return;}for(Stringkey:stocks){CouponRedemptioncouponRedemptionnewCouponRedemption();couponRedemption.setUserId(String.valueOf(key));//真是神仙代码Longo(Long)redisTemplate.opsForHash().get(quene,key);couponRedemption.setCouponId(String.valueOf(o));couponRedemption.setRedemptionTime(newDate());couponRedemption.setStatus(1);iCouponRedemptionService.save(couponRedemption);redisTemplate.opsForHash().delete(quene,key);}}catch(Exceptione){e.printStackTrace();}}}mysql外键错误商品卷约束到父表user去了-笑死我了alter table coupon_redemption add constraint coupon_redemption_coupon_coupon_code_fk foreign key (coupon_id) references coupon (coupon_code);优惠卷展示Override public R lsit() { //这里偷懒不用游标了 //权限校验 SetString keys redisTemplate.keys(coupon*); ListObject values new ArrayList(); for (String key : keys) { values.add(redisTemplate.opsForValue().get(key)); } return R.success(values); }拦截器修复拦截knife4ipublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { /* HttpSession session request.getSession(); String token (String) session.getAttribute(session_account);*/ HandlerMethod handlerMethod(HandlerMethod)handler; //判断如果请求的类是swagger的控制器直接通行。 if(handlerMethod.getBean().getClass().getName().equals(springfox.documentation.swagger.web.ApiResourceController)){ return true; }总结项目地址https://gitee.com/laomaodu/anli01api地址https://apifox.com/apidoc/shared-20ef25e6-5dfe-482f-88a0-ae48011048a3心得对于代码逻辑来讲简单-但是总会涉及到很多bug-很多的bug都是再设计时候埋下的坑下一次项目就会注重设计了https://www.bilibili.com/video/BV14N1qYNEbU/?spm_id_from333.999.0.0
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

建自己的网站兰州seo整站优化服务商

第一章:智能Agent能源管理的演进与挑战随着分布式计算和边缘智能的快速发展,智能Agent在能源管理系统中的角色日益关键。从早期基于规则的控制逻辑,到如今融合强化学习与联邦学习的自主决策系统,智能Agent已能动态响应电网负载、用…

张小明 2026/1/17 22:59:04 网站建设

数字今天科技 网站安阳网站seo

5个让Vue3后台管理系统开发效率翻倍的实战技巧 【免费下载链接】vue-element-plus-admin A backend management system based on vue3, typescript, element-plus, and vite 项目地址: https://gitcode.com/gh_mirrors/vu/vue-element-plus-admin 还在为开发企业级后台系…

张小明 2026/1/17 22:59:04 网站建设

网站建设与维护课程总结做外贸单网上都做的那些网站

在软件测试领域,可视化测试通过捕捉用户界面(UI)的视觉元素来验证功能与设计一致性。2025年,随着AI和自动化技术的普及,截图与录屏工具已从简单的记录设备演变为智能诊断助手。本文聚焦进阶使用策略,针对测试工程师、QA专家等从业…

张小明 2026/1/17 22:59:03 网站建设

兰州网站建设推荐q479185700顶你wordpress n点资讯主题

操作系统中的异步I/O、页框回收与文件系统详解 1. 异步I/O POSIX 1003.1 标准定义了一组用于异步访问文件的库函数。“异步”意味着当用户模式进程调用一个库函数来读取或写入文件时,该函数在读写操作入队后就会立即终止,甚至可能在实际的 I/O 数据传输发生之前就结束。这样…

张小明 2026/1/17 22:59:05 网站建设

梅州做网站多少钱网络公司网站首页图片

一、背景:分布式系统与 Scale-Out 架构在讲解 Scale-Out(横向扩展)之前,先介绍一下分布式系统的概念。当计算机系统发展成熟后,单一系统往往面临单点故障和性能瓶颈的问题。为解决这些问题,出现了两个主要发…

张小明 2026/1/17 22:59:06 网站建设

丰城网站建设办公室设计平面图

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个简单的WebSocket聊天应用,要求:1.使用WebFlux的WebSocketHandler 2.支持多房间聊天 3.包含前端HTML页面 4.有消息历史记录功能。请生成完整可运行项…

张小明 2026/1/17 22:59:07 网站建设