• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

springboot中通过lua脚本来获取序列号的方法

springboot 搞代码 4年前 (2022-01-05) 43次浏览 已收录 0个评论

这篇文章主要介绍了springboot中通过lua脚本来获取序列号的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

序言:

事件:此web项目的功能及其简单,就是有客户端来访问redis序列号服务时发送jison报文,项目已经在测试环境成功运行2周了,具体的代码我就直接上了,此博客仅是自己的记录,同学们可做参考!

一、工程目录结构

二、配置文件

1、pom.xml

   4.0.0 org.springframework.bootspring-boot-starter-parent2.2.6.RELEASE<!-- lookup parent from repository -->com.testseq-gen0.0.1-SNAPSHOTseq-gengenerate sequence from redis UTF-8UTF-81.8 <!--引入日志依赖--><!-- org.slf4j slf4j-log4j12 1.7.21   commons-logging commons-logging 1.2 --><!-- log4j2的api、core和web包 --> org.apache.logging.log4jlog4j-api2.11.1 org.apache.logging.log4jlog4j-core2.11.1 org.apache.logging.log4jlog4j-web2.11.1<!-- slf4j与log4j2的连接包 --> org.apache.logging.log4jlog4j-slf4j-impl2.11.1<!-- log4j与log4j2的连接包 --> org.apache.logging.log4jlog4j-1.2-api2.11.1<!-- log4j2支撑完全异步模式的关键api --> com.lmaxdisruptor3.4.2 org.slf4jslf4j-api1.7.21 org.springframework.bootspring-boot-starter-data-redis com.alibabafastjson1.2.62 redis.clientsjedis org.springframework.bootspring-boot-starter-web org.springframework.bootspring-boot-starter  org.springframework.bootspring-boot-starter-logging<!-- 热部署,集成测试--> org.springframework.bootspring-boot-devtoolstrue org.projectlomboklomboktrue org.springframework.bootspring-boot-starter-testtest   org.apache.maven.pluginsmaven-compiler-plugin 1.81.8 org.springframework.bootspring-boot-maven-plugin   repackage org.apache.maven.pluginsmaven-surefire-plugin2.4.2 true

2、applicaiton.properties

 spring.redis.database= 0 spring.redis.host= 127.0.0.1 spring.redis.port= 6379 spring.redis.pool.max-active= 8 spring.redis.pool.max-wait= -1ms spring.redis.pool.max-idle= 8 spring.redis.pool.min-idle= 0 spring.redis.pool.timeout= 2000ms server.port= 8085

