当前位置: 首页> 财经> 访谈 > 在线设计制作_国内bi软件排名_西安seo_独立站seo优化

在线设计制作_国内bi软件排名_西安seo_独立站seo优化

时间:2025/7/8 5:48:22来源:https://blog.csdn.net/weixin_44682264/article/details/146501339 浏览次数:1次
在线设计制作_国内bi软件排名_西安seo_独立站seo优化

springboot使用StringRedisTemplate对redis数据库进行操作

添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
opsForValue(操作字符串)
/*** @author Gjing**/
@Component
public class RedisString {@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** 新增一个字符串类型的值,key是键,value是值。** set(K key, V value)*/public void set() {// 存入永久数据stringRedisTemplate.opsForValue().set("test2", "1");// 也可以向redis里存入数据和设置缓存时间stringRedisTemplate.opsForValue().set("test1", "hello redis", 1000, TimeUnit.SECONDS);}/*** 批量插入,key值存在会覆盖原值** multiSet(Map<? extends K,? extends V> map)*/public void multiSet() {Map<String,String> map = new HashMap<>(16);map.put("testMultiSet1", "value0");map.put("testMultiSet2", "value2");stringRedisTemplate.opsForValue().multiSet(map);}/***  批量插入,如果里面的所有key都不存在,则全部插入,返回true,如果其中一个在redis中已存在,全不插入,返回false**  multiSetIfAbsent(Map<? extends K,? extends V> map)*/public void multiSetIfAbsent() {Map<String,String> map = new HashMap<>(16);map.put("testMultiSet4", "value1");map.put("testMultiSet3", "value3");Boolean absent = stringRedisTemplate.opsForValue().multiSetIfAbsent(map);System.out.println(absent);}/*** 如果不存在则插入,返回true为插入成功,false失败** setIfAbsent(K key, V value)*/public void setIfAbsent() {Boolean absent = stringRedisTemplate.opsForValue().setIfAbsent("test", "hello redis");System.out.println(absent);}/*** 获取值,key不存在返回null** get(Object key)*/public void get() {System.out.println(stringRedisTemplate.opsForValue().get("testMultiSet1"));}/*** 批量获取,key不存在返回null** multiGet(Collection<K> keys)*/public void multiGet() {List<String> list = stringRedisTemplate.opsForValue().multiGet(Arrays.asList("test", "test2"));assert list != null;System.out.println(list.toString());}/*** 获取指定字符串的长度。** size(K key)*/public void getLength() {Long size = stringRedisTemplate.opsForValue().size("test");System.out.println(size);}/*** 在原有的值基础上新增字符串到末尾。** append(K key, String value)*/public void append() {Integer append = stringRedisTemplate.opsForValue().append("test3", "database");System.out.println(append);}/*** 获取原来key键对应的值并重新赋新值** getAndSet(K key, V value)*/public void getAndSet() {String set = stringRedisTemplate.opsForValue().getAndSet("test", "set test");System.out.println(set);}/*** 获取指定key的值进行减1,如果value不是integer类型,会抛异常,如果key不存在会创建一个,默认value为0** decrement(k key)*/public void decrement() {stringRedisTemplate.opsForValue().decrement("test2");stringRedisTemplate.opsForValue().decrement("test1");}/*** 获取指定key的值进行加1,如果value不是integer类型,会抛异常,如果key不存在会创建一个,默认value为0* * increment(k key)*/public void increment() {stringRedisTemplate.opsForValue().increment("test2");stringRedisTemplate.opsForValue().increment("test1");}/*** 删除指定key,成功返回true,否则false* * delete(k key)*/public void delete() {Boolean delete = stringRedisTemplate.opsForValue().getOperations().delete("test1");System.out.println(delete);}/*** 删除多个key,返回删除key的个数* * delete(k ...keys)*/public void deleteMulti() {Long delete = stringRedisTemplate.opsForValue().getOperations().delete(Arrays.asList("test1", "test2"));System.out.println(delete);}
}
opsForList(操作集合)
/*** @author Gjing**/
@Component
public class RedisList {@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** 在变量左边添加元素值。如果key不存在会新建,添加成功返回添加后的总个数* * leftPush(K key, V value)*/public void leftPush() {Long aLong = stringRedisTemplate.opsForList().leftPush("list", "a");System.out.println(aLong);}/*** 向左边批量添加参数元素,如果key不存在会新建,添加成功返回添加后的总个数* * leftPushAll(K key, V... values)*/public void leftPushAll() {Long pushAll = stringRedisTemplate.opsForList().leftPushAll("list", "e", "f", "g");System.out.println(pushAll);}/*** 向集合最右边添加元素。如果key不存在会新建,添加成功返回添加后的总个数* * rightPush(K key, V value)*/public void rightPush() {Long aLong = stringRedisTemplate.opsForList().rightPush("list2", "a");System.out.println(aLong);}/*** 如果存在集合则添加元素。* * leftPushIfPresent(K key, V value)*/public void leftPushIfPresent() {Long aLong = stringRedisTemplate.opsForList().leftPushIfPresent("list", "h");System.out.println(aLong);}/*** 向右边批量添加元素。返回当前集合元素总个数* * rightPushAll(K key, V... values)*/public void rightPushAll() {Long aLong = stringRedisTemplate.opsForList().rightPushAll("list2", "b", "c", "d");System.out.println(aLong);}/*** 向已存在的集合中添加元素。返回集合总元素个数* * rightPushIfPresent(K key, V value)*/public void rightPushIfPresent() {Long aLong = stringRedisTemplate.opsForList().rightPushIfPresent("list", "e");System.out.println(aLong);}/*** 获取集合长度* * size(K key)*/public void size() {Long size = stringRedisTemplate.opsForList().size("list2");System.out.println(size);}/*** 移除集合中的左边第一个元素。返回删除的元素,如果元素为空,该集合会自动删除* * leftPop(K key)*/public void leftPop() {String pop = stringRedisTemplate.opsForList().leftPop("list2");System.out.println(pop);}/*** 移除集合中左边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。* * leftPop(K key, long timeout, TimeUnit unit)*/public void leftPopWait() {String pop = stringRedisTemplate.opsForList().leftPop("list2", 10, TimeUnit.SECONDS);System.out.println(pop);}/*** 移除集合中右边的元素。返回删除的元素,如果元素为空,该集合会自动删除* * rightPop(K key)*/public void rightPop() {String pop = stringRedisTemplate.opsForList().rightPop("list2");System.out.println(pop);}/*** 移除集合中右边的元素在等待的时间里,如果超过等待的时间仍没有元素则退出。* * rightPop(K key, long timeout, TimeUnit unit)*/public void rightPopWait() {String pop = stringRedisTemplate.opsForList().rightPop("list2", 10, TimeUnit.SECONDS);System.out.println(pop);}/*** 移除第一个集合右边的一个元素,插入第二个集合左边插入这个元素* * rightPopAndLeftPush(K sourceKey, K destinationKey)*/public void rightPopAndLeftPush() {String s = stringRedisTemplate.opsForList().rightPopAndLeftPush("list2", "list3");System.out.println(s);}/*** 在集合的指定位置插入元素,如果指定位置已有元素,则覆盖,没有则新增,超过集合下标+n则会报错。* * set(K key, long index, V value)*/public void set() {stringRedisTemplate.opsForList().set("list2", 2, "w");}/*** 从存储在键中的列表中删除等于值的元素的第一个计数事件。count> 0:删除等于从左到右移动的值的第一个元素;* count< 0:删除等于从右到左移动的值的第一个元素;count = 0:删除等于value的所有元素* * remove(K key, long count, Object value)*/public void remove() {Long remove = stringRedisTemplate.opsForList().remove("list2", 2, "w");System.out.println(remove);}/*** 截取集合元素长度,保留长度内的数据。* * trim(K key, long start, long end)*/public void trim() {stringRedisTemplate.opsForList().trim("list2", 0, 3);}/*** 获取集合指定位置的值。* * index(K key, long index)*/public void index() {Object listValue = stringRedisTemplate.opsForList().index("list2", 3);System.out.println(listValue);}/*** 获取指定区间的值。* * range(K key, long start, long end)*/public void range() {List<String> list = stringRedisTemplate.opsForList().range("list", 0, -1);System.out.println(list);}/*** 删除指定集合,返回true删除成功* * delete(K key)*/public void delete() {Boolean delete = stringRedisTemplate.opsForList().getOperations().delete("list2");System.out.println(delete);}
}
opsForHash(操作hashMap)
/*** @author Gjing**/
@Component
public class RedisHash {@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** 新增hashMap值* * put(H key, HK hashKey, HV value)*/public void put() {stringRedisTemplate.opsForHash().put("hash","hash-key","hash-value");stringRedisTemplate.opsForHash().put("hash","hash-key2","hash-value2");}/*** 以map集合的形式添加键值对* * putAll(H key, Map<? extends HK,? extends HV> m)*/public void putAll() {Map<String, String> map = new HashMap<>(16);map.put("hash-key3", "value3");map.put("hash-key4", "value4");stringRedisTemplate.opsForHash().putAll("hash", map);}/*** 如果变量值存在,在变量中可以添加不存在的的键值对,如果变量不存在,则新增一个变量,同时将键值对添加到该变量。添加成功返回true否则返回false* * putIfAbsent(H key, HK hashKey, HV value)*/public void putIfAbsent() {Boolean absent = stringRedisTemplate.opsForHash().putIfAbsent("hash", "hash-key", "value1");Boolean absent2 = stringRedisTemplate.opsForHash().putIfAbsent("hash", "hash-key5", "value5");System.out.println(absent);System.out.println(absent2);}/*** 获取指定变量中的hashMap值。* * values(H Key)*/public void values() {List<Object> values = stringRedisTemplate.opsForHash().values("hash2");System.out.println(values.toString());}/*** 获取变量中的键值对。* * entries(H key)*/public void entries() {Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("hash");System.out.println(entries.toString());}/*** 获取变量中的指定map键是否有值,如果存在该map键则获取值,没有则返回null。* * get(H key, Object hashKey)*/public void get() {Object value = stringRedisTemplate.opsForHash().get("hash", "hash-key");System.out.println(value);}/*** 获取变量中的键。* * keys(H key)*/public void keys() {Set<Object> keys = stringRedisTemplate.opsForHash().keys("hash");System.out.println(keys.toString());}/***  获取变量的长度*  *  size(H key)*/public void size() {Long size = stringRedisTemplate.opsForHash().size("hash");System.out.println(size);}/*** 使变量中的键以long值的大小进行自增长。值必须为Integer类型,否则异常* * increment(H key, HK hashKey, long data)*/public void increment() {Long increment = stringRedisTemplate.opsForHash().increment("hash", "hash-key2", 1);System.out.println(increment);}/*** 以集合的方式获取变量中的值。* * multiGet(H key, Collection<HK> hashKeys)*/public void multiGet() {List<Object> values = stringRedisTemplate.opsForHash().multiGet("hash", Arrays.asList("hash-key", "hash-key2"));System.out.println(values.toString());}/*** 匹配获取键值对,ScanOptions.NONE为获取全部键对,ScanOptions.scanOptions().match("hash-key2").build()匹配获取键位map1的键值对,不能模糊匹配。* * scan(H key, ScanOptions options)*/public void scan() {Cursor<Map.Entry<Object, Object>> scan = stringRedisTemplate.opsForHash().scan("hash", ScanOptions.NONE);while (scan.hasNext()) {Map.Entry<Object, Object> next = scan.next();System.out.println(next.getKey() + "---->" + next.getValue());}}/*** 删除变量中的键值对,可以传入多个参数,删除多个键值对。返回删除成功数量* * delete(H key, Object... hashKeys)*/public void delete() {Long delete = stringRedisTemplate.opsForHash().delete("hash", "hash-key", "hash-key1");System.out.println(delete);}}
opsForSet(操作set集合)
/*** @author Gjing** 以下可能有部分方法含有参数传Collection的,本案例没有描述,你们可以根据实际参数类型传参**/
@Component
public class RedisSet {@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** 向变量中批量添加值。返回添加的数量** add(K key, V... values)*/public void add() {Long add = stringRedisTemplate.opsForSet().add("set", "a", "b", "c");System.out.println(add);}/*** 获取变量的值** members(K key)*/public void members() {Set<String> set = stringRedisTemplate.opsForSet().members("set");System.out.println(set);}/*** 获取变量中值得长度** size(k key)*/public void size() {Long size = stringRedisTemplate.opsForSet().size("set");System.out.println(size);}/*** 随机获取变量中的某个元素** randomMember(k key)*/public void randomMember() {String member = stringRedisTemplate.opsForSet().randomMember("set");System.out.println(member);}/*** 随机获取变量中指定个数的元素** randomMembers(k key, long count)*/public void randomMembers() {List<String> members = stringRedisTemplate.opsForSet().randomMembers("set", 2);System.out.println(members);}/*** 检查给定的元素是否在变量中,true为存在** isMember(k key, object value)*/public void isMember() {Boolean member = stringRedisTemplate.opsForSet().isMember("set", "b");System.out.println(member);}/*** 转义变量的元素值到另一个变量中** move(k key, v value, k targetKey)*/public void move() {Boolean move = stringRedisTemplate.opsForSet().move("set", "b", "set2");System.out.println(move);}/*** 弹出变量中的元素。当元素全部弹完,变量也会删除** pop(k key)*/public void pop() {String pop = stringRedisTemplate.opsForSet().pop("set");System.out.println(pop);}/*** 批量删除变量中的元素,返回删除的数量** remove(k key, v ...values)*/public void remove() {Long remove = stringRedisTemplate.opsForSet().remove("set2", "b");System.out.println(remove);}/*** 匹配获取键值对,ScanOptions.NONE为获取全部键值对;ScanOptions.scanOptions().match("C").build()匹配获取键位map1的键值对,不能模糊匹配。** scan(K key, ScanOptions options)*/public void scan() {Cursor<String> set = stringRedisTemplate.opsForSet().scan("set", ScanOptions.NONE);while (set.hasNext()) {String next = set.next();System.out.println(next);}}/*** 通过集合求差值。** difference(k key, k otherKey)*/public void difference() {Set<String> difference = stringRedisTemplate.opsForSet().difference("set", "set2");System.out.println(difference);}/*** 将求出来的差值元素保存** differenceAndStore(K key, K otherKey, K targetKey)*/public void differenceAndStore() {Long aLong = stringRedisTemplate.opsForSet().differenceAndStore("set", "set2", "set3");System.out.println(aLong);}/*** 获取去重的随机元素** distinctRandomMembers(K key, long count)*/public void distinctRandomMembers() {Set<String> set = stringRedisTemplate.opsForSet().distinctRandomMembers("set", 2);System.out.println(set);}/*** 获取两个变量中的交集** intersect(K key, K otherKey)*/public void intersect() {Set<String> intersect = stringRedisTemplate.opsForSet().intersect("set", "set2");System.out.println(intersect);}/*** 获取2个变量交集后保存到最后一个变量上。** intersectAndStore(K key, K otherKey, K targetKey)*/public void intersectAndStore() {Long aLong = stringRedisTemplate.opsForSet().intersectAndStore("set", "set2", "set3");System.out.println(aLong);}/*** 获取两个变量的合集** union(K key, K otherKey)*/public void union() {Set<String> union = stringRedisTemplate.opsForSet().union("set", "set2");System.out.println(union);}/*** 获取两个变量合集后保存到另一个变量中** unionAndStore(K key, K otherKey, K targetKey)*/public void unionAndStore() {Long aLong = stringRedisTemplate.opsForSet().unionAndStore("set", "set2", "set3");System.out.println(aLong);}
}
opsForZset
/*** @author Gjing***/
@Component
public class RedisZSet {@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** 添加元素到变量中同时指定元素的分值。** add(K key, V value, double score)*/public void add() {Boolean add = stringRedisTemplate.opsForZSet().add("zset", "a", 1);System.out.println(add);}/*** 通过TypedTuple方式新增数据。** add(K key, Set<ZSetOperations.TypedTuple<V>> tuples)*/public void addByTypedTuple() {ZSetOperations.TypedTuple<String> typedTuple1 = new DefaultTypedTuple<>("E", 2.0);ZSetOperations.TypedTuple<String> typedTuple2 = new DefaultTypedTuple<>("F", 3.0);ZSetOperations.TypedTuple<String> typedTuple3 = new DefaultTypedTuple<>("G", 5.0);Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();typedTupleSet.add(typedTuple1);typedTupleSet.add(typedTuple2);typedTupleSet.add(typedTuple3);Long zset = stringRedisTemplate.opsForZSet().add("zset", typedTupleSet);System.out.println(zset);}/*** 获取指定区间的元素** range(k key, long start, long end)*/public void range() {Set<String> zset = stringRedisTemplate.opsForZSet().range("zset", 0, -1);System.out.println(zset);}/*** 用于获取满足非score的排序取值。这个排序只有在有相同分数的情况下才能使用,如果有不同的分数则返回值不确定。** rangeByLex(K key, RedisZSetCommands.Range range)*/public void rangeByLex() {Set<String> rangeByLex = stringRedisTemplate.opsForZSet().rangeByLex("zset", RedisZSetCommands.Range.range().lt("E"));System.out.println(rangeByLex);}/*** 用于获取满足非score的设置下标开始的长度排序取值。** rangeByLex(k key, range range, limit limit)*/public void rangeByLexAndLimit() {Set<String> zset = stringRedisTemplate.opsForZSet().rangeByLex("zset", RedisZSetCommands.Range.range().lt("E"),RedisZSetCommands.Limit.limit().offset(1).count(2));System.out.println(zset);}/*** 根据设置的score获取区间值。** rangeByScore(K key, double min, double max)*/public void rangeByScore() {Set<String> zset = stringRedisTemplate.opsForZSet().rangeByScore("zset", 1, 3);System.out.println(zset);}/*** 获取RedisZSetCommands.Tuples的区间值。** rangeWithScores(K key, long start, long end)*/public void rangeWithScores() {Set<ZSetOperations.TypedTuple<String>> zset = stringRedisTemplate.opsForZSet().rangeWithScores("zset", 1, 3);assert zset != null;for (ZSetOperations.TypedTuple<String> next : zset) {String value = next.getValue();Double score = next.getScore();System.out.println(value + "-->" + score);}}/*** 获取区间值的个数。** count(k key, double min, double max)*/public void count() {Long zset = stringRedisTemplate.opsForZSet().count("zset", 1, 3);System.out.println(zset);}/*** 获取变量中指定元素的索引,下标开始为0** rank(k key, object o)*/public void rank() {Long rank = stringRedisTemplate.opsForZSet().rank("zset", "a");System.out.println(rank);}/*** 匹配获取键值对,ScanOptions.NONE为获取全部键值对;ScanOptions.scanOptions().match("C").build()匹配获取键位map1的键值对,不能模糊匹配。** scan(K key, ScanOptions options)*/public void scan() {Cursor<ZSetOperations.TypedTuple<String>> zset = stringRedisTemplate.opsForZSet().scan("zset", ScanOptions.NONE);while (zset.hasNext()) {ZSetOperations.TypedTuple<String> next = zset.next();System.out.println(next.getValue() + "-->" + next.getScore());}}/*** 获取指定元素的分值** score(k key, object o)*/public void score() {Double score = stringRedisTemplate.opsForZSet().score("zset", "a");System.out.println(score);}/*** 获取变量中元素的个数** zCard(k key)*/public void zCard() {Long zset = stringRedisTemplate.opsForZSet().zCard("zset");System.out.println(zset);}/*** 修改变量中元素的分值** incrementScore(K key, V value, double delta)*/public void incrementScore() {Double score = stringRedisTemplate.opsForZSet().incrementScore("zset", "a", 2);System.out.println(score);}/*** 索引倒序排列指定区间的元素** reverseRange(K key, long start, long end)*/public void reverseRange() {Set<String> zset = stringRedisTemplate.opsForZSet().reverseRange("zset", 1, 3);System.out.println(zset);}/*** 倒序排列指定分值区间的元素** reverseRangeByScore(K key, double min, double max)*/public void reverseRangeByScore() {Set<String> zset = stringRedisTemplate.opsForZSet().reverseRangeByScore("zset", 1, 3);System.out.println(zset);}/*** 倒序排序获取RedisZSetCommands.Tuples的分值区间值** reverseRangeByScore(K key, double min, double max, long offset, long count)*/public void reverseRangeByScoreLength() {Set<String> zset = stringRedisTemplate.opsForZSet().reverseRangeByScore("zset", 1, 3, 1, 2);System.out.println(zset);}/*** 倒序排序获取RedisZSetCommands.Tuples的分值区间值。** reverseRangeByScoreWithScores(K key, double min, double max)*/public void reverseRangeByScoreWithScores() {Set<ZSetOperations.TypedTuple<String>> zset = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores("zset", 1, 5);assert zset != null;zset.iterator().forEachRemaining(e-> System.out.println(e.getValue() + "--->" + e.getScore()));}/*** 获取倒序排列的索引值** reverseRank(k key, object o)*/public void reverseRank() {Long aLong = stringRedisTemplate.opsForZSet().reverseRank("zset", "a");System.out.println(aLong);}/*** 获取2个变量的交集存放到第3个变量里面。** intersectAndStore(K key, K otherKey, K destKey)*/public void intersectAndStore() {Long aLong = stringRedisTemplate.opsForZSet().intersectAndStore("zset", "zset2", "zset3");System.out.println(aLong);}/*** 获取2个变量的合集存放到第3个变量里面。 返回操作的数量** unionAndStore(K key, K otherKey, K destKey)*/public void unionAndStore() {Long aLong = stringRedisTemplate.opsForZSet().unionAndStore("zset", "zset2", "zset3");System.out.println(aLong);}/*** 批量移除元素根据元素值。返回删除的元素数量** remove(K key, Object... values)*/public void remove() {Long remove = stringRedisTemplate.opsForZSet().remove("zset", "a", "b");System.out.println(remove);}/*** 根据分值移除区间元素。返回删除的数量** removeRangeByScore(k key, double min, double max)*/public void removeRangeByScore() {Long zset = stringRedisTemplate.opsForZSet().removeRangeByScore("zset", 1, 3);System.out.println(zset);}/*** 根据索引值移除区间元素。返回移除的元素集合** removeRange(K key, long start, long end)*/public void removeRange() {Set<String> zset = stringRedisTemplate.opsForZSet().reverseRange("zset", 0, 4);System.out.println(zset);}
}

五大常用数据类型使用场景
  • String

缓存:将数据以字符串方式存储
计数器功能:比如视频播放次数,点赞次数。
共享session:数据共享的功能,redis作为单独的应用软件用来存储一些共享数据供多个实例访问。
字符串的使用空间非常大,可以结合字符串提供的命令充分发挥自己的想象力

  • hash

字典。键值对集合,即编程语言中的Map类型。适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值。适用于:存
储、读取、修改用户属性。也可以用Hash做表数据缓存

  • list

链表(双向链表),增删快,提供了操作某一段元素的API。适用于:最新消息排行等功能;消息队列。

  • set

集合。哈希表实现,元素不重复,为集合提供了求交集、并集、差集等操作。适用于:共同好友;利用唯一性,统计访问网站的所有独立ip;> 好友推荐时,根据tag求交集,大于某个阈值就可以推荐。

  • sorted set

有序集合。将Set中的元素增加一个权重参数score,元素按score有序排列。数据插入集合时,已经进行天然排序。适用于:排行榜;带权重的消息队列。

StringRedisTemplate与RedisTemplate的区别?

两者的关系是StringRedisTemplate继承RedisTemplate。
两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据
RedisTemplate只能管RedisTemplate中的数据。
SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。


友情提示:目前数据类型已经达到八种,本文只讲解了五种常用类型,其余的自行学习
源代码地址:redis-demo

关键字:在线设计制作_国内bi软件排名_西安seo_独立站seo优化

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: