电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

springboot中通過lua腳本來獲取序列號的方法

瀏覽:2日期:2023-05-13 14:07:36

序言:

事件:此web項目的功能及其簡單,就是有客戶端來訪問redis序列號服務時發送jison報文,項目已經在測試環境成功運行2周了,具體的代碼我就直接上了,此博客僅是自己的記錄,同學們可做參考!

一、工程目錄結構

springboot中通過lua腳本來獲取序列號的方法

二、配置文件

1、pom.xml

<?xml version='1.0' encoding='UTF-8'?><project xmlns='http://maven.apache.org/POM/4.0.0' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd'><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.6.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.test</groupId><artifactId>seq-gen</artifactId><version>0.0.1-SNAPSHOT</version><name>seq-gen</name><description>generate sequence from redis</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><!--引入日志依賴--><!--<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.21</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency>--><!-- log4j2的api、core和web包 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.11.1</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.11.1</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-web</artifactId><version>2.11.1</version></dependency><!-- slf4j與log4j2的連接包 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.11.1</version></dependency><!-- log4j與log4j2的連接包 --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-1.2-api</artifactId><version>2.11.1</version></dependency><!-- log4j2支撐完全異步模式的關鍵api --><dependency><groupId>com.lmax</groupId><artifactId>disruptor</artifactId><version>3.4.2</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.62</version></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><!-- 熱部署,集成測試--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.4.2</version><configuration><skipTests>true</skipTests></configuration></plugin></plugins></build></project>

2、applicaiton.properties

spring.redis.database= 0spring.redis.host= 127.0.0.1spring.redis.port= 6379spring.redis.pool.max-active= 8spring.redis.pool.max-wait= -1msspring.redis.pool.max-idle= 8spring.redis.pool.min-idle= 0spring.redis.pool.timeout= 2000msserver.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 endendreturn get_next_seq()

4、log4j2.xml

<?xml version='1.0' encoding='UTF-8'?><!--日志級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --><!--Configuration后面的status,這個用于設置log4j2自身內部的信息輸出,可以不設置,當設置成trace時,你會看到log4j2內部各種詳細輸出--><!--monitorInterval:Log4j能夠自動檢測修改配置 文件和重新配置本身,設置間隔秒數--><configuration status='INFO' monitorInterval='30' packages='org.apache.logging.log4j.core.layout'> <Properties> <Property name='baseDir'>logs</Property> </Properties> <!--先定義所有的appender--> <appenders> <!-- 這個輸出控制臺的配置 --> <Console name='Console' target='SYSTEM_OUT'> <!-- 控制臺只輸出level及以上級別的信息(onMatch),其他的直接拒絕(onMismatch) --> <ThresholdFilter level='info' onMatch='ACCEPT' onMismatch='DENY'/> <!-- 這個都知道是輸出日志的格式 --> <PatternLayout pattern='[%date{DEFAULT}]-[%highlight{%level}]-[%threadName]-[%-class{4}:%line]-%msg%n'/> </Console> <!-- 這個會打印出所有的info及以下級別的信息,每次大小超過size,則這size大小的日志會自動存入按年份-月份建立的文件夾下面并進行壓縮,作為存檔--> <RollingFile name='RollingFileInfo' fileName='${baseDir}/seq_all.log' filePattern='${baseDir}/$${date:yyyy-MM}/all-%d{yyyy-MM-dd}-%i.log'> <!--控制臺只輸出level及以上級別的信息(onMatch),其他的直接拒絕(onMismatch)--> <ThresholdFilter level='info' onMatch='ACCEPT' onMismatch='DENY'/> <PatternLayout pattern='[%date{DEFAULT}]-[%highlight{%level}]-[%threadName]-[%-class{4}:%line]-%msg%n'/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size='500 MB'/> </Policies> </RollingFile> <RollingFile name='RollingFileWarn' fileName='${baseDir}/seq_warn.log' filePattern='${baseDir}/$${date:yyyy-MM}/warn-%d{yyyy-MM-dd}-%i.log'> <ThresholdFilter level='warn' onMatch='ACCEPT' onMismatch='DENY'/> <PatternLayout pattern='[%date{DEFAULT}]-[%highlight{%level}]-[%threadName]-[%-class{4}:%line]-%msg%n'/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size='100 MB'/> </Policies> <!-- DefaultRolloverStrategy屬性如不設置,則默認為最多同一文件夾下7個文件,這里設置了20 --> <DefaultRolloverStrategy max='20'/> </RollingFile> <RollingFile name='RollingFileErrorCommon' fileName='${baseDir}/seq_error.log' filePattern='${baseDir}/$${date:yyyy-MM}/error-%d{yyyy-MM-dd}-%i.log'> <ThresholdFilter level='error' onMatch='ACCEPT' onMismatch='DENY'/> <PatternLayout pattern='[%date{DEFAULT}]-[%highlight{%level}]-[%threadName]-[%-class{4}:%line]-%msg%n'/> <Policies> <TimeBasedTriggeringPolicy/> <SizeBasedTriggeringPolicy size='100 MB'/> </Policies> </RollingFile> </appenders> <!--然后定義logger,只有定義了logger并引入的appender,appender才會生效--> <loggers> <!--過濾掉spring和mybatis的一些無用的DEBUG信息--> <logger name='org.springframework' level='DEBUG'></logger> <logger name='org.mybatis' level='DEBUG'></logger> <logger name='com.alicl oud.openservices.tablestore' level='ERROR' additivity='false'> <appender-ref ref='RollingFileOtsError'/> </logger> <root level='INFO'> <appender-ref ref='Console'/> <appender-ref ref='RollingFileInfo'/> <appender-ref ref='RollingFileWarn'/> <appender-ref ref='RollingFileErrorCommon'/> </root> </loggers></configuration>