3、luaScripts脚本

 local function get_next_seq() --KEYS[1]:第一个参数代表存储序列号的key 相当于代码中的业务类型 local key = tostring(KEYS[1]) --KEYS[2]:第二个参数代表序列号增长速度 local incr_amoutt = tonumber(KEYS[2]) --KEYS[3]`:第四个参数为序列号 (yyMMddHHmmssSSS + 两位随机数) local seq = tonumber(KEYS[3]) --序列号过期时间大小,单位是秒 -- local month_in_seconds = 24 * 60 * 60 * 7 --Redis的 SETNX 命令可以实现分布式锁,用于解决高并发 --如果key不存在,将 key 的值设为 seq,设置成成功返回1 未设置返回0 --若给定的 key 已经存在,则 SETNX 不做任何动作,获取下一个按照步增的值 if (1 == redis.call('setnx', key, seq)) --不存在key, then --设置key的生存时间 为 month_in_seconds秒 -- 由于序列号需要永久有效,不能过期,所以取消这个设置,需要的可以取消注释 -- redis.call('expire', key, month_in_seconds) --将序列返回给调用者 return seq else --key值存在,直接获取下一个增加的值 local nextSeq = redis.call('incrby', key, incr_amoutt) return nextSeq end end return get_next_seq()

4、log4j2.xml

  <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --><!--Configuration后面的status,这个用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,你会看到log4j2内部各种详细输出--><!--monitorInterval:Log4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->  logs<!--先定义所有的appender--> <!-- 这个输出控制台的配置 --> <!-- 控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch) --><!-- 这个都知道是输出日志的格式 --><!-- 这个会打印出所有的info及以下级别的信息,每次大小超过size,则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,作为存档--> <!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->   <!-- DefaultRolloverStrategy属性如不设置,则默认为最多同一文件夹下7个文件,这里设置了20 -->  <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效--> <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->  

三、代码部分

1、启动类

 package com.test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SeqGenApplication { private static final Logger log = LoggerFactory.getLogger(SeqGenApplication.class); public static void main(String[] args) { SpringApplication.run(SeqGenApplication.class, args); log.info("start SeqGenApplication sucessfully........"); } }

2、Bean

 package com.test.bean; import com.alibaba.fastjson.annotation.JSONField; /** * Copyright (C), 2019-2020 * * 此类是请求和响应中对应的属性 * * @author fanhf * @date  2020-03-25 * @version v1.0.0 */ public class RspBean { public RspBean(){} /* 开始序列号 */ @JSONField(name = "SNNumB") private Integer sNNumB; /* 从redis中获取的序列号 */ @JSONField(name = "SNNumE") private Integer sNNumE; /* 发起方操作流水 */ @JSONField(name = "OprNumb") private String 	oprNumb; /* 落地方操作时间 */ @JSONField(name = "OprTime") private String oprTime; /* 返回码 */ @JSONField(name = "BizOrderResult") private String bizOrderResult; /* 返回码描述 */ @JSONField(name = "ResultDesc") private String resultDesc; public Integer getSNNumB() { return sNNumB; } public void setSNNumB(Integer sNNumB) { this.sNNumB = sNNumB; } public Integer getSNNumE() { return sNNumE; } public void setSNNumE(Integer sNNumE) { this.sNNumE = sNNumE; } public String getOprNumb() { return oprNumb; } public void setOprNumb(String oprNumb) { this.oprNumb = oprNumb; } public String getOprTime() { return oprTime; } public void setOprTime(String oprTime) { this.oprTime = oprTime; } public String getBizOrderResult() { return bizOrderResult; } public void setBizOrderResult(String bizOrderResult) { this.bizOrderResult = bizOrderResult; } public String getResultDesc() { return resultDesc; } public void setResultDesc(String resultDesc) { this.resultDesc = resultDesc; } @Override public String toString() { return "RspBean{" + "sNNumB=" + sNNumB + ", sNNumE=" + sNNumE + ", oprNumb='" + oprNumb + '\'' + ", oprTime='" + oprTime + '\'' + ", bizOrderResult='" + bizOrderResult + '\'' + ", resultDesc='" + resultDesc + '\'' + '}'; } }

3、Controller

 package com.test.controller; import com.test.bean.RspBean; import com.test.service.RedisService; import com.test.util.CommonUtils; import com.alibaba.fastjson.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; /** * Copyright (C), 2019-2020 * * 此类是web层的入口,用来接收json请求 * * @author fanhf * @date  2020-03-29 * @version v1.0.0 */ @RestController public class RedisControlLer { private static final Logger log = LoggerFactory.getLogger(RedisControlLer.class); @Autowired private RedisTemplate redisTemplate; @Autowired private RedisService redisService; @PostMapping(path = "/app/v1/sync/bizOrder/QuerySerialNumber", consumes = "application/json", produces = "application/json") public String rcvReq(@RequestBody String jsonparam){ String prettyJson= CommonUtils.prettyJson(jsonparam); log.info("receive requset: "); log.info("\r\n"+prettyJson); JSONObject jsonObject = new JSONObject(); RspBean rw = new RspBean(); String response = null; Map jsonMap = new HashMap(); try { // 将报文放入map中 jsonMap = CommonUtils.putReq2Map(jsonparam); response = redisService.createResponse(jsonMap); prettyJson = CommonUtils.prettyJson(response); log.info("send Response: "); log.info("\r\n"+prettyJson); } catch (Exception ex) { if (null == jsonObject || 0 == jsonObject.size()) { try { String oprNumb = jsonMap.get("oprNumb"); rw.setOprNumb(oprNumb); rw.setBizOrderResult("30000"); rw.setResultDesc(ex.getMessage()); JSONObject json = (JSONObject) JSONObject.toJSON(rw); response = json.toString(); } catch (Exception e) { e.printStackTrace(); } return response; } } return response; } }

4、Service

 package com.test.service; import java.util.Map; public interface RedisService { String createResponse(Map jsonMap); }

ServiceImpl

 package com.test.service; import com.test.bean.RspBean; import com.test.util.CommonUtils; import com.test.util.RedisUtil; import com.alibaba.fastjson.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.*; /** * Copyright (C), 2019-2020 * * 此类是service处理层,根据接收到的序列名称和步长值,从redis中获取序列号,再对返回的信息进行组装 * 以及对异常情况时返回数据的处理 * * @author fanhf * @date  2020-04-05 * @version v1.0.0 */ @Component @Service public class RedisServiceImpl implements RedisService { private static final Logger log = LoggerFactory.getLogger(RedisServiceImpl.class); @Override public String createResponse(Map jsonMap) { String response = null; RspBean rw = null; JSONObject json = null; // 之所以要遍历map是因为怕传过来的key值有小写的,怕get不到对应的值 String key = null; String sNNameValue = null; String increAmountValue = null; for (Map.Entry entry : jsonMap.entrySet()) { key = entry.getKey(); if ("SNName".equalsIgnoreCase(key)) { sNNameValue = entry.getValue(); } else if("SNNum".equalsIgnoreCase(key)){ increAmountValue = entry.getValue(); } } String seq="0"; // 从redis中获取序列号(根据序列号名称和步长获取序列号) List busilist = Arrays.asList(sNNameValue,increAmountValue,seq); Long seqFromRedis = null; try { seqFromRedis = RedisUtil.getBusiSeq(busilist); } catch (Exception e) { log.error("cannot get seq from redis cluster ,please check redis cluster"+ "_" + e.getMessage(), e); } log.info("seqFromRedis:{}", seqFromRedis); String oprNumb = jsonMap.get("OprNumb"<mark style="color:transparent">来源gaodaimacom搞#代%码网</mark>); String oprTime = CommonUtils.getCurDateTimestamp(); try { rw = new RspBean(); int sNNumB; if(!StringUtils.isEmpty(seqFromRedis)){ sNNumB=seqFromRedis.intValue(); rw.setSNNumB(sNNumB); rw.setSNNumE(sNNumB+Integer.parseInt(increAmountValue)); rw.setBizOrderResult("00000"); rw.setResultDesc("Success"); }else{ rw.setSNNumB(0); rw.setSNNumE(0); rw.setBizOrderResult("30000"); rw.setResultDesc("business handles failed...."); } rw.setOprNumb(oprNumb); rw.setOprTime(oprTime); json = (JSONObject) JSONObject.toJSON(rw); response = json.toString(); } catch (Exception e) { log.error("boxing response of json happend error "+ "_" + e.getMessage(), e); if (rw != null) { rw.setBizOrderResult("30000"); rw.setResultDesc("business handles failed......"); json = (JSONObject) JSONObject.toJSON(rw); response = json.toString(); } log.info("send Response: [ {} ]", response ); jsonMap.put("responseToWzw", response); return response; } return response; } }

5、Utils

5.1 CommonUtils

 package com.test.util; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Map; /** * 工具类 * @author fanhf * @date  2020-04-01 * @version v1.0.0 */ public class CommonUtils { private static final Logger log = LoggerFactory.getLogger(CommonUtils.class); public static Map putReq2Map(String jsonparam) { // 将json字符串转换为json对象 return (Map) JSONObject.parse(jsonparam); } /** * @Description 获取系统当前时间 * @return 时间字符串 */ public static String getCurDateTimestamp(){ DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); LocalDateTime localDateTime = LocalDateTime.now(); String now=localDateTime.format(dateTimeFormatter); return now; } /** * 美化json格式,将一行json转为为有回车换行的json * @param reqJson * @return 美化后的json */ public static String prettyJson(String reqJson){ JSONObject object = JSONObject.parseObject(reqJson); String prettyJson = JSON.toJSONString(object, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,SerializerFeature.WriteDateUseDateFormat); return prettyJson; } }

5.2 ReadConfigsPathUtil

 package com.test.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Properties; /** * @ Description : 用来获取linux和windows的config的绝对路径 * @ Author  : fanhf * @ CreateDate : 2020/4/11 0:33 * @ UpdateUser : fanhf * @ UpdateDate : 2020/4/11 0:33 * @ UpdateRemark : 修改内容 * @ Version  : 1.0.0 */ public class ReadConfigsPathUtil { private static final Logger log = LoggerFactory.getLogger(ReadConfigsPathUtil.class); private ReadConfigsPathUtil() {} private static Properties properties = null; /** * @Description 获取linux和windows系统中config的目录 * @param configPath lua脚本的相对路径 * @return linux和windows系统中config的目录的绝对路径 */ public static String getPropertiesPath(String configPath) { String sysPath = getRelativePath(); log.info("sysPath:{}",sysPath); String filepath = new StringBuffer(sysPath) .append(File.separator) .append("config") .append(File.separator) .append(configPath).toString(); log.info("filepath:{}",filepath); return filepath; } /** * @Description 获取系统字符型属性 * @author add by fanhf * @date 2020-04-08 */ public static String getRelativePath() { return System.getProperty("user.dir"); } /** * @Description 读取lua脚本的内容 * @param luaScriptPath lua脚本的绝对路径 * @return 读取到的lua脚本的内容 * @author add by fanhf * @date 2020-04-15 */ public static String readFileContent(String luaScriptPath) { String filename = getPropertiesPath(luaScriptPath); File file = new File(filename); BufferedReader reader = null; StringBuffer sbf = new StringBuffer(); try { reader = new BufferedReader(new FileReader(file)); String tempStr; while ((tempStr = reader.readLine()) != null) { sbf.append(tempStr); sbf.append("\r\n"); } reader.close(); return sbf.toString(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e1) { e1.printStackTrace(); } } } return sbf.toString(); } }

5.3 RedisUtil

 package com.test.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.support.EncodedResource; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.DefaultScriptExecutor; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.stereotype.Component; import org.springframework.util.FileCopyUtils; import java.io.IOException; import java.util.List; /** * @ Description : 用来加载和读取lua脚本并加载 * @ Author  : fanhf * @ CreateDate : 2020/4/01 0:32 * @ UpdateUser : fanhf * @ UpdateDate : 2020/4/01 0:32 * @ UpdateRemark : 修改内容 * @ Version  : 1.0.0 */ @Component public class RedisUtil { private static final Logger log = LoggerFactory.getLogger(RedisUtil.class); private static StringRedisTemplate redisStringTemplate; private static RedisScript redisScript; private static DefaultScriptExecutor scriptExecutor; private RedisUtil(StringRedisTemplate template) throws IOException { RedisUtil.redisStringTemplate = template; // 之所以会注释掉是由于这段代码可以直接读取resource目录下的非application.properties的文件, // 但是这个方法在生产和测试环境不适用,因为配置文件必须暴露初打的jar包里 //  ClassPathResource luaResource = new ClassPathResource("luaScript/genSeq.lua"); //  EncodedResource encRes = new EncodedResource(luaResource, "UTF-8"); //  String luaString = FileCopyUtils.copyToString(encRes.getReader()); String luaString = ReadConfigsPathUtil.readFileContent("luaScript/genSeq.lua"); redisScript = new DefaultRedisScript(luaString, Long.class); scriptExecutor = new DefaultScriptExecutor(redisStringTemplate); } public static Long getBusiSeq(List Busilist) throws Exception{ Long seqFromRedis = scriptExecutor.execute(redisScript, Busilist); return seqFromRedis; } }

总结

到此这篇关于springboot中通过lua脚本来获取序列号的文章就介绍到这了,更多相关springboot中通过lua脚本来获取序列号内容请搜索gaodaima搞代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持gaodaima搞代码网

以上就是springboot中通过lua脚本来获取序列号的方法的详细内容,更多请关注gaodaima搞代码网其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:springboot中通过lua脚本来获取序列号的方法

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址