springboot2.1.3 + redisTemplate + Lock 操作 redis 3.0.5
近期在整合springboot + redis 的功能,本来想用原生的jedit api,最后想想有点 low,搜了一把,boot已经提供给我们操作的方法,那就是
使用 redisTemplate 或 StringRedisTemplate, 两者是有区别的,可以看下面的说明
1. 两者的关系是StringRedisTemplate继承RedisTemplate。
2. 两者的数据是不共通的;也就是说StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。
3. SDR默认采用的序列化策略有两种,一种是String的序列化策略,一种是JDK的序列化策略。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的。
引自: https://blog.csdn.net/yifanSJ/article/details/79513179
好了,有关概念的解释不在此处详细说明,这里只是记录如何快速搭建和实现操作redis,先看下我的工程结构,如图:
引入相关jar包,pom.xml如下:
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-redis</artifactId>
- </dependency>
<!-- 因为需要使用lettuce连接池,这个包必须添加 -->- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-pool2</artifactId>
- <version>2.6.1</version><!--$NO-MVN-MAN-VER$-->
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-cache</artifactId>
- </dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-core</artifactId>
- <version>2.9.8</version><!--$NO-MVN-MAN-VER$-->
- </dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-annotations</artifactId>
- <version>2.9.8</version><!--$NO-MVN-MAN-VER$-->
- </dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-databind</artifactId>
- <version>2.9.8</version><!--$NO-MVN-MAN-VER$-->
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>1.18.2</version><!--$NO-MVN-MAN-VER$-->
- </dependency>
- <dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version><!--$NO-MVN-MAN-VER$-->
</dependency>- </dependencies>
配置Redis参数 application.properties:
- # 配置redis参数
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器连接密码(默认为空)
spring.redis.password=
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# 连接超时时间,单位(毫秒)
spring.redis.timeout=5000
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=20000
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=10
# 集群
#spring.redis.cluster.nodes=192.168.211.134:7000,192.168.211.134:7001,192.168.211.134:7002
#spring.redis.cluster.max-redirects=6
创建RedisConfiguration类:
- package com.szl.demo.common.redisConfig;
- import org.springframework.cache.annotation.CachingConfigurerSupport;
- import org.springframework.cache.annotation.EnableCaching;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.data.redis.connection.RedisConnectionFactory;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
- import org.springframework.data.redis.serializer.RedisSerializer;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
- import com.fasterxml.jackson.annotation.PropertyAccessor;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.annotation.*;
- @EnableCaching
- @Configuration
- public class RedisConfiguration extends CachingConfigurerSupport {
- /**
- * @param connectionFactory
- * @return
- * @desc redis模板,存储关键字是字符串,
- * 值jackson2JsonRedisSerializer是序列化后的值
- */
@Bean- public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
- RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
- redisTemplate.setConnectionFactory(connectionFactory);
- // 开启事务
- redisTemplate.setEnableTransactionSupport(true);
- // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
- Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
- new Jackson2JsonRedisSerializer<>(Object.class);
- ObjectMapper objectMapper = new ObjectMapper();
- objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
- jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
- // 使用StringRedisSerializer来序列化和反序列化redis的key值
- RedisSerializer<?> redisSerializer = new StringRedisSerializer();
- // key
- redisTemplate.setKeySerializer(redisSerializer);
- redisTemplate.setHashKeySerializer(redisSerializer);
- // value
- redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
- redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
- redisTemplate.afterPropertiesSet();
- return redisTemplate;
- }
- }
DTO 类:
- package com.szl.demo.common.dto;
- import java.io.Serializable;
- import lombok.Data;
- @Data
- public class UserDto implements Serializable {
- private static final long serialVersionUID = -8858511759866491158L;
- private String userName;
- private Integer userAge;
- }
UserService接口:
- package com.szl.demo.service;
- import com.szl.demo.common.dto.UserDto;
- public interface UserService {
- /**
- * @param userDto
- * @desc 将字符串保存到redis中
- */
- public void saveUserInfoToRedis();
- /**
- * @param key
- * @return
- * @desc 从redis中读取字符串
- */
- public String getUserInfoFromRedis(String key);
- /**
- * @param userDto
- * @desc 将对象保存到redis中
- */
- public void saveUserObject(UserDto userDto);
- /**
- * @param userName
- * @return
- * @desc 从redis中获取对象
- */
- public UserDto findUserObject(String userName);
- /**
- * @param userDto
- * @desc 锁机制保存对象数据
- */
- public void lockOfUserProcess(UserDto userDto);
- }
UserServiceImpl实现接口:
- package com.szl.demo.service.impl;
- import java.util.concurrent.TimeUnit;
- import javax.annotation.Resource;
- import org.springframework.beans.BeanUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.stereotype.Service;
- import com.szl.demo.common.dto.UserDto;
- import com.szl.demo.common.redisConfig.RedisDistributedLock;
- import com.szl.demo.common.util.JsonWare;
- import com.szl.demo.service.UserService;
- import lombok.extern.slf4j.Slf4j;
- @Slf4j
- @Service("userService")
- public class UserServiceImpl implements UserService {
- @Autowired
- private RedisTemplate<String, Object> redisTemplate;
- @Autowired
- private RedisDistributedLock redisDistributedLock;
- /**
- * @param userDto
- * @desc 将字符串保存到redis中
- */
- public void saveUserInfoToRedis() {
- // 判断redis中是否存在key
- boolean isExist = redisTemplate.hasKey("demo_test02");
- if (!isExist) {
- // 保存key,有效期为30秒
String msg = "abc123,你好,welcome.";- redisTemplate.opsForValue().set("demo_test02", msg, 30, TimeUnit.SECONDS);
- } else {
- // 删除key
- redisTemplate.delete("demo哈哈");
- }
- }
- /**
- * @param key
- * @return
- * @desc 从redis中读取字符串
- */
- public String getUserInfoFromRedis(String key) {
- String val = (String)redisTemplate.opsForValue().get(key);
- return val;
- }
- /**
- * @param userDto
- * @desc 将对象保存到redis中
- */
- public void saveUserObject(UserDto userDto) {
- // 判断redis中是否存在key
- boolean isExist = redisTemplate.hasKey(userDto.getUserName());
- if (!isExist) {
- // 保存key,有效期为30秒
- redisTemplate.opsForValue().set(userDto.getUserName(), userDto, 30, TimeUnit.SECONDS);
- } else {
- // 删除key
- redisTemplate.delete(userDto.getUserName());
- }
- }
- /**
- * @param userName
- * @return
- * @desc 从redis中获取对象
- */
- public UserDto findUserObject(String userName) {
- UserDto userDto = (UserDto) redisTemplate.opsForValue().get(userName);
- return userDto;
- }
- /**
- * @param userDto
- * @desc 锁机制保存对象数据
- */
- public void lockOfUserProcess(UserDto userDto) {
- String key = "myLock_" + userDto.getUserName();
- int timeout = 300 * 1000;//超时时间 5分钟
- long value = System.currentTimeMillis() + timeout;
- try {
- // 加锁
- if (!redisDistributedLock.setLock(key, String.valueOf(value))) {
- throw new Exception("对不起,redis被挤爆了,请休息片刻再重试。");
- }
- // 做一些业务相关操作,这里只是demo,随便保存个对象信息
- redisTemplate.opsForValue().set(userDto.getUserName(), userDto, 60, TimeUnit.SECONDS);
- log.info("原来值内容:" + JsonWare.beanToJson(userDto));
- // 修改值,重新保存到redis中
- UserDto dto = new UserDto();
- BeanUtils.copyProperties(userDto, dto);
- dto.setUserAge(30);
- redisTemplate.opsForValue().set(dto.getUserName(), dto, 60, TimeUnit.SECONDS);
- log.info("修改值内容:" + JsonWare.beanToJson(dto));
- } catch (Exception e) {
- log.error("异常发生,信息如下:", e.getMessage());
- } finally {
- // 释放锁
- redisDistributedLock.releaseLock(key, String.valueOf(value));
- }
- }
- }
Controller类:
- package com.szl.demo.controller;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.ModelMap;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RequestParam;
- import com.szl.demo.common.dto.UserDto;
- import com.szl.demo.service.UserService;
- @Controller
- public class DemoController {
- @Autowired
- private UserService userService;
- @RequestMapping(value = "/saveUser", method = RequestMethod.POST)
- public void saveUser(HttpServletRequest request, HttpServletResponse response, ModelMap model) {
- userService.saveUserInfoToRedis();
- }
- @RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)
- public void getUserInfo(HttpServletRequest request, HttpServletResponse response,
- @RequestParam(value = "key", required = false) String key) {
- String msg = userService.getUserInfoFromRedis(key);
- System.out.println(msg);
- }
- @RequestMapping(value = "/saveUserObject", method = RequestMethod.POST)
- public void saveUserObject(HttpServletRequest request, HttpServletResponse response) {
- UserDto dto = new UserDto();
- dto.setUserName("Jimmy Shan");
- dto.setUserAge(21);
- userService.saveUserObject(dto);
- }
- @RequestMapping(value = "/getUserObject", method = RequestMethod.GET)
- public void getUserObject(HttpServletRequest request, HttpServletResponse response,
- @RequestParam(value = "key", required = false) String key) {
- UserDto dto = userService.findUserObject(key);
- System.out.println("姓名: " + dto.getUserName() + ", 年龄: " + dto.getUserAge());
- }
- @RequestMapping(value = "/lockDealWithDemo", method = RequestMethod.GET)
- public void lockDealWithDemo(HttpServletRequest request, HttpServletResponse response) {
- UserDto dto = new UserDto();
- dto.setUserName("JimmyShan");
- dto.setUserAge(16);
- userService.lockOfUserProcess(dto);
- System.out.println("这是lock的demo请求");
- }
- }
RedisDistributedLock类(锁的工具类) :
- package com.szl.demo.common.redisConfig;
- import javax.annotation.Resource;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.stereotype.Component;
- import org.springframework.util.StringUtils;
- import lombok.extern.slf4j.Slf4j;
- /**
- * @author Jimmy Shan
- * @desc Redis 锁工具类
- */
- @Slf4j
- @Component
- public class RedisDistributedLock {
- @Resource
- private RedisTemplate<String, Object> redisTemplate;
- /**
- * @param key redis key, 唯一键
- * @param value redis value, 这里是时间戳
- * @return
- * @desc 加锁 true已锁 false未锁
- */
- public boolean setLock(String key, String value) {
- if(redisTemplate.opsForValue().setIfAbsent(key, value)) { // 对应setnx命令
- //可以成功设置,也就是key不存在
- return true;
- }
- // 判断锁超时 - 防止原来的操作异常,没有运行解锁操作 防止死锁
- String currentValue = (String) redisTemplate.opsForValue().get(key);
- // 如果锁过期
- // currentValue 不为空且小于当前时间
- if(!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
- // 获取上一个锁的时间value
- // 对应getset,如果key存在返回当前key的值,并重新设置新的值
- // redis是单线程处理,即使并发存在,这里的getAndSet也是单个执行
- // 所以,加上下面的 !StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)
- // 就能轻松解决并发问题
- String oldValue = (String) redisTemplate.opsForValue().getAndSet(key,value);
- if(!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
- return true;
- }
- }
- return false;
- }
- /**
- * @param key redis key, 唯一键
- * @param value redis value, 这里是时间戳
- * @return
- * @desc 释放锁 true已释放 false未释放
- */
- public void releaseLock(String key, String value) {
- try {
- String currentValue = (String) redisTemplate.opsForValue().get(key);
- if(!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
- redisTemplate.opsForValue().getOperations().delete(key);// 删除key
- }
- } catch (Exception e) {
- log.error("解锁出现异常了,{}", e);
- }
- }
- }
我们去控制台看下效果
现在我们能看到,value为 "abc123,你好,welcome." 中的 中文字体已经被序列化了, 还有 UserDto对象,是以 json格式存储。
以上属于直连模式,这种方式在访问量不高的时候,足够应付,游刃有余,反之,该如何处理呢 ?
答案是:连接池
下面是如何使用连接池的方法,以上的代码项保持不变,只要修改 “ RedisConfiguration ” 这个类即可,看下面具体实现
使用连接池的 RedisConfiguration 类:
- package com.szl.demo.common.redisConfig;
- import java.time.Duration;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.cache.annotation.CachingConfigurerSupport;
- import org.springframework.cache.annotation.EnableCaching;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.core.env.Environment;
- import org.springframework.data.redis.connection.RedisConnectionFactory;
- import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
- import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
- import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
- import org.springframework.data.redis.serializer.RedisSerializer;
- import org.springframework.data.redis.serializer.StringRedisSerializer;
- import com.fasterxml.jackson.annotation.PropertyAccessor;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import redis.clients.jedis.JedisPoolConfig;
- import com.fasterxml.jackson.annotation.*;
- @EnableCaching
- @Configuration
- public class RedisConfiguration extends CachingConfigurerSupport {
- @Autowired
- private Environment env;
- /**
- * @param connectionFactory
- * @return
- * @desc redis模板,存储关键字是字符串,
- * 值jackson2JsonRedisSerializer是序列化后的值
- */
- @Bean
- public RedisTemplate<String, Object> redisTemplate() {
- RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
- redisTemplate.setConnectionFactory(connectionPoolsFactory());
- // 开启事务
- //redisTemplate.setEnableTransactionSupport(true);
- // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
- Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
- new Jackson2JsonRedisSerializer<>(Object.class);
- ObjectMapper objectMapper = new ObjectMapper();
- objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
- objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
- jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
- // 使用StringRedisSerializer来序列化和反序列化redis的key值
- RedisSerializer<?> redisSerializer = new StringRedisSerializer();
- // key
- redisTemplate.setKeySerializer(redisSerializer);
- redisTemplate.setHashKeySerializer(redisSerializer);
- // value
- redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
- redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
- redisTemplate.afterPropertiesSet();
- return redisTemplate;
- }
- /**
- * @desc 使用jedis pool创建连接(连接池配置)
- */
- private RedisConnectionFactory connectionPoolsFactory() {
- JedisPoolConfig poolConfig = new JedisPoolConfig();
- // 最大空闲连接数, 默认8个
- poolConfig.setMaxIdle(Integer.parseInt(env.getProperty("spring.redis.jedis.pool.max-idle")));
- // 最小空闲连接数, 默认0
- poolConfig.setMinIdle(Integer.parseInt(env.getProperty("spring.redis.jedis.pool.min-idle")));
- // 最大连接数, 默认8个
- poolConfig.setMaxTotal(Integer.parseInt(env.getProperty("spring.redis.jedis.pool.max-active")));
- // 获取连接时的最大等待毫秒数, 如果不超时设置: -1
- poolConfig.setMaxWaitMillis(Long.parseLong(env.getProperty("spring.redis.jedis.pool.max-wait")));
- // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
- poolConfig.setTimeBetweenEvictionRunsMillis(-1);
- // 在获取连接的时候检查有效性, 默认false
- poolConfig.setTestOnBorrow(true);
- // 在空闲时检查有效性, 默认false
- poolConfig.setTestWhileIdle(true);
- JedisClientConfiguration jedisClientConfiguration =
- JedisClientConfiguration.builder().usePooling().poolConfig(poolConfig).and()
- .readTimeout(Duration.ofMillis(Long.parseLong(env.getProperty("spring.redis.timeout"))))
- .connectTimeout(Duration.ofMillis(Long.parseLong(env.getProperty("spring.redis.timeout"))))
- .build();
- RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
- redisStandaloneConfiguration.setDatabase(Integer.parseInt(env.getProperty("spring.redis.database")));
- redisStandaloneConfiguration.setHostName(env.getProperty("spring.redis.host"));
- redisStandaloneConfiguration.setPassword(env.getProperty("spring.redis.password"));
- redisStandaloneConfiguration.setPort(Integer.parseInt(env.getProperty("spring.redis.port")));
- return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
- }
- }
至此,我们就跑起来看效果了,以上是本人经过测试并通过的代码和配置,另外需要说明一点,redis服务器本人使用3.0.5, 之前在使用2.4.5的时候,总是连接死锁(win环境),折腾了许久,
最后还是更新高版本解决问题。
如有朋友参考本人的笔记,有问题可以留言,转载请注明原著,谢谢。
锁来源参考:https://blog.csdn.net/qq_26525215/article/details/79182687
springboot2.1.3 + redisTemplate + Lock 操作 redis 3.0.5的更多相关文章
- 使用Spring操作Redis的key-value数据
前言 最近工作一直忙的不可开交,小Alan已经很久没有和大家分享知识了,在深圳待了两年多,依然感觉自己还是个小菜鸟,工作中还是会遇到很多自己在短期内无法搞定的事情,每当这个时候总是会感觉到很沮丧,就会 ...
- 【快学springboot】13.操作redis之String数据结构
前言 在之前的文章中,讲解了使用redis解决集群环境session共享的问题[快学springboot]11.整合redis实现session共享,这里已经引入了redis相关的依赖,并且通过spr ...
- 使用RedisTemplate的操作类访问Redis(转)
深入理解Spring Redis的使用 (三).使用RedisTemplate的操作类访问Redis 事务需要开启enableTransactionSupport,然后使用@transactional ...
- Spring中使用RedisTemplate操作Redis(spring-data-redis)
RedisTemplate如何检查一个key是否存在? return getRedisTemplate().hasKey(key); 由一个问题,复习了一下redis 抄自: https://www. ...
- springboot之使用redistemplate优雅地操作redis
概述 本文内容主要 关于spring-redis 关于redis的key设计 redis的基本数据结构 介绍redis与springboot的整合 sringboot中的redistemplate的使 ...
- SpringBoot 使用RedisTemplate操作Redis
新版: import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.T ...
- spring-data-redis 中使用RedisTemplate操作Redis
Redis 数据结构简介 Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串).List(列表).Set(集合).Hash(散列)和 Zset(有序集合 ...
- RedisTemplate操作Redis
RedisTemplate Redis 可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串).List(列表).Set(集合).Hash(散列)和 Zset(有序 ...
- Java 使用Jedis和RedisTemplate操作Redis缓存(SpringBoot)
package com.example.redis.controller; import com.example.redis.entity.User; import com.example.redis ...
随机推荐
- openresty开发系列37--nginx-lua-redis实现访问频率控制
openresty开发系列37--nginx-lua-redis实现访问频率控制 一)需求背景 在高并发场景下为了防止某个访问ip访问的频率过高,有时候会需要控制用户的访问频次在openresty中, ...
- VS Code中配置python版本以及Python多版本
VS Code中配置python版本VS Code十分方便配置python的版本:可以选在在本地setting.json或者全局setting.json文件中配置:python.pythonPath在 ...
- 使用EF 4.1的DbContext的方法大全
简述:EF4.1包括Code First和DbContext API.DbContext API为EF提供更多的工作方式:Code First,Database First和Model First. ...
- [LeetCode] 12. Integer to Roman 整数转为罗马数字
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. Symbol Value I 1 ...
- [LeetCode] 202. Happy Number 快乐数
Write an algorithm to determine if a number is "happy". A happy number is a number defined ...
- 【Python学习之二】Python基础语法
环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 python3.6 一.Python的注释及乱码1.单行注释:以#开头 ...
- postman上传文件对参数的contentType类型设置方式
项目中使用postman模拟上传文件接口时,总是不成功,发现content-type设置不对,设置head的contentType后,还是不行,后来无意中发现文件参数默认的content-type类型 ...
- java email发送(附件中文的处理)
这里使用的是commons-email-1.3.2.jar进行的开发,自认为这是简单的邮件发送. package com.yt.base.common; import java.io.Unsuppor ...
- Java开发笔记(一百零六)Fork+Join框架实现分而治之
前面依次介绍了普通线程池和定时器线程池的用法,这两种线程池有个共同点,就是线程池的内部线程之间并无什么关联,然而某些情况下的各线程间存在着前因后果关系.譬如人口普查工作,大家都知道我国总人口为14亿左 ...
- python学习-37 其他的文件处理方法
f = open('test.txt','r+',encoding='utf-8') f.flush() # 刷新 f.readline() print(f.tell()) # 说明光标位置在哪里 ( ...