三、代碼部分

1、啟動類

package com.test;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic 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 */@RestControllerpublic class RedisControlLer { private static final Logger log = LoggerFactory.getLogger(RedisControlLer.class); @Autowired private RedisTemplate<String, String> 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('rn'+prettyJson); JSONObject jsonObject = new JSONObject(); RspBean rw = new RspBean(); String response = null; Map<String ,String> jsonMap = new HashMap<String,String>(); try { // 將報文放入map中 jsonMap = CommonUtils.putReq2Map(jsonparam); response = redisService.createResponse(jsonMap); prettyJson = CommonUtils.prettyJson(response); log.info('send Response: '); log.info('rn'+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<String, String> 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@Servicepublic class RedisServiceImpl implements RedisService { private static final Logger log = LoggerFactory.getLogger(RedisServiceImpl.class); @Override public String createResponse(Map<String, String> 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<String, String> 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<String> 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'); 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<String, String> putReq2Map(String jsonparam) { // 將json字符串轉換為json對象 return (Map<String, String>) 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('rn'); } 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 */@Componentpublic class RedisUtil { private static final Logger log = LoggerFactory.getLogger(RedisUtil.class); private static StringRedisTemplate redisStringTemplate; private static RedisScript<Long> redisScript; private static DefaultScriptExecutor<String> 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<String> Busilist) throws Exception{ Long seqFromRedis = scriptExecutor.execute(redisScript, Busilist); return seqFromRedis; }}

總結

到此這篇關于springboot中通過lua腳本來獲取序列號的文章就介紹到這了,更多相關springboot中通過lua腳本來獲取序列號內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
主站蜘蛛池模板: 除湿机|工业除湿机|抽湿器|大型地下室车间仓库吊顶防爆除湿机|抽湿烘干房|新风除湿机|调温/降温除湿机|恒温恒湿机|加湿机-杭州川田电器有限公司 | 欧盟ce检测认证_reach检测报告_第三方检测中心-深圳市威腾检验技术有限公司 | 河北凯普威医疗器材有限公司,高档轮椅系列,推车系列,座厕椅系列,协步椅系列,拐扙系列,卫浴系列 | 杭州顺源过滤机械有限公司官网-压滤机_板框压滤机_厢式隔膜压滤机厂家 | 24位ADC|8位MCU-芯易德科技有限公司 | 展厅装修公司|企业展厅设计|展厅制作|展厅搭建—广州展厅装饰公司 | 电磁流量计_智能防腐防爆管道式计量表-金湖凯铭仪表有限公司 | 小型单室真空包装机,食品单室真空包装机-百科 | 深圳希玛林顺潮眼科医院(官网)│深圳眼科医院│医保定点│香港希玛林顺潮眼科中心连锁品牌 | 上海新光明泵业制造有限公司-电动隔膜泵,气动隔膜泵,卧式|立式离心泵厂家 | 浙江红酒库-冰雕库-气调库-茶叶库安装-医药疫苗冷库-食品物流恒温恒湿车间-杭州领顺实业有限公司 | 广州印刷厂_广州彩印厂-广州艺彩印务有限公司| 苏州柯瑞德货架-仓库自动化改造解决方案 | 活性氧化铝球|氧化铝干燥剂|分子筛干燥剂|氢氧化铝粉-淄博同心材料有限公司 | 考勤系统_考勤管理系统_网络考勤软件_政企|集团|工厂复杂考勤工时统计排班管理系统_天时考勤 | 上海网站建设-上海网站制作-上海网站设计-上海做网站公司-咏熠软件 | MVR蒸发器厂家-多效蒸发器-工业废水蒸发器厂家-康景辉集团官网 | 济南玻璃安装_济南玻璃门_济南感应门_济南玻璃隔断_济南玻璃门维修_济南镜片安装_济南肯德基门_济南高隔间-济南凯轩鹏宇玻璃有限公司 | PTFE接头|聚四氟乙烯螺丝|阀门|薄膜|消解罐|聚四氟乙烯球-嘉兴市方圆氟塑制品有限公司 | 高柔性拖链电缆-聚氨酯卷筒电缆-柔性屏蔽电缆厂家-玖泰电缆 | 平面钻,法兰钻,三维钻-山东兴田阳光智能装备股份有限公司 | 北京自然绿环境科技发展有限公司专业生产【洗车机_加油站洗车机-全自动洗车机】 | 济南铝方通-济南铝方通价格-济南方通厂家-山东鲁方通建材有限公司 | HYDAC过滤器,HYDAC滤芯,现货ATOS油泵,ATOS比例阀-东莞市广联自动化科技有限公司 | 西安展台设计搭建_西安活动策划公司_西安会议会场布置_西安展厅设计西安旭阳展览展示 | 烽火安全网_加密软件、神盾软件官网 | MTK核心板|MTK开发板|MTK模块|4G核心板|4G模块|5G核心板|5G模块|安卓核心板|安卓模块|高通核心板-深圳市新移科技有限公司 | 硫化罐_蒸汽硫化罐_大型硫化罐-山东鑫泰鑫智能装备有限公司 | 对夹式止回阀厂家,温州对夹式止回阀制造商--永嘉县润丰阀门有限公司 | 便携式XPDM露点仪-在线式防爆露点仪-增强型烟气分析仪-约克仪器 冰雕-冰雪世界-大型冰雕展制作公司-赛北冰雕官网 | 蒜肠网-动漫,二次元,COSPLAY,漫展以及收藏型模型,手办,玩具的新媒体.(原变形金刚变迷TF圈) | 恒温恒湿箱(药品/保健品/食品/半导体/细菌)-兰贝石(北京)科技有限公司 | HDPE土工膜,复合土工膜,防渗膜价格,土工膜厂家-山东新路通工程材料有限公司 | 理化生实验室设备,吊装实验室设备,顶装实验室设备,实验室成套设备厂家,校园功能室设备,智慧书法教室方案 - 东莞市惠森教学设备有限公司 | 基本型顶空进样器-全自动热脱附解吸仪价格-AutoHS全模式-成都科林分析技术有限公司 | 北京网站建设|北京网站开发|北京网站设计|高端做网站公司 | 青岛侦探调查_青岛侦探事务所_青岛调查事务所_青岛婚外情取证-青岛狄仁杰国际侦探公司 | 一体化净水器_一体化净水设备_一体化水处理设备-江苏旭浩鑫环保科技有限公司 | 寮步纸箱厂_东莞纸箱厂 _东莞纸箱加工厂-东莞市寮步恒辉纸制品厂 | 电动卫生级调节阀,电动防爆球阀,电动软密封蝶阀,气动高压球阀,气动对夹蝶阀,气动V型调节球阀-上海川沪阀门有限公司 | 火锅底料批发-串串香技术培训[川禾川调官网]|